Вы находитесь на странице: 1из 20

Game Development - Unity Lab 2

Making Your Tank Move


As always, make sure to double-click the Tank scene under the Project Assets folder to get
the current working version.

This tutorial will cover the following:

Adding movement to our 2D tank sprite

Adding a Terrain background layer

Adding a GroundDetector to our tank

Basic scripting

Some Basic Scripting


Scripts allow us to add behavior to our GameObjects. Lets start by creating a simple C# tank
controller script to move the tank around. Click the Create drop down under the Project panel
like so:

This will generate an empty script for us, please select the script and rename it to
TankController. You should see the following code:
using UnityEngine;
using System.Collections;
public class TankController : MonoBehaviour {
// Use this for initialization
void Start () {
}

// Update is called once per frame


void Update () {
}
}

This will not be very helpful for making our tank move around so lets update it a bit with some
moving and jumping logic.
using UnityEngine;
using System.Collections;

public class TankController : MonoBehaviour {

[HideInInspector]
public bool jump = false;

public float moveForce = 365f;


public float maxSpeed = 5f;
public float jumpForce = 1000f;

private Transform groundDetector;


private bool grounded = false;

void Awake()
{
// Setting up references.
groundDetector = transform.Find("GroundDetector");
}
void Update()
{
// The player is grounded if a linecast to the groundcheck position hits
anything on the ground layer.
grounded =Physics2D.Linecast(transform.position, groundDetector.position,
1 << LayerMask.NameToLayer("Terrain"));

// If the jump button is pressed and the player is grounded then the player
should jump.
if(Input.GetButtonDown("Jump") && grounded)
jump = true;
}
void FixedUpdate ()
{
// Cache the horizontal input.
float h = Input.GetAxis("Horizontal");

if(h * rigidbody2D.velocity.x < maxSpeed)


rigidbody2D.AddForce(Vector2.right * h * moveForce);

if(Mathf.Abs(rigidbody2D.velocity.x) > maxSpeed)


rigidbody2D.velocity

new

Vector2(Mathf.Sign(rigidbody2D.velocity.x) * maxSpeed, rigidbody2D.velocity.y);

// If the player should jump...


if(jump)
{
rigidbody2D.AddForce(new Vector2(0f, jumpForce));
jump = false;
}
}
}

Ok, now that we have our new motion script, we must make a couple of modifications to our
Unity game scene.

Adding a GroundDetector
We will now need to add a GroundDetector we can use to determine whether or not our tank
is touching the ground.

This ground detector will be an empty GameObject (consisting of nothing more than a
transform component and a red oval placeholder shape). The end user will not be able to see
this object, but it will be useful in code.

Create an empty GameObject (GameObject -> Create Empty). Now select your new empty
GameObject, rename it to GroundDetector in the Inspector window and choose a red pill
outline for it (this makes it easy to see in the game scene).

Now, move the GroundDetector into our Tank GameObject at the bottom of our tank, it should
look like this when you have finished.

Ok, before we finish we have one more minor task, which is to add our Terrain to the Terrain
Layer. Start by selecting Layers -> Edit Layers in the upper right hand corner of the main
Unity window.

In Unity, layers help us to sort GameObjects into categories for determining how collisions are
to be resolved. If we have a number of background game objects which never interact with
anything on the screen (such as clouds or other scenic elements), we can simply move those
objects into a Scenery layer to get them out of the way.
On the Edit Layers menu, add a Terrain layer as below.

Next, click our Terrain object and set its layer to Terrain.

This isnt exactly ideal, we will need to make some changes to our tanks physics behavior to
make it behave less spastically.
Change your tanks mass to 20
Change Max Speed to 5
Change Jump Force to 5000
Modify your Tanks Box Collider 2Ds center Y value to -0.4
Modify your Tanks Box Collider 2Ds size Y value to 0.2

Get to the Chopper


Right now our tank is a single unified sprite. However, we need to chop it up a bit so we can
allow fun behaviors like aiming the tanks turret, allow individual wheel movements and (later)
allow us to blow up our tank if we lose the game.
As before, click the tanks sprite in the project panel at the very bottom of the Unity
screen. Select Sprite mode -> Multiple to indicate that our Tank sprite actually contains
many small sprites.

