Creators – Week 12

This week we took our Blender creations back into Unity. We started with the same file, ShipsAndEnv3.5,blend, which can be found here on our Teams site (for site members only).

Export from Blender

Blender offers extensive export options and we quickly ran through the list. The one we’re going to use is FBX. It’s a widely used format, well supported in lots of 3D software, with good material and animation support.

To export the file, we made sure all object were unhidden, and chose File|Export|FBX. We left all the options as-is except the “Apply Transforms” option, which we selected. This option has a warning next to it, as it doesn’t work with animations, but that doesn’t apply to us here.

The resulting FBX file was saved to the same folder as our BLEND file.

Import into Unity

To import the FBX file into Unity, we created a new folder called “Model” and dragged the FBX file from Windows Explorer/macOS Finder into it.

We decided to extract the materials from the file. This will allow us to change them in Unity. To do that we selected the FBX in the Model folder in Unity and in the Inspector window, went to the Material tab and chose “Extract Materials”. All the materials in the FBX were then extracted as Unity materials in the same folder as the FBX file.

Prefabs

We then wanted to break apart the combined FBX file into it’s separate parts. To do that we first created a blank scene and dropped the model from the “Model” folder into the Hierarchy window. We checked the Inspector window to make sure it was positioned at (0, 0, 0) and adjusted it if needs be.

Note that Unity showed the model coloured blue in the Hierarchy. This means it was treating it as a “Prefab”. A prefab in Unity is just a collection of GameObjects and components that are treated as a template. It’s easy to create copies of them at run-time.

We want prefabs of all the things in the FBX file, not the FBX model itself. To separate out the bits from the FBX model, we right-clicked on it in the hierarchy and chose Prefab|Break Apart Completely. Not much obviously changed except everything in the hierarchy turned black, indicating it was no longer a prefab, just normal objects.

We then created a new folder called “Prefabs” and dragged everything inside the FBX model (but not the FBX model itself) into it. That’s all you have to do to make something you already have in a Unity scene into a prefab, drag it into the Project window. Now we can create copies of all these objects at run-time very easily.

Adding our Ship to the Scene

To add our ship to the scene, we dragged the Ship prefab from the Prefabs folder and dropped it onto the Player gameobject in the Hierarchy. The Ship model was then a child of the Player object. We needed to rotate the Ship by -90 around the Y axis to make it point in the correct direction. We also set the scale of teh Plater object to (1, 1, 1) and removed the Mesh Filter, Mesh Renderer and Box Collider components from Player, as these were no longer needed.

Our game looks better already with a ship model rather than a flying mattress!

Some Test Code

We tested two simple components on a test cube added to the scene. One which created constant movement in a particular direction and the other which deletes the attached gameobject once we’ve traveled a set distance from where we started.

The first of these, ConstantMovement.cs looks like this:

using UnityEngine;

public class ConstantMovement : MonoBehaviour
{
  public Vector3 Direction = Vector3.forward;
  public float Speed = 10.0f;

  // Update is called once per frame
  void Update()
  {
    Vector3 offset = Direction.normalized * Speed * Time.deltaTime;
    transform.position = transform.position + offset;
  }
}

Two public variables define the direction and speed respectively. In Update() we calculate how to move this frame by multiplying the normalised version of the Direction (normalised meaning the length is set to 1) by the speed and Time.deltaTime (the time since the last frame). We then set a new value for the position by adding this offset to the previous position.

The second DestroyAfterDistance.cs looks like this:

using UnityEngine;

public class DestroyAfterDistance : MonoBehaviour
{
  public float Distance = 10.0f;

  private Vector3 _initPos;

  // Start is called before the first frame update
  void Start()
  {
    _initPos = transform.position;      
  }

  // Update is called once per frame
  void Update()
  {
    Vector3 offset = _initPos - transform.position;
    float offsetDist = offset.magnitude;

    if (offsetDist >= Distance)
    {
      Destroy(gameObject);
    }
  }
}

