Enemy movement, it’s not a bug, it’s a feature.

6-15-2018

In a prior article, I encountered a bit of a bug, on some occasions, our enemy sprites will run into walls and then will pass through them. This destroys the rules of the game, the walls are supposed to be deadly for both the player and the enemy. What does it say if the enemy can occasionally move through a wall but you cannot, the game cheats and we cannot have that! So let’s delve back into our enemy movement code and play with that a little more.

This is our original routine, we know there is some sort of bug that causes the enemy to occasionally crash into walls.

``````//if the enemy is in the center of the tile, need to look which direction we need to travel
if ((enemyXX == xCenterofTile) && (enemyYY == yCenterofTile))
{
centerValue = grassfire[center];
northValue = grassfire[north];
southValue = grassfire[south];
eastValue = grassfire[east];
westValue = grassfire[west];

if ((northValue < southValue && northValue < eastValue && northValue < westValue))
{
//go north
enemyDirection = 1;
}
else if ((southValue < northValue && southValue < eastValue && southValue < westValue))
{
//go south
enemyDirection = 2;
}
else if ((eastValue < northValue && eastValue < southValue && eastValue < westValue))
{
//go east
enemyDirection = 3;
}
else if ((westValue < northValue && westValue < southValue && westValue < eastValue))
{
//go west
enemyDirection = 4;
}
else if (centerValue == 1)
{
// STOP, found the target
enemyDirection = 5;
}
//decide which way the enemy should travel
}//end decisions``````

First, let’s do a simple change, and enclose each of the conditions in the IF statements.

``````//if the enemy is in the center of the tile, need to look which direction we need to travel
if ((enemyXX == xCenterofTile) && (enemyYY == yCenterofTile))
{
centerValue = grassfire[center];
northValue = grassfire[north];
southValue = grassfire[south];
eastValue = grassfire[east];
westValue = grassfire[west];

//decide which way the enemy should travel
if ((northValue < southValue) && (northValue < eastValue) && (northValue < westValue))
{
//go north
enemyDirection = 1;
}
else if ((southValue < northValue) && (southValue < eastValue) && (southValue < westValue))
{
//go south
enemyDirection = 2;
}
else if ((eastValue < northValue) && (eastValue < southValue) && (eastValue < westValue))
{
//go east
enemyDirection = 3;
}
else if ((westValue < northValue) && (westValue < southValue) && (westValue < eastValue))
{
//go west
enemyDirection = 4;
}
else if (centerValue == 1)
{
// STOP, found the target
enemyDirection = 5;
}
//decide which way the enemy should travel
}//end decisions``````

And it gives me the exact same result. Intermittent crashing in those darn walls.

Instead of using the AND operator, let’s try OR, just for fun.

``````//if the enemy is in the center of the tile, need to look which direction we need to travel
if ((enemyXX == xCenterofTile) && (enemyYY == yCenterofTile))
{
centerValue = grassfire[center];
northValue = grassfire[north];
southValue = grassfire[south];
eastValue = grassfire[east];
westValue = grassfire[west];

//decide which way the enemy should travel
if ((northValue < southValue) || (northValue < eastValue) || (northValue < westValue))
{
//go north
enemyDirection = 1;
}
else if ((southValue < northValue) || (southValue < eastValue) || (southValue < westValue))
{
//go south
enemyDirection = 2;
}
else if ((eastValue < northValue) || (eastValue < southValue) || (eastValue < westValue))
{
//go east
enemyDirection = 3;
}
else if ((westValue < northValue) || (westValue < southValue) || (westValue < eastValue))
{
//go west
enemyDirection = 4;
}
else if (centerValue == 1)
{
// STOP, found the target
enemyDirection = 5;
}
//decide which way the enemy should travel
}//end decisions``````

Well, sadly, that works like crud. The enemy just moves back and forth.

Let’s mix things up and try a combo of AND and OR.

