Errata for the second edition of Artificial Intelligence for Games. This page is based on a backup of the official errata webpage and the arrata at perl-hackers.net.
first code block, line 13, orientation
should read rotation
.
7 # Update the position and orientation
8 position += velocity * time
9 orientation += rotation * time
10
11 # and the velocity and rotation
12 velocity += steering.linear
13 rotation += steering.angular
code block, line 8, static
should read velocity
We use the Static
data structure should read We use the Kinematic
data structure
code block, line 37, explicitTarget
should read target (this class target, not the super class one)
first code block, line 20, explicitTarget
should read target
(this class target, not the super class one)
code block, line 34 and 38 should use target.position
instead of target
code block, line 21, currentPos
should read currentParam
code block, line 29, currentPos
should read currentParam
code block, line 30, direction
should be calculated the other way around, or the objects will attract and not separate.
30 direction = character.position - target.position
An error in the source code, line 66. In the source code for collision avoidance, there is a mistake on line 66.The variable 'distance' is referred to, but that variable has fallen out of scope by this point. Line 66 should read:
if firstMinSeparation <= 0 or firstDistance < 2*radius:
in the code block, the steering variable is not initialized as usual. So, for instance, on line 74, should be:
74 steering = new Steering
in the code block, line 35 and 67 should be calculated the other way around:
35 relativePos = character.position - target.position
...
67 relativePos = character.position - firstTarget.position
in the algorithm, line 34 should use target.position
in the end of the algorithm, max value is computed, min should be. Also, it should be pointed out that we are overloading Min with the possibility to compare a vector (steering.linear) with a real value (maxAcceleration).
26 steering.linear = min(steering.linear, maxAcceleration) # this is the overloaded one
27 steering.angular = min(steering.angular, maxRotation)
line 33 of the algorithm is not needed. That variable is never used. Maybe it was there for a less-algorithmic approach, where break continue
wasn't allowed.
line 42 of the algorithm, should use constraint.willViolate(path)
, accordingly with API defined in the next pages.
first code block, line 14 should use start
and end
, instead of startNode
and endNode
.
In the same block, before calling Astar, heuristic should be initialized. Probably it is worth a heuristicNode
information, to compute the heuristic only if the end node changed from last time the heuristic was used?
An error in equation 3.3. The two terms used to calculate the change in height are reversed, changing the sign of the delta-height. In the parentheses under the square root, it should read:
pyt - py0
method suggest
should have a first line with segment = path[problemIndex]
for correctness, method checkJumpTime
should return canAchieve
code block:
line 28, goal
should read end
;
line 31, current
should read current.node
;
line 78, goal
should read end
;
line 93 should be: current = closed.find(current.connection.getFromNode())
code block:
line 32, goal
should read end
;
line 35, current
should read current.node
line 81, .cost
should read .estimatedTotalCost
line 114, goal
should read end
;
line 129 should be: current = closed.find(current.connection.getFromNode())
This section is interesting and relevant, but misses some strong opinions to the casual reader. When reading the heaps section the reader will be convinced that that data structure is great. But it is not clear, for someone not familiar with heaps, that the find
, the contains
and the remove-element
methods are too inefficient (full tree look-up, and probably full heap reordering during random element removal. Removal is just a problem for A*, given that Dijkstra removes only the tree head.
When discussing que Average Minimum Distance, the paragraph concludes with “So the average cost of moving from C to D is 31/2”, where it should be 7/2, or if you want to use the same digits, “3 1/2” 😄
The algorithm “as is” does not work, as it has an infinite loop, as currentLevel
doensn't get changed. My correction is presented below. Also, line 7 is not needed, as startNode
gets rewritten in the loop.
21: currentLevel--
22:
23: # Are the start and end node the same?
24: if startNode == endNode:
25: # Skip this level
26: continue
27:
28: # Otherwise we can perform the plan
29: graph.setLevel(levelOfNodes)
30: ...
Figure 4.42, can't understand how the maximin costs were computed. For example, the route from the upper room to the smaller center room, should be 8 (the maximum of all minimum routes). So, not sure this example is correct. A fixed (?) example on perl-hackers.net
class Action should extend DecisionTreeNode.
the code should be a class, not a struct.
first code block, like 11 should be result = UpdateResult()
for consistency with line 35 of page 327. Also, I would add a parent
variable, of type HSMBase, that is already used in the algorithm. It would be None at the top level, and would include its parent on other levels.
the Pause task should return True, not the non initialized variable result
lines 26/27 of the code should appear before the foreach look in line 20.
line 50 of the algorithm, should read currentTime = resetTime
line 8 could cycle through actions[1..]
like previous algorithms.
line 23 is for goal in goals
line 28 should call getDiscontentment(newValue)
– but I would use discontentment += newValue * newValue
line 29 is missing return discontentment
I can't see why setting the getDiscontentment method in a class (see previous item)
line 7 is for goal in goals
line 16 is missing return discontentment
In the bottom paragraphs, “The last two items” should refer “The last item”.
Code, line 8, should say 'isInstanceOf' instead of 'insistence' Page 438 Code, line 11, should use 'if not identifier.isWildcard()'
Code, line 8, should say 'isInstanceOf' instead of 'insistence'
Code, line 11, should use 'identifier.isWildcard()' as the previous algorithm
line 24 of the algorithm, function
should be called with the full array, just like in the beginning of the algorithm.
line 24 of the algorithm, function
should be called with the full array, just like in the beginning of the algorithm.
after 20 times should read after 100 times.
Subarray selections (slices) are kind of weird, or my mind complete blow up.
Line 40, subActions = actions[i:nValue-1]
Code, line 17, there is no need for attribute self