It just has once public variable, the distance the GameObject is allowed to travel. It also has one private variable, set in Start(), which stores the initial position.

In Update() we check how far we’ve travelled by getting the vector difference between the start position and our current position and then getting it’s magnitude (aka length). This tells us how far we have moved. if this distance is greater than the the specified Distance, we call Destroy(gameObject) thereby destroying the GameObject this component is attached to.

Getting the Code

All the code we’re made this year is on our GitHub. It can be found here. If you don’t have the latest version of our code before any session, use the green Code button on that page to get the “Download ZIP” option which will give you a full copy of all code we’ll be writing this year.

Creators – Week 11

This week we completed our ship from the previous week by adding some materials. Materials are what provides colour to models.

Out model, by default, contains a single material slot. This default material is a grey material and because there’s a single slot, it’s applied to all faces.

To start colouring our model we went to the material properties panel on the right-hand-side of the screen. It has a red circular icon as seen at (1) below.

We removed the default material slot by using the – key at (2) above then then added two new materials, called Ship and Ship_Detail by pressing + at (2) to make two new material slots and using the “New” button at (3) when those empty slots where selected to actually make a new material.

The default material component has a lot of inputs, but we can ignore most of them for now. The most important ones are:

  1. Base Colour: This is the main colour of the material
  2. Metallic: How much like a metal the material is. Although a slider, its normally to be either zero (not a metal) or 1 (a metal) rather than anything in-between.
  3. Roughness: How smooth or rough the material is. Will greatly impact how light reflects off the object. Metallic materials with very low roughness look mirror-like.

We set Ship and Ship_Detail with contrasting colours, metallic finish and low roughness.

Environment

We are going to create loads of environment sections that snap together. The follow the basic pattern show above. A flat area 90x100m in size, with a vertical edge 4m high and a 20m flat area beyond that. We can add any embellishments to the raised flat area on the sides, so long as they’re not too high on the side facing the camera. We don’t want to obscure the ship.

Like the ship, we created two contrasting materials for the environment, one dark as a base and one bright as a contrast colour for details.

Getting the Model

The Blender model for this week can be downloaded from our Teams site here.

Medtronic Foundation – Laptop Donation

Medtronic Logo

We are very grateful to the Medtronic Foundation, through Medtronic employee and mentor Declan Fox, for the donation of several laptops to CoderDojo Athenry. Our loaner laptop program helps those who cannot otherwise afford a laptop to attend CoderDojo Athenry. Keeping CoderDojo Athenry free to attend and as inclusive as possible is always one of our key aims.

The Medtronic Foundation partners to improve health for underserved populations, as well as supports communities where Medtronic employees live and give. They empower Medtronic employees to positively impact local communities by leveraging their skills, time and resources. If you’d like to read more about their work you can find their webpage here.

Creators – Week 10

This week we took our cube and made it vaguely more spaceship-shaped by moving it up to (0, 2, 0) and resizing it to (5, 1, 4). We also took our ground plane and scaled it to (10, 10, 10). Now it looks vaguely more like a flying craft than before!

The ship controls still work as before. WASD move the ship horizontally over the ground and there’s no vertical movement. To make it look more like a flying craft, we’d like it to bank (aka. tilt over) as it moves horizontally. That’s going to take a bit of figuring out.

Angles in Unity

Let’s take a little aside to talk about angles in Unity.

In the Unity Inspector we see three numbers for a transform’s rotation. These numbers represent rotations around the X, Y and Z axis respectively. This way of storing a rotation is known as “Euler angles”. It seems simple and straightforward and, if you’re rotating around just one of the X,Y or Z axes, it is, but for complex rotations it actually has a lot of problems. The order in which you apply the rotations matters. If you rotate first in X then Y and the Z, you get one orientation, but choose a different order and you’ll get something different. It’s ambiguous.

