Homework #3

Bot Navigation


Description

The ability for Bots to move around a map is taken for granted when you are fighting for survival in a Death Match game.  After all, you as a player learn your way around a map relatively quickly.  However, this ability does not come naturally to Bots.  For a Bot to learn its way around a map and to remember the best way to get from one point to the next is a complicated problem for artificial intelligence.  Even more complicated is for a Bot to recognize its own location in the map so that it can choose a best path.  Instead of building sophisticated intelligence into the Bot, the "knowledge" about how to navigate around a map is encoded into the map itself.

One of the duties of a level designer is to insert what are called "path nodes" into the map.  These path nodes are invisible when the game is played but bots can "see" the path nodes use them to find their way from one place to the next.  Each path node can tell the Bot the next path node they should visit in order to get to a given final destination.  In the following diagram, the bot wants to reach path node 8 (maybe this is where the rocket launcher is located).

There are two possible paths.  In order to find it's way to path node 8, it asks the nearest path node, node 4, where to go.  Path node knows that the best way to get to node 8 is to go through node 1 and tells the Bot so.  The Bot then proceed to path node 1 but does not know what to do after that.  The Bot again asks the nearest path node -- this time the nearest path node is node 1 -- where to go.  Path node 1 knows that to get to node 8, the Bot should go through node 2.  The cycle continues until the Bot finally reaches it's final destination.

Most of the intelligence built into the path nodes is pre-computed by the level editor itself.  Each path node knows which node the Bot should visit next for each path node in the entire level.  However, in order to learn more about how Bot navigation works, we are going to ignore the fact that this functionality is already supported, and build our own system of path nodes and our own algorithms for computing best paths.

For this assignment, you will create a special Bot, a CamDroid, that wanders around the level.  The CamDroid is special in that it does not partake in combat.  Instead, players will be able to “see” through the eyes of the Camdroid when they type in a special command.


How Bot navigation really works

Bot navigation relies on invisible PathNode objects distributed throughout the map by the level designer.  When UnrealEd builds the map, one of the many tasks it performs is a all-pairs-shortest-path calculation on the PathNode object. 

The all-pairs-shortest-path algorithm pairs every possible starting node with every possible destination node and finds the shortest path through the network of PathNodes .

For each possible pairing of starting node and destination node, the starting node has a special data structure called a ReachSpec.  The ReachSpec records the final destination and the next closest node in the network.  Thus when a Bot needs to know how to get to a particular destination, it can quickly look up the ReachSpec in the nearest PathNode and find out the next place to go.  The Bot never knows the path further than one node in the future.

Since the all-pairs-shortest-path algorithm is done when the level is built, the algorithm never needs to be run during game-time.  This is important to game play because the all-pairs-shortest-path algorithm is computationally expensive and Bots cannot afford to be running slow algorithms while participating in a game.

In order for a Bot to get to a location in the map that does not coincide with a PathNode (for example, it is trying to get to another enemy player -- enemy players are not recorded by ReachSpecs because they can move around freely), it merely has to find the PathNode that is nearest to (and visible from) its desired location and use the network of nodes to reach that PathNode.  Once at the final PathNode , it can make a bee-line to that non-node position.  This system only works if the level designer has placed the nodes in the map such that there is one or more other node visible from every node.

Bot navigation is handled by a function in the Controller base class, FindPathToward(Actor anActor)anActor is the final destination that the Bot wishes to arrivate at.  Notice that the type is Actor and not NavigationPoint.  This means the Bot can find its way to any location, regardless of whether it is part of the path node network or not.  FindPathToward() returns an Actor object that is the next closes point to move to.  The return value may or may not be the same as anActor, depending on whether the route to anActor is complicated.

Once the next point to move to is known, the Bot moves by calling MoveToward(Actor newTarget)MoveToward() is usually called by state code and the newTarget usually depends on the goal of the Bot (e.g. attack or retreat or collect power-ups, etc.).  you may find it beneficial to look at some of the state code in the Bot class to see how moving is handled there.


What you are actually going to do

You have two tasks:

