CTIN 483

Week 5 Tuesday

Today

  • Smarter collisions (review)

  • Layers

  • Raycasting

  • Visualizing raycasts

Smarter Collisions

Smarter Collisions

Here are three ways to decide what the other object is, in a collision:

  1. What is its name?
  2. What is its tag?
  3. Does it have a certain script attached?

Note that there are many others.

  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();
}

Even Smarter Collisions

with Layers

Stretch Break

Raycasting

is useful

Raycasting is drawing an invisible line (the "ray") out into the game world to see what game objects are in that direction.

?

You can use raycasting to answer questions like:
 

  • Where will the player's grappling hook hit the ceiling?
     
  • Can that guard see the player character?
     
  • Is Mario standing on solid ground?
     
  • Is the mouse over that object?

Where will the grappling hook hit the ceiling?

Can that guard see the player character?

Can that guard see the player character?

Sometimes it's not enough to know whether two objects are colliding.

 

For example, Mario can only jump when he is standing on something.

Is Mario standing on solid ground?

 

You could use collisions to

answer this. But...

Is Mario standing on solid ground?

You could draw a ray

down from his center and

see whether it hits

something.

 

But...

In old 2D platformers like Mario, having even a small part of the character over solid ground is enough.

So you'd do something like this, with two raycasts.

 

If either of the raycasts

hits solid ground, then

Mario doesn't fall.

The mouse doesn't exist in the game world. It's just a position on a 2D screen.

Image source: Sha Qian via  Noteworthy

So you convert the mouse's screen position into a world position. Then you send a ray forward into the game world to see what it hits.

The syntax (what you have to type) is annoying.

 

And you can't see a raycast so it can be hard to know if you're doing it right.

 

But it's a key tool.

Stretch Break

Raycast Syntax (2D)

RaycastHit2D hit2D = Physics2D.Raycast(
   startOfRay,
   direction,
   distance
);

This is the basic form of the 2D raycast function:

The 2D raycast function needs at least three pieces of information:

 

  • where to start the ray
    This is a point, so a
     
  • which direction it goes
    A direction, so a
     
  • how far the ray should go
    A length, so a

Vector3

Vector3

float

  • Returns a RaycastHit2D, which is a package of information about what happened with the raycast. Here's the documentation.

     
  • Very similar to a Collision object

This is how you can get to the GameObject that the ray hit:

hit2D.collider.gameObject

Then you can ask that other GO for its components, tag, and so on:

GameObject otherGO = hit2D.collider.gameObject;
otherGO.GetComponent<SpriteRenderer>()

otherGO.gameObject.tag

otherGO.SetActive(false)
  • Returns a RaycastHit2D, which is a package of information about what happened with the raycast. Here's the documentation.

     
  • Very similar to a Collision object

The RaycastHit2D itself will never be null. So you might think you can do something like this:

Beware

if (hit2D != null) {
  print (hit2D.collider.name);
}

But this code will always run, whether or not the raycast actually hit something.

!

!

To find out if the ray hit something:

if (hit2D.collider != null) {
  print (hit2D.collider.name);
}

Beware

By default, the raycast will hit the same GameObject that is casting the ray. You can fix this:

 

  • by starting the ray outside of the GameObject's collider
     
  • or by setting up a layer mask.
[SerializeField]
LayerMask layerMask;

This will show a dropdown in the Inspector. The raycast will hit the layers with checks.

RaycastHit2D hit2D = Physics2D.Raycast(
   startPosition,
   direction,
   distance,
   layerMask
);
[SerializeField]
LayerMask layerMask;
RaycastHit2D hit2D = Physics2D.Raycast(
   startOfRay,
   direction,
   distance
);
RaycastHit2D hit2D = Physics2D.Raycast(
   transform.position,
   directionToPlayer,
   playerCheckDistance
);
RaycastHit2D hit2D = Physics2D.Raycast(
   transform.position,
   Vector2.down,
   groundCheckDistance
);

Stretch Break

Raycast Syntax (3D)

RaycastHit raycastHit;

Physics.Raycast(
   startOfRay,
   direction,
   out raycastHit
);

This is the basic form of the 3D raycast function:

This function needs at least three pieces of information:

 

  • where to start the ray
    This is a point, so a
     
  • which direction it goes
    A direction, so a
     
  • an out parameter to hold the result
    This is a

Vector3

Vector3

RaycastHit

???

Unity wrote this raycast function to use something called an out parameter. You don't need to understand anything about the why or how.

 

To use it:

  1. Declare a RaycastHit variable.
  2. For the third parameter of Physics.Raycast, type the word "out" and then your variable name.

This is how you can get to the GameObject that the ray hit, just like with the 2D function:

raycastHit.collider.gameObject

Stretch Break

Visualizing Raycasts

It can be hard to set up raycasting correctly because the ray is invisible.

 

You can't directly make the ray visible, but you can draw a line where the ray is using Debug.DrawRay.

 

It is almost the same as the raycast function...but slightly different.

Debug.DrawRay(
   startPosition,
   directionAndDistance,
   color
);
Vector3 dirToPlayer =   
      player.transform.position -  
      transform.position;

Debug.DrawRay(
   transform.position,
   dirToPlayer,
   Color.red
);

But dirToPlayer is a vector that points directly to the player. If you want to look in the player's direction, but only a certain distance, you will normalize the vector.

Stretch Break

Made with Slides.com