Home / Legacy / Lesson 8: Finishing the Environment

Lesson 8: Finishing the Environment


In this lesson we will finish the environment by importing all the necessary models to create the village and placing all targets on the scene.

Lesson Outline

Creating the Village

Import all the necessary models to create the village. If you choose to follow exactly the Project Demo, in the end your environment should look something like this.

Lesson 8: Finishing the Environment

The idea is to have three different shooting stages. In each stage the Player should be facing a specific direction and the targets should appear only when the Player is on the correct spot.

In the Project Demo the following stages were created:

Lesson 8: Finishing the Environment

All models used to create the village were downloaded from the Asset Store. Almost all of them are from Unity Technologies from the Shanty Town package:

Lesson 8: Finishing the Environment
Search for Shanty Town on Asset Store

Create your own village with as many shooting stages as you like.

Create a Target Controller

The Target Components are ready: TargetMovement, TargetRotation and TargetCollider. Each one has its own responsibilities and may or may not exist in all targets. For example I am sure that all Targets will have a TargetCollider but not all of them will need a TargetMovement or TargetRotation. When working with such a dynamic structure I like to maintain each component confined to itself and a global one to rule them all. This will be the TargetController.

This new component will be responsible to coordinate all the other ones. External entities will communicate with the target object using this controller and all communication inside the target structure will be done through this one. So create a new script called TargetController.

Create a new Target Root and add the Target object and the duplicate as childs. The TargetController will be applied to this new target root.

Lesson 8: Finishing the Environment

The environment has three different shooting stages. The targets will belong to one of them and will only be active when the stage is enabled. So the main responsibility of the TargetController is to activate the targets at runtime. Add a public method on the TargetController.

Now we need a public reference to the object with the behaviour controllers.

When the activate target method is called we will activate the target object.

The target object should start disabled. Lets make sure we don’t forget this by deactivating the object on the Awake method.

Lesson 8: Finishing the Environment

The TargetController is now responsible for controlling all the existing behaviours. However the target components are still communicating among each other. But I prefer to direct all communication to the main controller isolating each individual component from the others. Each target component should only communicate with the main controller and only the main controller should know about the others.

Right now the TargetCollider component is communicating directly with the other two components.

Lets change this by directing the communication to the main controller. First lets create a public method called TargetWasHit on the Target Controller script.

Now the TargetCollider should call this method when  Hit is called. Since we don’t have a public reference to the controller we will use the GetComponentInParent to find it.

The TargetController is now responsible for dealing with the target destruction. So when this method is called we will just destroy the target GameObject.

On the last lesson we made the target rotate back before being destroyed but I think the behaviour was not as good as I imagined so I lets just the destroy the target automatically.

Now the Target Controller is in full control. The other components are completely isolated from their “siblings”.

Placing the Targets

To place the targets on the scene we will create some prefabs. First we need to make some changes to our target object. Lets start by scaling down a little bit our target.

Lesson 8: Finishing the Environment

If you are still using the old duplicate, create a new one using the new target object hierarchy.

Lesson 8: Finishing the Environment

Create a new Prefab to hold this target configuration. This target will be moving and rotating on the X axis – down/up.

Lesson 8: Finishing the Environment

Make some copies of this prefab and place on the first stage area. Don’t forget to adjust the duplicate position.

Lesson 8: Finishing the Environment

There will be some special cases where the target should not move but only rotate. In these cases you can use the same prefab and just remove the components you don’t need. But if you think you will be using this kind of target multiple times you can also create a new prefab.

Lesson 8: Finishing the Environment

Lets create another prefab. This one will be stationary and only rotating on Y Axis – left/right. To create this new prefab we need to change the target pivot.

Lesson 8: Finishing the Environment

Lesson 8: Finishing the Environment

Lesson 8: Finishing the Environment

Lesson 8: Finishing the Environment

Now that the object is ready to rotate on the right axis lets place it correctly on the scene before creating the prefab. Adjust the initial rotation on the Y axis and the rotation angles on the Target Rotation script. Also disable the movement if you don’t want to target to move.

Lesson 8: Finishing the Environment

To make the target rotate on the other direction just change the rotation angles.

Lesson 8: Finishing the Environment

Use the prefabs and place the targets for each scene. Create a root object to group the targets for each stage. later we will create a Stage Manager that will be applied to this root object.

Lesson 8: Finishing the Environment

Lesson 8: Finishing the Environment

Shooting stuff

Now that we have our weapon working and our targets ready we need to actually be able to shoot and destroy them. So let’s see how to destroy the targets when hit by the Raycast.

In order to destroy the targets we need to change two scripts: Weapon and the TargetRotation.

First we need to change the Weapon script so it calls the Hit method on the TargetCollider when the object is hit.  When hit we check if the hit object has a TargetCollider and if true we call the Hit method.

Add the following code to the Weapon script inside the Raycast if block.

On the third lesson we locked our cage door with a physics object. We also need to shoot this one so the player can exit the cage. Just like we did for the target objects, we need to detect if the Raycast is hitting a physics object. Add the following code to the Weapon script inside the Raycast if block.

Now when the object has a rigidbody we are going to disable the is Kinematic property so the object responds to physics. Add the following inside the if block.

We will also apply  a force in the direction of the raycast. This will make the object being pushed by the “bullet” impact.

We will use the method AddForceAtPosition of the Rigidbody. This method applies a force at a specific point.

void AddForceAtPosition(Vector3 force, Vector3 position, ForceMode mode = ForceMode.Force);

  • Vector3 force – the force to apply, it defines the direction and the magnitude of the force;
  • Vector3 position – the point where we the force will be applied;
  • ForceMode mode – the type of force to apply ( we will leave this empty to use the default one).

First we need to get the force vector. The direction will be a vector drawn between the the hit point and the position of the camera. To get a Vector between two positions we subtract each other.

Check this great article on Vector Arithmetic.

For the force lets create a public variable to hold the value.
Now that we have the necessary variables lets add the full code. Use the normalized direction vector to prevent the force from being influenced by the distance between the objects.
Assign a force value and test.

Lesson 8: Finishing the Environment

We have a problem to correct. First the bullet holes are not following the objects when they move.

Lesson 8: Finishing the Environment

We need to parent them to the object being hit. Add the bullet hole as a child of the hit object on the Weapon Script.

 Adding sound effects

To finish this lesson lets add a hit sound effect to our targets.

We will be using this sound effect.

Download here: 80588^gun_shoot_metal.

Now the first option would be to apply the sound to the target object and play it upon the raycast collision. The problem with this approach is that since we are destroying the object the sound won’t have enough time to play before being destroyed as well.

In these cases I like to create a prefab to play the sound. Then upon collision the prefab is instantiated and automatically destroyed when the sound is over.

Lets create a new GameObject with an AudioSource and the corresponding AudioClip assigned.

Lesson 8: Finishing the Environment

Don’t forget to leave the Play On Awake property enabled. We want the sound to be played as soon as the object is created. But we need a script to destroy the object and the sound is finished.

Create a HitSoundController script and apply it to the prefab. On this script we will verify when the sound is not playing anymore and destroy the object.

Now on the Target Collider script create a public reference to hold this prefab and instantiate when its hit.
Assign the prefab to the target collider script and don’t forget to update all target prefabs by applying the changes.

Lesson 8: Finishing the Environment

Full Codes







Names to keep

What’s next…

On the following lessons we will start creating the game logic.

  • Facebook
  • Twitter
  • Google+
  • Linkedin
  • Pinterest
  • Reddit

Talk to me :)
%d bloggers like this: