Unity – Tanks Tutorial Part 2

Introduction

This week we looked at getting our tank to move.

Tanks, and all tracked vehicles, have a very particular way of moving. By turning their tracks on both sides in the same direction, they can move forwards or backwards. By turning their tracks in opposite directions, they can turn around. In our game, we don’t model the tracks explicitly, but we do want our tank to behave in this same way.

Input Manager

In our previous two projects, we didn’t concern ourselves too much with how the keys we pressed caused actions to occur in the game. It mostly “just worked”.

In Roll-A-Ball we used the method Input.GetAxis() with axes called “Horizontal” and “Vertical” and these allowed us to control our player object.

The Input Manager allows control axes to be defined. It can be found under the Edit|Project Settings|Input menu. We can add as many control schemes as we need for our game here.

Screen Shot 2016-03-06 at 21.16.37

In the case of Tanks, we need controls for two players so we have Horizontal1, Vertical1 and Fire1 and also then Horizontal2, Vertical2, and Fire2.

When we retrieve the axis values in our code, it will have a value between -1 (full negative) and 1 (full positive). A value of zero indicates no input on this axis. When we’re dealing with keys, the only possible values are (-1, 0, 1) but if we had an alternative controller such as a gamepad, we would have values in-between too.

Calculating How Much to Move

The tank’s vertical axis controls how much to move forwards and backwards. To calculate how much the tank should move in one physics frame and in what direction we use the following code:

 Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;

It’s a vector, so it it has direction as well as magnitude. The direction comes from transform.forward – this vector always points in the tank’s forward direction, regardless of how the tank has been turned, and is always 1 unit long. It’s worth noting that there are companion vectors called right and up.

The m_MovementInputValue part is how much the user is currently pressing the keys in the vertical axis. As already discussed, it will be either -1 (full speed backwards), 0 (no movement) or 1 (full speed forwards).

The m_Speed property is a value we’ve set which sets the tanks maximum forwards/backwards speed. We have it set to 12 (distance units per second).

If we multiply all of these three things above together, we get a vector that points from the tank’s current position to the location the tank will be at in one second, if nothing else changes.

This is good, but it isn’t taking into account how often we’re doing our physics calculations (i.e several times a second). Time.deltaTime is the time since the last physics calculation. It will be some fraction of a second. Multiplying by this, we get a vector that points from the tank’s current position to the location the tank will be at after one physics calculation. That is what we want.

Calculating How Much to Turn

Calculating how much to turn is easier. This is the code:

 float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;

It’s a float describing how many degrees we’re turning.

As before, m_TurnInputValue represents the user input. The value is either -1 (turn anticlockwise), 0 (don’t turn) or 1 (turn clockwise).

The m_TurnSpeed property is a value we’ve set which sets the tanks maximum turning rate. We have it set to 180 (degrees per second).

Finally, for the same reason as before, we multiply by Time.deltaTime to get the number of degrees we’re turning in this physics calculation.

Applying the Movement

The movement was hard to calculate, but it’s easy to apply:

 m_Rigidbody.MovePosition (m_Rigidbody.position + movement);

We just tell the Rigidbody to move to a new position. That new position is simply the old position with the movement vector we calculated added on.

Applying the Turn

The turn was easy to calculate, but applying it is a little more complex. It’s not important to understand why it work the way it does, just know that if you’re applying an additional rotation to something that you can’t just “add it on” as we did with the positioning. Here is the code:

Quaternion turnRotation = Quaternion.Euler (0.0f, turn, 0.0f);
m_Rigidbody.MoveRotation (m_Rigidbody.rotation * turnRotation);

To turn the rotation into something we can use, we need to construct a Quaternion. A Quaternion is a special way of storing a rotation. The Quaternion.Euler() method allows us to create a Quaternion from X,Y,Z axis rotations. Here our turn was about the Y axis and the values for the X and Z rotations are simply zero.

Once we have our Quaternion, you might imagine that we add it to the Rigidbody’s existing rotation, but that wouldn’t work. We actually have to multiply it to get the correct new rotation for our Rigidbody.

Changing the Engine Sound

Another thing we spent a good bit of time on was checking to see if the tank was moving and changing the engine sound between an idle and driving sound.

We used the Mathf.Abs() function to get the absolute value of m_MovementInputValue and m_TurnInputValue. The absolute value of something is the value with the negative sign ignored. We compared these to a very small value to determine if the tank was currently stationary, or not.

