Sprite를 사용하면 이미지, 위치, 충돌 처리를 통합해서 처리할 수 있습니다.
Sprite를 단독으로 사용하는 경우
# 스프라이트 클래스 정의
class SimpleSprite(pygame.sprite.Sprite):
def __init__(self, image, position): # 생성자 파라미터로 스프라이트에 사용될 이미지 경로와 스프라이트 초기 위치를 받는다
pygame.sprite.Sprite.__init__(self)
self.user_src_image = pygame.image.load(image) # 스프라이트에 사용될 이미지를 저장할 사용자 변수
self.user_position = position # 스프라이트의 위치를 저장할 사용자 변수
self.user_rotation = 30 # 스프라이트의 회전 각도를 저장할 사용자 변수
def update(self): # 스프라이트의 상태를 업데이트 하는 함수. 필요에 따라 파라미터가 추가될 수도 있다.
# 여기에 게임 상태에 따라 스프라이트의 위치(user_position), 회전 각도(user_rotation), 이미지(user_src_image)를 변경시키는 코드가 들어가야 한다.
# {{
# ...
# }}
# 출력에 사용될 이미지, 위치를 정한다
self.image = pygame.transform.rotate(self.user_src_image, self.user_rotation) # 이미지를 회전 각도 만큼 회전시킨다
self.rect = self.image.get_rect()
self.rect.center = self.user_position # 이미지의 출력 위치를 정한다
...
# 초기화시 해야할 부분
simple = SimpleSprite('simple.png', (100, 100))
simple_group = pygame.sprite.RenderPlain(simple)
# -> RenderPlain 클래스는 여러개의 스프라이트를 묶어주는 역활을 하며,
# 상태 업데이트나 화면에 그릴 때에 RenderPlain 클래스를 통해서 하게된다.
...
# 게임 상태 업데이트시 해야할 부분
simple_group.update() # RenderPlain 객체를 통해 업데이트한다
...
# 게임 상태 화면에 출력시 해야할 부분
simple_group.draw(screen) # RenderPlain 객체를 통해 출력한다
Sprite를 그룹으로 사용하는 경우
# 스프라이트 클래스 정의
class SimpleSprite(pygame.sprite.Sprite):
def __init__(self, image, position): # 생성자 파라미터로 스프라이트에 사용될 이미지 경로와 스프라이트 초기 위치를 받는다
pygame.sprite.Sprite.__init__(self)
self.user_src_image = pygame.image.load(image) # 스프라이트에 사용될 이미지를 저장할 사용자 변수
self.user_position = position # 스프라이트의 위치를 저장할 사용자 변수
self.user_rotation = 30 # 스프라이트의 회전 각도를 저장할 사용자 변수
def update(self): # 스프라이트의 상태를 업데이트 하는 함수. 필요에 따라 파라미터가 추가될 수도 있다.
# 여기에 게임 상태에 따라 스프라이트의 위치(user_position), 회전 각도(user_rotation), 이미지(user_src_image)를 변경시키는 코드가 들어가야 한다.
# {{
# ...
# }}
# 출력에 사용될 이미지, 위치를 정한다
self.image = pygame.transform.rotate(self.user_src_image, self.user_rotation) # 이미지를 회전 각도 만큼 회전시킨다
self.rect = self.image.get_rect()
self.rect.center = self.user_position # 이미지의 출력 위치를 정한다
...
# 초기화시 해야할 부분
multiple = [
SimpleSprite('simple.png', (100, 100)),
SimpleSprite('simple.png', (100, 200)),
SimpleSprite('simple.png', (100, 300))
]
multiple_group = pygame.sprite.RenderPlain(*multiple) # 그룹으로 사용시 * 연산자가 들어가야 한다
# -> RenderPlain 클래스는 여러개의 스프라이트를 묶어주는 역활을 하며,
# 상태 업데이트나 화면에 그릴 때에 RenderPlain 클래스를 통해서 하게된다.
...
# 게임 상태 업데이트시 해야할 부분
multiple_group.update() # RenderPlain 객체를 통해 업데이트한다
...
# 게임 상태 화면에 출력시 해야할 부분
multiple_group.draw(screen) # RenderPlain 객체를 통해 출력한다
Sprite와 Sprite 그룹 사이의 충돌 체크
class BlockSprite(pygame.sprite.Sprite):
def __init__(self, position):
pygame.sprite.Sprite.__init__(self)
self.user_image_normal = pygame.image.load("block_normal.png"); # 보통 상태에서 표시할 이미지를 로딩
self.user_image_hit = pygame.image.load("block_hit.png"); # 충돌시에 표시할 이미지를 로딩
self.user_position = position;
# 충돌을 체크하는 spritecollide 함수 호출시 rect 정보가 사용되는데
# udpate가 spritecollide 이후에 호출되기 때문에 생성자에서 rect 초기값을 설정하여야 한다.
self.image = self.user_image_normal
self.rect = self.image.get_rect()
self.rect.center = self.user_position
def update(self, hit_list): # 충돌된 객체 리스트를 파라미터로 추가한다
if self in hit_list: # 자기 자신의 리스트에 포함 여부에 따라 상태 업데이트를 한다
self.image = self.user_image_hit # 이미지를 충돌 상태 이미지로 설정
else:
self.image = self.user_image_normal # 이미지를 보통 상태 이미지로 설정
self.rect = self.image.get_rect()
self.rect.center = self.user_position
...
blocks = [
BlockSprite((100, 100)),
BlockSprite((100, 200)),
BlockSprite((100, 300))
]
block_group = pygame.sprite.RenderPlain(*blocks)
...
collisions = pygame.sprite.spritecollide(simple, block_group, False)
# 첫번째 파라미터로 단일 스프라이트 객체가, 두번째 파라미터로 스프라이트의 그룹 객체가 온다.
# 두번째 파라미터의 스프라이트 그룹에 포함된 객체 중에서 첫번째 파라미터의 객체와 충돌하는
# 객체의 리스트를 반환한다.
# 세번째 파라미터는 스프라이트 그룹내 충돌된 스프라이트의 자동 제거 여부로,
# True로 할 경우, 충돌 발생시 바로 그룹에서 제거된다.
block_group.update(collisions) # 충돌된 객체 리스트를 스프라이트 객체로 넘겨서 처리한다.
...
block_group.draw(screen)
Sprite 객체 외부에서 충돌 처리
다른 스프라이트 객체를 참조하거나 전체 스프라이트에 공통으로 처리해야하는 경우, 다음과 같은 방법으로 스프라이트 객체 외부에서 처리할 수 있다.
collisions = pygame.sprite.spritecollide(simple, block_group, False)
if collisions:
for block in block_group.sprites():
block.image = block.user_image_hit # 그룹내 모든 스프라이트의 이미지를 바꾼다
배경 이미지 사용시
배경 이미지 사용시, 매번 전체 이미지를 blit하지않고, 다음과 같은 방법으로 Sprite에 해당하는 영역만 효율적으로 복원할 수 있다.
# 메인 루프 바깥에서 배경 이미지를 출력
background = pygame.image.load('background.png')
screen.blit(background, (0,0))
...
# 메인 루프 안에서 Sprite 영역만 복원해줌. (기존에 screen.fill(...) 호출하던 부분)
simple_group.clear(screen, background)
block_group.clear(screen, background)
종합 예제
플레이어를 이동시켜 장애물에 충돌시켜 볼 수 있는 예제 소스이다.
다음의 이미지 파일들이 소스와 같은 경로에 있어야 한다.
simple.png : 플레이어 이미지
block_normal.png : 장애물 이미지 (보통 상태)
block_hit.png : 장애물 이미지 (충돌 상태)
background.png : 배경 이미지
# -*- coding: utf-8 -*-
import math, sys
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((1024, 768), DOUBLEBUF)
clock = pygame.time.Clock()
class SimpleSprite(pygame.sprite.Sprite):
def __init__(self, image, position):
pygame.sprite.Sprite.__init__(self)
self.user_src_image = pygame.image.load(image)
self.user_position = position
self.user_rotation = 30
self.user_speed = 0
self.user_rotation_speed = 0
def update(self, deltat):
# 속도, 회전 속도에 따라 위치 정보를 업데이트한다
self.user_rotation += self.user_rotation_speed
x, y = self.user_position
rad = self.user_rotation * math.pi / 180
x += -self.user_speed * math.sin(rad)
y += -self.user_speed * math.cos(rad)
self.user_position = (x, y)
self.image = pygame.transform.rotate(self.user_src_image, self.user_rotation)
self.rect = self.image.get_rect()
self.rect.center = self.user_position
class BlockSprite(pygame.sprite.Sprite):
def __init__(self, position):
pygame.sprite.Sprite.__init__(self)
self.user_image_normal = pygame.image.load("block_normal.png");
self.user_image_hit = pygame.image.load("block_hit.png");
self.user_position = position;
self.image = self.user_image_normal
self.rect = self.image.get_rect()
self.rect.center = self.user_position
def update(self, hit_list):
if self in hit_list:
self.image = self.user_image_hit
else:
self.image = self.user_image_normal
self.rect = self.image.get_rect()
self.rect.center = self.user_position
rect = screen.get_rect()
simple = SimpleSprite('simple.png', rect.center)
simple_group = pygame.sprite.RenderPlain(simple)
blocks = [
BlockSprite((200, 200)),
BlockSprite((800, 200)),
BlockSprite((200, 600)),
BlockSprite((800, 600))
]
block_group = pygame.sprite.RenderPlain(*blocks)
background = pygame.image.load('background.png')
screen.blit(background, (0,0))
while True:
deltat = clock.tick(30)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# 키입력에 따라 속도, 회전 속도를 설정
if hasattr(event, 'key'):
down = event.type == KEYDOWN
if event.key == K_RIGHT:
simple.user_rotation_speed = down * -5 # 시계 방향이 마이너스인 것에 유의
elif event.key == K_LEFT:
simple.user_rotation_speed = down * 5
elif event.key == K_UP:
simple.user_speed = down * 10
elif event.key == K_DOWN:
simple.user_speed = down * -10
simple_group.update(deltat)
collisions = pygame.sprite.spritecollide(simple, block_group, False)
block_group.update(collisions)
simple_group.clear(screen, background)
block_group.clear(screen, background)
simple_group.draw(screen)
block_group.draw(screen)
pygame.display.flip()
<테스트 환경>
OS : Windows 7
Python 버전 : 2.7
pyGame 버전 : 1.9.1
'1. 연구 모듈 > Python' 카테고리의 다른 글
| [wxPython] Launcher 어플 Template (0) | 2015.09.29 |
|---|---|
| Python 게임 관련 라이브러리들 (0) | 2015.08.28 |
| pyGame 사용법 요약 - 1. 기본 기능 (0) | 2015.08.15 |
| [wxPython] Vertical BoxSizer에서 가로로 꽉 차게 컨트롤 추가하는 방법 (0) | 2014.04.20 |
| [Python 팁] ImportError: DLL load failed 에러 해결 (1) | 2013.08.08 |


