목록슈팅게임 알고리즘(pygame) (12)
개발이 취미인 개발자
슈팅게임에서 배경은 화면의 속도감을 주는 역할을 한다. 속도감이 생기는 이유는 착시 효과를 이용한 것으로 배경을 빠르게 이동시켜 멈춰 있는 메인 캐릭터 빠른 속도로 움직인다는 느낌을 받게 된다. 코드 구현도 무척 간단하다. 최초 맨 위에서 출발한 이미지가 화면에 마지막에 도달하게 되면 배경이미지의 높이만큼 다시 위로 이동시키면 끝이다. 여기서는 조금 입체적인 효과를 주기 위해 배경 이미지를 4장을 사용했다. 별 이미지 2장과 성운 이미지 2장을 처리했는데 이미지를 더 추가하면 훨씬 더 속도감 있는 효과를 줄 수가 있을 것이다. game_background.py 파일을 새로 만들고 아래 소스코드를 추가한다. class Background(pygame.sprite.Sprite): def __init__(se..
슈팅게임에서 스테이지별 시작과 끝은 전통적으로 메인캐릭터의 출격하는 장면과 철수하는 장면이 나온다. 이번에는 그동안 개발한 소스에서 제트기류를 뒤로 뿜어내면서 출격하는 씬과 철수하는 씬을 추가하도록 하자. 우선 출격하는 장면을 구현해 보자 제트기류 연출은 이전에 처리한 총알 구현 파트에서 레이저 발사를 응용하면 된다. 제트기류가 뒤로 발사된 후 시간이 지나면서 사라지도록 처리하면 된다. 제트 기류의 발생 위치는 메인캐릭터의 꼬리 부분에 맞춰서 생성해준다. 시간이 모두 지나면 생성한 제트기류 객체를 삭제하면 끝이다. 제트기류 처리하는 class는 아래 소스코드를 참고하자. class FlightJet(pygame.sprite.Sprite): def __init__(self, sx, sy): pygame.s..
원래는 이번에는 스테이지 처리에 대해 구현하려고 했는데 스테이지 처리 전에 먼저 소개할 부분이 있다는 생각이 들었다. 그것은 바로 메인 캐릭터와 총알과의 충돌 처리 부분이다. 이제까지 많은 예제를 만들면서 충돌 처리와 같은 필수적인 부분을 추가하지 않았는데 지금이라도 설명하고 넘어가는 것이 앞으로 남은 강좌에 꽤나 필수적이라는 생각이 들었다. 충돌 처리는 게임 개발하는 과정에서 꽤 난이도가 높은 편이다. 특히 적기의 모양이 복잡할 수록 많은 연산과 로직이 들어가야 한다. 그래서 과거 하드웨어 성능이 떨어지던 시절에는 충돌 영역을 단순하게 박스 모양으로 설정해서 영역 안에 총알이 들어간 경우, 충돌로 판정하도록 처리했다고 한다. 하드웨어의 연산 속도가 빠르지 않았기 때문에 게임이 충돌 처리에 많은 자원을 ..
지난 번에는 회전을 하는 편대비행을 구현했다면 이번에는 회전이 없는 편대비행을 구현해 봤다. 사실 별로 코드상의 차이는 없다. rotate하는 부분을 코드를 주석으로 막으면 무회전하는 편대비행을 구현할 수가 있다. 적 생성 시점에 설정값 중에 회전 여부를 아래와 같이 추가하고 enemy_class 생성 시 회전여부를 속성값으로 설정할 수 있도록 처리했다. # 0 속도(vel) # 1 가속도(acceleration) # 2 회전속도(angle_speed) # 3 최대속도(max_vel) # 4 회전여부(rotated) true(1): false(0) # 5 회전시감속(curved_speed) enemy_config = [ [1, 0.1, 5, 7, 0, 1.5] , [1, 0.1, 5, 7, 0, 1.5]..
슛팅게임에서 보스전 만큼 중요한 건 바로 현란한 적기의 움직임이라고 생각한다. 인터넷에 있는 슛팅게임 예제를 많이 봐 왔는데 매번 아쉬운 점은 적기의 움직임이 단조롭다는 것이다. 대부분 위에서 아래로 내려오는 일직선 정도로 구현이 되고 끝이 나 버린다. 그래서 조금 더 다양한 패턴의 움직임을 가진 적기가 등장하는 것을 구현해 봤다. 적기의 움직임도 탄의 종류만큼이나 다양하게 나올 수가 있다. 총알과 다른 점이 있다면 방향이 바뀌면서 움직이는 경우, 더 자연스럽게 움직이도록 처리를 해줘야한다는 점이다. 총알도 각도가 변하는 경우는 많지만 화면에 노출되는 시간이 길지 않고 크기도 작은 편이라 다소 부자연스러운 움직임을 보이더라도 플레이어가 눈치를 채기가 매우 어렵다. 하지만 적기의 움직임은 그렇지가 않다. ..
보스전은 그동안 여러 종류의 총알을 구현하면서 사용한 코드를 그대로 재활용해서 구현해 보았다. 보스의 본체 위에 터렛을 올리고 보스와 터렛이 함께 움직이도록 처리했다. 그리고 총알 발사하는 로직은 기존에 개발한 조준탄, n-way탄, 원형 회전탄을 거의 그대로 사용했다. 수정한 부분은 거의 발사 간격 정도이다. 보스의 움직임은 처음에는 좌우로 한번 움직이고 그리고 가운데로 이동 한 뒤에 아래로 이동했다가 다시 제자리로 돌아오도록 처리했다. 움직임을 처리하는 데이터는 배열 형태로 만들었다. 보스의 움직임 배열의 기본 구조는 아래와 같다. 0 start_x (시작 위치 -1인 경우 현재 위치) 1 start_y (시작 위치 -1인 경우 현재 위치) 2 dx (x의 좌표 이동값) 3 dy (y의 좌표 이동값)..
슈팅게임에서 화면을 어지럽게 채우는 일명 탄의 장막, 탄막을 만들기 위해서는 360도 회전하면서 발사하는 회전탄을 빼놓을 수가 없다. 360도 회전탄의 경우 탄 사이의 각도와 탄의 속도를 조금만 변경해도 난이도를 상당히 어렵게 만들 수가 있다. 360도 방향탄을 구현하는 경우, 게임 난이도 측면에서 안전지대에 대해서 고려해야 한다. 만약 처음 총알을 15도 각도로 발사 했다고 가정하면 발사된 총알과 총알 사이에 15도 각도 영역만큼 안전지대가 생성이 된다. 문제는 360도 회전을 모두 마치고 2회차도 동일한 각도로 총알이 회전을 하게 되면 결국 안전지대에서 플레이어는 아무런 움직임 없이도 현란한 총알을 모두 피하게 된다. 그래서 360도 회전을 마치고 0도로 돌아 왔을때 회전 각도를 살짝 틀어줘서 1회차..
회전탄은 발사된 총알이 원을 그리며 움직이는 탄이다. 여러 개의 총알이 회전을 하기 때문에 현란해 보일 뿐만 아니라 위의 구현된 회전탄처럼 점점 그리는 원의 반경을 넓혀주면 플레이어가 예상하는 움직임을 빗나가게 피하기 어렵게 만든다. cx, cy를 총알의 움직이는 중심 좌표로 두고, 총알이 움직이는 원의 반지름을 rad로 가정할 때, 원을 그리면서 움직이는 총알의 좌표는 아래와 같은 공식을 통해 얻을 수 있다. x = cx + rad * cos(θ) y = cy + rad * sin(θ) 위의 공식을 코드로 구현하면 아래와 같다. def update(self, GameMain): self.x = self.cx + self.rad * math.cos(math.radians(self.theta)) self...