CTIN 583

Week 4 Monday

Today

  • Prefabs

  • Instantiate

  • Collision lab/demo

Prefabs

are templates

Prefabs

Prefabs are templates or definitions of different kinds of GameObjects.

 

To make a prefab, set up the object you want in your scene as you would usually.

 

Then drag the object into the Project tab. It will make a file that remembers all the details.

Prefabs are necessary in order to spawn (create) new things during your game – enemies, bullets, etc.

Why? Because Unity needs to have a template to work from when you tell it to make something new.

Prefab

A template object, saved as a file.

 

Instance

An individual copy of the prefab. You can have several per scene. You may have instances of a prefab in any scene of your game.

 

Instantiate

To make a new copy of a prefab. Usually only refers to instantiating from code.

An instance may have some small differences from its prefab — for example, its position. These changes to individual instances are called overrides.

 

Overridden properties have a light blue line next to them.

 

When you are looking at an instance, you can click on the "Overrides" button to see a list of all properties it is overriding.

Sometimes you adjust an instance with overrides and decide you want to make the same changes to all instances.

 

You can push your changes "up" to the prefab by choosing "Apply". Then the prefab will push the changes "down" to other instances in the game (including in other scenes).

Got a good thing going

Sometimes you adjust an instance with overrides and decide you don't like them.

 

You can undo your changes by clicking "Revert". This will copy the prefab's values to your instance, undoing any overridden properties.

Never mind

In larger projects, you may find it useful to create nested prefabs and variants. See the resources below for more details.

Larger projects

Instantiate:
The Power of Creation

Once you have a prefab to work with, you can stamp out as many copies as you like.

 

There are two steps.

First, in the script that is going to spawn new objects, give yourself a [SerializeField] variable to hold a reference to the prefab.

[SerializeField]
GameObject blockPrefab;

This will usually be of type GameObject.

But later on you will sometimes find it more useful to use another type.

Then you can use Unity's Instantiate function to crank out the new objects.

Instantiate (blockPrefab);

This is the simplest version. It will make a new copy of the prefab. The new object's position will be whatever the prefab has as its position.

Instantiate (
    blockPrefab,
    position,
    rotation
);

Often you want to set the position of the new object at the moment you make it.

 

But this function requires you to set a rotation as well.

What to make (prefab)

Where (V3)

How to rotate it (Quaternion)

About 99% of the time you will use one of these two values for the rotation:

Quaternion.identity



transform.rotation

no rotation

use this GO's rotation

You will use these two versions of Instantiate about 90% of the time.

 

There are others that let you set the parent of the new object, or all of the above. See the documentation.

 

But notice you can set the same properties yourself after you've instantiated... if you saved a reference.

File Land vs

Game Land

A prefab is a file.

 

You can instantiate a prefab in any scene.

 

But you can't give a prefab a reference to something inside a scene.

 

Files can't see into scenes.

At some point you will try to drag a scene object onto a slot on a prefab, and it will show a "no" sign. This is why!

Remembering your child

Sometimes, as with bullets in Ikaruga or splats in Splatoon, you just need to crank out a bunch of objects and forget about them.

 

In that case you can simply do this:

Instantiate (
    splatPrefab,
    position,
    rotation
);

Other times you will want to remember the thing you instantiated.

 

Sometimes it is just for a moment, so you can set its properties. Other times you want to keep the reference for longer. Either way, this is how you save a reference to the new object:

Instantiate (
    thingPrefab,
    position,
    rotation
);
GameObject newThing =

Once you have the reference to the new instance, you can do anything you can do with a GameObject or its components.

newThing.transform.parent =
                     gameObject.transform;

newThing.GetComponent<Renderer>().enabled
                     = false;

Remember, your scripts are components too. Here is how to get a script component from a newly instantiated object and call a method on it.

Instantiate (...);
HomingMissile newMissile =
newMissile.SetTarget(player);

assumes the HomingMissile script has a public method called SetTarget

GameObject newmissileGO =
newMissileGO.GetComponent<HomingMissile>();

Collision Lab

Smarter Collisions

Smarter Collisions

Sometimes you will want to do the same thing regardless of what your GO collides with.

 

For example, you might play a "clack" sound every time your billiard ball hits something.

 

Or if your player GO collides with anything it ends

the game.

But often you will want different collisions to cause different things to happen.

 

A Goomba causes Mario to lose a life. A pipe or brick block does not.

So your Mario script, for example, needs to be able to tell a Goomba from the other objects.

 

In pseudocode:

  if (the other object is a Goomba)
  {
       Die();

  } else
  {
       //do nothing
  }

In a regular collision, all the information about the collision is in the Collision parameter.

void OnCollisionEnter(Collision collision)
{
   //do stuff
}

The only thing you generally care about inside that Collision object is what the other GameObject is.

collision.gameObject

Since you have a reference to the other GameObject, you can get its name, its tag, its components, and more.

collision.gameObject.name

collision.gameObject.tag

collision.gameObject.GetComponent<Rigidbody>()

This gives you several ways to figure out what the other object is. Some are more useful (and less likely to break) than others.

collision.gameObject.name

collision.gameObject.tag

collision.gameObject.GetComponent<Rigidbody>()
  if (collision.gameObject.name == "Goomba")
  {
       Die();
  }
  • likely to break because people change GO names a lot
  • level designers work quickly, make copies of GOs with names like "Goomba (1)"
  • easy

Pros:

Cons:

  • one tag per GO, but a GO might belong to multiple groups
  • difficult to wrangle more than a couple dozen tags
  • easy

Pros:

Cons:

  if (collision.gameObject.tag == "Goomba")
  {
       Die();
  }

Another way to know whether some GO is the kind of GO you care about: ask for its script components.

collision.gameObject.GetComponent<Goomba>()

If the other GO has a Goomba script attached, you can assume it's a Goomba.

collision.gameObject.GetComponent<Goomba>()

If the other GO has a Goomba component, this will get you a reference to it.

 

If the other GO does not have a Goomba component, this will return the special value null, which is nothingness.

So to determine whether the other GO has the script, you ask if the result is not null.

 

Not-nothing is something. So it must be a Goomba.

Goomba potentialGoomba = 
  collision.gameObject.GetComponent<Goomba>();

if (potentialGoomba != null)
{
   Die();
}
  • a little annoying to set up
  • sometimes GOs don't really need scripts and it's awkward to add them just for this
  • reliable
  • tells you what you probably really want to know, which is how the other object acts
  • now you have a reference to the other script

Pros:

Cons:

if (potentialGoomba != null)
{
   Die();
}
Made with Slides.com