1. Create a functioning Camdroid bot.  Camdroid is made up of CamdroidPlayer – a subclass of AIController – and CamdroidPawn – a type of xPawn.  Modify the stub CamdroidPlayer so that the bot randomly picks a PathNode to travel to.  Note, I have put special path nodes called MyPathNodes into the test levels.  The only difference is that they are visible.  Once it travels to that location, it picks a new location.  The stub CamdroidPlayer class has a single stubbed out function, Start.  Start is called by the DroidGame after Camdroid is created (by the game) and after the match has started.  Here is what I recommend.  Create a function called PickNewDestination that randomly chooses a PathNode for the final destination.  Create a special state, called navigating that loops forever.

2. Modify the player’s controller and pawn, CameraPlayer and CameraPawn, respectively, so that when the user types “spy” into the console, the user’s camera is attached to the camdroid.  When the user types “unspy” into the console, the camera returns to the player’s body.  I recommend using the CameraPawn to override the SpecialCalcView() function.  SpecialCalcView takes three parameters: out Actor ViewActor, out Vector CameraLocation, out VectorCameraRotation.  Changing the value of the pass-by-reference variables will tell UT where to place the user’s camera (we don’t ask how this is done, only that it works).  Note that SpecialCalcView is only called when bSpecialCalcView variable is true.


Classes that you should be aware of

Controller

The base class for all Bots and human users.

function Actor FindPathToward (Actor anActor, optional bool bWeightDetours)

Use the built-in ReachSpec information for the nearest NavigationPoint to find the next closest node in the network to anActor.  Returns an Actor that the Bot should visit next.

function Actor FindPathTo (vector aPoint)

Works the same as FindPathToward() except it takes a vector instead of an Actor.

function MoveToward (Actor newTarget, optional Actor viewFocus, optional float destination offset, optional bool bUseStrafing, optional bool bShouldWalk)

If called in state code, causes the Controller to move toward newTarget.  This function assumes that newTarget is visible from the Controller's current position.  viewFocus specifies what the actor should look at as it is moving to the next position.

function MoveTo (vector newDestination, optional Actor viewFocus, optional bool bShouldWalk)

Works the same as MoveToward() except it takes a vector instead of an Actor.

MoveTarget

A reference to an Actor.  Frequently used as a holder for the next intermittent node in the path.

PlayerController

The base class of all human users.

event PlayerTick (float deltaTime)

This is the tick function for PlayerControllers.  The normal Tick() does not work here, but instead PlayerTick() is called every tick.

function PlayerMove (float deltaTime), function ProcessMove (...)

This function is called when the player sends the command to walk forwards or backwards.

state PlayerWalking

This state code is running when the player is standing or walking on solid ground.  You will notice that functions such as ProcessMove() are handled specially in this state.

state PlayerFlying

This state code is running when the player is falling or flying through the air.  You will notice that functions such as ProcessMove() are handled specially in this state.

Actor

Base class for everything that can manifest itself in a level.

function bool FastTrace (vector TraceEnd, optional vector TraceStart)

Quickly traces a ray between the object making the call and the position, TraceEnd.  If there are no obstructions between the object making the call and TraceEnd, this function returns true.  If TraceStart is specified, it uses that position as the place to originate the ray.

Location

A vector specifying this object's absolute position in the level.

NavigationPoint

The base class for all objects that can be used by Bots for navigation.  This includes PathNode, PlayerStart, and InventorySpot .

PathList

An array of ReachSpecs.  You may notice that there are no functions that actually reference this array.  All path navigation routines are native to the game engine and not UnrealScript.

PathNode

The most basic type of NavigationPoint that is placed into maps by level designers.  It doesn't really add any functionality to the NavigationPoint (at least visibly, there may be native code hidden from the UnrealScript) except this class is placeable.

Pawn

The base class for all pawns.

Bool SpecialCalcView (out Actor ViewActor, out vector CameraLocation, out vector CameraRotation)

This function places the camera when bSpecialCalcView = true.  The three parameters are pass-by-reference and changing them determines where UT will use as the user’s viewpoint.

 


Exec functions

Certain functions in the Controller and its subclasses are specified as "exec" functions.  This means that these functions can be executed directly from the console window.

The console window is a message window that slides down from the top of the screen when you press the '~' key.  In the console window you can see the previous broadcast messages.  There is also a prompt where you can enter exec funtions.  For example, typing "ghost " allows you to fly through the air and walk through walls.