Look at these two boxes. Each are rotated by 90degrees around the X and Z axis but in a different order. They end up in completely different orientations:

Rotations internally in Unity are stored using a special variable called a Quaternion. Euler angles can easily be converted to Quaternions and back again. Quaternions store the axis that the object rotates around and the amount of the rotation. It’s completely unambiguous with no order to worry about.

When we code, we use Quaternions for rotations because that’s what Unity uses.

Variables for Ship Tilt

In ShipControls.cs we add two variables TiltSpeed and TiltLimit to control banking. TiltLimit represents the amount of degrees we’re going to bank as we move horizontally and TiltSpeed is how quickly we can change angle. We don’t want the craft immediately going from tilting one direction to tilting the other – we want a smooth change of rotations. That will look a lot better.

  public float TiltSpeed = 10.0f;
  public float TiltLimit = 10.0f;

Because these are public properties, we see them appear in the inspector for Ship Controller.

Determining What Tilt We Should Have

Tilt is dependent on the user input. If the user is pressing right, we should be titled to the right. If the user is pressing left, we should be tilted to the left. If the user isn’t pressing left or right, we should be level.

In the Update() function in ShipControls.cs we add this code near the top:

    float tiltTarget = 0;

    if (moveInput.x < 0)
      tiltTarget = TiltLimit;
    else if (moveInput.x > 0)
      tiltTarget = -TiltLimit;

    Quaternion targetRotation = Quaternion.Euler(tiltTarget, 0, 0);

So depending on user input, tiltTarget will either be 0, TiltLimit or -TiltLimit (note the minus). We then turn this into a Quaternion representing this amount of a rotation around the X axis.

Moving Smoothly Between Rotations

How do we move smoothly between two rotations, namely the rotation we’re at and the rotation we want to be at?

There’s a general concept called “linear interpolation” for finding a value some proportion of the way between two other values. Let’s imagine a trivial example; if our numbers were 0 and 10 then the number 50% of the way (aka. half) between these would be 5. In Unity linear interpolation is known as “Lerp” and it can be used not just for simple numbers but for Vector3’s (representing positions and directions) and Quaternions (representing rotations) too.

For Quaternions, Unity has a special “Lerp” that works really well for rotations called Quaternion.Slerp(). “Slerp” stands for Spherical liner interpolation. Not a function name you’ll quickly forget. So to “Slerp” between the angle we’re currently at and the angle we’d like to be at, we need to know what proportion of that change we can make this frame. Here’s how we calculate that proportion:

  1. Find the angular different between the rotation we’re at and the rotation we’d like to be at
  2. Calculate how long, given the speed we’ve specified for changing angle, it would take to fully make that change in rotation
  3. Calculate, given the time since the last frame, what proportion of that change we can actually make (it will be just a small bit of the change).

Here’s what the code looks like:

    float rotationDiff = Quaternion.Angle(targetRotation, 
                                          transform.rotation);
    float timeToFullyRotate = rotationDiff / TiltSpeed;
    float rotationProportion = Time.deltaTime / timeToFullyRotate;

Finally we actually set the transform’s rotation using Slerp(), the rotation we’re at, the rotation we’d like to be at and the proportion of the change that we’ve calculated:

transform.rotation = Quaternion.Slerp(transform.rotation, 
                                      targetRotation, 
                                      rotationProportion);

Tuning the Variables

Testing the ship control code we found that good values for the variables were as follows:

Move Speed50
Tilt Speed100
Tilt Limit30

We also noted that any values entered in the inspector override defaults in the code.

Simple Blender Spaceship

We started on a simple spaceship model in Blender, using the proportions of our cube in Unity as a guide [5m x 1m x 4m].

This was mine, but everyone had their own take. If anyone wants to download mine, it can be found here on our Teams site. If you’re not a member of our Teams site yet, get in touch to be added.

When we return after our break, we’ll look to texture this model and export it from Blender and import it into Unity.

