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
관리 메뉴

개발이 취미인 개발자

슈팅게임 알고리즘-레이저 구현하기 본문

슈팅게임 알고리즘(pygame)

슈팅게임 알고리즘-레이저 구현하기

도그풋79 2022. 4. 11. 00:07

 

슈팅게임 개발 시 레이저를 구현하는 거에 대해 알아보자.

최초 레이저의 발사되는 방향과 속도, 또 그에 따른 이동거리는 계산은 기존에 배운 조준탄과 동일하다.

조준탄의 경우 플레이어를 향해 발사되면 끝이 났다. 하지만 레이저의 경우에는 발사으로 끝이 나지 않는다.

위의 그림처럼 1번 레이저가 발사된 후 1번 레이저를 뒤 따라오는 2번과 3번 레이저를 만들어줘야한다.

자연스러운 레이저의 이동을 위해서는 1번 레이저가 그려진 후 다음 위치로 이동하기 전에 2번 레이저를 생성해 줘야한다.

 

 1번 레이저가 이동한 후, 생성된 2번 레이저는 원래 1번 위치에 그려진다. 이를 위해서는 2번 레이저가 생성되는 시점에 1번 레이저의 원래 x, y, theta, angle의 값으로 생성되어야 한다.

 

 3번 레이저를 생성할 때는 여러 방법이 있겠지만 여기서는 1번 레이저가 생성하는 걸로 구현했다. 따라서 1번 레이저를 head(머리) 라고 설정하고 head값이 True 인 경우에만 2번, 3번과 같은 꼬리를 만들도록 처리했다. 레이저의 총 길이를 laser_length 설정하고 꼬리 레이저를 만들 때마다 값을 1씩 빼주며 0이면 그 후로는 꼬리 레이저를 생성하지 않도록 처리했다. 조준탄과 동일하게 레이저에게 가속도를 부여했는데 이때 주의할 점은 최고 속도를 레이저 asset의 길이보다 크게 설정해서는 안된다. 그렇게 되면 길게 연결되어야 할 레이저에 간격이 발생하여 아래 그림처럼 레이저가 끊겨서 보이게 된다.

레이저의 폭과 길이보다 레이저의 속도가 너무 빠르게 되면 마치 레이저가 끊어져서 그려진다.

 조준레이저 구현의 핵심은 맨 앞에 발 사되는 레이저와 그 뒤로 발사되는 레이저를 구분하는 것이다.

맨 앞 머리 역할이 아닌 레이저는 원래 위치에서 설정된 방향과 속도로 이동하는 것 외에는 아무런 동작을 하지 않는다. 하지만 맨 앞 머리 레어지는 뒤 따라오는 레이저를 생성하면서 자신도 이동을 계속 해야한다. 

import pygame
import os
import math

game_main_dir = os.path.dirname(os.path.abspath(__file__))
img_dir = os.path.join(game_main_dir)

class EnemyLaser(pygame.sprite.Sprite):
    def __init__(self, enemy_id, x, y, angle, theta, speed, head, laser_length=20):
        pygame.sprite.Sprite.__init__(self)        
        self.image = pygame.transform.rotate(\
            pygame.image.load(img_dir + "/img/enemy_laser_01.png"), theta)
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.angle = angle
        self.theta = theta
        self.speed = speed        
        self.max_speed = 8.0
        self.x = x
        self.y = y
        self.orig_speed = speed
        self.orig_x = x
        self.orig_y = y
        self.head = head
        self.laser_length = laser_length
        self.enemy_id = enemy_id        

    def update(self, GameMain):
        if self.head:
            if self.laser_length > 0:
                enemyLaser = EnemyLaser(self.enemy_id, self.orig_x, self.orig_y, \
                    self.angle, self.theta, self.orig_speed, False, 0)
                GameMain.bullet_group.add(enemyLaser)
                self.laser_length -= 1
            elif self.laser_length == 0:
                for e in GameMain.enemy_group:
                    if e.id == self.enemy_id:
                        e.aiming = True
                self.laser_length -= 1

        self.dx = math.cos(self.angle) * self.speed
        self.dy = math.sin(self.angle) * self.speed
        if self.max_speed > self.speed:
            self.speed += 0.2

        self.x += self.dx
        self.y += self.dy
        self.rect.centerx = int(self.x)
        self.rect.centery = int(self.y)

        if self.rect.y < -10:
            self.kill()
        elif self.rect.y > 810:
            self.kill()
        elif self.rect.x < -10:
            self.kill()
        elif self.rect.x > 810:
            self.kill()

 추가적으로 레이저를 발사하는 동안에 잠시 포열이 조준하는 것을 멈춰두는 것이 필요하다.

 레이저를 발사하는 도중에 플레이어를 포열이 다시 조준해 버리게 되면 레이저가 다 발사되지도 않은 상태에서 포열이 돌아가 버린다. 게이머 입장에서는 이상하게 보일 수가 있다.

레이저가 발사 중에 포열이 움직이면 위와 같이 부자연스럽게 보인다.

 

 아래와 같이 포의 움직임은 self.aiming이 True인 경우에만 동작하도록 처리했다.

    def update(self, GameMain):
        if self.aiming:                
            self.current_frame += 1
            ty = GameMain.flight.rect.centery
            sy = self.rect.centery
            tx = GameMain.flight.rect.centerx
            sx = self.rect.centerx
            self.angle = math.atan2(ty - sy, tx - sx)
            self.theta = math.degrees(self.angle) * -1
            self.image = pygame.transform.rotate(self.images[0], self.theta)
            self.rect = self.image.get_rect()
            self.rect.center = [self.x, self.y]

            if self.current_frame >= self.delay_frame:
                self.behavior(GameMain)
                self.current_frame = 0

 레이저가 원래 길이만큼 모두 발사된 경우, 포열의 조준 기능을 동작하도록 변경해 줘야한다. 레이저 소스 파일을 전체를 첨부한다.

02_aming_laser.zip
0.01MB