HiveBrain v1.2.0
Get Started
← Back to all entries
patterncModerate

Optimize code to track player shot

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
trackplayershotoptimizecode

Problem

This code is for a simple 2D tile-based game. x1 and y1 are the mouse coordinates in the world. entity->x1 and entity->y1 is the point where the player is, the shot origin.

I would like to know how to keep the current output while simplifying the code and improving performance.

void shoot(Map *map, Entity *entity, int x1, int y1)
{
    float slope = (y1 - entity->y1) / (x1 - entity->x1);
    float y = entity->y1; //Weapon position
    Block *block;

    if(x1 > entity->x1){
        y += slope;
        for(float x = entity->x1 + 1; x width && y height && y > 0; ++x){

            //Get block at position x y. Check if found a hit
            if((block = map_block_at(map, x, y))->type != EMPTY){
                block_cause_damage(block, entity->hand_item->weapon.damage);
                return;
            }

            y += slope;
        }
    }

    else
    if(x1 x1){
        y -= slope;
        for(float x = entity->x1 - 1; x > 0 && y height && y > 0; --x){

            //Get block at position x y. Check if found a hit
            if((block = map_block_at(map, x, y))->type != EMPTY){
                block_cause_damage(block, entity->hand_item->weapon.damage);
                return;
            }

            y -= slope;
        }
    }

    //When the player shoots up or down 
    else {
        slope = (y1 > entity->y1) ? 1 : - 1;
        y += slope;
        while(y height && y > 0){

            //Get block at position x y. Check if found a hit
            if((block = map_block_at(map, x1, y))->type != EMPTY){
                block_cause_damage(block, entity->hand_item->weapon.damage);
                return;
            }

            y += slope;
        }
    }
}


The code for Entity and Map:

```
typedef struct Entity {
Renderable renderable;
plist_id render_id;
Point (get_current_position)(struct Entity , uint32_t);
int health, attack_damage, running, jumping;
float x0, y0, x1, y1;
uint32_t t0, t1;
enum {

Solution

It's a little difficult to do a good review because there are so many pieces missing, but I've guessed at a number of things and I believe I can help.

Specifically, it looks like your Map is a rectangular grid of Blocks and that all x and y coordinates are integers. If so, then your shot routine is really doing the equivalent of drawing a line from the entity location to the passed x1,y1 coordinates and one very efficient way to do that is to use Bresenham's line-drawing algorithm. Using a slight modification of that algorithm, since your shot routine seems to want to go until it either hits something or goes off the Map, we get a very efficient and very small routine:

void shoot(Map *map, Entity *entity, int x1, int y1)
{
    int sx = entity->x1 y1 x1);
    int dy = abs(y1 - entity->y1);
    int err = (dx>dy ? dx : -dy)/2;
    int e2;

    x1 = entity->x1;
    y1 = entity->y1;
    Block *block;
    while (inbounds(map,x1,y1)) {
        e2 = err;
        if (e2 > -dx) {
            err -= dy;
            x1 += sx;
        }
        if (e2 type != EMPTY){
            block_cause_damage(block, entity->hand_item->weapon.damage);
            return;
        }
    }
}


I've assumed that you have or can easily write an inbounds routine that returns true if the passed coordinates are within the Map.

Code Snippets

void shoot(Map *map, Entity *entity, int x1, int y1)
{
    int sx = entity->x1 < x1 ? 1 : -1;
    int sy = entity->y1 < y1 ? 1 : -1;
    int dx = abs(x1 - entity->x1);
    int dy = abs(y1 - entity->y1);
    int err = (dx>dy ? dx : -dy)/2;
    int e2;

    x1 = entity->x1;
    y1 = entity->y1;
    Block *block;
    while (inbounds(map,x1,y1)) {
        e2 = err;
        if (e2 > -dx) {
            err -= dy;
            x1 += sx;
        }
        if (e2 < dy) {
            err += dx; 
            y1 += sy;
        }
        if((block = map_block_at(map, x1, y1))->type != EMPTY){
            block_cause_damage(block, entity->hand_item->weapon.damage);
            return;
        }
    }
}

Context

StackExchange Code Review Q#48212, answer score: 10

Revisions (0)

No revisions yet.