Unfortunately, the Unity Editor has a problem reading data from our network mounted drives. Don't create Unity projects in your home directory (which is a networked drive). Instead, create a folder with your cs name in the /scratch directory, which will be your work space on the local hard-drive. For instance, for me the directory would be /scratch/lechszym. It's probably a good-idea to right-click on that folder, select "Get Info" and change permissions for "Everyone" to "No Access", so that no one else who logs into that machine can't read your files. All your Unity projects and your game project should be saved into that directory. Remember, this directory is local, so you won't see it if you login to a different machine.
Because your home directory is on a networked drive, caching of files in Unity might be affected - you might see a message about Failure to change file flags. Just ignore that warning.
The default script editor that comes with Unity is MonoDevelop, but we will use Visual Studio Code (VSCode), because it is slightly easier to work with (apart from this initial setup that you have to do).
If, after opening, VSCode gives you an error "The .NET CLI tools cannot be located...", this is most likely a path set up problem.
First check if the tools are installed. Open terminal and check if directory /usr/local/share/dotnet/ exists. If it doesn't, let the lab demonstrator know.
You need to add /usr/local/share/dotnet/ to the PATH variable in your profile file (your profile file is located in your home directory, and it's either .bashrc, or .bash_profile, or .profile).
To verify that dotnet tools are in you path now, open a new terminal window and issue the command which dotnet. It should return the path /usr/local/share/dotnet/dotnet.
Close VSCode and Unity. Just to be safe you may need to log out and log in to make sure changes take effect. Reopen the Unity project and click on a script file to open VSCode. It should not complain about .NET CLI tools. You might have to give it a minute to complete its installation of debugger tools.
There are a number of coordinate systems in Unity - depending on the task, different coordinate systems are easier to work with. At this point let's just worry about the main two coordinate systems.
World coordinates give the location in the virtual 3D game space with respect to the "world origin", the point (0,0,0). These coordinates give an absolute position of an object in the game space.
Local coordinates give a relative position of an object with respect to another object, usually the parent object.
The figure below demonstrates how spatial relationship between two objects, A and B, can be defined in two different coordinate systems. In the "world coordinates" the position of A and the position of B are given with respect to the "world origin". In the second scenario the position of A can be specified with respect to B's local coordinate system.
You might be wondering why you need 3D coordinates, that is (X,Y,Z), for location when making a 2D game. The main reason is that Unity is really a 3D engine, 2D mode being just a special engine configuration. But there are advantages to having a third coordinate. Did you notice the arrows originating from the camera icon in the Scene view (when the Main Camera is selected in the Hierarchy panel)? These show the local coordinates with respect to the camera - camera local coordinates are kind of important, since they define what the player sees. The green arrow (pointing up) is the Y axis, the red arrow (pointing right) is the X axis...and there's also Z axis - it's the blue circle, right over the camera icon, representing a blue arrow pointing away from you (into the screen). Because the Main Camera doesn't have any rotation about the world axis (see the "Transform" component) its local coordinates system is perfectly lined up with the world coordinate system (though Main Camera's centre is shifted 10 units on the Z axis). When the game engine renders a scene in a 2D project, it flattens everything along the camera's Z-axis...and so all the physics and collisions are done in the XY plane. However, the Z-axis is still useful for specifying the rendering order - which object are in front, and which in the back, of the scene.
The size of the Main Camera is defined by the Camera | Size attribute, which specifies the height of the camera from it's centre. Currently it's set to 5, which means that camera is 10 units high (5 going up, and 5 going down from its centre). The width is relative to height and it follows the desired screen ratio. The screenshot below shows the size and position of the camera in the scene in "world units".
If your camera outline doesn't fit within the background image (like in the screenshot above), it because your camera aspect might be set differently to mine. You have two choices. You can keep your camera aspect and scale the Background game object a bit more to fill out the entire camera view. Alternately, you can change your camera aspect ratio.
To change the camera aspect, select the Game view and change the camera aspect tor 4:3, as shown in the screenshot below:When you're done go back to Scene view and check if the camera outline now fits within the background.
Recall that the Main Camera's Z-coordinate was set to -10, and the Background's to 0. You have just set the Star's Z position to -1. The figure below shows the position order of these game objects along the Z-axis. The Main Camera (as shown in the image) is looking in the positive direction of the Z-axis, and so the Star will be rendered in front of the Background. When it comes to collisions and physics, the Z position does not matter in 2D games (it's just ignored). However, it does affect the rendering order. If it's helpful, you can think of the Z-dimension as depth from the camera, but only for drawing. There are other ways of selecting rendering order of sprites (such as using the Order in Layer property of the Sprite Renderer component), but for now stick with the Z-axis method.
It is possible to switch the Scene view to 3D mode. This is useful for checking the order of the sprites along the Z-axis. In the video below:
In the game mode you get to play the game. You'll know when you're in game mode because the play control buttons turn blue and all the panels become dimmer. You can pause the game and step through it frame by frame. It is also possible to switch to the Scene view while still in the game mode (sometimes that is useful to see what is happening with the game objects outside the view of the "Main Camera"). However, changes made to the scene while in the game mode are temporary, and will disappear after you exit game mode. Make sure to turn off game mode (by clicking the play button again) before continuing to work on your scene.
For your game development, you're free to choose any language you like, however, the labs in this course will use C#.
01: 02: 03: 04: 05: 06: 07: 08: 09: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
C# is an Object Oriented scripting language. A .cs file is expected to implement a class of the same name as the file name (without the cs extension). Therefore, "Planet.cs" implements aclass. When you add the Planet script component to a game object, you instantiate an object of type and associate it with that game object.
The first line of "Planet.cs" specifies the library containing the engine itself, so that you can reference engine types and classes. The definition of theclass follows. Object that hook into the game engine need to extend the class, which provides a set of instance variables and behaviour methods that the engine is going to invoke. You can add new variables and methods as well as overwrite existing methods, to customise the behaviour of your game object.
Theclass shown above defines two new member variables: and of type . These control the speed and amplitude of the planet's bobbing motion. Note that the values of these variables are not specified in the code. If you recall, you have set those values in the Inspector panel. All the variables appear as properties of the script component, which can be set in the Inspector panel. For some reason Unity changes the format (separating tokens based on capitalisation), so "bobRate" appears as "Bob Rate" and "bobScale" as "Bob Scale" in the Inspector panel, but they are the same variables. Unless it's explicitly specified as , a member variable is taken to be private
Theclass has only one method called Update(). However, before explaining what the code inside that method does, you need to understand how the engine invokes this method and how the game loop operates.
The fundamental operation of the game engine is to perform the following:
This sequence of steps is done over and over again and is referred to as the game loop. How fast it takes to go through one iteration of the game loop will determine how quickly the next frame can be rendered - which is what determines the frame rate. To produce 30 Frames Per Second (FPS), the entire loop has about 3.3ms to run.
In the "Check for input" phase, any events from input devices (such as pressing of a given key on the keyboard) are recorded for later processing
In the "Update the game state" phase, the engine iterates over all the game objects in the scene - if a game object happens to have a script component, the Update() method of that component will be invoked. The default implementation of Update() indoes nothing. However, if a script implements this method, it overrides 's one. The Update() method will get executed on every iteration of the game loop before the next frame is rendered. Inside this function you can place code that changes the game state: such as what happens in response to user input
In the rendering phase, the engine figures out what game objects are in the Main Camera's view, and how to draw them to create a frame for display
The Update() method of theclass has only two lines of code, and they are responsible for animation of the planet object:
The animation of the planets is a simple up and down bobbing motion based on a sine wave calculated from the variable. The Time class is a built-in class used by the engine to record information about various aspects of the passage of time. gives the number of seconds since the start of the game. Mathf is another built-in class that provides useful mathematical functions. The variable is the phase, and the variable is the amplitude of the sine wave that dictates the change in distance, .
The last line of the Update() method uses inherited member variable Transform object, which changes the position of the game object by a specified vector. Vector3 is another built-in class that allows the programer to specify a vector with x,y,z coordinates. The computed change in distance is passed in as a Y coordinate of a new object, hence the change position will be along the vertical axis., which is a reference to the Transform component of the game object. It invokes the method of the
01: 02: 03: 04: 05: 06: 07: 08: 09: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
The script defines four public variables of type KeyCode, which is a built-in class that contains codes for keyboard keys. Representing key codes as variables allows for arbitrary key mapping. The four variables in the above script correspond to left, right, up and down movement.
There's another variable of type, which determines the movement speed of the Player game object.
There is an Update() function in this script, which will be called once per frame. Thevariable calculates the range of the movement in this frame.
The length of time it takes the game engine to complete one iteration of the game loop is not constant. As the state of the game changes, the number of things to do in each iteration of the loop may vary. Hence, Update() gets called at varying time intervals. In order to move an object at a constant speed, say some number of "units" per second, the change in position needs to be integrated over time since the last Update(). The Time class provides the variable that records time in seconds since the completion of the last frame. This value is multiplied by the speed to get the distance.
For example, if("units"/s), and (s), then the computed distance is:
2 ("units"/s) * 0.33 (s) = 0.66 ("units").
When the moveRight key is pressed, the Player game object will be translated by dist "units" in the x direction. If the moveLeft key is pressed, the Player game object will be translated by dist "units" in the negative x direction.
If the moveUp key is pressed, the Player game object will be rotated about Z-axis by dist. If the moveDown key is pressed, the Player game object will be rotated in the opposite direction about Z-axis by dist.
These movement mechanics might seem odd - it's best to get a feel for it by playing the game. However you still need to define the keys and the speed of movement
What is going on there? Initial left and right movement should be straight forward. Rotation by going up and down is a bit strange, but still it's doing exactly what the Player script prescribed. But after a bit of rotation the left/right movement is not horizontal with respect to the camera. Instead, it's horizontal with respect to the the new rotated position of the player. Take a second to ponder why this is happening (before reading the answer below).
The left/right movement of the Player sprite is relative to its own rotation, because the Translate() method (by default) takes its argument vector to be in local co-ordinate system of the game object. The translation into the shift in world coordinates is computed internally. It is possible to specify the desired coordinates system of the shift vector with an extra argument to the Translate function, but most of the time (as in this case) the local co-ordinate system is what we want.
Unity will refuse to play the game when there is something wrong with the script. But, at least in this case, it's pretty good in letting you know what the problem is (and even how to fix it). Go ahead and change back that variable to.
When things don't work as you expect, even when scripts compile fine, there's a chance you got one of these common errors: