PyMunk에 pyGame을 결합한 예제 코드입니다.

우선 pyGame 기본 예제는 아래 글을 참고하시기 바랍니다.

>> pyGame 기본 예제

 

사전 설치 요구사항

pygame 모듈 사용시, 추가적인 pygame 모듈 설치를 필요로 합니다.

pip install pygame

 

예제 코드

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import pygame
from pygame.locals import *
import pymunk
import pymunk.pygame_util
 
SCREEN_WD = 400
SCREEN_HT = 400
TARGET_FPS = 60
 
screen = pygame.display.set_mode((SCREEN_WD, SCREEN_HT), 0, 32)
pygame.display.set_caption("PyMunk_Example")
clock = pygame.time.Clock()
 
space = pymunk.Space()
space.gravity = 0, -1000
draw_options = pymunk.pygame_util.DrawOptions(screen)
 
ground = pymunk.Body(body_type=pymunk.Body.STATIC)
ground.position = 50, 50
  
ground_shape = pymunk.Segment(ground, (-50, 0), (50, 0), 1)
space.add(ground_shape)
 
body = pymunk.Body(1, 1666)
body.position = 50, 100
  
poly = pymunk.Poly.create_box(body, (10, 10))
space.add(body, poly)
 
timeStep = 1.0 / 60
 
running = True
while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
            continue
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            running = False
            continue
 
    screen.fill((0, 0, 0, 0))
 
    space.debug_draw(draw_options)
 
    space.step(timeStep)
 
    pygame.display.flip()
    clock.tick(TARGET_FPS)
 
pygame.quit()
print("done")

PyMunk에서는 다음 두 호출을 통해 기본적인 내용을 자동적으로 pyGame 영역에 그려주게 됩니다. 다만 (0, 0)에서부터 그려주므로 앞의 예제에서 전체적으로 (+50, +50) 만큼 좌표를 이동시켰습니다.

draw_options = pymunk.pygame_util.DrawOptions(screen)
...

space.debug_draw(draw_options)

 

정찰 위성 이미지

 

<테스트 환경>
  - OS : Windows 7
 - Python 버전 : 3.6
 - Pymunk 버전 : 5.3.2
 - PyGame 버전 : 1.9.3

 

,


Sprite를 사용하면 이미지, 위치, 충돌 처리를 통합해서 처리할 수 있습니다.


Sprite를 단독으로 사용하는 경우

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
32
33
34
35
36
37
38
39
# 스프라이트 클래스 정의
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를 그룹으로 사용하는 경우

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
32
33
34
35
36
37
38
39
40
41
42
43
# 스프라이트 클래스 정의
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 그룹 사이의 충돌 체크

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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 객체 외부에서 충돌 처리


다른 스프라이트 객체를 참조하거나 전체 스프라이트에 공통으로 처리해야하는 경우, 다음과 같은 방법으로 스프라이트 객체 외부에서 처리할 수 있다.

1
2
3
4
collisions = pygame.sprite.spritecollide(simple, block_group, False)
if collisions:
    for block in block_group.sprites():
        block.image = block.user_image_hit # 그룹내 모든 스프라이트의 이미지를 바꾼다



배경 이미지 사용시

배경 이미지 사용시, 매번 전체 이미지를 blit하지않고, 다음과 같은 방법으로 Sprite에 해당하는 영역만 효율적으로 복원할 수 있다.

1
2
3
4
5
6
7
8
9
# 메인 루프 바깥에서 배경 이미지를 출력
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 : 배경 이미지


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# -*- 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


,

Python에서 게임 제작에 사용할 수 있는 pyGame 라이브러리 기본 기능에 대해 긴 설명없이 빠르게 훓어볼 수 있도록 정리해보았습니다.


우선 Python에서 UTF-8 한글로 된 주석을 사용하기 위해서는 소스 앞부분에 다음 구문을 추가하여야 한다

# -*- coding: utf-8 -*-


->



모듈 import

1
2
import pygame                   # pygame 모듈을 import
from pygame.locals import *     # pygame.locals 하위 모듈을 import


pyGame 라이브러리 초기화

라이브러리 초기화를 하지 않을 경우, 일부 기능이 정상 동작하지 않을 수 있다.

