Upload
nam-ngoc
View
116
Download
1
Embed Size (px)
DESCRIPTION
AI in Games- Steering, Wander and Flocking behavior
Citation preview
Steering, Wander and Flocking behavior of an AI game character
Using Processing to implement various dynamic movement algorithms and compare their performance. “Processing (http://www.processing.org) is an open source programming language and environment for people who want to create images, animations, and interactions.” Processing contains an IDE and runtime execution environment. Java classes can extend the base Processing classes to work in an IDE like Eclipse. Specific instructions on how to build a processing PApplet with Eclispse can be found here: http://processing.org/learning/eclipse/
1. Kinematic Motion
Problem: Using kinematic motion, to have a shape start at the bottom left corner of the screen, and traverse around the edge until it returns to its starting location. The character leaves breadcrumbs as it traverses the screen.
Solution: There are only four directions in which the shape could move, so I represented the four directions with a
variable ‘state’. I took only the velocity and not the acceleration. Also I took velocity to be scalar variables as
direction was not very important. On each frame, the character will move with the max velocity towards the
direction was managed by the ‘state’ variable. Whenever the character reaches any end of the canvas the state will
change and make the character move along the other edge. I stored the breadcrumbs in an array. Throughout the
motion, I added the new position of shape at the first position and shifted the array repeatedly to the end. Then I
drew a point at each location stored in that array. I also included the change of orientation in this solution. For
calculating the orientation, I used atan2() which returned the arctan of the ratio of velocities along Y and X
directions. I subtracted this target orientation with current orientation to get the desired value of rotation. Then I
scaled it so that the character rotates towards the shorter rotation and changed the rotation of the character by
dividing this value in 10 steps. I tried various ways and combinations of rotation and translation and finally found a
suitable solution, which is translate the grid to the current position of character, rotate it by the required value and
translate the grid back to its original position. The screenshots are shown in the figure 1.1 and 1.2.
Figure -1.1 and 1.2 showing the basic motion with breadcrumbs
2. Seek Steering Behavior
Problem: To implement seek algorithms to make the shape seek the location of mouse clicks. Making sure the
shape is oriented in the direction of travel, which can be accomplished by implementing an orientation matching
steering behavior. Test out multiple methods for implementing arriving and compare their performances.
Solution: For the seek steering behavior, I used the mousePressed() function to get the position of mouse-click.
The seek() function takes the two axis values as argument. I tried the following two ways to get the seek behavior-
1) First way, without using any acceleration component. I stored the difference between the current and
target positions in a variable ‘direction’. I calculated the distance to the target and compared it with the
radius of satisfaction. If it is larger, the values of the target difference will be stored in X and Y
components of velocity vector. Then I normalized the velocity and scaled it to max acceleration. I used the
time elapsed between each frame and updated the position by using ‘position += velocity * time’. This
method gave me motion in straight line. (As shown in figure 2.1)
2) For the second method, I calculated the acceleration using the distance from the target and normalized
and scaled it to max acceleration. If the distance is larger than radius of deceleration the acceleration is
positive. If the distance is lesser than radius of deceleration then acceleration is negative or zero
depending on the situation. I tried two different ways of using this acceleration: one by adding the
acceleration directly to velocity and other by using the proper equations of motion. I also experimented
for different values of max velocity and max acceleration. I found two different results. One of the
motions was curved (figure 2.2). That is because if the character is already in motion, the application of
acceleration in any other direction results in curved motion. The other method gave zig-zag motion (figure
2.3). If any of the components of velocity overshoots the components of target position, the character
moves ahead and back many times before settling in the mean position.
Among these three kinds of motion, I think the first method best serves the problem mentioned. To move in the
direction of mouse click, calculating acceleration is not necessary. The first method also gives motion in linear way
without any oscillations, which is suitable for simple board games. But for games where it is necessary to make the
motion look real, it is necessary to introduce acceleration. So for actual game scenarios, the second method will be
better as it provides human-like motion which follows the laws of physics. This results in motion in a curve which is
more realistic and applicable to motion games like racing. Also the values of max acceleration and max velocity
need to be chosen carefully, to allow the desired way of motion.
Figure-2.1 Linear motion with only velocity component.
Figure 2.2 Motion with linear acceleration
Figure 2.3 A bad case of motion with acceleration which leads to zig-zag motion.
3. Wander Steering
Problem: Implement the wander algorithm to make the character move randomly in the canvas. Make sure your
shape is oriented in the direction of travel and to handle boundary violations gracefully. Implement at least two
different methods for changing orientation and compare which one in better.
Solution: Wander steering behavior can be implemented in many different ways. The challenge is to keep the
velocity along or slightly deviated from the orientation.
1) The first method I used simply calculates a small random orientation and adds it to the current
orientation. The character then moves in the direction of new orientation by applying velocity or
acceleration in that direction. This wander is limited to a maximum rotation of 15 degrees in each step. It
provides very smooth motion as shown in figure 3.1. The values of maximum rotation could be varied for
different wandering behaviors.
2) Then I implemented the target seeking behavior. I calculated a random binomial value, multiplied it with
wander rate and added it to current orientation to get a new target orientation. The character imagines a
target in the direction of new orientation and seeks it. As the target position is calculated using a binomial
value the resultant motion is along the orientation or slightly deviated. This gives a better motion which is
more oriented towards the direction of motion (figure 3.2). I tried it for different values of wander rate,
wander radius, max acceleration and max velocity and all of them gave different ways of motion. These
parameters need to be chosen properly for a smooth motion.
Both the ways provide decent wander behavior. I found the first method to be smoother than the second one. I
tried both the implementations with different boundary conditions. In one case I limited the motion within the
frame and in other I allowed the character to cross one edge and appear from the other edge. Both the above
methods perform smoother when I allowed wrap around. But the limited frame also works well if the orientation is
reversed slowly at the edge.
I also tried different ways to orient the character in the direction of motion. It didn’t work very well with angular
acceleration. While using angular acceleration the character generally overshoots the desired orientation and
oscillates before settling in the right direction. So instead of using the angular acceleration I have used only angular
rotation. The align() method calculates the required rotation and achieves the target orientation in 10 steps. This
method feels more realistic and it is stable in the way that it doesn’t overshoot.
Figure 3.1 Wander without using seek
Figure 3.2 Wander with seek implementation
4. Flocking Behavior
Problem: Using multiple independent shapes, and implement flocking behavior. Elect one of the shapes as a leader
and have them wander the screen. Use the remaining shapes as the flock, incorporating the appropriate steering
behaviors to avoid collisions with other characters and provide way for the leader. Try it with different number of
followers and with two leaders where the followers follow the closest wanderer.
Solution: For the flocking behavior I created a separate class Leader which extends the basic class Shape. The class
Leader has all the functionalities of wandering and breadcrumbs. The class shape has the basic functionalities of
seek and align, along with three new methods- follow(), separation() and evade(). The three methods are
explained below-
1) The follow() method computes a position behind the leader and delegates to seek function to make all
followers move behind the leader. It takes the leader’s velocity, changes its direction and scales it
properly to get a position which is slightly behind the motion of the leader. The other characters follow
this new position instead of following the leader’s position. This is important otherwise they will create
chaotic motion where followers may come in front of the leader. The seek function handles the motion by
accelerating all the followers towards the position behind the leader.
2) By using the follow() method all the followers will converge at a place and then move as a single entity.
There needs to be a way to separate the characters and avoid collisions between the followers and also
collision between the followers and the leader. Separation() method ensures that the characters do not
get too close. For each follower it checks the distance of all the other followers from it. If the distance of
separation between one follower and any other follower is lesser than a threshold value
(separationDistance) then that character receives a force in opposite direction so as to move away from
the other follower. This change in acceleration is calculated for all the followers and the resultant is added
to the original acceleration with a specified weight. The weight of separation is kept higher than the
original acceleration to give more preference to collision avoidance between the followers. This method
also checks the separation between the leader and followers and the followers are moved away if the
leader is in very close proximity. The flocking motion with proper separation is shown in figure 4.2
3) The final important step is to make way for the leader. If the leader moves around, the followers should
move away to provide sufficient passage for the leader. The evade() function ensures that by estimating
the position where the leader would arrive in the next few frames and moves the followers away from
that position. It estimates the front position in a similar way as that estimated by the follow() function. If
any of the followers comes within a specified range of the front position it receives a force which pushes it
away from there. Thus, providing ample space for the leader to move between the crowds. This is shown
in figures 4.3 and 4.4. Again, the acceleration is applied with a specific weight to the followers. And ideally
the evade function should have the high weightage than follow function.
The combination of these three methods provides a very real-looking flocking and following behavior. First I tried
the above methods for only two followers and then gradually increased the number of followers to fifty. It worked
very well with small number of followers, but as the number of followers increase, the inconsistency increases.
Some of the followers start colliding and overlapping with each other. So it’s harder with larger number of
followers, but the extent of collision can be controlled by adjusting the weights given to different parts.
I have implemented collision avoidance using the distance between the characters. This was suitable for flocking
problem. But for other games, an alternative is to use the closest point of approach method. In this method we
predict the time and position of closest point of approach and the positions is less than a threshold we move the
character away from each other.
Figure 4.1 Multiple followers and leader randomly placed at the beginning.
Fig 4.2 (a)
Figure 4.2 (a) and (b) Multiple characters obediently following the leader.
(a)
(c)
(b)
Figure 4.3 (a) (b) and (c) Followers providing way for the leader by moving away from front positions.
Followers in (a) and (b) have higher distances of front separation than (c)
I implemented the same flocking behavior for two leaders, so that any follower follows the leader who is closest to
him. This works well with the same methods of follow, separation and evade. Each follower compares the distance
from both the leaders and follows the one which is closer. Initially both the leaders have approximately equal
number of followers but the ratio changes depending on the motion. The scenario is shown in figure 4.4
Figure 4.4 Flocking with two leaders, where the followers follow the nearest leader.
Figure 4.4 Flocking with two leaders, when the followers change their leader.
Obstacle avoidance-
I also implemented obstacle avoidance in this flocking example. I created a wall between the canvas and
implemented an obstacleAvoidance() function in the Shape class. It checks whether the target of any follower is at
the other side of the wall. If so, it applies a large force in the opposite direction of the wall and forces the followers
to not be able to cross it (shown in figure 5). The leader could cross the walls but not the followers. I tried it with
different positions and lengths of the wall. At first the followers would just get stuck on one side even if there was
a passage along the sides. So I implemented a random component of acceleration against the wall. So the
characters would move randomly around the wall till they find a passage to cross it. obstacleAvoidance() has the
highest weightage for acceleration. This motion of finding passage and moving through was not very smooth, but it
could be made better through selecting the weights properly.
Figure 5. Obstacle avoidance where the followers cannot move through the wall.
In all the above examples the behavior can be changed by adjusting the weights. Ideally the weights have the
following precedence-
Obstacle avoidance > Separation > Pursue.
But these can be changed to fit the game. If bumping into each other and into obstacles is allowed occasionally
then the weights can be similar. But if we need the avoidance and separation to be strict, their weights must be
significantly higher than the other weights.