Home / Developer Diary / Developer Diary #3: Adventures with Raycasting.
Ziggy Piggy

Developer Diary #3: Adventures with Raycasting.

Have I really written 3?

archer holding up finger to hot redhead
One second while I finish this Chocolate caramel.

I’m back, had to finish off this chocolate caramel box I got at Sam’s Club. Honestly that was not an endorsement. Programming does a number on the mind. I’ve been at it since 6am and oftentimes finish “the task” around 10pm. I then load up the Nintendo Switch and take out some guardians in Breath of the Wild. A game bought on release day and haven’t yet finished. Why? Unity3D, that’s why. Ever since I learned the magic of raycasting, I’ve been scouring Google and the Unity forums for the perfect formula. Sadly, everyone’s solution is just so complex and over the top.

SideTrack: When it comes to AI and game design, I feel every object needs to be self aware and take care of it’s own hit detection. The player shouldn’t be going “hey I hit you and took 10 hitpoints”. The object should detect collision and deal with the damages on it’s own internals. Granted there are exceptions, this is a game. That’s why I went down this RayCast path.

My RayCasting Solution

I wanted a solution that would cast rays in a straight line above, below, whichever direction I needed. I needed several rays and was looking for a very specific thing, in this case, the player character. My original “solution” cast rays overhead at -45, 0 and 45 degree angles. Coming from the center, this presented a problem. The edges would detect the player standing on a ledge and proceed to kill the monster. A well placed jump would go between the raycast and kill the player instead. Not the solution I was looking for. So I created a ray spreader of sorts. It shoots rays straight from one side of the collision box to the other. This is all done through the magic of basic maths.

Raycasting the right way.
This used to kill the NPC. Now it doesn’t.

Did I mention I hate Math?

Now granted this code is still in the works, (as noted in the picture the raycasting doesn’t yet start at the very edge) but it’s “working”. So the first step I had to do was find the extents of the BoxCollider2D. This was simple enough after a few hours of Google to find the right words to use. Sorry, I don’t have a WordPress Syntax Highlighter yet.

float leftExtent = npcCollider.bounds.center.x - npcCollider.bounds.extents.x;
float rightExtent = npcCollider.bounds.center.x + npcCollider.bounds.extents.x;

Basically I grab the left and right side of the box. Then I detect the “step” value by dividing it with the difference between left and right.

float step = (leftExtent - rightExtent) / numSensors;

 

The numSensors in this case is 4. Because Ziggy Piggy’s BoxCollider is only 0.8 wide, the step ends up being around 0.2. I forget the actual numbers so let’s just pretend.

Getting Loopy

That was it for the setup. Now it’s time to enter the loop.

for (int i = 0; i < numSensors; i++)
{
    if(Physics2D.Raycast(new Vector2(leftExtent, transform.position.y), Vector2.up, scanDistance, playerLayer))
    {
        StartCoroutine(InvulnerableTimer(0.5f));
        npcState = NPCStates.detectedSomething;
        return;
    }

    leftExtent += Mathf.abs(step;
    Debug.DrawRay(new Vector2(leftExtent, transform.position.y), Vector2.up * stompedDistance, Color.red);
}

 

This was basically it. I love short and to the point functions. It basically loops through the number of Sensors desired (Serialized for inspector).  It raycasts from an if statement. If nothing is detected it just moves on. If something is found it flags the character as “invulnerable” to prevent further detecting for 0.5 seconds. It sets a transitional state to grant time to bump the Player out of the hit zone and act on hitpoint/death factoring.

If nothing is discovered, it will add the Absolute (remove the negative sign) Step size from the left working the scanners to the right.

But this is pretty much it. This makes a great and extensible foundation for detecting in other directions. Instead of Vector.up you could do down, left or right…  Though scanning to the sides would require use of the Top/Bottom extents working on the Y axis.

Blooper moments

Yeah. I screwed up a lot here. Spent all morning wondering why the RayCasting worked when the X was negative and got left behind when the NPC wandered into the positive X world coordinates.  I was “trying too hard”. I originally did a ternary detection.

leftExtent = (leftExtent < 0) ? leftExtent -= step : leftExtent += step;

 

This did not work and left the scans behind.

diary3 something wrong
Raycasting gone wrong.

So I printed everything to the console. I found that the extents were done properly on the negative side, but quickly dropped back below zero instead of “adding” now that left was greater. I forgot that step was negative and the magic of negative numbers stabbed me good.

Simplifying the expression after rebooting my computer, I crashed Unity hard, the scene was loaded and BAM! it worked throughout the number range. How? I don’t really care :-p

Crashing my PC was the fun part. I originally put the Step into the for loop.

for (float i = leftExtent; i < rightExtent; i += step)

 

Looks like it would work right? Wrong. This created an infinite loop and eventually brought down my machine. I was posting on Facebook at the time and it was possibly a good thing to crash.

SideTrack: I know a lot of people, especially the plethora of tutorials I watched, they use empty Gameobjects and sensors… I’m wondering if this is industry standard due to the cost of raycasting, or if it’s just “easier and less code”.

Wrapping up

I’m new to C# as well as Unity3d. This platformer was supposed to be a simple week long project that’s turned on 3 months. But I ended up rewriting the AI into some pretty decent code, I may release to the Unity store if it’s ever “good enough”.

The Raycasting solution though is working and now I’ve started to use this implementation for “fall” detection and other sensors to add realistic behaviors to stupid platformer NPC’s.

About Chaos Meister

Chaos Meister is our Youtube personality with a boring national geographic voice. He does most of the Let's Play's and other videos.

Talk to us!