강의, 책/[DirectX, C++] 게임 매니악스 알고리즘 시리즈

[슈팅 알고리즘] Chapter 2. 탄환 (조준탄)

hye3193 2024. 4. 17. 13:16

2.1 조준탄 (float를 이용해서 탄환을 이동)

적기에서 플레이어의 위치를 향해 발사하는 조준탄

void InitAimingBullet(
    float mx, float my, // 플레이어 위치
    float ex, float ey, // 적 위치
    float speed,
    float& x, float& y, // 탄환 좌표
    float& vx, float& vy // 탄환 속도 벡터
) {
    x = ex; y = ey;
    
    // 플레이어와 적 사이의 거리
    float d = sqrt((mx - ex) * (mx - ex) + (my - ey) * (my - ey));
    
    if (d == 0) {
        vx = 0;
        vy = speed;
    } else {
        vx = (mx - ex) / d * speed;
        vy = (my - ey) / d * speed;
    }
}

* d를 구해서 계산하는 이유는 플레이어와 적의 거리에 따라 탄환이 날아가는 속도가 달라지지 않고, 일정하게 유지하기 위함

만약 플레이어와 적 사이의 거리가 0이라면

1. 탄환 발사 X

2. 아래쪽/위쪽 등 정해진 방향이나 임의의 방향으로 발사

하면 되고, 위 코드에서는 탄환 속도벡터의 y값을 speed값으로 지정해, speed의 속도로 위로 날아가게 되어있다

void MoveAimingBullet(
    float& x, float& y, // 탄환의 좌표
    float vx, float vy // 탄환의 속도 벡터
) {
    x += vx;
    y += vy;
}

탄환을 움직일 때는 위와 같이 탄환의 좌표에 속도 벡터를 더해주면 된다

 

2.2 조준탄 (DDA를 사용하여 탄환을 이동시키기)

DDA(Digital differential Analyzer, 디지털 미분 해석기)란 정수 연산만을 이용해서 실제 직선에 가장 가까운 화소를 재빨리 구하는 알고리즘이다

void InitAimingBulletDDA(
    int mx, int my, // 플레이어의 위치
    int ex, int ey, // 적의 위치
    int& x, int& y, // 탄환의 좌표
    int& vx, int& vy, // 탄환의 이동 벡터
    int& dx, int& dy, // X방향과 Y방향의 차
    int& diff // 오차
) {
    x = ex; y = ey;
    
    // 탄환의 이동 방향을 1 또는 -1의 값으로 구하기
    vx = mx >= ex ? 1: -1;
    vy = my >= ey ? 1: -1;
    
    // x좌표와 y좌표 각각 차이의 절대값 구하기
    dx = mx >= ex ? (mx - ex): (ex - mx);
    dy = my >= ey ? (my - ey): (ey - my);
    
    // dx가 dy 이상일 경우 dx/2, 아닐 경우는 dy/2로 오차를 설정
    diff = dx >= dy ? (dx / 2): (dy / 2);
}

 

void MoveAimingBulletDDA(
    int& x, int& y,
    int vx, int vy,
    int dx, int dy,
    int& diff,
    int speed
) {
    if (dx >= dy) {
        for (int i = 0; i < speed; i++) {
            x += vx;
            diff += dy;
            if (diff >= dx) {
                diff -= dx;
                y += vy;
            }
        }
    }
    else {
        for (int i = 0; i < speed; i++) {
            y += vy;
            diff += dx;
            if (diff >= dy) {
                diff -= dy;
                x += vx;
            }
        }
    }
}

dx >= dy일 경우에는, speed 만큼 for문을 돌면서 x 좌표에는 계속 방향 벡터를 더해준다

y는 오차를 누적시켜서 누적된 오차가 dx보다 같거나 커질 경우 방향 벡터를 더해서 이동시켜 준다

dx < dy일 경우에는 반대로 진행하면 된다

 

* 단, 이렇게 DDA 방식으로 이동시키게 될 경우 수평이나 수직 방향이 아닌 비스듬히 날아가는 동안은 수평/수직 방향으로 날아가는 것보다 빨라지게 된다(45도 각도일 때 속도가 최대가 되며, 이는 수평/수직으로 날아갈 때의 약 1.4배(1/sin45)이다)

→ for문 한번에 x좌표와 y좌표 모두 이동하는 경우 둘 중 한 방향으로만 이동하는 것보다 빠르게 이동하게 됨

 

2.3 조준탄 (고정소수점수를 사용하여 탄환을 이동시키기)

고정소수점수 연산에서는 소수에 특정한 수(100, 10000)를 곱함으로써 소수를 정수로 바꾸여 처리한다

 

x << 8; y << 8; 과 같이 소수 자리수를 올려준 다음 2.1 방법과 동일하게 탄환의 x, y 좌표를 구해주면 된다

책에서도 탄환을 그리는 자리는 별도의 함수에서 처리하는 것으로 명시하고 넘어가고 있으므로 별다른 코드를 정리하지 않겠다