Jump to content
IGNORED

Enemy AI


Random Terrain

Recommended Posts

Repost by request from the other recent thread:

 

Quite a lot of old game logic is just a mix of randomness and "seek player" type of thing. Obviously a game will usually be too hard if the enemy constantly heads for the player, so you can do stuff like only change direction periodically, and make that direction change a mix of randomness and seeking.

 

Then you have the arcade Pac-Man "Head him off at the pass" philosophy - don't necessarily head for the player, head for a position that's near where the player is.

 

And you have Asteroids Deluxe "prediction" logic where the enemy saucer will sometimes shoot at a position where the player is anticipated to be if he keeps moving at current speed/direction.

 

So, for a simple algorithm for an enemy you might have a few variables that you periodically change:

 

Timer - this counts down and at zero you load a new timer value, which can be random. When the timer hits zero, you then make a decision to change other variables.

Velocity X/Y- dictates direction and speed of an enemy. This changes when enemy hits a boundary, obstacle, or timer counts down. You can decide randomly whether the new value is random, or is set to a strategic value based on "seeking".

 

Randomness - a threshold value that dictates what percentage of an enemies behaviour is random and how much it's based on strategic seeking.

 

On top of that, you might also have set paths that are followed and broken on certain conditions, e.g. randomly, or if the player wanders within a certain range.

 

To add a little further info - you might also have trigger points where a player might pass, and they can be used to alter the way a particular enemy/s behave.

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

I've learned it's handy to incorporate a "stuck" routine in my enemy AI. Sometimes just heading toward a player will leave the critter just banging into the same wall. I increment a variable every turn the monster stays stuck in one location. When a certain threshold is reached I tell the monster to move in a new direction or change behavior.

Edited by theloon
Link to comment
Share on other sites

  • 6 months later...

This is my first attempt at writing an Enemy AI routine. It's not absolutely perfect, but it works fairly well. The enemy will always follow the player until it hits a wall. If it gets stuck on a wall for too long, it will choose a random alternate path to try and get around the obstacle. The demo has a player sprite you control and an enemy sprite that will follow you. If you stay still for long enough, the enemy will eventually find his way to you.

 

The biggest area this could be improved would be the logic used when the enemy chooses a different path. It's completely random right now, but checking the current position of the player and heading in that general direction would make it better. The problem is that heading directly to the player isn't always the best path to take. It would be easier to code it if the playfield was always static, but I was looking to do something that would work with any playfield configuration.

 

Putting in a very complex playfield would probably make this sample code much less effective. The distance traveled when an alternate path is chosen would have to be tweaked, as well as how many turns are taken and how long that routine runs before switching back to the simple "head towards the player" movement. I'll post again when I've had more time to work on it, but I wanted to share what I have so far.

 

Any thoughts, comments or suggestions would be appreciated.

 

Steve

enemyai.txt

enemyai.txt.bin

  • Like 2
Link to comment
Share on other sites

  • 8 years later...

This was the absolute smallest one I ever came up with.

Quote

 for sswap = 0 to 3
  if !COLUP2[sswap]  || diceroll/32<sswap then goto skipthisenemy
  if NUSIZ2[sswap]=%00100000 then player2x[sswap]=player2x[sswap]-1
  if player2x[sswap]<15 then NUSIZ2[sswap]=%00101000
  if NUSIZ2[sswap]=%00101000 then player2x[sswap]=player2x[sswap]+1
  if player2x[sswap]>147 then NUSIZ2[sswap]=%00100000
skipthisenemy
 next

In this program when an enemy was "dead" I just made them colored black because of the cycle efficiency of checking for it. This bit of code made each of four enemy sprites move from one side of the screen to the other, turning around when they hit the edge to face the other way, and they all moved at different speeds (Which was governed by the single "diceroll" randomizer that I used for every pseudo-random operation I needed to do) and when they either got hit a bad dice roll or had been marked as "dead" they would get skipped over completely to save extra cycles. I calculated at the time that it was about 138bytes lighter than if I had done it without a loop. It just shows that if you think a little outside the box you can save a lot of resources.

Link to comment
Share on other sites

Sometimes you can let the players position determine monster behavior.  In this case the AI uses the players (player1 sprite) coordinates to decide some of the dragons (player0) movements.  Usually people just use the players coordinates to "heat seek" towards the player.  But, you can do more than that.

 

Not really a code example.  I glossed over _west, _east, _north and _south being constants.  Also didn't explain p0ref being a bitwise define of a variable.  Just included the code from one of my games to demonstrate intent :)

 

movegdragon
 if direction = _west then player0x = player0x + 1 : p0ref = 0
 if direction = _east then player0x = player0x - 1 : p0ref = 1
 if direction = _north then player0y = player0y + 1
 if direction = _south then player0y = player0y - 1
 goto main_begin


moveydragon
 if player1y > player0y then player0y = player0y + 1
 if player1y < player0y then player0y = player0y - 1
 if direction = _west then player0x = player0x + 1 : p0ref = 0
 if direction = _east then player0x = player0x - 1 : p0ref = 1
 if direction = _north then player0y = player0y + 1
 if direction = _south then player0y = player0y - 1
 goto main_begin


moverdragon
 if player1x > player0x then player0x = player0x + 1 : p0ref = 0
 if player1x < player0x then player0x = player0x - 1 : p0ref = 1
 if player1y > player0y then player0y = player0y + 1
 if player1y < player0y then player0y = player0y - 1

 if direction = _west then player0x = player0x + 1 : p0ref = 0
 if direction = _east then player0x = player0x - 1 : p0ref = 1
 if direction = _north then player0y = player0y + 1
 if direction = _south then player0y = player0y - 1
 goto main_begin

 

  • Like 1
Link to comment
Share on other sites

In Bag Boy, the closest thing I have to an enemy was the boss at the top of the screen. It starts off with simple right to left movement. But to make them more difficult I have their position determined by the location of the passing cars below so that the move in a somewhat erratic but not too limited way. 

 

In Manatee Madness, I have a couple different enemies. Some are simple back and forth movement with maybe a change to the y-axis based on player location. Some move in a set path. Right now the most complicated are the gator and diver. The gator moves towards the player. So does the diver. But if the gator gets too close to the diver he goes towards the diver. If the manatee hides behind the sea grass, the diver tries to surface until the player is visible again. 

 

I haven't made any real complex AIs to date, as I am still learning, but so far I have found a mix of randomness and conditional statements give a good degree of simulated intelligence.

  • Like 1
Link to comment
Share on other sites

This is how I do extremely simple platforming enemy AI that can walk and fall of ledges:
 

 rem gravity 
 player0y = player0y + 1
 rem enemy stops when in contact with playfield
 if collision(player0,playfield) then player0y = player0y - 1
 rem enemy walks right or left if it touches the screen borders
 if u = 0 then _P0_L_R = _P0_L_R - 0.35
 if u = 1 then _P0_L_R = _P0_L_R + 0.35
 if player0x = 15 then u = 1
 if player0x = 140 then u = 0

 

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...