So far, the player can throw the ball at the monster, with little effect. If you managed to hit the monster in your testing, you likely noticed the ball just bounces off, which is certainly not the result we are looking for. What we need now is a way of detecting when the ball hits the monster, or the plane for that matter. Fortunately, the Unity physics engine has a couple of methods to determine when an object collides with another object. Here are the standard options:
OnCollisionEnter
: The object has a collider, which makes contact with another game object that also has a collider. The objects will make contact and then push away from each other depending on the force of the collision, and if either or both objects have a rigidbody attached. An object does not need a rigidbody in order to collide, but it does need a collider, as we have seen.OnTriggerEnter
: This occurs when an object has a collider, but the collider is set to be a trigger. A collider set to be a trigger will detect collisions, but then will allow the object to pass right through it. This is useful for things such as doors, portals, or other areas you want to detect when an object enters.As you have already suspected, we will be using OnCollisionEnter
to determine when our objects collide. However, instead of writing a single script for each object we want to check for collisions, we will instead implement a collision event system. The problem with writing a collision script for each object is that you will often end up with duplicate code, in different scripts attached to various objects. Each script then often manages its own collisions but often has different rules depending on what object it collides with. Take a look at the following diagram that shows how this may work:
Example of hard-coded collision scripts
As you can see in the diagram, the Monster and Plane objects both need some of the same code to handle a ball collision. Additionally, the ball object needs to react differently to its hits on the Monster or Plane. If we add more objects to the scene, we would need to expand that script to account for each object collision. We want a generalized way of acting and reacting to collisions that is also extensible.
Instead of writing three custom scripts in order to manage the collisions in our scene, we will use two, one for the collision (action) and another for the object's reaction. The scripts are aptly named CollisionAction and CollisionReaction, and a revised diagram showing them attached to the scene objects is as follows:
CollisionAction and CollisionReaction scripts used in scene
Before taking a closer look at the script code, we will add the collision scripts to the scene. Perform the following instructions to add the scripts to the objects:
Assets/FoodyGo/Scripts/PhysicsExt
folder in the Project window. You will see the CollisionAction
and CollisionReaction
scripts in the folder.CollisionAction
script onto the CatchBall
object in the Hierarchy window. If you don't see the CatchBall
object, just expand the CatchScene
object.CollisionReaction
script onto the CatchMonster
and Plane
objects in the Hierarchy window.Plane
object in the Hierarchy window.
The Collision Reaction component settings
CatchBall
) we want this component to manage reactions for. By checking Destroy Object, we make sure that the ball will now be destroyed when it hits the Plane
. Don't worry about setting the particle settings just yet; we will get to that shortly.CatchMonster
object in the Hierarchy window and repeat step 4.As you saw, it was fairly simple to set up those collision scripts. You may expect those scripts to be quite complex, but fortunately they are quite simple. Open up the scripts in the editor of your choice, and we will review them:
CollisionAction
: This script is attached to objects that are intended to collide with other objects, such as our ball or bullets and so on. The script detects a collision and then notifies objects with a CollisionReaction
component that a collision occurred. Let's take a look at the OnCollisionEnter
method:void OnCollisionEnter(Collision collision) { if (disarmed == false) { reactions = collision.gameObject.GetComponents<CollisionReaction>(); if(reactions != null && reactions.Length>0) { foreach (var reaction in reactions) { if (gameObject.name.StartsWith (reaction.collisionObjectName)) { reaction.OnCollisionReaction(gameObject, collision); } } } } }
This method doesn't actually manage the collision. Instead, it notifies the CollisionReaction
components of the other object it collided with. First, it makes sure that the object is not disarmed. An object is armed when a player engages it and throws it. Next, it grabs all the CollisionReaction
components that may be on the collision object. An object may have multiple CollisionReaction
components attached that react differently for each object. After that, it loops through all the collision reactions and makes sure that object wants to handle collisions by testing the collisionObjectName
. If it does, then it calls the OnCollisionReaction
method.
CollisionReaction
: This handles the messy details of what happens when an object collides with it; the code is fairly straightforward:public void OnCollisionReaction(GameObject go, Collision collision) { ContactPoint contact = collision.contacts[0]; Quaternion rot = Quaternion.FromToRotation(Vector3.up, contact.normal); Vector3 pos = contact.point; if (particlePrefab != null) { var particle = (Transform)Instantiate(particlePrefab, pos, rot); Destroy(particle.gameObject, destroyParticleDelaySeconds); } if (destroyObject) { Destroy(go, destroyObjectDelaySeconds); } collisionEvent.Invoke(gameObject, collision); }
The first part of the code determines the impact point and direction of the collision. Then, it checks whether a particlePrefab
is set. If it is, it instantiates the prefab at the impact point. Then, it calls the Destroy
method with a delay defined in the properties. Next, it checks whether the colliding object should be destroyed. If so, it destroys the object after a delay is defined in the settings. Finally, a Unity Event called collisionEvent
is invoked, and the collision is passed on to any listeners of that event. This allows for other custom scripts to subscribe to this event and handle the collision additionally, as needed. We will use this event to handle the freezing effects on the Monster later.
CollisionEvent
: At the bottom of the CollisionReaction
script, there is another class definition for CollisionEvent : UnityEvent<GameObject, Collision>
, which is just empty. This is the definition for a custom Unity Event we use to notify other scripts or components that a collision has occurred. Unity Event is similar to the C# event or delegate pattern we used earlier but is slower in performance. However, Unity Events can easily be wired up between components in the editor rather than hardcoded in a script, which is essential for any script we want to generalize.3.139.81.58