Once we determined if the tank was stationary or not, we checked the engine sound that was playing. If it wasn’t the one it should be, we swapped in the correct one, taking time to randomly alter the pitch a little so that the two tanks won’t sound identical.

Project Download

The up-to-date files for the project are here. Please download these and we will all start from this point next week!

Unity – Tanks Tutorial Part 1

Update: This post has been updated with a link to download the project. See the bottom of the post.

Screen Shot 2016-02-29 at 00.17.14

This week we started work on the Unity Tanks tutorial. This is a single-keyboard, two-player, tank game where users can complete in a number rounds against each other.

We began with downloading the tutorial assets from the Unity Assets Store. This tutorial comes with many lovely assets including 3d models and audio clips.

The assets, as downloaded, contained a “Completed” folder. We deleted this first, as it has a second copy of many of the scripts and assets in the project and had the potential to create confusion.

We created a new scene and deleted the default directional light as we wouldn’t be needing it. Then we added the provide “LevelArt” prefab. This prefab contains the entire playing area and also contains a directional light. We discussed the different types of lighting that we can have in a game: ambient, directional, point, and spotlight. The image below shows the same scene lit in each of these four ways, respectively.

lighting

We then set our camera to be orthographic. We described the difference between orthographic and perspective cameras. With perspective cameras, the space the camera sees in front of it is shaped like a pyramid and things that are further away look smaller (as in real life). With an orthographic camera, the space the camera sees in front of it is box-shaped and things do not get smaller the further away they get. For some game types, the less realistic orthographic camera is a good stylistic choice. We also removed the standard skybox and just changed the background to a solid colour, again a good stylistic choice for this game.

We then started to build our tank. The 3d model was pre-supplied, so we added it to the hierarchy. We then added a rigidbody, a box collider and two audio sources for the playback of sounds. We were able to add constraints on the rigidbody to prevent the tank from ever moving vertically, or from rolling or pitching. Applying these constraints both prevents unwanted movements and makes the physics engine’s job much easier.

Screen Shot 2016-02-29 at 01.02.07

Finally, we added two dust trail particle effects to the tracks of the tank. These were also pre-supplied as assets for the project.

We had just started to look at tank movement and that’s where we’ll pick it up again next week. The project can be downloaded here.

Remember that you should now be starting to plan and work on your own projects for the end of the year. Best of luck and we’re here to help in any way we can!

Playing With Unity Physics and Wheel Colliders

Hi folks. This week we continued work on our Amazing Racer project. We explained what heightmaps are and we imported a standard heightmap into a terrain object. We also added water and trees to our game map.

Apart from that, I also showed two little fun experimental projects that I worked on over the Christmas break to test a couple of game ideas. I thought I’d upload them here so you can play with them yourselves; maybe even use them as the basis for a game idea?

PhysicsTest

The first project, called “Physics Test”, is just a Jenga-like tower of bricks, a ramp and a dropped sphere. The sphere and the bricks have custom physics materials to define their friction and bounciness. It can be downloaded from here.

WheelColliderTest

The second is called “Wheel Collider Test”. It uses Unity’s Wheel Collider on a simple vehicle made of a box and four cylinders. The whole thing is on a simple map made from a basic terrain with a flat interior and a raised edge (to keep the car in!). The awesome (cough) textures are from random Windows backgrounds. The Unity documentation for the WheelCollider can be found here. I note reading it that our project sets up the visual elements to represent the wheels differently to the method recommended in the documentation, but it seems to work OK. The project itself can be downloaded from here.

See you all next week!

Unity – Week 7

unityssample

This week we started with a very short demonstration of some additional C# concepts, building on what we’d done last week.

After that, we continued with Roll-A-Ball.

We quickly finished off our walls and moved on to the Pick Up objects.

Pick Up objects are small cubes that float over the paying surface and that rotate to catch the user’s attention.

We added one Pick Up object and made it rotate. After that, we made it a “prefab”. Setting a property on one prefab object will automatically replicate that setting to all other prefabs of the same type. We didn’t take advantage of that this week, but we will next week.

We duplicated our Pick Up object and arranged twelve of them around our playing surface.

Next Week

Next week we’ll hopefully have enough momentum to finish off Roll-A-Ball completely.

After that we will start on some terrain modelling basics.

To be ready for terrain modelling basics, please be sure to have imported the standard assets package into a new empty project in Unity. To do this, follow these steps:

  1. Open Unity and create an empty 3D project, call it “Amazing Racer”
  2. Under the Windows menu in Unity, open the “Assets Store”
  3. In the “Assets Store” look for the “Unity Essentials” category
  4. Under “Unity Essentials”, find “Standard Assets” and import them