Getting the Code

All the code we’re made this year is on our GitHub. It can be found here. If you don’t have the latest version of our code before any session, use the green Code button on that page to get the “Download ZIP” option which will give you a full copy of all code we’ll be writing this year.

Creators – Week 9

I decided, since we weren’t making a lot of progress with our Dungeon game, that we might need to switch to something simpler. We are going instead to make a game in the style of an isometric side-scrolling arcade shooter. This style of game first appeared back in 1982 with Sega’s Zaxxon (pictured below) but there have been many examples since.

We decided to call our game “Speedy Spaceship”.

To start with the game we opened a new Unity project and used the Package Manager to install the new Unity Input Manager package. This is the preferred way to define user inputs in Unity these days as it’s far more flexible when you want to add alternative control schemes (gamepad instead of keyboard, for example).

We first created a folder called Input and in there we made a new “Input Actions” asset and called it “ShipControls”. Opening this, we defined a simple control scheme, for keyboard and mouse, as follows:

At the moment it only contains one action “Move” but we’ll be adding at least one more action later to enable shooting. Movement is bound to the WASD keys on the keyboard.

Once we’d done that, with this Input Actions asset still selected in the Project view, we selected the “Generate C# Class” option in the Inspector and pressed the “Apply” button. This made a script file called “ShipControls.cs” next to our Input Actions asset in the inputs folder. This file contains a lot of code for handling the interactions, but we don’t need to worry about it’s contents; it’s easy for us to make use of it.

We then added a plane, which we added a material to, and a cube positioned just above the plane, to our current scene. With the cube selected, we positioned ourselves in the Scene View such that the cube’s X-axis (red) was pointing right and away from us and the cube’s Z-axis (blue) was pointing left and away from us.

We then selected “Main Camera” in the scene and used the GameObject|Align with View menu command to set the camera to the same angle as the Scene View. Toggling between Scene View and Game View now show the exact same angle, at least until we move in the scene view again.

We create a Scripts folder and made a new C# script inside called “ShipController”. We dragged and dropped this script over the cube in the scene view to assign it.

The first thing we needed to do was to attach the ShipControls to the ShipController (similar names, but two different things). We made a new private property in ShipController to hold a reference to a ShipControls instance, added the Awake() function where we created a new ShipControls object and then used the OnEnable() and OnDisable() functions to enable and disable the ShipControls when the ShipController was itself enabled or disabled. This is what that code looks like:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShipController : MonoBehaviour
{
  private ShipControls _controls;

  private void Awake()
  {
    _controls = new ShipControls();
  }

  // Start is called before the first frame update
  void Start()
  {
        
  }

  private void OnEnable()
  {
    _controls.Enable();
  }

  private void OnDisable()
  {
    _controls.Disable();
  }
}

For movement we then just need to find out what the value of our input is at every frame and move appropriately. First though, we need some control over the speed we’re going to move. We add a new public property for MoveSpeed:

public class ShipController : MonoBehaviour
{
  public float MoveSpeed = 10.0f;


Now we can add code to Update(), the function that Unity calls every time that a frame is drawn, to move the cube around in response to player input.

If we have a speed and a time, we just need to multiply them together to see how far we’ve gone. This is a simple mathematical way of expressing it:

speed * time = distance

If, for example, I’m travelling 100kph and I drive for two hours then the distance I’ve gone is 200km.

100km/h * 2h = 200km

The time between frames in Unity is stored in a special variable Time.deltaTime. This value for time is dependent on our framerate. As long as we use this value when we’re calculating distance moved in a single frame, the answer will be correct no matter if our computer is generating 20FPS or 200FPS.

Let’s see the final Update() function code:

