Patrol and Chasing
GAGE HOLSTON
03 Apr 2020, 05:19In my game, there is a certain section where a robot is patrolling an area for the player.
The way I want it is:
- The robot follows a set path, that loops afterwards back to the beginning of the patrol.
- If the player enters a room on the robot's path and the robot enters the room (or the robot is already there), it will drop the previous behavior to chase the player.
- If the player enters certain areas, the robot will lose you and return to the patrol.
- The player needs the robot chasing them to perform certain actions. (For example, one way to destroy the robot would be to get him to chase you, climb up a cliffside, and push a boulder on top of the robot before the robot gives up and returns to patrol, for instance. This is the least important point needed solved, as I doubt will be difficult to find out)
The way I tried it, so far, was by having a turn script activate when in this area where the robot moves to a new room on the path every turn. The main issue I'm having with this is none of the checks I made to trigger #2 don't work. I tried doing this also through a turn script, but it didn't work.
I'd like to know how to get this to work, and in an efficient enough way.
mrangel
03 Apr 2020, 16:21Hmm… I'd give the robot an objectlist attribute path
containing the list of rooms it needs to move through. And then set up a turnscript to move it:
nextstep = null
if (HasAttribute (robot, "chasing")) {
// If the player runs into a room and back out again while being chased, the robot won't go into the room
while (ListContains (robot.chasing, game.pov.parent)) {
list remove (robot.chasing, ListItem (robot.chasing, ListCount (robot.chasing) - 1))
}
if (robot.parent = game.pov.parent) {
// The robot is chasing the player, but the player hasn't moved away
// If the robot is going to attack the player, the code would go here
}
else {
// Making a list of which way the player went, so the robot can follow them.
list add (robot.chasing, game.pov.parent)
}
// I've made it so that when the player gets 5 rooms away from the robot, it loses interest and returns to patrolling.
// You said you want it to give up when the player reaches a certain area
// so change this 'if' statement to test for whatever condition makes the robot give up
if (ListCount (robot.chasing) > 5) {
robot.chasing = null
}
// The robot has an 80% chance of moving each turn, to allow the player to get a few rooms ahead of it.
// If you want the robot to move as fast as the player, just change this to: if (ListCount (robot.chasing) > 0) {
if (RandomChance (80) and ListCount (robot.chasing) > 0) {
nextstep = ListItem (robot.chasing, 0)
list remove (robot.chasing, nextstep)
// we make a list of rooms the robot has already chased the player through, so it knows the way to return to its patrol path
while (ListContains (robot.return, nextstep)) {
list remove (robot.return, ListItem (robot.return, ListCount (robot.return) - 1))
}
list add (robot.return, robot.parent)
}
}
else if (game.pov.parent = robot.parent) {
// The player has walked into the robot's room
msg ("The robot bleeps angrily and starts chasing you!")
robot.chasing = NewObjectList()
if (not HasAttribute (robot, "return")) {
robot.return = NewObjectList()
}
}
else if (HasAttribute (robot, "return")) {
// The robot is returning from chasing the player
if (ListContains (robot.path, robot.parent)) {
// robot is back on its path, so clear the chase data from its memory
robot.return = null
// And cycle the path, so it knows where it currently is
for (i, 0, IndexOf (robot.path, robot.parent) + 1) {
nextstep = ListItem (robot.path, 0)
list remove (robot.path, nextstep)
list add (robot.path, nextstep)
}
}
else {
// Robot is returning from a chase, but isn't back on its patrol path yet
nextstep = ListItem (robot.return, ListCount(robot.return) - 1)
list remove (robot.return, nextstep)
}
}
else {
// The robot is on its path, patrolling normally
nextstep = ListItem (robot.path, 0)
list remove (robot.path, 0)
list add (robot.path, 0)
}
// We've now determined where the robot will move, whether it's patrolling, chasing, or returning
if (not nextstep = null) {
// move the robot
robot.parent = nextstep
// And check if it's patrolled into the player
if (robot.parent = game.pov.parent) {
if (HasAttribute (robot, "chasing")) {
// We can just show a message here; if the robot is going to attack the player, the script will do that next turn
// But if you want to be mean to the player, you could do it here
msg ("The robot chases you into the room!")
}
else {
msg ("A robot moves into the room and turns to face you like it's about to attack.")
robot.chasing = NewObjectList()
if (not HasAttribute (robot, "return")) {
robot.return = NewObjectList()
}
}
}
}
(This is all off the top of my head, so there could be mistakes here)
GAGE HOLSTON
03 Apr 2020, 17:05This seems like an interesting solution. The only problem is that I've never had to use lists before, so I have to figure out that first.
mrangel
03 Apr 2020, 19:43Another thought… if the robot is designed to pursue sensibly, you could improve its pathfinding. This could be interesting, especially if the room layout is complex or maze-like.
Still keeping fairly simple, you could replace:
else {
// Making a list of which way the player went, so the robot can follow them.
list add (robot.chasing, game.pov.parent)
}
with:
else {
if (not Equal (null, GetExitByLink (robot.parent, game.pov.parent))) {
// the player is in a room adjacent to the robot
// so we forget the route the player has taken to get there; the chase route is just "go to that room"
robot.chasing = NewObjectList()
}
else if (ListContains (robot.return, game.pov.parent)) {
// The player is passing through a room the robot has already chased them through
// If it would be quicker to turn back, the robot should do so
if (ListCount (robot.chasing) > ListCount (robot.return) - 1 - IndexOf (robot.return, game.pov.parent)) {
robot.chasing = NewObjectList()
for (i, ListCount (robot.return) - 1, IndexOf (robot.return, game.pov.parent) + 1, -1) {
list add (robot.chasing, ListItem (robot.return, i))
}
}
}
list add (robot.chasing, game.pov.parent)
}
That means that in a more complex map, the robot will move straight into the player's room if it passes through a room adjacent to them; and will double back if the player crosses the path it has already taken.
Depending on the style of your game, you might want these optimisations or just keep it simple. Whether this is beneficial really depends on how far ahead of the robot the player is likely to get. If it's only one room apart then it might not make much difference.