Vous êtes sur la page 1sur 17

Unity3D Tank Tutorial

A tutorial on how to create the basic functions of a tank using Unity3D.

Created by Kevin and Colin Hopcraft.

Contents

1.
2.
3.
4.
5.
6.

Introduction
How Real Tanks Compare
How to Control the Tank in this Tutorial
Getting Started: Setting up the Scene
Applying the Scripts to the Tank
Explanations of the Scripts
a. Movement
b. Turret Rotation
c. Gun Rotation
d. Shoot
e. Tank Shell
f. Additional Tank Shell Information
7. Conclusion

p.3
p.3
p.4
p.5
p.8
p.10
p.12
p.12
p.13
p.14
p.16
p.17

Introduction
This tutorial will guide you through the steps to give a basic model tank movement and
firing function, such that you could use in a game. The tank and other aspects of the
tutorial have all been created and included; you need only follow directions. This tutorial
is for those who are already familiar with Unity3D and Javascript (sometimes referred to
as Unityscript). It is not intended to teach you how to build models or how to write script,
but rather will show you how to use existing models and some theories of scripting to
achieve our objective, that is to make a working tank.
There are two versions of the project being offered. The included project is incomplete:
It has all the necessary components, such as models and scripts, but must be
assembled and set-up by following the tutorial. The second, separately available project
is a completed work that may be used as a reference point while working through the
tutorial. This separate project already functions fully and can be used as instant
gratification for those who want to try the finished product.
The tutorial was to focus on a vehicle of our choice; we could have chosen any vehicle,
from a skateboard to a jumbo jet. We chose to focus on a tank. Like many different
vehicles, the properties of tank movement are unique and interesting in the real world,
and so make for an interesting adaptation to computer games. This tutorial however,
focuses not on making the tank realistic but rather making it fun, as though it were in a
game. Ultimately how fun a game is has less to do with how realistic it is that one might
expect - at least in our experience. This is one reason we chose to use a model tank
that is simplistic - there are no actual treads, for example. Making a tank with treads
would be a great challenge, and using a model with that level of detail would make this
tutorial too involved and the reader might be left overwhelmed. So the tank in the project
is a simple one, but it still performs well.

How Real Tanks Compare


Real tanks use combustion engines to power hydraulic motors that turn geared wheels.
These geared wheels turn treads made up of many plates of metal that ride along other
passive wheels to maintain the treads shape. The purpose of the treads is to provide a
very large surface with which to achieve traction. This surface is so large that most any
terrain can be traversed, even though tanks are typically extremely heavy.
The passive wheels that guide the treads are often designed with the ability to move
vertically, enabling them to give to the shape of the terrain and allow the treads to
maintain traction on uneven surfaces.
The model tank used in this tutorial has no actual treads. Instead it has been given
shapes and textures that give the impression of treads. The shapes also do not change
as the tank goes over different shapes of terrain there are no wheels to give and no

actual treads to change shape. If the tank did have actual treads it still would not have
much suspension due to the overall shape of the treads being symmetric along the
horizontal plane, making them more akin to the treads found on excavators.
With all treaded machines, including tanks and excavators, the principal of movement is
the same. Each tread is controlled independently to give the vehicle its desired motion.
The two treads both move forward together to move the vehicle forward, and move
backward to reverse the vehicle. To make a right turn the left tread continues moving
forward while the right is either slowed or stationary. To make a left turn the right tread
continues to move forward while the left is slowed or stationary. When one tread is
stationary it acts as a pivot, stopping that side of the vehicle so that the other side may
move around it, thus turning the vehicle. The same effect works in the reverse direction,
where a tread may move backward while the other is slowed or stationary. There is also
a way to make treaded vehicles rotate in one spot, and that is to move one tread in the
opposite direction to the other tread. For example, moving the left tread forward and the
right tread backward would cause the vehicle to rotate to the right.
Real machines often have multiple and sometimes variable speeds to make the motion
more precise. In our tutorial the movement is produced using only a single speed, but by
choosing to move forward or backward while turning, or to simply turn, one can make
the tank go forward, backward, forward and left, backward and left, forward and right,
backward and right, and rotate right or left in one spot. This makes for a flexible range of
movement that is a fair simulation of how actual treaded vehicles feel.
How to Control the Tank in this Tutorial
There are nine keys used to operate the tank in this project. The tank is moved using
the Up, Down, Left and Right arrow keys. Pressing Up or Down moves the tank ahead
and back. Pressing the Left or Right keys at the same time will steer the tank. Pressing
the Left or Right keys alone will make the tank rotate. The Gun Turret is rotated by
pressing the A and D keys. The Gun is aimed higher or lower using the W and S keys.
The Space Key fires the projectile.

Getting Started: Setting up the Scene

