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.

How about turning that lemon into lemonade.

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.

Advertisements

Author: andydansby

I'm a hobbyist coder working with the ZX Spectrum. Living in New York state near the Syracuse area. I grew up in Virgina. The first computer my parents bought for me was a Timex Sinclair 2068.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s