0

I'm looking for an optimization for my loops searching for enemies in a tile based horizonal scroller. My enemy array is in a struct and I am looping through the array with 3 loops. First loop finds the enemy on the left side of the screen within the array, the second loop finds the enemy on the right side of the screen. The third loop then displays all enemies that fall within the two parameters.

This routine certainly seems to do the job, but it seems too bulky being 3 loops. Any suggestions for better optimizations to cull down the code length or improvements in speed?

void apple()
{
    unsigned char baddyStart = 0;
    unsigned char baddyEnd = 0;
    unsigned char enemyLow = 0;
    unsigned char enemyHigh = 0;
unsigned char windowStart = player.tile_X_position - 1;
unsigned char windowEnd = player.tile_X_position + NEAR_PLAYER;

unsigned char arrayScan = 0;

if (windowEnd > MAX_PLAYER_POS)
{
    windowEnd = MAX_PLAYER_POS;
}

//need to find enemy closest to player in window
for (temp1 = 0; temp1 < enemies_per_level; temp1++)
{
    baddyStart = enemy_locations[temp1].tile_X_position;

    if (baddyStart == windowStart)
    {
        //found the lowest location in window
        enemyLow = temp1;
        break;
    }
}

//find the enemy furthest to player in window
for (temp2 = temp1; temp2 < enemies_per_level; temp2++)
{
    baddyEnd = enemy_locations[temp2].tile_X_position;

    if (baddyEnd == windowEnd)
    {
        //found the highest location in window
        enemyHigh = temp2;
        break;
    }
}

//show the ranges
printf ("enemyLow = %d\n", enemyLow);
printf ("enemyHigh = %d\n", enemyHigh);
printf ("baddyStart = %d\n", baddyStart);
printf ("baddyEnd = %d\n", baddyEnd);

arrayScan = enemyLow;

while (arrayScan <= enemyHigh)
{
    baddyStart = enemy_locations[arrayScan].tile_X_position;

    if(baddyStart >= baddyEnd)
    {
        //printf("GREATER THAN\n");
        return;
    }

    if (baddyStart == 0)
    {
        //printf("NOT EXISTING\n");
        //baddy deleted
    }//to bypass deleted baddies

    printf("arrayScan=%d   \n", arrayScan);
    printf("%d    ", enemy_locations[arrayScan].tile_X_position);
    printf("%d    ", enemy_locations[arrayScan].x_displacement);
    printf("%d    ", enemy_locations[arrayScan].y_position);
    printf("%d    ", enemy_locations[arrayScan].sprite_number);
    printf("%d    ", enemy_locations[arrayScan].movement);
    printf("%d    ", enemy_locations[arrayScan].energy);
    printf("%d    ", enemy_locations[arrayScan].param1);
    printf("%d    ", enemy_locations[arrayScan].param2);
    printf("\n");

    arrayScan ++;
}

}

EDIT.

I can bring the function a little closer to optimization by combining the find the minimum and maximum to 1 loop instead of 2 loops.

void apple()
{
    unsigned char baddyStart = 0;
    unsigned char baddyEnd = 0;
    unsigned char enemyLow = 0;
    unsigned char enemyHigh = 0;
unsigned char windowStart = player.tile_X_position - 1;
unsigned char windowEnd = player.tile_X_position + NEAR_PLAYER;

unsigned char arrayScan = 0;

if (windowEnd > MAX_PLAYER_POS)
{
    windowEnd = MAX_PLAYER_POS;
}

//need to find enemy closest and furthest to player in window
for (temp1 = 0; temp1 < enemies_per_level; temp1++)
{
    baddyStart = enemy_locations[temp1].tile_X_position;
    baddyEnd = enemy_locations[temp1].tile_X_position;

    if (baddyStart == windowStart)
    {
        //found the lowest location in window
        enemyLow = temp1;
    }
    if (baddyEnd == windowEnd)
    {
        //found the highest location in window
        enemyHigh = temp1;
        break;
    }
}

//show the ranges
printf ("enemyLow = %d\n", enemyLow);
printf ("enemyHigh = %d\n", enemyHigh);
printf ("baddyStart = %d\n", baddyStart);
printf ("baddyEnd = %d\n", baddyEnd);

arrayScan = enemyLow;

while (arrayScan <= enemyHigh)
{
    baddyStart = enemy_locations[arrayScan].tile_X_position;

    if(baddyStart >= baddyEnd)
    {
        //printf("GREATER THAN\n");
        return;
    }//seems working

    if (baddyStart == 0)
    {
        //printf("NOT EXISTING\n");
        //baddy deleted
    }//to bypass deleted baddies

    printf("arrayScan=%d   \n", arrayScan);
    printf("%d    ", enemy_locations[arrayScan].tile_X_position);
    printf("%d    ", enemy_locations[arrayScan].x_displacement);
    printf("%d    ", enemy_locations[arrayScan].y_position);
    printf("%d    ", enemy_locations[arrayScan].sprite_number);
    printf("%d    ", enemy_locations[arrayScan].movement);
    printf("%d    ", enemy_locations[arrayScan].energy);
    printf("%d    ", enemy_locations[arrayScan].param1);
    printf("%d    ", enemy_locations[arrayScan].param2);
    printf("\n");

    arrayScan ++;
}

} ```

  • Are your enemies in any particular order in the array? – DMGregory Mar 06 '21 at 16:28
  • I presort them pre-compiled by the starting tile in ascending order. – Andy Dansby Mar 06 '21 at 16:33
  • 1
    Is this actually a performance bottleneck in your game? Did you profile it? What does the profiler say about how many % of CPU time are used on these two loops? – Philipp Mar 07 '21 at 12:01
  • @Philpp I'm writing for a retro-computer using a Z80 processor, so every T-State is precious to the slow processor. There is certainly a difference between the first and second routine. Over 100 iterations, the first took 43219 ms and the second takes 42844 ms. which is a .88% difference. If it were a modern machine, it wouldn't matter all that much, – Andy Dansby Mar 07 '21 at 13:52

1 Answers1

1

I did eventually come across a way to optimize by using a completely different algorithm that had slipped my mind. I was searching for enemies by using a linear search. Things improved considerably by using a binary search.

static unsigned char search(unsigned char value)
{
    if(value < enemy_locations[0].tile_X_position)
    {
        return enemy_locations[0].tile_X_position;
    }
    if(value > enemy_locations[enemies_per_level-1].tile_X_position)
    {
        return enemy_locations[enemies_per_level-1].tile_X_position;
    }
    lo = 0;
    hi = enemies_per_level - 1;
    while (lo <= hi)
    {
        mid = (hi + lo) / 2;
        if (value < enemy_locations[mid].tile_X_position)
        {
            hi = mid - 1;
        }
        else if (value > enemy_locations[mid].tile_X_position)
        {
            lo = mid + 1;
        }
        else
        {
            return enemy_locations[mid].tile_X_position;
        }
    }
    output = enemy_locations[lo].tile_X_position - value;
    if (output < value - enemy_locations[hi].tile_X_position)
    {
        return enemy_locations[lo].tile_X_position;
    }
    else
    {
        return enemy_locations[hi].tile_X_position;
    }
}
Philipp
  • 119,250
  • 27
  • 256
  • 336