``````//if the enemy is in the center of the tile, need to look which direction we need to travel
if ((enemyXX == xCenterofTile) && (enemyYY == yCenterofTile))
{
centerValue = grassfire[center];
northValue = grassfire[north];
southValue = grassfire[south];
eastValue = grassfire[east];
westValue = grassfire[west];

//decide which way the enemy should travel
if ((northValue < southValue) && (northValue < eastValue) || (northValue < westValue))
{
//go north
enemyDirection = 1;
}
else if ((southValue < northValue) && (southValue < eastValue) || (southValue < westValue))
{
//go south
enemyDirection = 2;
}
else if ((eastValue < northValue) && (eastValue < southValue) || (eastValue < westValue))
{
//go east
enemyDirection = 3;
}
else if ((westValue < northValue) && (westValue < southValue) || (westValue < eastValue))
{
//go west
enemyDirection = 4;
}
else if (centerValue == 1)
{
// STOP, found the target
enemyDirection = 5;
}
//decide which way the enemy should travel
}//end decisions``````

This kinda works, the closest enemy finds you, whereas the remainder goes back and forth for quite a while. But it’s not working good enough.

Finally, I remove the else if and replace it with a plain IF statement.

``````//if the enemy is in the center of the tile, need to look which direction we need to travel
if ((enemyXX == xCenterofTile) && (enemyYY == yCenterofTile))
{
centerValue = grassfire[center];
northValue = grassfire[north];
southValue = grassfire[south];
eastValue = grassfire[east];
westValue = grassfire[west];

//decide which way the enemy should travel
if ((northValue < southValue) && (northValue < eastValue) && (northValue < westValue))
{
//go north
enemyDirection = 1;
}

if ((southValue < northValue) && (southValue < eastValue) && (southValue < westValue))
{
//go south
enemyDirection = 2;
}

if ((eastValue < northValue) && (eastValue < southValue) && (eastValue < westValue))
{
//go east
enemyDirection = 3;
}

if ((westValue < northValue) && (westValue < southValue) && (westValue < eastValue))
{
//go west
enemyDirection = 4;
}

if (centerValue == 1)
{
// STOP, found the target
enemyDirection = 5;
}
//decide which way the enemy should travel
}//end decisions``````

Well, it’s not perfect, but does seem to be an improvement and the enemies don’t run into the walls quite as much.

And, so I try for hours, playing around with the IF statements and not getting any better results. Very frustrating.

So, what do you do if you cannot get things working as expected? Take that Bug and make it a feature. We know that under normal circumstances, the enemy will have the shortest path to you and thus always has an advantage, however, if the enemy runs in a wall, why don’t we kill the enemy and add a point to your game. Therefore the enemy can make mistakes and rack up points in the game.

Let’s put in another IF statement.

``````//enhancement
//collision for enemies
//transport to another area of the screen
//if an enemy touches a barrier, transport it to a starting position
if (tiles[center] > 0)
{
transportEnemy();
}``````

Now, when the enemy goes to a tile that is occupied by an obstacle, let’s call up the function, transportEnemy.

Now, let’s create a function.

``````void transportEnemy()
{
M_OUTP(0xfe, 5);//flashes to show that sprite has touched a barrier
enemyX = 24;
enemyY = 24;
sprites[i].x = enemyX;
sprites[i].y = enemyY;
tilepaint(2, 2, 2, 2);FRAME;
sprites[i].n -= 128;//make sprite reappear
killed ++;
//update the scoreboard
}``````

In actuality, I never kill an enemy sprite, I just move it to another part of the screen. Our bullet code, which I haven’t discussed just yet, makes a sprite disappear by adding 18 to the sprites.n field, to make it reappear, we subtract 128 from the sprites.n field.

That’s what our code basically does above.

``````enemyX = 24;
enemyY = 24;``````

The enemyX and enemyY are now centered on tile 2,2.

``````sprites[i].x = enemyX;
sprites[i].y = enemyY;``````

Assigns the sprite to the position.

``tilepaint(2, 2, 2, 2);FRAME;``

Refresh the tile 2,2.

``sprites[i].n -= 128;//make sprite reappear``

Makes the sprite reappear.

``killed ++;``

Increase our score.

We’ll be able to reuse this function every time we kill an enemy as well.

We’ll come up with the scoreboard code at a later time.

The enemy has a little bit of a flaw since it now will occasionally run into walls, but when that happens we transport the enemy to another location. If was want to be crafty, that location can be in a sensitive place like, near the goal or in a tight passage, which will make the game harder, if we want to make the game easier, we transport the enemy to a far away tile. We could also transport the enemy to a random location. A lot of different possibilities.

By the way, if anyone else figures out where the silly bug is, I would appreciate it greatly.

Until next time, happy coding.