Thursday, December 13, 2007



After some "deliberation", my scissor creatures are now 3 times as large, and 10 times as few. Doing this allowed me to involve more complex sense and think routines as many many little scissors quickly bogged down the engine.

The perception function, only searching for the player, implements a distance check, uses the dot product to determine if the player is in front, and a ray cast to see if the player is not obstructed to determine if we can actually see the player. While this works very well for initial perception of the player, it can be easy to deceive the AI by running behind it. To overcome this, I crafted the logic so that when we have been following the player, and they run out of the field of view, we simply check the distance again and maintain pursuit if the player is close enough (most of the time).

When the AI is not chasing down the player, it will follow predetermined paths. Currently, I have 4 of these paths, with two AI spawned on each. Because of this, and the way that the AI move (quick, but slow to stop) they seem to race around some invisible track. In a way, this comes across as a game that the scissors play normally. The screen shot below shows one of these paths with the AI running about.



Within the AI, I have 4 important functions.

  • The first, "think", is a scheduled routine that calls the sensory "checkFOVPlayer", then carries out the simple finite state automata. The FSA has two states, following the player, and not following the player. The states are guided simply by whether or not the AI can "see" the player (or if it has "forgotten" where the player is, see above).

  • The second, "checkFOVPlayer", determines if the player is in the field of view of the AI. It is explained in some detail above, and is included below.

  • The "onCollision" callback event is being used for attacking the player. When the AI rams into the player, it will push them both apart and damage the player. Very simple response, but it is effective.

  • The last, "onReachDestination", is another callback which is triggered when the engine finishes moving the object to its destination. When this occurs, and the AI is not following the player (running the track), it will iterate to the next node and let the engine move us to the next node.




function scissorbody::checkFOVPlayer(%this,%obj) {
%line = VectorSub(%obj.player.getPosition(),%obj.getPosition());
//%dist = VectorLen(%line);
%dist = manhattanDistance(%line);
%cantsee = true;
if (%dist < dot =" VectorDot(%obj.getEyeVector(),%line);"> 0.0) {
%typemask = %TypeMasks::TerrainObjectType & $TypeMasks::StaticShapeObjectType;
if (ContainerRayCast(%obj.getPosition(),%obj.player.getPosition(),%typemask) $= 0) {
%obj.setMoveDestination(%obj.player.getPosition(),true);
%obj.followPlayer = true;
%cantsee = false;
}
}
}
if (%cantsee && ($dist > 30)) {
%obj.followPlayer = false;
%obj.stop();
}
}

Monday, December 3, 2007

Scissor AI

Before I talk about AI and my current progress, I'll say that I made myself a nice little function to warp my character around the map by right clicking on it. Nothing big, but it sure is helpful.







Alright, so the main antagonist to the boxman character is a race of scissor people. Fitting, right? Now, they don't need to be all that intelligent, basically just chase the player out of their area and chop him up. Ancillary behaviour is to just roam around (with some range of speed to establish different amounts of "determination") and probably have them sometimes fight amongst themselves, as they are vicious scissors. I would also like them to have a very simple learning scheme where they are capable of mapping limited states to good or bad outcomes (mostly just to learn that walking into water is bad, and possibly that a player carrying a rock is bad). I figure I can establish this by having limited state knowledge (where am I? is the player nearby? does the player have a weapon?), then by examining immediate outcomes, downplay states with negative outcome for a short time.

As it stands now, I've got some simple reflex agents that will watch for the player and charge them when they show up in the line of sight. The problem is that I'm using built in functions that set the aim object, which just happens to cause the AI to literally stare at the player no matter where they are. This is not the behaviour I want, they cannot be aware of the player at all times, they must happen to see the player then charge. To do this, I will have to build my own sight sensor function.







This morning, I was toying around with placement of the scissor race. I placed a marker out in the field and randomly placed n(100 now) scissor people around this marker. I soon found that when I let them all come at me, an interesting cluster pattern appears due to the collision amongst them. While this looks pretty cool, the collision also causes the player to become stuck. Immediately I thought I could overcome this by removing the collision between player objects. Of course, this caused the AI to combine on the field. It also did something crazy to the dynamic shadows produced for the AI shapes. You can see in the image that there is a yellow glow on the shadow. This is certainly not a desired effect, so I believe I will have to do something else to fix the sticking of the player. I'm thinking to just have the scissor people bounce off of the player, or the player from the AI or both.