Your CameraPlayer has two special exec function called spy and unspy.  When spy is run from the console, it will cause the player’s camera to become attached to the camdroid so that the player sees what the droid sees.  When unspy is run from the console, the user’s viewpoint returns to the player’s pawn’s body.

Here is an example of an exec function that lists the location of a given actor in the game.

exec function foo (coerce string name)
{
   local Actor a;
  
   foreach AllActors (class'Actor', a) {
      if (name ~= string(a.name)) {
         // Found the actual object with this name
         Level.Game.Broadcast(self, a.Location);
         break;
      }
   }
}

The parameter that you pass in is forced to be of type string.  This function figures out what object in the level corresponds to this name.  Note that every Actor has a name variable and that that name can be typecast into a string.  the ~= is a special operator that checks string equality without case sensitivity.

For example, when you type

foo mypathnode4

into the console, you should see a broadcast message with mypathnode4 object's location.

Obviously, spy and unspy will be very different.  But I wanted you to be familiar with how to parameterize exec functions.


Files that you will need

In order to complete your project you will need the following files:

  1. MyPathNode.uc.  This is a stub of a class that declares the special type of navigation node your project will use.  The only difference is that these path nodes are visible.
  2. DroidGame.uc.  This is the game that will create the Camdroid and call its Start function.
  3. Hw3.int.  So the game will be playable.
  4. CamdroidPlayer.uc.  The stub class for the Camdroid’s brain.
  5. CamdroidPawn.uc.  The class for the Camdroid’s body.  You shouldn’t have to modify this function.
  6. CameraPlayer.uc.  The stub class for the special player type.
  7. CameraPawn.uc.  The stub class for the special pawn type.
  8. NavGame.uc.  This is a stub of a class that declares the new type of game.
  9. NAV-maze.ut2.  This is a test map that contains MyPathNode objects and should only be used by DroidGames .  You may wish to open this file and edit the path nodes within.  You must have a successfully compiled hw3.u before you can open this map in UnrealEd.

Setting up your homework project

You must create a new package in the UT2004 class library.  All the new classes you write should be part of this package.  The name of your package should be "Hw3".

  1. Create a new directory, UT2004\Hw3\Classes.  All your class files should go in this directory.
  2. Open WOTGreal and select "ut2004" -> "Refresh Package/Class Tree" menu option.
  3. Edit UT2004\System\UT2004.ini and add "EditPackages= Hw3" to the appropriate section of the file.
  4. Don't forget to create Hw3.int sothat your new game type will be recognized!

Testing your project

To test your project, run UT2004 and select the "CamDroid Game" from the Instant Action menu.  You should be able to choose the NAV-test.ut2 map.  I recommend setting the number of bots to zero.

You may also wish to use other maps.  I do not expect your droid to be able to navigate across jumps or movers.  Make sure to rename the map file to a "NAV-" prefix.

Other things to consider when testing your code is whether the droid s the edge of walls (line of sight calculations do not consider the fact that your body has width).  I will not take off points if this happens, but you should be wary of situations where you get caught on a wall and stop moving altogether.  You should either avoid clipping the wall or programmatically handle the situation where you get stuck on the wall.

For your final grade, I will test your code on a map that does not have MyPathNodes.  So don’t hard code any dependencies to MyPathNodes.


Getting started

Get the droid working first.  The camera part is pretty easy after that.  You’re welcome.


What you must turn in

To get credit for your work, you must submit a single UMod file.

The UMod file should contain MyPathNode.uc, DroidGame .uc, CameraPlayer.uc, CameraPawn.uc, CamdroidPlayer.uc, CamdroidPawn.uc, Hw3.u, and Hw3.int. Your UnrealScript files should unpack automatically into UT2004\Hw3 directory.  Your .u and .int files should unpack into UT2004\System directory.

You should also write a readme.txt which describes any assumptions or optimizations you have made to the basic functionality enumerated in this document.  Also describe any additional functionality that you program into your game or your Controller (for example, are there ways to abort the auto-movement once it has begun?).  The readme.txt should be in your UT2004/Hw3 directory (not UT2004/Hw3/Classes).  Make sure that this file is included in your UMod.