Оптимизируйте код для отслеживания роли игрока

Этот код предназначен для простой 2D-плитки. x1 и y1 являются координатами мыши в мир. entity->x1 и entity->y1 - это точка, в которой игрок, начало отсчета.

Я хотел бы знать, как сохранить текущий вывод, упрощая код и улучшая производительность.

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 < map->width && y < map->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 < entity->x1){
        y -= slope;
        for(float x = entity->x1 - 1; x > 0 && y < map->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 < map->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;
        }
    }
}

Код для Entity и 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 {LEFT, RIGHT} side;
    Image **texture;
    Item *hand_item;
    Backpack backpack;
} Entity;

typedef struct {
    Renderable renderable;
    plist_id render_id;
    int width, height;
    Block *blocks;
    Camera *camera;
} Map;
11 голосов | спросил 2013Asker 26 AMpSat, 26 Apr 2014 10:23:30 +040023Saturday 2014, 10:23:30

2 ответа


10

Немного сложно сделать хороший обзор, потому что так много штук пропало без вести, но я догадываюсь о некоторых вещах, и я считаю, что могу помочь.

В частности, это выглядит как Map - прямоугольная сетка Block s и что все x и y - целые числа. Если это так, то ваша подпрограмма shot действительно выполняет эквивалент рисования строки из entity для переданного x1, y1 и один очень эффективный способ сделать это - использовать Алгоритм рисования линии Брешенема . Используя небольшую модификацию этого алгоритма, поскольку ваша подпрограмма shot, похоже, хочет идти до тех пор, пока она либо не ударит, либо не отключится от Map, мы получаем очень эффективную и очень маленькую рутину:

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;
        }
    }
}

Я предположил, что вы можете или легко написать подпрограмму inbounds, которая возвращает true, если переданные координаты находятся в пределах Map.

ответил Edward 26 PMpSat, 26 Apr 2014 23:23:08 +040023Saturday 2014, 23:23:08
7

У меня есть несколько замечаний:

  • У вас может быть проблема с этой строкой кода:

    float slope = (y1 - entity->y1) / (x1 - entity->x1);
    

    Если entity уже на долготе x1, это приведет к делению на 0. Такое деление - неопределенное поведение. Все может случиться. Самолет может упасть на ваш дом. Сначала проверьте, следует ли x1 == entity->x1 и правильно обрабатывать этот случай. Я вижу, что последний else конец вашей программы обрабатывает этот случай (//When the player shoots up or down), но деление на 0 появляется до , которое вы обрабатываете.

  • Я не знаю, entity.x и entity.y являются int или float. Если они являются типами int, я думаю, что вы можете избавиться от float: единственное, что может потребовать больше точности, чем целое число, это slope, а если entity.x и entity.y являются целыми типами, затем slope будет содержать целое число, отличное от float (начиная с он был инициализирован целым делением).

Ему не хватает контекста для полного обзора. Вы должны опубликовать код не менее Map и Entity, чтобы мы не могли принимать вещи.

ответил Morwenn 26 PMpSat, 26 Apr 2014 16:10:30 +040010Saturday 2014, 16:10:30

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132