This process takes quite a bit of bandwidth and time, so you will need to have this done before coming to Dojo next week.

See you all then!

Unity – Week 6

C#

This week we had a short session because of the fantastic demonstration that Colmac Robotics were kind enough to give us.

Following feedback from a few ninjas and ninja parents, I decided to do an impromptu session on the C# language. I had hoped that we’d perhaps just try to pick this up as we went along, learning through practical examples, but it was clear that the transition from visual languages to code-based languages was tough for some.

We used MonoDevelop to create a simple test application. Originally I had intended to use Visual Studio, but some people have had installation problems with it. I encourage everyone to re-install Unity at home when they have time, so that we can all standardise on Visual Studio in the near future.

Concept of Classes and Basic Structure of A C# File

I ran over these topics quickly again, but they were covered in last week’s post. Please do review it if you didn’t get a chance to read it before. It can be found here.

Simple Test Application

In our test application, apart from reinforcing the basic concepts mentioned above, we also touched on number of other concepts:

  • We looked how the class definitions in our files are blueprints for how the class is structured and operates. We never actually have a copy, more commonly known as an instance, of that class until we actually create one ourselves with the new keyword.
  • We discussed class constructors, the special method, with the same name as the class itself, that is called when we make an instance of that class.
  • We saw how Console.WriteLine() can output text to the Windows console.
  • We created a class called Shape. We said it was abstract; which meant that we would never be making an instance of the Shape class itself. We would purely be using it as a base for other classes.
    • We said that Shape had a public method called Area(). We made its return type double, but we also marked it as abstract and provided no body for the method. This meant that we were saying all classes based on Shape would have to provide their own version of Area(), but that Shape itself had no definition for it.
  • We defined a class called Circle. We made it so that it was derived from Shape.
    • We gave it a property called Radius of type double and marked it public.
    • We used the override keyword to make our own Circle specific version of Area(); “override” meaning that we were over-riding or replacing the method definition from the base class (Shape).
    • We provided a means to set the Radius property through an optional argument to the constructor method Circle().
  • We defined a class called Square. We made it so that it was derived from Shape.
    • We gave it a property called Length of type double and marked it public.
    • We used the override keyword to make our own Square specific version of Area(); “override” meaning that we were over-riding or replacing the method definition from the base class (Shape).
    • We provided a means to set the Length property through an optional argument to the constructor method Length().
  • When writing our Circle.Area() and Square.Area() methods, we saw how the built-in Math object has lots of useful mathematical properties and methods. We used the property Math.PI and the method Math.Pow() (to raise a number to a given power) to perform our area calculations.

Inheritence

In the end we had a small sample program that could defined instances of circles and squares, calculate their areas and output the results to the console window (command prompt window).

On-line Resources for Learning C#

If you want to brush up on your C# skills, outside of our CoderDojo sessions, there are a number of useful on-line resources:

  • LearnCS.org: An on-line tutorial for C# which lets you build and test code right in a browser window
  • tutorialspoint.com: Another on-line tutorial for C# which also lets you build and test code right in a browser window
  • msdn.microsoft.com: Microsoft’s vast library of C# related resources including tutorials

Next Week

Next week, we’ll be taking a few minutes to close off this sample application, so that we can quickly illustrate a few outstanding points, and then return to roll-a-ball to, hopefully, close it out. See you next week!

Week 5 – Unity

UnityLogo

This week we returned to the Roll-A-Ball game that we had shown in the introductory session. Because people were at different levels of completion with this, we started from the beginning again, but we put some detail around things that we’d glossed over the first time around.

Concept of Classes

A class is a programming concept that allows you to define objects which contain both Properties and Methods. Properties are what they sound like; a value associated with object that we can get or set. Methods are actions, in the form of a function, that we can ask the object to perform.

SampleObject

If you think of yourself as a Person object then you could imagine some of the Properties and Methods you might have.

For Properties you might have things like NameAge, HeightWeight, etc. An example of a Method you might have could be SayHi() [notice the round brackets after the name marking this as a method]. That would make you say “Hi!”. A method might have arguments, so it could be SayHiTo(“Dave”) which would make you say “Hi Dave!”.

A method could equally calculate a value. An example might be CalculateBMI() which would calculate your Body Mass Index (BMI) value based on your Height and Weight properties.

