Saturday, 23 March 2013

Adventures in time and raycasting

Francis Programming

Since last post I've rewritten my AI around the 5 states I mentioned in last post (spawn, walk, proximity, collide, attack) so it's now much more readable and much easier for me (and hopefully anyone else) to fix when things don't work.


--------------------◄|~☼~|►--------------------


I spent a good portion last week trying to figure out why my intelligent direction finding was crashing everything. Eventually I learned that you shouldn't use a WHILE loop in a function called by update, because that can wreck everything. After I figured that out it didn't take long to get that part of the code working as it should.


--------------------◄|~☼~|►--------------------


The next problem I had to code around was the width of my zombie. I had a function dedicated to finding a good direction to move in to avoid obstacles. This worked fine, except for the fact that it relied on raycasting to check if the zombies path was obstructed. So, if the obstacle wasn't directly in front of the zombie the ray would never hit it. This resulted in lots of unintelligent obstacle humping from the zombies. The obvious solution was to add raycast whiskers. Then I just had to figure out how to do that.

Obviously the whiskers had to be one unit away from the central ray on either side (the zombie is one unit wide) so the zombies would allow half a unit when navigating around obstacles. Unfortunately raycasting doesn't operate on local coordinates. So what I assumed would be something simple like:

float xCoord = transform.position.x
Vector3 leftWhisker = new Vector3(xCoord + 1, transform.position.y, transform.position.z)

Vector3 leftWhisker = new Vector3(xCoord - 1, transform.position.y, transform.position.z)
if(Physics.Raycast(leftWhisker, direction, out hit, 4)
{
     Do code in here
}
if(Physics.Raycast(rightWhisker, direction, out hit, 4)
{
     Do code in here
}

, it was much more complicated. After a bunch of time and a bunch of failed attempts, I asked a teacher, Paul for help, and he quickly found the command I needed. Once I had that command which could generate world coordinates from local coordinates I was apples. The finished code looks like this.


Vector3 direction;
Vector3 leftWhisker = new Vector3(-1.0f, 0, 0);
Vector3 rightWhisker = new Vector3(1.0f, 0, 0);
Vector3 worldWhisker;
RaycastHit hit;

...



worldWhisker = transform.TransformPoint(leftWhisker);

if(Physics.Raycast(worldWhisker, direction, out hit, 4) || task == "collide")
{
if(hit.transform.tag != "zomb")
{
directionFound = false;
leftHit = hit.distance;
}
}

worldWhisker = transform.TransformPoint(rightWhisker);

if(Physics.Raycast(worldWhisker, direction, out hit, 4) || task == "collide")
{
if(hit.transform.tag != "zomb")
{
directionFound = false;
rightHit = hit.distance;
}
}

Using that code I created a system by which the zombie can intelligently pick a new direction based on whether the obstacle was further away from the right or the left whisker.

--------------------◄|~☼~|►--------------------

For the sake of consistency I recoded the zombie ai and spawn scripts to operate on a timer rather than a series of different counters. This means that the zombies will act the same way on any system in any conditions, independent of frame rates. The zombies controlled by the old code would moved faster on a machine with a better processor and slower when there were lots of zombies on screen.


--------------------◄|~☼~|►--------------------

I also fixed some minor bugs (as in bug that weren't caused by huge errors in my logic, and were easy to fix once found). So, for better or worse, zombies will no longer fly into the air if they bump another zombie too hard and they no-longer lazily turn when they should be going forward (these bugs fixed courtesy of rigidbody, freeze position and rotation in the inspector). Zombies will no longer walk into an obstacle walk straight back the walk into the obstacle again without turning, repeating indefinitely.

--------------------◄|~☼~|►--------------------


The zombies now consistently avoid obstacles and rarely get stuck on things. They adopt a variable from the spawner which tells them to walk in a straight line for a period of time, so they can spawn in awkward spots. There is nothing else the ai needs, so unless I've missed something or something new comes up, the ai is done. The only work it will need from now is fixing any unexpected behaviours and a little polish.

On to key game systems I guess.
Francis.

No comments:

Post a Comment