Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발이 취미인 개발자

슈팅게임 알고리즘-360도 방향탄 구현하기 본문

슈팅게임 알고리즘(pygame)

슈팅게임 알고리즘-360도 방향탄 구현하기

도그풋79 2022. 6. 3. 21:01

 슈팅게임에서 화면을 어지럽게 채우는 일명 탄의 장막, 탄막을 만들기 위해서는 360도 회전하면서 발사하는 회전탄을 빼놓을 수가 없다. 360도 회전탄의 경우 탄 사이의 각도와 탄의 속도를 조금만 변경해도 난이도를 상당히 어렵게 만들 수가 있다. 

 360도 방향탄을 구현하는 경우, 게임 난이도 측면에서 안전지대에 대해서 고려해야 한다.

만약 처음 총알을 15도 각도로 발사 했다고 가정하면 발사된 총알과 총알 사이에 15도 각도 영역만큼 안전지대가 생성이 된다. 문제는 360도 회전을 모두 마치고 2회차도 동일한 각도로 총알이 회전을 하게 되면 결국 안전지대에서 플레이어는 아무런 움직임 없이도 현란한 총알을 모두 피하게 된다. 그래서 360도 회전을 마치고 0도로 돌아 왔을때 회전 각도를 살짝 틀어줘서 1회차에 안전지대를 위험지대로 바꿔줘야 플레이어가 게임의 긴장감을 유지시킬 수 있다.

 360도 방향탄은 이제까지 설명드린 탄과 다른 부분이 있다. 플레이어의 위치를 계산해서 조준할 필요가 없다는 점이다. 처음 발사되는 총알을 물론 조준탄으로 설정해도 상관은 없다. 여기서는 플레이어 위치를 정확하게 계산하기 보다는 포탄과 기체의 위치에 따라 시계방향으로 돌지 반시계방향으로 돌지만 체크했다.

    def update(self, GameMain):
        self.fire_frame += 1        
        self.animation_frame += 1
        sy = self.rect.centery
        sx = self.rect.centerx

        if self.turret_status == TURRET_OPEN:
            inc = 1            
        elif self.turret_status == TURRET_CLOSE:
            inc = -1
        else:
            inc = 0
        
        if self.fire_frame >= self.fire_delay_frame:
            if self.animation_frame >= self.animation_interval:
                self.image_idx += inc
                self.animation_frame = 0
                if self.turret_status == TURRET_STOP:
                    self.turret_status = TURRET_OPEN
                elif self.turret_status == TURRET_FIRE:
                    if self.isFireBullet():
                        self.createBullet(GameMain.bullet_group, sx, sy, self.theta_inc, 2)
                        self.animation_frame = 0
                    else:
                        self.turret_status = TURRET_WAIT
                        self.animation_frame = self.animation_interval

                elif self.turret_status == TURRET_WAIT:
                    self.turret_status = TURRET_CLOSE

                if self.image_idx > 5:
                    self.image_idx = 5
                    self.turret_status = TURRET_FIRE
                    #기체의 위치에 따라 회전방향을 바꿔준다.
                    self.theta_inc *= -1 if GameMain.flight.rect.centerx > sx else 1
                elif self.image_idx < 0:
                    self.image_idx = 0
                    self.turret_status = TURRET_STOP
                    self.fire_frame = 0
        
        self.image = self.images[self.image_idx]

 self.theta_inc 변수는 기체의 x좌표(flight.rect.centerx)에 자신의 x좌표(sx)를 비교하여 각도를 시계방향로 잡을지 반시계방향으로 잡을지 체크한다.

    def createBullet(self, bullet_group, sx, sy, theta_inc, speed):
        self.theta += theta_inc

        #360도 회전 완료 후 발사각도를 5도 정도 더한다.
        if abs(self.theta) >= 360:
            self.theta = -90
            self.rotated = not(self.rotated)
        
        if self.rotated:
            self.theta += 5 if self.theta > 0 else -5

        enemyBullet = Rotation2Bullet(sx, sy, self.theta, speed)
        bullet_group.add(enemyBullet)

 위에서 설명한 것처럼 360도의 모든 방향으로 발사를 마친 경우, 각도를 기존 각도에서 +5도, 또는 -5도씩 틀어준다.

def isFireBullet(self):
        self.fire_cnt += 1
        #최대 총알 갯수를 넘어서면 총알 발사를 중지한다.
        if self.fire_cnt >= self.fire_max_cnt:
            self.fire_cnt = 0
            return False
        else:
            return True

 무한대로 계속 총알을 발사하는 것보다는 일정 갯수 이상 총알을 발사하면 잠시 멈추도록 처리했다. 최대 총알 갯수(fire_max_cnt)는 처음 생성될 시점에 무작위로 설정했다.

 전체 실행 소스를 아래 첨부한다. 이제 어느정도 여러가지 탄 패턴에 대해 알아봤으니 다음 강좌에서는 이제까지 배운 탄을 활용한 보스전을 개발해보려고 한다.

06_rotation2_bullet.zip
0.03MB