Another nice thing about classes are that we can create specialised versions of them. They get all the Properties and Methods of the base class, plus all the new Properties and Methods that we defined for the derived ones. In this example, we might want to declare SchoolChild and Worker as new classes, both based on Person. SchoolChild might have additional properties such as School and Class while Worker would have WorkPlace and JobTitle. They would still share Name/Age/Height/Weight, etc.

Classes in Unity

Unity has a base class called MonoBehaviour and when we define behaviour for a game object, we do this by deriving a specialised class of our own design based on MonoBehaviour.

There are four Methods that MonoBehaviour has that we have looked at so far:

  • Start()
  • Update()
  • FixedUpdate()
  • LateUpdate()

We have provided custom versions of these in our own classes to define the behaviour that we want. This behaviour is also known as “overriding” as we are overriding the base behaviour of these Methods (which is to do nothing).

  • Start() is called when our game object is created. We can so things here that we need to do once when the game object is created.
  • Update() is called every time the scene is drawn. It’s a good place to do any updates that impact how the scene looks. However, it’s not called at a constant rate and that makes it unsuitable for some jobs.
  • FixedUpdate() is called every time the internal game timer for physics calculations fires. This is guaranteed to be at a regular interval. Any physics based calculations where time is a component should therefore should be done within FixedUpdate() rather than Update().
  • LateUpdate() is called after all game objects have had their Update() functions called. Use this when we need to be sure that another object has definitely been updated before we do something based on that object’s Properties.

Vectors & Physics

If I tell you that someone is moving at 5kph and ask you were they’ll be in 10mins, you won’t be able to answer that question. If I tell you that they’re moving 5kph due North, then you will. That combination of a quantity and a direction is called a vector.

vectors_basicA vector in 3D space is usually represented as three numbers, written as (X, Y, Z). Let’s see what the vector (1, 2, 3) looks like.

We’re familiar enough with using vectors like this to indicate a position, but what about representing a velocity or a force? The direction is apparent, but what about the quantity? Well the quantity is simply the length of the vector. This is calculated using Pythagoras’ theorem:

distanceeq3

So we can calculate the quantity or magnitude of the vector (1, 2, 3) as approximately 3.74.

Note too that if our vector (1, 2, 3) represents a force then a vector (2, 4, 6) also representing a force, would be a force in the same direction but twice as strong. You can see that each part of the vector has simply been multiplied by two.

Basic Structure of a C# File

When we derive custom behaviours for our game objects, Unity is kind enough to provide us with a basic file containing a class definition containing empty methods for Start() and Update()monobehaviour

It’s tricky making the transition from a visual language like Scratch to a language like C# where you have to type code. A few simple rules may help:

  • Lines starting in two forward slashes (//) are comment lines. They have no effect on the program; they’re there for you to read. You can delete or change them as you need.
  • Semicolons (a dot over a comma) mark the end of statements. They’re easy to forget at first so you need to be careful.
  • You need spaces and newlines to separate things, but this does not have to be precise. Two spaces are equivalent to one. Because a statement doesn’t end until a semicolon, you can split if across several lines and it will still be fine. Hard to read though.
  • Braces (or curly brackets) enclose things and they must always be in pairs (open/close). In the sample code the braces are such that the methods Start() and Update() are inside of (and belong to) the class NewBehaviourScript because they are inside its braces. Similarly any lines we add inside Start() will belong to that method because they are inside its braces.
  • Neat formatting really helps keep your code readable and helps you quickly find mistakes. Try to mimic how code is formatted in the examples, especially the practice of “indenting” lines; placing spaces at the start of the line to make it clear what it is inside of.

Next Week

Next week we will continue to develop Roll-A-Ball and hopefully get it finished up.

Taster Session Week 4 – Unity 3D

UnityLogo

For our fourth taster session, on next Saturday 17th October, we’ll be giving an introduction to Unity. Unity is a cross-platform game engine which has been used to create many successful games.

In preparation for next week please:

  1. Go to the unity website: www.unity3D.com
  2. Click the “Get Unity 5” button
  3. Download and install the free “Personal Edition”
  4. Run Unity once and register an account – you will need your email address

We will be trying to build as much as possible of the “Roll-a-ball” demo that I showed in our introductory session. Ongoing participation in the Unity group will require a good understanding of advanced programming concepts, but for the taster session, we will try to keep that stuff to a minimum so everyone can follow along and have fun.

unityssample