- Home /
where to trigger which collision event?
Hello, I know that there is maybe no "one and only" answer to this question but i cant get my head around collision events and rigidbodies.
I am working an a top down shooter. I have the player, collectibles, enemies and bullets.
Is there a preferable way of composing those 4 Objects in terms of rigidbodies, triggers, colliders and so on? Should only the player and enemy have a rigidbody? Should everything have a rigidbody? When the enemy and the player collides, the player get damaged. Should i trigger the event on the player via code or should i trigger it on the enemy via code? Both get knocked back. Should i trigger the player's knockback on the player and the enemie's knockback on the enemy? or everybody only handles their own stuff? Should bullets be trigger? Collectibles be trigger?
I get my code to work but its really messy.
I cant find any best practice for all of this stuff. I know its not a real question but maybe someone can explain the whole architectural idea to me or share a link.
Answer by Captain_Pineapple · Feb 11 at 03:30 PM
Hey there,
a disclaimer up front: you are right, there is no "correct" answer to this. But there are some design patterns you can follow which have been recognized as being "good".
That being said:
In general most stuff boils down to some easy rules:
Keep your code "D.R.Y." (Don't repeat yourself)
This is important to keep your code maintainable. So any form of behaviour should if done right only be written once.
Avoid hard dependencies
This is important as it often simplifies your code and enables you to reuse it easily in other places. An example: your projectile can do mutliple checks on impact. It can check the tag of an object and so on but in the end if you will probably end up with a GetComponent<Player>().DoSomething()
call else if GetComponent<Enemy>().DoSomething()
. This is the point where an Interface or object inheritance comes in handy.
In my game i handle this by deriving all objects that are supposed to be descructible from a common class DestructibleObject
which is a Monobehaviour. This class automatically gives a derived class attributes like health
or isDead
as well as some function like applyDamage(float value)
.
What this in return helps with is thta your call from earlier on Projectile impact reduces itself to: GetComponent<DestructibleObject>().applydamage(value)
This way you can automatically make everything in your game interactable with your projectiles by simply deriving from DestructibleObject
A similar behaviour can be achived by introducing an interface IDamagable
so your projectiles can check for GetComponent<IDamagable>().applydamage(value)
. (same as before you can then make anything damagable by making it implement the IDamage
interface.
That being said lets apply that to your question if not already done:
Should i trigger the player's knockback on the player and the enemie's knockback on the enemy?
Depends.
As already pointed out it is easy to give your objects an Interface IKnockbackable
for which existance you can check on impact. If it exists, call the knockback function on said object. This means however that you have to reimplement the function on each object again. An more DRY solution would be to have your own "knockback" script which you attach to your objects. Check for its existance and apply knockback if it is there. Pros: You can adjust knockback for each object by some script values. You can add knockback to any object by just adding a script. Cons: Each knockback behaviour is the same. If the knockback should be different for some object then that calls for a new script.
Should only the player and enemy have a rigidbody? Should everything have a rigidbody?
This depends on how you move things. Do you want to make it physics based? Then give stuff that moves a rigidbody. If not, then don't - except you need OnCollision methods, then you need at least one Rigidbody. As the player is most likly to be involved in these collisions give your player one. If you want knockback on each of them, then you probably are using physics based movement and thus also your enemys should have a rigidbody.
When the enemy and the player collides, the player get damaged. Should i trigger the event on the player via code or should i trigger it on the enemy via code?
I personally would do it half half. Enemy collides with something, the event for collision triggers and the enemy checks for what it collided with and does something accordingly (e.g. call applydamage
on some destructible object). But this is a matter of taste here, the other way round can be just as good. Putting everything on the player may clutter the collision method though as you might have to differentiate between a lot of different objects you could collide with. So to keep things clean it might be better to split that up.
Should bullets be trigger?
Imo no. I personally advise to not use any collision based bullets but instead go for raycasts. The reason for this is that unity physics can be somewhat buggy and imprecise for small fast objects. So calculating a raycast each frame is a more reliable way. (even though it might cost a bit more performance)
*Should collectibles be triggers?`
Why not. If there is no reason for them to have a "solid" form then make them triggers. this is the best argument there is pro/con in this case.
I will end my throwup of words here, let me know if that helped or if something was unclear. I hope it all makes sense.
Thank you very much. Thats a very good and comprehensive answer. I really appreciate it. The solution with the Interface is a good one and i think that now i have a better understanding on how to structure my functions.
Your answer
Follow this Question
Related Questions
Why is there no Rigidbody2D.SweepTest() ? 1 Answer
rigidbody2D.addforce in collider 1 Answer
2D motion/collision: physics, or direct translation? 2 Answers
2D Mouse Look with Collisions 1 Answer