1
pygame.init()

디스플레이 초기화

1
2
3
4
5
6
# 1) 화면 해상도를 480*320으로 초기화. 윈도우 모드, 더블 버퍼 모드로 초기화하는 경우
screen = pygame.display.set_mode((480, 320), DOUBLEBUF)
pygame.display.set_caption('Hello World!'# 타이틀바의 텍스트를 설정
 
# 2) 화면 해상도를 480*320, 전체 화면 모드, 하드웨어 가속 사용, 더블 버퍼 모드로 초기화하는 경우
screen = pygame.display.set_mode((480, 320), FULLSCREEN | HWSURFACE | DOUBLEBUF)


두번째 파라미터는 다음과 같은 flag들을 | 연산자로 조합하여 사용할 수 있다.


FULLSCREEN : 전체 화면 모드를 사용
HWSURFACE : 하드웨어 가속 사용. 전체 화면 모드에서만 가능
OPENGL : OpenGL 사용 가능한 디스플레이를 초기화
DOUBLEBUF : 더블 버퍼 모드를 사용. HWSURFACE or OPENGL에서 사용을 추천



메인 루프

pyGame의 메인 루프는 아래와 같이 크게 세 부분으로 나뉘어진다.

1
2
3
4
5
6
7
8
9
10
while True:
  for event in pygame.event.get():
      # 이벤트를 처리하는 부분 -> 키보드, 마우스 등의 이벤트 처리 코드가 들어감
      ...
 
  # 게임의 상태를 업데이트하는 부분
  ...
 
  # 게임의 상태를 화면에 그려주는 부분 -> 화면을 지우고, 그리고, 업데이트하는 코드가 들어감
  ...

종료 이벤트 처리

1
2
3
4
5
6
7
8
import sys
 
 
# 윈도우의 닫기 버튼이 눌렸을 때, 프로그램을 종료하도록 처리
for event in pygame.event.get():
  if event.type == QUIT:
    pygame.quit()
    sys.exit()


키 이벤트 처리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for event in pygame.event.get():
  if not hasattr(event, 'key'):                    # 키 관련 이벤트가 아닐 경우, 건너뛰도록 처리하는 부분
    continue
  if event.type == KEYDOWN:
    if event.key == K_RIGHT:
      # 오른쪽 키에 대한 처리
      ...
    elif event.key == K_LEFT:
      # 왼쪽 키에 대한 처리
      ...
    elif event.key == K_UP:
      # 위쪽 키에 대한 처리
      ...
    elif event.key == K_DOWN:
      # 아래 키에 대한 처리
      ...
    elif event.key == K_ESCAPE:
      # ESC 키에 대한 처리
      ...


마우스 이벤트 처리

1
2
3
4
5
6
7
8
9
10
11
12
LEFT = 1  # 왼쪽 버튼에 대한 버튼 인덱스
RIGHT = 3  # 오른쪽 버튼에 대한 버튼 인덱스
 
if event.type == MOUSEBUTTONDOWN and event.button == LEFT:
  # 왼쪽 버튼이 눌렸을 때의 처리
  print "left mouse up (%d, %d)" % event.pos
elif event.type == MOUSEBUTTONUP and event.button == LEFT:
  # 왼쪽 버튼이 떨어졌을 때의 처리
  print "left mouse down (%d, %d)" % event.pos
elif event.type == pygame.MOUSEMOTION:
  # 마우스 이동시의 처리
  print "mouse move (%d, %d)" % event.pos

색 정의

1
2
3
4
5
BLACK = (0, 0, 0# R, G, B
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLUE_A = (0, 0, 255, 127# R, G, B, Alpha(투명도, 255 : 완전 불투명)


사각형 정의

1
rectangle = (0, 10, 100, 100# 왼쪽 X, 위 Y, 너비, 높이


화면의 업데이트

1
2
3
4
5
6
# 전체 화면을 업데이트할 경우
pygame.display.flip()                           # 화면 전체를 업데이트
 
# 화면의 일부만 업데이트할 경우
pygame.display.update(rectangle)                # 업데이트할 rectangle을 지정
pygame.display.update(rectangle_list)           # 업데이트할 rectangle을 여러개 지정


프레임 수 맞추기

메인 루프 안에서 FPS(초당 프레임수)를 맞추기 위한 딜레이를 추가해주는 코드. 파라미터로 딜레이 시간이 아닌 목표로 하는 FPS 값이 들어간다.

1
2
3
4
5
6
7
TARGET_FPS = 30
clock = pygame.time.Clock()
 
while True:
  ...
 
  clock.tick(TARGET_FPS)  # 30 FPS를 맞추기 위한 딜레이를 추가


화면 지우기

1
2
3
# 화면을 그리기에 앞서 지우기 위해 호출한다
 
screen.fill(BLACK)


기본 도형 그리기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 네 점을 지나는 폴리곤을 그린다
pygame.draw.polygon(screen, RED, ((10, 10), (20, 10), (30, 20), (10, 20)))    
 
# 두 점을 지나는 선을 그린다
pygame.draw.line(screen, BLUE, (10, 10), (20, 20))                            
 
# 사각형을 그린다 (왼쪽, 위, 너비, 높이 순)
pygame.draw.rect(screen, RED, (10, 10, 100, 50))                              
 
# (100, 100)을 중심으로 하는 반지름 10인 원을 그린다
pygame.draw.circle(screen, BLUE, (100, 100), 10)                              
 
# 사각형 안을 지나는 타원을 그린다
pygame.draw.ellipse(screen, RED, (10, 10, 100, 50))                           
 
# 두 점을 지나는 두께 4의 선을 그린다 (모든 그리기 함수에 두께가 추가될 수 있다)
pygame.draw.line(screen, BLUE, (10, 10), (20, 20), 4)                         


점 찍기

1
2
3
4
pixelArray = pygame.PixelArray(screen)
pixelArray[10][100] = RED
pixelArray[50][100] = BLUE
del pixelArray  # 사용 후, 반드시 PixelArray를 del해줘야 Surface가 lock되는 것을 방지할 수 있다


이미지 파일 다루기

1
2
3
4
5
6
7
8
9
10
11
12
13
# 이미지 파일 그리기
img = pygame.image.load('image.jpg')
screen.blit(img, (50, 100))             # 지정한 좌표가 이미지의 왼쪽 위에 위치하도록 출력된다
 
# 이미지 파일 회전하여 그리기
img = pygame.image.load('image.jpg')
x = 100
y = 100
degree = 45                             # 회전할 각도를 도(degree) 단위로 지정
rotated = pygame.transform.rotate(img, degree)
rect = rotated.get_rect()
rect.center = (x, y)                    # 지정한 좌표가 이미지의 중심에 오도록 출력된다
screen.blit(rotated, rect)


투명도 처리

pygame.display.set_mode()로 얻어진 기본 Surface에 출력할 경우 투명도는 적용되지 않기 때문에, 아래와 같이 별도의 Surface를 생성하여 처리하여야 한다.

1
2
3
4
5
6
7
8
9
t_surface = screen.convert_alpha()              # 기본 Surface(screen)로부터 투명도 처리를 위한 Surface 생성
 
...
 
 
t_surface.fill((0, 0, 0, 0))                    # t_surface 전체를 투명한 검정색으로 지운다
 
pygame.draw.rect(t_surface, (0, 0, 255, 127), (30, 30, 40, 40))  # t_surface에 투명도를 적용하여 그려줌
screen.blit(t_surface, (0, 0))                  # t_surface를 기본 Surface에 blit

텍스트 출력하기

1
2
3
4
5
6
7
8
9
10
11
12
13
fontObj = pygame.font.Font('myfont.ttf', 32)                  # 현재 디렉토리로부터 myfont.ttf 폰트 파일을 로딩한다. 텍스트 크기를 32로 한다
textSurfaceObj = fontObj.render('Hello Font!', True, GREEN)   # 텍스트 객체를 생성한다. 첫번째 파라미터는 텍스트 내용, 두번째는 Anti-aliasing 사용 여부, 세번째는 텍스트 컬러를 나타낸다
textRectObj = textSurfaceObj.get_rect();                      # 텍스트 객체의 출력 위치를 가져온다
textRectObj.center = (150, 150)                               # 텍스트 객체의 출력 중심 좌표를 설정한다
screen.blit(textSurfaceObj, textRectObj)                      # 설정한 위치에 텍스트 객체를 출력한다
 
 
# Font 객체 생성의 다른 예
fontObj = pygame.font.Font(None, 32)                                    # 폰트 파일에 None을 지정할 경우 기본 폰트가 사용된다
fontObj = pygame.font.Font('C:\\Windows\\Fonts\\tahoma.ttf', 32)        # 윈도우 경로에 있는 폰트를 사용할 경우
 
# render 함수 사용의 다른 예
textSurfaceObj = fontObj.render('Hello font!', True, GREEN, BLUE)       # 텍스트 색을 녹색, 배경색을 파란색으로 설정한다


사운드 출력하기

Wav, Ogg 형식의 사운드 파일을 지원한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
soundObj = pygame.mixer.Sound('beeps.wav')              # 사운드 파일을 로딩한다
soundObj.play()                                         # 사운드 파일을 플레이한다 (플레이가 끝나는 것을 기다리지 않고 바로 리턴된다)
 
 
# 5초 후에 플레이를 정지하는 경우
import time
 
soundObj.play()
time.sleep(5)
soundObj.stop()
 
 
# 반복해서 플레이하는 경우 (BGM)
pygame.mixer.music.load('background.mp3')
pygame.mixer.music.play(-1, 0, 0)


종합 예제

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# -*- coding: utf-8 -*-
 
import sys
import pygame
from pygame.locals import *
 
# 초당 프레임수를 정의
TARGET_FPS = 30
 
clock = pygame.time.Clock()
 
 
# 색 정의
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
 
 
# 마우스 버튼 인덱스 정의
LEFT = 1  # 왼쪽 버튼에 대한 버튼 인덱스
RIGHT = 3  # 오른쪽 버튼에 대한 버튼 인덱스
 
# 라이브러리 및 디스플레이 초기화
pygame.init()
screen = pygame.display.set_mode((480, 320), DOUBLEBUF)
 
# 이미지 파일을 로딩
img = pygame.image.load('image.jpg')
 
# 폰트 로딩 및 텍스트 객체 초기화
fontObj = pygame.font.Font('myfont.ttf', 32)
textSurfaceObj = fontObj.render('Hello Font!', True, GREEN)
textRectObj = textSurfaceObj.get_rect();
textRectObj.center = (150, 200)
 
# 사운드 파일을 로딩
soundObj = pygame.mixer.Sound('beeps.wav')
 
# 메인 루프
while True:
  for event in pygame.event.get():
    # 이벤트를 처리하는 부분
    if event.type == QUIT:
      pygame.quit()
      sys.exit()
 
 
    # 키보드 이벤트 처리
    if event.type == KEYDOWN:
      if event.key == K_RIGHT:
        # 오른쪽 키가 눌리면 사운드를 플레이한다
        soundObj.play()
 
 
    # 마우스 이벤트 처리
    if event.type == MOUSEBUTTONDOWN and event.button == LEFT:
      # 왼쪽 버튼이 눌렸을 때의 처리
      print "left mouse up (%d, %d)" % event.pos
    elif event.type == MOUSEBUTTONUP and event.button == LEFT:
      # 왼쪽 버튼이 떨어졌을 때의 처리
      print "left mouse down (%d, %d)" % event.pos
    elif event.type == pygame.MOUSEMOTION:
      # 마우스 이동시의 처리
      print "mouse move (%d, %d)" % event.pos
 
 
  # 게임의 상태를 업데이트하는 부분
 
  # 게임의 상태를 화면에 그려주는 부분
 
 
  screen.fill(BLACK)  # 화면을 검은색으로 지운다
 
  pygame.draw.line(screen, GREEN, (10, 0), (20, 10))  # 두 점을 지나는 선을 그린다
 
  # 수동으로 점 찍기
  pixelArray = pygame.PixelArray(screen)
  pixelArray[5][5] = RED
  pixelArray[10][10] = RED
  del pixelArray
 
  # 이미지 파일 그리기
  screen.blit(img, (50, 100))
  
  # 이미지 파일 회전하여 그리기
  x = 200
  y = 100
  degree = 30
  rotated = pygame.transform.rotate(img, degree)
  rect = rotated.get_rect()
  rect.center = (x, y)
  screen.blit(rotated, rect)
 
  # 텍스트 오브젝트를 출력
  screen.blit(textSurfaceObj, textRectObj)
 
  pygame.display.flip()  # 화면 전체를 업데이트
  clock.tick(TARGET_FPS)  # 프레임 수 맞추기



<테스트 환경>
OS : Windows 7
Python 버전 : 2.7
pyGame 버전 : 1.9.1


,
[Python] pyBox2D 사용 예제 - 4. pyGame + Box2D 기본 예제 (1)


pyGame에 pyBox2D를 결합한 첫번째 예제 코드입니다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import pygame
from pygame.locals import *
from Box2D import *
from Box2D.b2 import *
 
SCREEN_WD = 400
SCREEN_HT = 400
TARGET_FPS = 60
PPM = 20.0
 
screen = pygame.display.set_mode((SCREEN_WD, SCREEN_HT), 0, 32)
pygame.display.set_caption("PyBox2D_Example")
clock = pygame.time.Clock()
 
world = b2World(gravity = (0, -10), doSleep = True)
 
ground1BodyDef = b2BodyDef()
ground1BodyDef.position.Set(0, 1)
ground1Body = world.CreateBody(ground1BodyDef)
ground1Shape = b2PolygonShape()
ground1Shape.SetAsBox(50, 5)
ground1Body.CreateFixture(shape = ground1Shape)
 
box1BodyDef = b2BodyDef()
box1BodyDef.type = b2_dynamicBody
box1BodyDef.position.Set(10, 15)
box1Body = world.CreateBody(box1BodyDef)
box1Shape = b2PolygonShape()
box1Shape.SetAsBox(2, 1)
box1FixtureDef = b2FixtureDef()
box1FixtureDef.shape = box1Shape
box1FixtureDef.density = 1
box1FixtureDef.friction = 0.3
box1Body.CreateFixture(box1FixtureDef)
 
timeStep = 1.0 / 60
velIters = 10
posIters = 10
 
colors = {
    staticBody  : (255,255,255,255),
    dynamicBody : (127,127,127,255),
}
 
running = True
while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
            continue
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            running = False
            continue
 
    screen.fill((0, 0, 0, 0))
 
    for body in (ground1Body, box1Body):
        for fixture in body.fixtures:
            shape = fixture.shape
            vertices = [(body.transform * v) * PPM for v in shape.vertices]
            vertices = [(v[0], (SCREEN_HT - v[1])) for v in vertices]
            pygame.draw.polygon(screen, colors[body.type], vertices)
                      
    world.Step(timeStep, velIters, posIters)
    pygame.display.flip()
    clock.tick(TARGET_FPS)
 
pygame.quit()
print("done")
전반적으로는 앞서 두개의 예제가 합쳐진 것이라고 볼 때 크게 다르지 않습니다.


주의할 부분은 Box2d의 객체들을 화면으로 그려주는 부분인데,


생성된 지면과 박스의 body 객체 각각에 대해 처리하도록 하면서,
    for body in (ground1Body, box1Body):
body 객체에 연결된 모든 fixture 객체에 대해 처리하도록 합니다.
    for fixture in body.fixtures:
fixture 객체에 연결된 shape 객체를 가져옵니다.
    shape = fixture.shape
Shape 객체 내의 정점 집합에 대해 body 객체 자체의 확대 배율(body.transform)과 미터당 포인트 비율(Point Per Meter, PPM)을 곱하여(Box2D 내부의 좌표 체계는 미터로 되어있음), 결과 또한 집합으로 얻습니다.
    vertices = [(body.transform * v) * PPM for v in shape.vertices]
Box2D 좌표계 상의 Y좌표는 위로 갈수록 커지고, pyGame 좌표계 상의 Y좌표는 아래로 갈수록 커지므로 이를 보정해줍니다. (v[0] : X 좌표, v[1] : Y좌표)
    vertices = [(v[0], (SCREEN_HT - v[1])) for v in vertices]
마지막으로 최종적으로 구해진 좌표 집합으로 polygon을 그리는데, 타입이 static이냐 dynamic이냐에 따라 다른 색으로 그려줍니다.
    pygame.draw.polygon(screen, colors[body.type], vertices)
,