First, start Unity3d, then from the application open the project folder that contains the project file. Once
open, look in the Project tab for the Models folder and open the Tank folder within.
In the Tank folder there
is an object named
Tank with a blue box for
an icon. Drag this object
into the scene to place
the tank model.

Look at the Hierarchy tab and select the tank. In the Inspector tab set the x, y and z coordinates of the
Position to 0. Select the Scene view and press the F key to focus on the tank object.

From the Menubar or


Toolbar (Mac and
Windows systems)
select Component, then
Physics, then
Rigidbody. A window
will appear to tell you
that the object is losing
prefab - click okay. This
window will only appear
once during this tutorial.
The Rigidbody
component gives the
tank object gravity and
physics.

In the Hierarchy tab


click the triangle beside
the Tank object and
select Body from the
list. Again, from the
Menubar or Toolbar
select Component,
Physics and Box
Collider. This allows the
rough shape of our tank
to collide with the terrain
in the scene. With Body
still selected in the
Hierarchy tab, change
the y value under Size
in the Inspector tab to
0.75.

From the Game Object


menu item select Create
Empty. A new object
named Game Object will
appear in the Hierarchy.
Name this object Turret
Rotator.

Now drag this object to


the Tank object in the
Hierarchy. It will be
added to the Tank
object. Select the Turret
Rotator and in the
Inspector tab set the x,
y and z coordinates of
its Position to 0.

In the Hierarchy drag the Turret object into the


Turret Rotator object.

Create a new empty object and name it Gun Object.


Drag the Gun Object into the Tank Object. Select
the Gun Object and set its x and z coordinates to 0,
then set the y coordinate to 0.2697082. The reason
the y coordinate is different is because this places
the Gun Object at the same height as the gun in the
tank Object.

Now drag the two


objects named Inside
Gun and Outside Gun
into the Gun Object.
Drag the Gun Object
into the Turret Rotator
object. Make a new
game object and name
it Fire. Drag the Fire
object into the Gun
Object within the Turret
Rotator object. Set the x
and y coordinate
positions of the Fire
object to 0 and set the z
coordinate to 1.35.

Now we have made the tank ready for the scripts we will give it.

Applying the Scripts to the Tank

Click on the Tank


object in the
Hierarchy. In the
Menubar or Toolbar
select Component,
Scripts to open the
list of scripts and
select Movement.
Select the Turret
Rotator object and
do the same to open
the list of scripts and
select Turret
Rotation. Select the
Gun Object give it
the script Gun
Rotation. Select the
Fire object and give
it the script Shoot.

While Fire is
selected open
Component, Audio
and select Audio
Source. This Audio
Source component
allows the Fire
object to use a
sound.

In the Inspector for


the Shoot script,
select the Tank
Shell game object
variable. Click on
the variable to
change it and from
the list select the
Tank Shell prefab.
Below the Tank
Shell variable select
the Boom Noise
variable and click on
it to change it.
Select the Tank Fire
sound. Below Audio
Source in the
Inspector make sure
Play on Awake is
unchecked.

Select Game
Object, Create
Other and Camera.
The object Camera
appears in the
Hierarchy. Drag the
Camera object into
the Turret Rotator
object. With the
Camera selected
set its x coordinate
to 0, y to 1.75 and z
to -3.95.

At this point the tank is functional and can be tried by pressing the play button.

Explanations of the Scripts


