Class hours: 10:05 – 2:45
Mr. Bohmann | wbohmann@ewsd.org
10:05 Today’s Notes & Attendance
Game Idea Generator – kind of nifty JS project
Noon – Student Leadership Meeting
10am Using Instantiate() to Create PreFabs
We’ve seen how we can write code to destroy gameObjects. You are doing this for your Breakout game.
void OnCollisionEnter2D(Collision2D otherObject)
{
Destroy (otherObject.gameObject);
}
The Destroy() logic can be placed anywhere in your scripts, so long as you have a reference to the target object. You might remove objects in the OnCollisionEnter2D() and OnTriggerEnter2D() functions, or from the Update() function or in some other function – whatever makes sense to your game.
If we put that bit of code on your breakout ball, it would destroy any game object it collides with.
The Destroy() function can take a second parameter that allows you to delay the effect. You can pass in a number of seconds such as 0.5 or 2.0 and the object will not actually be destroyed until that much time passes.
void OnCollisionEnter2D(Collision2D otherObject)
{
Destroy (otherObject.gameObject, 1.0F);
}
We can also use code to create gameObjects too. This is really handy with PreFabs, spawning enemies, handling bullets managing random power-ups – I could go on. Let’s start basic then add some heavy lifting:
- Open your Lunar Lander game.
- Add an asteroid sprite to the hierarchy
- Add circle collider 2D
- If you have a rotation script, pop that on as well
- Drag to your PreFabs folder – you now have a prefab
- Delete your PreFab from the hierarchy
- Open your LunarLander Script and
- Create a Public GameObject asteroidPreFab variable
- Populate that new variable slot with your PreFab from the PreFabs folder
- In the void Start method of your LunarLander add in the following line of code
// create a variable that is public
public GameObject asteroidPreFab;
void Start ()
{
Instantiate(asteroidPreFab); // create a new copy of the prefab
}
We have chosen to call Instantiate() in the Start() function of this script, because we want the asteroid to be created right away when the game starts. But, you can call Instantiate() from anywhere that makes sense for your game! For example, if you are firing bullets from a gun, you might call Instantiate() from inside the Update() function when you detect the trigger key.
Level Up – Round 1
What happens if we run this script – where do the Asteroids go?
public GameObject asteroidPreFab;
void Start ()
{
Instantiate(asteroidPreFab); // create a new copy of the prefab
Instantiate(asteroidPreFab); //copy 2
Instantiate(asteroidPreFab); // copy 3
Instantiate(asteroidPreFab); // copy 4
Instantiate(asteroidPreFab); // copy 5
Instantiate(asteroidPreFab); // copy 6
}
You can actually call Instantiate() with one or more additional parameters to configure the cloned object. This version lets us add a new position and rotation to the new object.
Instantiate (asteroidPreFab, new Vector3(4.0F,2.0F,0), Quaternion.identity);
The Vector3 parameter contains the X, Y, and Z coordinates of the new object in world units. You can get a good sense of the X and Y units by looking at the grid lines within the camera rectangle on the scene. Each grid line is 1 world unit, so if your camera is showing 5 boxes vertically and 8.5 horizontally in every direction from the center.
ProTip: You can toggle grid lines on and off (look for the Y icon near the grid icon at the top of Scene)
The third parameter is a Quaternion that represents the rotation angles in the X, Y, and Z directions. A Quaternion is actually a complex object that you don’t want to try and modify yourself. Fortunately, if you don’t want your new object to be rotated, you can pass in the value Quaternion.identity, and the object will be created with no rotation.
A 2D (“orthographic”) camera like the one we are using has two handy properties that we can read to find the size of the screen. The orthographicSize property shows us half of the screen height, in world coordinates. The aspect property gives us the ratio of width and height. So, we can easily calculate the screen dimensions as shown below. Aspect is calculated as width divided by height.
// calculate the size of the screen, in world units
float worldHeight = Camera.main.orthographicSize * 2.0F;
float worldWidth = worldHeight * Camera.main.aspect;
We can get a new random value by simply writing Random.value as part of an expression. Random.value is a Unity property that will return a random number between 0.0 and 1.0 (including both 0.0 and 1.0 in the possible range). Let’s use this random value and some math to calculate random positions on the visible scene in world coordinates. However, to use this expression, we need to add a library to the top of our script where we want to use it – or we’ll get an error message.
using Random = UnityEngine.Random;
// calculate random starting location
float randomX = (worldWidth * Random.value) - worldWidth / 2.0F;
float randomY = (worldHeight * Random.value) - worldHeight / 2.0F
Each line will get a random number and then multiply that by the width or height of the screen. So if a screen is 14 world units wide, for example, we will have a random number between 0 and 14. We then subtract out half the width or height because the origin (0, 0) is in the middle of the screen. Subtracting half of 14 from a random number between 0 and 14 would give us a random number between -7 and +7.
Confused Yet? Probably with the math. So just copy the code and its all good man.
void Start ()
{
// clone 3 asteroids at random locations
CreateAsteroid();
CreateAsteroid();
CreateAsteroid();
}
void CreateAsteroid()
{
// calculate the size of the screen, in world units
float worldHeight = Camera.main.orthographicSize * 2.0F;
float worldWidth = worldHeight * Camera.main.aspect;
// calculate random starting location
float randomX = (worldWidth * Random.value) - worldWidth / 2.0F;
float randomY = (worldHeight * Random.value) - worldHeight / 2.0F;
Instantiate(asteroidPreFab, new Vector3(randomX,randomY,0), Quaternion.identity);
}
We can even clean up our code some. Seems redundant to write CreateAsteroid function 3 times. Let’s add a Loop to repeat a block of code.
for (int i = 0; i < 3; i++)
{
CreateAsteroid();
}
//what this means is we are going to initialize a variable [i], check if a condition //is true (if i is less than 3) and if the condition is true we are going to add one //to the variable and loop this block until the condition is not met anymore
10:50 Break
11:00 More programming…..
Level Up – Round 3 – It’s getting heavy now –
Controlling Object Lifespans with Invoke and Coroutines
Can you think of some objects in your game that should have a limited lifespan? Power up, bullets, enemies spawning.
The word “invoke” means to cause or request something to happen. Within the Unity engine, invoke is used to mean “run a function“. You can define your own functions that contain script logic that needs to be run at a later time or regular intervals. Unity will then invoke that function based on the timing information you provide.
Invoke("CreateAsteroid", 3.0F); //you need a string of the method name and then the delay
The Invoke() function will only call the target function one time. But how can you cause a function to be
called repeatedly on a regular schedule? Unity has a second function called InvokeRepeating() that does the job!
InvokeRepeating(string functionName, float secondsDelay, float rate)
//for example this will create an asteroid after 3 seconds and 1 every second after
InvokeRepeating("CreateAsteroid", 3.0F, 1.0F);
A coroutine is when you create something and then you may want some other task to be performed on that object later. Like asteroids being created and then later they get smaller and disappear, or blow up or….. whatever we want. We’ll tackle coroutines in another lesson.
Your Turn:
In your Lunar Lander game, create some Aliens to appear at the start of your game. Can you do more than one kind of alien. Try using Instantiate and Invoke. Write your own method and then call that method in the Start(). Ask questions – don’t close your game if you have errors.
Then,
Instantiate some new objects at specific locations using your new knowledge. Maybe you instantiate a star each time the rocket lands correctly. Can you make the stars line up?
If we finish early, add scoring to your breakout game (if you do not have it). What about Game Over text, add that if you are missing. Do you have a win condition? Are your blocks different point values? If you hit a special block can you invoke a new object to destroy that’s worth more points!
11:45 Breakout Game
Today, build out the rest of your Breakout Game and add Scoring to your game. You have all the tools from examples we did before– remember the UI canvas on the Lunar Lander
- Can you set different blocks to have different point values!
- Adding a Score
- Add a custom font
- Add KillBox and GameOver Screen
- Design / Implement / Test
- Try to keep your ball bouncy – you may need some different physics materials on some of your colliders
Try to complete your Project by lunch on Wednesday, May 8th
- An A grade will be awarded for hitting the bulleted list above and for a nice looking game
- A B grade will be awarded for just totaling a score
- A C grade will be for an unfinished game with a score
12:25 – 12:55 Lunch
12:55 Independent Reading
1:20 Break
1:30 Design Challenge
1:55 Production Time and Guided Support
- Exploring Game Careers – Due Friday
- Breakout Game – Due next Wednesday
2:40 Dailies
Dailies can be placed in the CAWD2 Dailies Folder on the CAWD2 Public Folders drive