1. 실행 코드
import pygame as pg # 이미지 초기화 def 스프라이트_생성(이미지): 스프라이트 = pg.sprite.Sprite() 스프라이트.image = 이미지 스프라이트.rect = 스프라이트.image.get_rect() return 스프라이트 pg.init() # 게임 기본 설정 실행여부 = True 화면가로길이, 화면세로길이 = 800, 450 화면 = pg.display.set_mode([화면가로길이, 화면세로길이]) pg.display.set_caption('동족을 노역장에서 구출하라!') 배경이미지 = pg.image.load('img/배경.png') 배경이미지 = pg.transform.scale(배경이미지, (화면가로길이, 화면세로길이)) 개리점프이미지 = pg.image.load('img/개리-뛰는-모습5(점프).png') 개리점프이미지 = pg.transform.scale(개리점프이미지, (100, 100)) 개리착지이미지 = pg.image.load('img/개리-뛰는-모습6(착지).png') 개리착지이미지 = pg.transform.scale(개리착지이미지, (100, 100)) 개리뛰기이미지리스트 = [pg.image.load(f'img/개리-뛰는-모습{인덱스}.png') for 인덱스 in range(1, 5)] for 인덱스 in range(len(개리뛰기이미지리스트)): 개리뛰기이미지리스트[인덱스] = pg.transform.scale(개리뛰기이미지리스트[인덱스], (100, 100)) 개리스프라이트 = 스프라이트_생성(개리뛰기이미지리스트[0]) 돌이미지 = pg.image.load('img/돌.png') 돌이미지 = pg.transform.scale(돌이미지, (100, 100)) # 게임 요소 초기화 개리시작높이 = 255 개리뛰기상태 = 0 개리뛰는흐름 = 1 개리동작업데이트시간 = 0 점프기본속도 = 0.1 점프속도 = 점프기본속도 점프상태 = False 개리위치 = [70, 개리시작높이] 시계 = pg.time.Clock() while 실행여부: 화면.blit(배경이미지, (0, 0)) # 게임 시간 계산 경과시간 = 시계.tick(60) / 1000 개리스프라이트.rect.x, 개리스프라이트.rect.y = 개리위치[0], 개리위치[1] 화면.blit(개리스프라이트.image, 개리스프라이트.rect) 화면.blit(돌이미지, (500, 280)) # 개리 점프 if 점프상태: 개리스프라이트.image = 점프속도 > 0 and 개리점프이미지 or 개리착지이미지 개리위치[1] -= 점프속도 * 경과시간 * 1000 점프속도 -= 점프기본속도 * 경과시간 * 2 if 개리위치[1] >= 개리시작높이: 개리위치[1] = 개리시작높이 점프상태 = False 점프속도 = 점프기본속도 else: 개리동작업데이트시간 += 경과시간 if 개리동작업데이트시간 > 0.2: 개리동작업데이트시간 = 0 개리스프라이트.image = 개리뛰기이미지리스트[개리뛰기상태] 개리뛰기상태 += 개리뛰는흐름 if 개리뛰기상태 == len(개리뛰기이미지리스트) - 1 or 개리뛰기상태 == 0: 개리뛰는흐름 *= -1 for 이벤트 in pg.event.get(): if 이벤트.type == pg.QUIT: 실행여부 = False elif 이벤트.type == pg.KEYDOWN: if 이벤트.key == pg.K_SPACE and not 점프상태: 점프상태 = True pg.display.update() pg.display.quit()
2. 상세 설명
2-1. 구현 방식(정리)
- 스프라이트_생성 함수를 만들고 개리의 랜더링 객체를 스프라이트로 만들어 줍니다.
- 각 모션들을 로드합니다.(달리기는 리스트에 점프와 착지는 별도)
- 달리기 모션에 필요한 요소(개리뛰는상태, 개리뛰는흐름)를 만들고 달리기 모션을 구현합니다.
- 프레임에 따라 속도도 다르고 너무 빠르므로 개리동작업데이트시간과 시계 객체를 만들어 프레임 동기적으로 모션이 바뀌도록 합니다.
- 점프상태를 만들어 점프할 때와 아닐 때를 구분한 후 점프에 필요한 요소(점프기본속도, 점프속도, 개리 위치)를 생성합니다.(이 때 점프기본속도는 임의로 조정합니다.)
- 점프 속도에 따라 이미지를 변경되도록 하고 프레임에 따라 점프 속도와 위치가 조정되도록 합니다.
- 중력 가속도를 구현하기 위한 방식에는 다음과 같은 2가지 방식이 있습니다.
- 실제 중력 가속도(일반적으로 9.8)와 적분을 활용하여 가속도와 좌표의 상관 관계를 구하여 식을 대입하는 방식
- 가속이 없는 일반적으로 구현하기 쉬운 방식에서 점프_속도를 조금씩 줄여나가는 방식 → 이 방식을 게임에 적용하였습니다.
- 점프를 하고 시작 위치보다 밑으로 가면 시작 위치로 변경하고 달리기 모션으로 전환합니다.
2-2. 구현
def 스프라이트_생성(이미지): 스프라이트 = pg.sprite.Sprite() 스프라이트.image = 이미지 스프라이트.rect = 스프라이트.image.get_rect() return 스프라이트
- 스프라이트 사용 용도 : 충돌 체크(collide 종류 함수), 이미지 변경(뛰는 모습, 달리는 모습)
- 스프라이트 생성 시 기본적으로 받는 크기와 Surface 객체는 동등하게 생성하기 때문에 함수 처리합니다.
- 스프라이트 기본 설명
- pg.sprite.Sprite()로 생성합니다.
- Sprite.image : pg.image.load(경로) 함수 등의 방식으로 가져온 Surface객체를 저장합니다.
- Sprite.rect : 스프라이트 객체의 크기와 좌표를 저장합니다.
- Rect 객체의 좌표는 top, left, x, y 등의 여러 속성이 있습니다.
스프라이트를 사용하는 가장 큰 이유는 각 객체들에 대한 다양한 충돌이벤트를 처리할 수 있기 때문입니다. 기존에 사용했던 collidepoint를 통한 객체의 rect에 대한 처리보다 더욱 쉽게 접근할 수 있습니다.
개리점프이미지 = pg.image.load('img/개리-뛰는-모습5(점프).png') 개리점프이미지 = pg.transform.scale(개리점프이미지, (100, 100)) 개리착지이미지 = pg.image.load('img/개리-뛰는-모습6(착지).png') 개리착지이미지 = pg.transform.scale(개리착지이미지, (100, 100)) 개리뛰기이미지리스트 = [pg.image.load(f'img/개리-뛰는-모습{인덱스}.png') for 인덱스 in range(1, 5)] for 인덱스 in range(len(개리뛰기이미지리스트)): 개리뛰기이미지리스트[인덱스] = pg.transform.scale(개리뛰기이미지리스트[인덱스], (100, 100)) 개리스프라이트 = 스프라이트_생성(개리뛰기이미지리스트[0])
- 각 상황에 맞는 이미지를 가져옵니다.
- 달리는 이미지는 하나의 모션이기 때문에 리스트로 분류합니다.
- [ 값 for x in range() ] : List comprehension 기법으로 파이썬의 강력한 기능입니다. 단 한줄의 코드로 range()만큼 순회하면서 요소들을 추가하여 리스트를 만들어 줍니다.
- for문으로 개리뛰기이미지리스트에 있는 요소들을 scale함수를 통하여 사이즈를 100 x 100으로 설정합니다.
- 개리스프라이트를 앞서 만든 함수를 통해 만듭니다. 이때, 리스트[0]으로 생성한 이유는 먼저 개리의 이미지를 대기인 상태로 만들기 위함입니다.
# 게임 요소 초기화 개리시작높이 = 255 개리뛰기상태 = 0 개리뛰는흐름 = 1 개리동작업데이트시간 = 0 점프기본속도 = 0.1 점프속도 = 점프기본속도 점프상태 = False 개리위치 = [70, 개리시작높이] 시계 = pg.time.Clock()
게임이 시작되면 개리는 크게 달리는 모션과 점프 및 착지 모션으로 분류됩니다.
- 개리뛰는상태 : 개리뛰기이미지리스트의 인덱스입니다.
- 개리뛰는흐름 : 달리기 이미지 모션이 1-2-3-4-3-2-1 순이므로 4까지 올라간 다음은 내려가야 합니다. 따라서 모션을 1-2-3-4의 정방향으로 바꾸어야 하는지 또는 4-3-2-1 순의 역방향으로 바꾸어야하는지 결정하기 위해서 개리뛰는상태의 연산을 도와주는 변수입니다.
- 개리동작업데이트시간 : 프레임별로 이미지를 바꾸게 되면 캐릭터의 속도가 너무 빠르게 보입니다. 그래서 특정시간마다 이미지를 바꾸어 주어 어떤 프레임에서도 자연스러운 동작을 보여주기 위하여 사용됩니다.
- 점프기본속도 : 점프의 최대 속도(힘)을 나타내는 변수입니다.
- 점프속도 : 중력가속도의 원리를 이용하기 위해서 올라가는 동안 서서히 느려지게 되도록 합니다.
- 점프상태 : 달리기 상태와 점프상태를 구분하는 변수입니다.
- 개리위치 : 점프시 개리 위치가 조정될 수 있도록 구성한 리스트입니다. 스프라이트의 rect 객체에서의 좌표는 정수단위의 연산밖에 할 수 없으므로 시간에 의한 동기적 연산을 위해서는 소수 연산이 필요하여 사용합니다.
- 시계 : 프레임을 고정하기 위해 사용합니다. 프레임을 고정하는 이유는 화면이 자연스럽게(부드럽게) 업데이트 되기 위함입니다.
경과시간 = 시계.tick(60) / 1000 개리스프라이트.rect.x, 개리스프라이트.rect.y = 개리위치[0], 개리위치[1] 화면.blit(개리스프라이트.image, 개리스프라이트.rect)
- 시계는 Clock 클래스의 객체이고 Clock.tick(milli) 함수는 milli(밀리)초를 1프레임으로 계산하고 그 시간값을 반환하는 함수입니다.
- 경과시간 : 한 프레임의 시간을 초 단위로 계산한 함수입니다.
- 개리위치리스트를 활용하여 개리스프라이트의 x,y좌표를 설정하고 화면에 추가합니다.
if 점프상태: 개리스프라이트.image = 점프속도 > 0 and 개리점프이미지 or 개리착지이미지 개리위치[1] -= 점프속도 * 경과시간 * 1000 점프속도 -= 점프기본속도 * 경과시간 * 2 if 개리위치[1] >= 개리시작높이: 개리위치[1] = 개리시작높이 점프상태 = False 점프속도 = 점프기본속도 else: 개리동작업데이트시간 += 경과시간 if 개리동작업데이트시간 > 0.2: 개리동작업데이트시간 = 0 개리스프라이트.image = 개리뛰기이미지리스트[개리뛰기상태] 개리뛰기상태 += 개리뛰는흐름 if 개리뛰기상태 == len(개리뛰기이미지리스트) - 1 or 개리뛰기상태 == 0: 개리뛰는흐름 *= -1
pygame에서의 좌표는 화면 왼쪽 위를 0, 0 기준으로 x좌표는 오른쪽, y좌표는 아래쪽으로 좌표값이 증가합니다. 따라서 캐릭터가 위로 가는 모션은 y좌표를 빼는 형태로 설정해야합니다.
- 점프 중일 때
- 점프 속도를 기준으로 이미지를 조정합니다
- 점프속도 > 0 이면 점프 이미지를 아니면 착지이미지를 사용합니다.(3항 연산자를 사용하였습니다.)
- 계산 방식 : 위치와 힘의 조정은 프레임을 기준으로 적용합니다.
- 점프속도을 기준으로 개리의 위치(y)를 조정합니다.
- 점프 속도를 조정합니다.(점프 속도가 음수가 되었을 때 떨어지게 됩니다.)
- 시작 높이까지 떨어지면 기본 높이로
- 개리위치[1] -= 점프속도 * 지난시간 * 1000 → 원래는 점프속도만 빼주나 지난시간 * 1000이라는 식이 1초를 1로 계산하는 방식이기 때문에 사용합니다.
- 달리는 중일 때
- 0.2초를 기준으로 이미지를 변경합니다.(개리동작업데이트시간의 기준이 짧을 수록 모션이 좀 더 빨리 변화합니다.)
- 모션의 변화가 1-2-3-4-3-2-1이므로 이를 나누면 1-2-3-4와 4-3-2-1이 됩니다. 즉 달리기 모션의 흐름을 각 인덱스의 끝에 다다랐을 때 변경해줌으로써 인덱스를 더해야 할지 빼야할지를 결정합니다.
elif 이벤트.type == pg.KEYDOWN: if 이벤트.key == pg.K_SPACE and not 점프상태: 점프상태 = True
- Space 키가 눌리고 점프상태가 아닐 때 점프를 할 수 있도록 이벤트를 줍니다.
3. 실행 화면