The following is the Movement Script. This script determines the movement of the tank.
The variables:
var moveAcceleration : float = 3;
This variable is the speed at which the tank will accelerate every
second.
var moveDecceleration : float = -3;
This variable is the speed at which the tank will decelerate every
second.
var tanksVelocity : float = 0;
This is the variable that controls how fast we move. If it is positive
we move forward, if it is negative we move backwards.
var maxSpeed : float = 5;
This is the speed we do not want to exceed.
var rotSpeed : float = 30;
How fast we want to rotate our tank left or right.
var jitControl : float = 0.02;
This is the lowest value the tanksVelocity variable can be before it
is set back to 0, this is to stop the tanks movement from jittering.
Code chunks:
transform.Translate(Vector3(0, 0, tanksVelocity * Time.deltaTime));
This simply states that this transform, will move at the speed of
tanksVelocity on the z axis, every second.
If tanksVelocity is negative, the transform will move in reverse
instead. Time.deltaTime simply spreads the tanksVelocity over one
second.
if (tanksVelocity <= jitControl && tanksVelocity >= -jitControl) {
tanksVelocity = 0;
}
This chunk of code states that if tanksVelocity is less than or equal
to jitControl, and greater than or equal to negative jitControl,
tanksVelocity will be set to 0.
if (Input.GetKey (KeyCode.UpArrow)) {
If the user is holding down the up arrow key on the keyboard.
if (tanksVelocity <= maxSpeed) {

tanksVelocity += moveAcceleration * Time.deltaTime;


}
If tanksVelocity is less than or equal to maxSpeed, add
moveAcceleration to the variable every second.
} else if (Input.GetKey (KeyCode.DownArrow)) {
Up arrow is not being held down, then if the down arrow is being held
down.
if (tanksVelocity >= -maxSpeed) {
tanksVelocity -= moveAcceleration * Time.deltaTime;
}
If tanksVelocity is greater than or equal to -maxSpeed, subtract
moveAcceleration to the variable every second.
} else {
If the up arrow and down arrow are not being held down.
if (tanksVelocity > 0) {
If tanksVelocity is greater than 0.
tanksVelocity += moveDecceleration * Time.deltaTime;
tanksVelocity will have moveDecceleration added to it every second.
Since moveDecceleration is negative, tanksVelocity will go down every
second.
} else if (tanksVelocity < 0) {
If it is not greater than 0, check if it is less than 0.
tanksVelocity -= moveDecceleration * Time.deltaTime;
tanksVelocity will have moveDecceleration subtracted from it every
second.
Since moveDecceleration is negative, tanksVelocity will go up every
second.
The following is to make sure when you are reversing and turning, that
you turn in the correct direction.
if (Input.GetKey (KeyCode.LeftArrow)) {
if (Input.GetKey(KeyCode.DownArrow)) {
transform.Rotate(Vector3(0, rotSpeed * Time.deltaTime, 0));
} else {
transform.Rotate(Vector3(0, -rotSpeed * Time.deltaTime, 0));
}
}
Makes sure that if you are holding down the left and down arrow keys,
you rotate right.

But if you are just holding down the left arrow key, you rotate left.
This makes the tank behave as expected. Compare to the way a car works
where if you are reversing and the steering wheel is to the left, the
car will travel to the left, but it will be rotating and the front
will face to the right.
if (Input.GetKey (KeyCode.RightArrow)) {
if (Input.GetKey(KeyCode.DownArrow)) {
transform.Rotate(Vector3(0, -rotSpeed * Time.deltaTime, 0));
} else {
transform.Rotate(Vector3(0, rotSpeed * Time.deltaTime, 0));
}
}
The opposite of the previous chunk of code.

The following is the Turret Rotation script. This script determines the rotation of the
turret.
var rotSpeed : float = 30;
The speed at which the Turret will rotate.
if (Input.GetKey (KeyCode.D)) {
If the D key is held down.
transform.Rotate(Vector3(0, rotSpeed * Time.deltaTime, 0));
Rotate the turret to the right at the speed of rotSpeed, every second.
if (Input.GetKey (KeyCode.A)) {
If the S key is held down.
transform.Rotate(Vector3(0, -rotSpeed * Time.deltaTime, 0));
Rotate the turret to the left at the speed of rotSpeed, every second.

This is the Gun Rotation script and determines the movement of the gun.
var rotSpeed : float = 15;
The speed at which the gun will rotate.
var thisRotation : float = 0;
The amount our gun has already rotated. This is important
because we need to restrict how far we can rotate our gun in order to
prevent it from moving through the body of the tank.

Code chunks:
if(Input.GetKey(KeyCode.W)) {
If the W key is being held down.
if(thisRotation > -11) {
If thisRotation is greater than -11.
transform.Rotate(Vector3(rotSpeed * Time.deltaTime, 0, 0));
Rotate the gun downward at the speed of rotSpeed every second.
thisRotation -= rotSpeed * Time.deltaTime;
Subtract thisRotation by rotSpeed every second, to make sure we can
stop the rotation when needed.
if(Input.GetKey(KeyCode.S)) {
If the S key is being held down.
if(thisRotation < 89) {
If thisRotation is less than 89.
transform.Rotate(Vector3(-rotSpeed * Time.deltaTime, 0, 0));
Rotate the gun upward at the speed of rotSpeed every second.
thisRotation += rotSpeed * Time.deltaTime;
Add rotSpeed to thisRotation every second.

This is the Shoot script and determines the way the gun fires.
var tankShell : GameObject;
This variable is the game object the gun shoots.
var boomNoise : AudioClip;
This is the sound we play when the gun fires.
var timer : float = 1;
This is the timer that has to reach timerMax before we can shoot. It
is set at a default of 1 so we can shoot right away.
var timerMax : float = 1;
This is the delay before we can fire again. This simulates time to
reload the gun.
var powerOfShot : float = 30;
This is how fast the projectile will be shot. I recommend this speed
for realism, but it is fun to play around with different values.

Custom functions:
shootProjectile()
This is our custom function that shoots the projectile when we call
it.
Code Chunks:
timer += 1 * Time.deltaTime;
Every second, the timer variable has a value of +1 every second.
if (Input.GetKey(KeyCode.Space)) {
While space is held down.
if(timer >= timerMax) {
If timer is greater than or equal to timerMax.
shootProjectile();
This goes to our shootProjectile function that we made for this
script.
timer = 0;
Sets the timer variable to 0.
var shellInstance = Instantiate(tankShell, transform.position,
transform.rotation);
Creates an instance of the tankShell variable, at the position and
rotation of the object with this script.
audio.PlayOneShot(boomNoise);
Plays the noise held in the boomNoise variable.
shellInstance.rigidbody.AddRelativeForce(Vector3.forward *
powerOfShot, ForceMode.Impulse);
Gives the last created shell instance a force of powerOfShot, once.

This is the Tank Shell script and determines what happens to the shell projectile.
var lifeTimer : float = 0.0;
The variable to tell us how long this shell (projectile) has been
alive.
var lifeTimerMax : float = 12.0;
The max amount of time this shell is allowed to exist before being
destroyed.

var explosionRadius : float = 5.0;


The radious of the full effect of the explosion.
var explosionPower : float = 350.0;
The full power of the explosion.
var explosion : GameObject;
The particle system that replaces the shell object once we hit
something.
custom functions:
explosionThing()
The custom function that is used when we want our projectile to
explode.
code chunks:
var thisDirection : Vector3 = transform.position +
transform.TransformDirection(Vector3.forward);
Makes a new variable, or sets it if it already exists. This variable
will be the direction of the shell, which lets us give it a proper
projectile arc.
rigidbody.AddForceAtPosition(Vector3.up * -9.81, thisDirection);
This adds a downward force to the nose of the projectile, allowing us
to make it rotate towards the ground while making it move to the
ground at the speed of gravity.
lifeTimer += 1 * Time.deltaTime;
Adds 1 to the lifeTimer variable every second.
if(lifeTimer >= lifeTimerMax) {
If lifeTimer is greater than or equal to lifeTimerMax.
Destroy (gameObject);
Destroy this Game Object.
explosionThing();
Go to our custom function explosionThing.
var explosionInstantiation = Instantiate(explosion,
this.transform.position, this.transform.rotation);
Instantiates an instance of our explosion particle system at the
position of this projectile with its rotation.
Destroy (gameObject);
Destroy this game object.

var colliders : Collider[] = Physics.OverlapSphere


(transform.position, explosionRadius);
Makes a collider which is with the radius of the explosionRadius
variable.
for (var hit in colliders) {
For everything this collider hits.
if (hit.rigidbody) {
If an object the collider hit is a rigidbody.
hit.rigidbody.AddExplosionForce(explosionPower, transform.position,
explosionRadius);
Make an explosion that affects the rigidbody it hits with full force,
and affects a lot of rigidbody within a large radius.

Additional Tank Shell Information:


Essentially the shell rotates with somewhat simulated physics.
If you look at the projectile's rigidbody, you will see that it is not using gravity.
This is because we need to give it gravity ourselves, at a specific point on the object.
This will cause its nose to dip to the ground during flight. However, we do not want it to
dip too much too soon, so in the rigidbody we use something called angular drag. This
makes sure that there is angular drag at the pivot point of the projectile. The pivot point
is behind the center of the object. Because of the drag, the object will fall and dip, but
will not fully dip for a while. To get the angular drag value, I needed to guesstimate. I
started with 20, and it was not enough. I went to 35, and then 40 and it was still not
enough. I knew it was not enough because when I fired the projectile was pointing 90
degrees downward when it should have been at less of an angle. I then tried it at 50,
where it was almost perfect. After a few more attempts voila, perfect simulated projectile
arc. This is all I think needs to be explained about the projectile, so I will leave the rest
for you to figure out, as it isn't all too hard.

Conclusion:
Using Unity3D and Javascript we have created a basic, functional tank suitable for use
in games. Our hope is that you have gained an understanding of how the motion of a
treaded vehicle works, and how this and the behavior of a projectile can be simulated to
create a convincing tank. With physics and movement properties that resemble real
tanks, the final product in this tutorial is close enough to reality to be entertaining while
leaving room for modifications and additions to make it a more complex vehicle.
Changes can be made to customize the vehicle for other scenarios, such as those that
might be found within different game environments. Many of the principals of code in
this tutorial would also lend themselves well to other treaded vehicles, such as
excavators or robots. The possibilities with Unity3D and Javascript are nearly endless
and always enjoyable. In the spirit of the Unity3D community, any and all media and
code within this tutorial is free to be used and incorporated into other works. We hope it
helps many people discover the joy of creating with Unity3D.
Sincerely,
Kevin and Colin Hopcraft

Vous aimerez peut-être aussi