  void Update()
  {
    Vector2 moveInput = _controls.Ship.Move.ReadValue<Vector2>();

    transform.position = transform.position +
                         new Vector3(moveInput.y * MoveSpeed * Time.deltaTime,
                                     0,
                                     -moveInput.x * MoveSpeed * Time.deltaTime);
  }

The first thing is that we ask for the value of the moveInput. This is defined as Vector2 value so it has an x and a y part (representing the horizontal and vertical axes respectively). The y component will be +1 when we’re pushing W (Up) and -1 when we’re pushing S (Down). Similarly the x component will be +1 when we’re pushing A (Left) and negative when we’re pushing D (Right).

We take transform.position, which controls the position of the cube and we set it to a new value which is it’s current position plus an new Vector3 which represents the change in position this frame. The x and z portions, which represent horizontal movement, are both calculated from the input. The y portion, representing vertical movement, is always zero. The other two are of the form:

distance = input * speed * time

Distance being speed multiplied by time we’ve seen, but what’s input doing in there? Well input is like a switch. When you’re not providing input, it’s zero. Anything multiplied by zero is zero, so distance must be zero when we’re not actively providing input. When you’ve providing input it’s either 1 or -1 which means we’ll move forward or backwards depending on what the input is.

Next week we’re going to make our ship a little more ship-like in proportion and make it bank when it goes sideways. We’ll also be creating a simple ship model in Blender.

All the code we’re made this year is on our GitHub. It can be found here. If you don’t have the latest version of our code before any session, use the green Code button on that page to get the “Download ZIP” option which will give you a full copy of all code we’ll be writing this year.

Creators – Week 7

Today we worked on our first Unity component, MapMaker, and attached it to a GameObject in the scene.

We added a TextAsset property to the class definition and saw how it became visible in the Unity Inspector. We were then able to associate our map file with this slot.

In the code, we created a new method (aka function) to our class definition called BuildMap() and added some code to it. Ultimately it was able to:

  1. Make sure that we had a map file specified before proceeding
  2. Show us name of the map file and its content
  3. Break the map file into individual lines
  4. Tell us how many lines were in the file

Then we created a pair of prefabs and a pair of matching materials. Prefabs are an essential Unity concept that represent pre-built combinations of GameObjects and associated components that we can quickly create copies of at runtime.

We are going to use these two prefabs to physically create our map from.

I have started a new GitHub repository to store our Unity project code. It can be found here. If you don’t have the latest version of our code before any session, use the green Code button on that page to get the “Download ZIP” option which will give you a full copy of all code we’ll be writing this year.

Creators – Week 6

This week we looked to get started with Unity. To install Unity:

  1. Go to https://unity.com/download
  2. Download and install Unity Hub
  3. Create an account with Unity, if you don’t have one already
  4. Log into Unity Hub with your Unity account
  5. In the Installs section of Unity Hub, install the latest version of Unity 2021.3. At the time of writing, this is 2021.3.35f1
  6. Make sure you pick the option to install Visual Studio Community Edition (Windows) or Visual Studio for Mac (macOS) when installing Unity

We just barely started on our first script before the end of the session. We’ll expand on that next week.

Creators – Week 5

This week we saw where we were going with the dungeon:

The screenshot shows a completed dungeon, made from the modular parts that we are currently building.

We finished off the two pillar designs, shaping one straight-sided and the other rounded and we worked on a wall section. For the wall section, we used a mirror modifier to make it two sided while only having to work on a single side.

Our file from today can be found here.

Creators – Week 4

This week we first created a crate:

This used many of the same techniques as the barrel last week.

We then started with a plan for our dungeon pieces. As long we we stick to these generic dimensions for floor, pillar and wall pieces, we can mix and match and everything will slot together easily:

Our file for today can be downloaded from here.

Creators – Week 3

This week we started Blender in earnest and created our first model, a wooden barrel with metal rings. The file is available here. You need to be a member of the Creators’ Teams group to download it, so let me know next week if you aren’t yet a member and I can get you added.

For those catching-up, Blender can be downloaded through the Windows App Store or from https://www.blender.org/download/.

You can review Blender basics using these videos: