Hi guys,
i have a little question: how do you decrease the enemy health? Till now i decreased the enemy health inside the script of the player bullet, having a dependecy with the enemy health script but i don’t like this much because good part of my project doesn’t have dependecies thanks to game events and scriptable objects. Anyway, do you decrease the enemy health inside the bullet script checking collision.tag == enemy or inside enemy health script checking collision.tag == playerBullet or even another method?
Thanks
The enemy should not deal with how much damage he receives - this information comes form the bullet, meaning the bullet should handle the damage calculation and thus check for collision. This also allows for more complex behavior if needed, where the bullet could bounce off, explode, deal different amounts of damage and so on, depending on what kind of surface or enemy it hits.
There may or may not be certain reasons to do it the other way around, but i cant really think of any right now. If i’m missing something i’m pretty sure somebody will add it tho.
Yeah i tought the same thing but i asked because i got stucked on a thing that i want to add. I tried to add a blinking effect on the enemy sprite when getting hit, so i added the code for this inside the script bullet under the collision with the enemy. The problem is that i used coroutine that is called on collision and set the sprite color to white and then reset the sprite to default but this doesn’t work because the coroutine doesn’t finish it’s execution because the bullet object is destroyed. In fact just the first portion of code of the coroutine is executed because the bullet object still exist but on the next update not so the coroutine expires too. Do you have any idea how could i do this?
This functionality should be part of the enemy, not the bullet. After all, the enemy does something (blinking).
If you have multiple enemies, create a base class ‘Enemy’ which handles common functionality. Your specific enemies (Wolf, Zombie, …) derive from this class and thus all contain its functionality + their own. The enemy base class could then have a function to ‘Blink()’, which gets called from the bullet if it collides with an object of type Enemy, and then starts your coroutine or does whatever else. In the same way you should apply your damage actually. You wouldnt just do ‘enemy.hp -= 5’ in the bullet script, you would call enemy.ReceiveDamage(bulletDamage). The ReceiveDamage function would then decrease the Hp of your enemy, check if it’s still alive, and in your case call the Blink() function internally.
You always want things to be modular and check what belongs together. Taking damage always causes an enemy to blink and lose health + potentially die, so it’s a) functionality of the enemy and b) always executes together.
This functionality, wrapped in the ‘ReceiveDamage’ function can now be accessed by outside sources, like your bullet, or the floor if you step on lava or some trap. It makes your code reusable, and receives variables to the behavior as parameters, in this case the damage received…
Hope this helps
Yeah, this helps me a lot. Till now i didn’t code object oriented, i just learned what i needed and started to code. Guess i have to study how to use classes in c# and then rewrite all my scripts. For example i have 3 types of enemies (small, medium, big) and all have 3 main scripts: movement, shooting, management where movement and shooting are different scripts and management is the same because it just checks hp inside update and handle death + death animation. Movement and shooting are different scripts because all enemies have different path and shooting. With classes i could handle this with an abstract enemy class with some abstract methods like movement and shooting and inherit from enemy class the subclasses small enemy, medium enemy etc, right?
Yes, you could implement your redundant code in the base class, then override or add to everything that needs to change for Small, Medium and Large enemies. Also adds the advantage of keeping the files smaller, thus easier to maintain, since each (sub)class only needs to add what actually defines the new type.
While you are at it, you may want to loot into interfaces, which can be helpful (especially when planning the project beforehand).
Thanks for the huge help. I would like to
Thanks for the huge help. I would like to ask you one more thing. Till now i coded normally having different scripts like movement1, movement2, etc… and attaching these scripts to different types of enemies for example:
Small Enemy OBJ
-movement1 script
-shooting1 script
Big Enemey OBJ
-movement2 script
-shooting1 script
So these two enemies have just different path. The question is: could it be there messy code with classes because i would just have 1 script containing all the behavior of an enemy? I would have a script like this, right?:
Enemy Script
-movement
-shooting
In most situations i would probably just have one movement script that can be parametrized and configured as you need it (different modes and so on). You then create a small enemy gameobject, attach all required scripts, edit the inspector values to your liking, and make the whole thing into a prefab. You can then use this prefab whenever you need it and it’s already set up exactly as you want it (plus if you want to change whatever a small enemy is, you just need to edit this prefab). Prefabs, in Unitys script based workflow, are a bit similar to objects in object oriented programming. You have types, can work with inheritance and attach additional functionality.
For a more code based solution, i would probably make Movement and Shooting into interfaces. With ‘Enemy’ being your abstract base class for enemies, a SmallEnemy would be defined as SmallEnemy : Enemy, iMovement, iShooter;
Other enemies, players or npcs, could implement a different set of interfaces, thus having different functionality.
Take this information with a grain of salt, as i mostly worked on algorithms (terrain generation and so on) in Unity so far, so i didnt exactly put a whole lot of thought into class hierarchy for something like RPGs. This would be closer to how i would implement something like this outside of Unity. There may be a more state of the art solution tailored to Unity, but it would probably go more in the direction of the previously mentioned prefab approach.
Hope i didnt miss the point of your question. There are really quite a few ways to do things ‘correctly’, and each may have their own advantages or disadvantages depending on your situation. In the end, if it works and performance is sufficient for your needs, then it’s a good solution, even if on paper there may exists a ‘better’ one.
Yeah that’s a good idea but i didn’t understand much the utility of interfaces. I know how they works but for example every type of enemy would move and shoot so i don’t get the difference using them or not. I would get something like:
Small Enemy: Enemy, iMovement, iShooting
//All the movement and shooting code here
Isn’t the same thing of having, with movement and shooting abstract methods
Small Enemy: Enemy
//All the movement and shooting code here
What i mean is that like i did till now i think i “simulated” a class because i have different scripts for the movements and was attaching them to a certain type of enemy and this also for other things like shooting. With class i would obtain the same “behavior” but without redundant code and all the movement code and shooting in one script that is just “Small Enemy” and not “SmalEnemyMovement” and “SmallEnemyShooting”, right?
I like to use a struct to carry damage information. For instance, in my game I have a struct
public struct sfDamage
{
public Principality principality;
public float damageValue;
public float pushback;
public Transform sender;
public bool ignoreDefense;
public int reactionID;
}
Then, any attack I need can use a sfDamage object that I can set the damage values etc in a prefab, then all I need to do is set the sender when the attack is used/spawned. The “Principality” is an enum I created for element types.
Edit* Forgot to add that then you just make a function that accepts the struct as a parameter and handle it inside the function
What I would do is, only have your Movement class, not SmallEnemyMovement and BigEnemyMovement. Then you make a ScriptableObject called MoveConfiguration. In your project you create different instances of the MoveConfiguration scriptableobject, one called SmallEnemyMovement, BigEnemyMovement, PlayerMovement etc. Then on your Movement script you give it a reference to MoveConfiguration. So if you have a BigEnemy in the scene, its Movement component, you set the configuration to BigEnemyMovement. So you only have the one Movement C# script, and the backing MoveConfiguration scriptable object, but multiple versions of the data that you can assign and tweak via the inspector. For something like MaxSpeed, inside the Movement script it would be like myMovementConfiguration.MaxSpeed
. Looking at the local reference to MovementConfiguration and getting the different values off that.
This way wouldn’t i get the same path but just with different values like speed? BigEnemyMovement and SmallEnemyMovement have a completly different code. Am i missing something?
As for your last statement, yes, you would effectively have it all in one class to reduce redundancy.
As for your confusion about interfaces: for the Enemy class it changes nothing. It just goes one step further on the road to reduce code-redundancy and increase flexibility and maintainability.
Imagine you introduce a new type NPC. NPCs are non-killable, thus dont require HP. They also (in this example) do not shoot, but can move. Now you could create a new class NPC, which implements the movement interface but not the shooting interface.
In reality you would build the entire thing into a class hierarchy. NPC would be the base class. It implements the iMovement interface and defines whatever else is the same for every NPC in your world. Deriving from that base class, we could have something like KillableNPC’s, who add the whole HP and ReceiveDamage() concept to the mix. Enemy would then be a child class to KillableNPC, adding things like ‘Attack()’ or, for example, the iShooting interface.
You end up with a class system where you can be pretty flexible about what your entities are supposed to be able to do or not do. Some may be able to move, some not, others can shoot or not… or some mix of the two, and any other interfaces you may add.
Now, in the example above you could still argue that you could directly add the movement code to the base NPC class, and the shooting code to the Enemy class, however you could later still arrive in a situation where two separate branches of children from the NPC class require the same interface. Then you would be in the situation where you either need to duplicate code, or use interfaces. One example would be that there could be invisible enemies, as well as other invisible NPCs (not the base NPC class, but some other NPCs down some other branch than KillableNPC). You couldnt add the functionality directly to the NPC class, since that would literally give every entity in your system the functionality to be invisible. You couldnt just add the code to Enemy, since that would leave out the NPCs needing this functionality.
Hope this example makes it a bit more clear where the strengths of using interfaces are. Keep in mind that it’s mostly about writing clean code, thus improving maintainability. You could still implement it in a gazillion other ways, and depending on the scope of your project may not require this approach at all. I just thought it would be worth looking into for you.
Sorry, I assumed they moved the same, just different in terms of things like speed and turning. You’re right it would only be different values. If the actual logic is different, yeah you’d need multiple scripts. But I wouldn’t think of it in terms of SmallEnemyMovement, I’d call it ChargeAtPlayer versus MaintainDistance scripts.
This definitely helps me a lot and i think i understood the difference. I could avoid the use of interface like invisible and just write the method invisible inside the type of enemy class but it would be better to say that it implements the interface invisible and then write the code because the class must implement that method
Dude it is your project so do it however you want, but don’t do this! Make an Invisible component. If you want invisible enemies, add the component to their gameobject. Same for invisible traps, invisible coins…
I know but i would like to learn the best way to code in Unity. Till now i would have do that like you said by just adding a script that do that but with classes and interfaces things change. There would be no point to use classes if when i want to add something i use a different script
If you want to see how Unity thinks it should be done, look at how they structure a new scene. They put the Camera, Transform, and AudioListener all as different classes, all on the same gameobject. The camera can move not because it implements IMove, or Camera inherits from some base class that has movement, but because the behavior is tacked on with the transform component and the relationship is implicit. If you really like the interface idea, take a step back and look at it from a bigger picture: the gameobject implements movement behaviour by adding the transform component the same way a class can implement IMove by adding a Move() function.
So you suggest to do like i did till now? Using for example 3 different monobehavior scripts like movement1, movement2, movement3 and attach a type of movement to a certain enemy? If you read my first question how would you handle it? Because i got stucked there. I use a prefab shot that has shot script component where i handle how much damage it does and check with what collides. If collides with an enemy it search the EnemyHealth component where hp are stored and decrease them. I tought it was all fine but when i tried to add a blinking effect got stucked because didn’t know how to check when the enemy was damaged or not, i could handle it inside the shot script but i know that’s not the right way. Maybe instead of decreasing enemy hp i should call a function TakeDamage and then inside enemy health script handle all the behavior when taking a damage?
I searched and found this https://discussions.unity.com/t/635782
So you suggest to go for a component based architecture instead of classes?