Now click Sprite Editor, you should see this.

Now click + drag inside the slice window to add slice boxes around the following
components: Slice each tank wheel, slice the turret barrel and slice the body of the tank.
When you slice each section, a blue box will appear indicating the size of the current slice.
When you are done with a section, simply release the mouse and then click + drag again
somewhere else to initiate a new slice.

When you are done slicing, click Apply to perform the slice and then close the window.

You should now see the following sub slices on your tank sprite (click the arrow to make the
sprite drawer slide out).

Before we get too excited, go back into the sprite editor, click each sprite slice and name them
like so: turrent, shell, wheel_1, wheel_2, wheel_3. Click apply to update the sprite names.

Adding Our New Parts


Well that was fun, but now we have a new problem: We must add all these sprites back into
our scene under our Tank GameObject. As you can see, our Tank Body Sprite now consists
of just our turret.

Next, systematically create new sprite renderers, nest them inside the tank GameObject and
select the appropriate sprites from the sprite sheet we just carved up and put all the pieces back
where they were before. The result (in wireframe mode) should look something like this:

Note: You get to wire-frame mode by selecting the drop down in the upper left hand menu in
the scene viewer.

Adding a Cannon

We have our new and improved cannon, what do we do with it? Drag and drop it into the
project and open up the Sprite Editor as in prior tutorials. Make sure to click Sprite Mode:
Multiple to get the Sprite Editor to show up.
This time, we will need to modify the pivot point so that our cannon will pivot at the base
instead of the center (default). It will look like this initially. Notice that the blue pivot point is
dead center. Thats not good.

Move the pivot to the bottom center by clicking the Pivot drop down and selecting Bottom.

Now the pivot should appear in the center, bottom of the cannon.

Ok, now go ahead and delete the old, lame cannon from our tank, create a new Sprite Renderer,
place that inside the Tank and then set our new cannon graphic as the sprite. Name this sprite
renderer Turret.
Make it look like this:
Now we need to make the cannon point at the mouse, this will require a new script. Create a
new script called TurretController and drop it onto the Turret Sprite Renderer you just
created.
Here is the script for it:
using UnityEngine;
using System.Collections;
public class TurretController : MonoBehaviour {
private Vector3 mouse_pos;
private Vector3 object_pos;
private float angle;
// Use this for initialization
void Start () {
}
void Update(){
}
void FixedUpdate () {
//
mouse_pos = Input.mousePosition;
mouse_pos.z = 0.0f;
object_pos =
Camera.main.WorldToScreenPoint(transform.position);

mouse_pos.x = mouse_pos.x - object_pos.x;


mouse_pos.y = mouse_pos.y - object_pos.y;
angle = Mathf.Atan2(mouse_pos.y, mouse_pos.x) *
Mathf.Rad2Deg - 90;
Vector3 rotationVector = new Vector3 (0, 0, angle);
transform.rotation = Quaternion.Euler(rotationVector);
}
}

Now click play

Game Development - Unity Lab 3

Prefabs are
& pre-fabulous
Unity prefabs are reusable GameObjects which can be placed or spawned in scenes over and
over again (and transferred easily between projects and scenes). Prefabs offer the benefit of
portability to our GameObjects. We are going to start by simply dragging our Tank into the
Project view at the bottom. This will turn its title blue and automatically convert it into a
Prefab. Also create a Prefabs folder just to stay organized and drop our tank into it.

Now that we have a prefab tank, lets create a prefab enemy to go with it.

A Simple Enemy
So for the sake of the tutorial we will be pretending that this looks like an evil, threatening
space alien bent on the destruction of earth. Download it and drag + drop it into the Unity
Assets folder, set its type to Sprite, create a new Sprite Renderer GameObject, use this as
the sprite and then name it to Alien. Drag and drop it into the Assets folder to convert it
into a Prefab.

Once you have the Alien prefab, also add a Circle Collider to it so it looks like this. Note,
you may want to tighten up the circle collider to more closely fit the alien sprite than the
below.

A Basic Alien Movement Script


Before moving our alien, we need to introduce the concept of tags. Open your Tank and click
the Tag drop down in the Inspector window. Choose Player.

Do the same with Alien and Terrain, respectively adding the Terrain and Alien tags by
clicking the Add Tag button. Tags are words we can apply to items in the scene to help
categorize them for scripting purposes. Tags may also be used to search for GameObjects in
the scene.

We will use these for some collision detection later on.


Now add this movement script to the Alien prefab. Make sure to also add a RigidBody2D
(required for collisions) and click the isKinematic to disable physics on it.

using UnityEngine;
using System.Collections;

public class AlienController : MonoBehaviour {

public float alienSpeed = .02f;

// Use this for initialization


void Start () {

// Update is called once per frame


void Update () {
transform.position += new Vector3(0, -alienSpeed, 0);
}

void OnCollisionEnter(Collision collision) {


}
}

Handling Collisions
Collisions in 2D can be extremely fiddly and there are a number of things which can go
wrong to screw them up so proceed with caution.

Trigger Happy
For this next part you need to refactor our scene to remove our old jagged terrain and replace
it with a flat terrain. This terrain is just a grey sprite with a box collider.

To check for collisions we will need to make use of the tags which we added in the last scene.
Converting a collider to a trigger causes it to be ignored by the physics engine and also
enables us to intercept trigger events from colliding with other objects. Please make sure that
our Aliens Circle Collider 2D has been set to a trigger as below.

Note that we also added a Rigidbody 2D (this is required for collisions to work properly with
triggers) and set its gravity scale to 0 to prevent it from interfering with the alien motion
logic.

Next, update the script for the AlienController to make it look like this:
using UnityEngine;
using System.Collections;
public class AlienController : MonoBehaviour {
public float alienSpeed = .02f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.position += new Vector3(0, -alienSpeed, 0);
}
void OnTriggerEnter2D(Collider2D col)
{
// If the alien hits the trigger...
if (col.gameObject.tag == "Player") {
Destroy (gameObject);
} else if (col.gameObject.tag == "Terrain") {
Destroy (gameObject);
}
}
}

By adding the OnTriggerEnter2D function, we can now intercept any and all colliders which
pass into the space occupied by our alien spaceship. We then check their tags and can destroy
the space ship on command.

NOTE: We will have to face many problems with triggers and collisions until realize that
some of the Z-values on a few of our prefabs were off. Because we are working in 2D, all Zvalues must be the same if you expect collisions to get triggered. If your objects dont seem
to be colliding double check that they are all on the same plane.

Basic UI with GUI Text


This guide covers some very basic UI text to track your score whenever an alien happens to
die.

A Basic Scoreboard
Start by clicking GameObject -> Create Other -> GUIText

Next, name this object Score and create the following script then name it
ScoreController.
using UnityEngine;
using System.Collections;

public class ScoreController : MonoBehaviour {

public int score = 0;

// The player's score.

private int previousScore = 0; // The score in the previous frame.

void Awake ()
{

void Update ()
{
// Set the score text.
guiText.text = "Score: " + score;
// Set the previous score to this frame's score.
previousScore = score;
}
}

Your score game object should look like this now:

Note: GUI elements behave in a different manner than other game objects, the coordinates for
the transform are not in world coordinates but in screen coordinates. Therefore, you must
make sure to constrain them between 0 and 1 if you want the GUI elements to appear in the
screen. Otherwise, you wont see your text. Please verify the Score is within 0 1 for both
its X and Y coordinates.

Now, open up the AlienController script and add the following script update:
using UnityEngine;
using System.Collections;
using UnityEngine;
using System.Collections;

public class AlienController : MonoBehaviour {

public float alienSpeed = .02f;


private ScoreController score;

// Use this for initialization


void Start () {
score = GameObject.Find("Score").GetComponent();
}

// Update is called once per frame


void Update () {
transform.position += new Vector3(0, -alienSpeed, 0);
}

void OnTriggerEnter2D(Collider2D col)


{
// If the alien hits the trigger...
if (col.gameObject.tag == "Player") {
Destroy (gameObject);

if(score.score >= 100)


score.score -= 100;
else if(score.score > 0)
score.score = 0;

} else if (col.gameObject.tag == "Terrain") {

score.score += 100;
Destroy (gameObject);
}
}

Now, when the alien dies by crashing into the ground, the score will update. The result will
look like this: