스프라이트
Ren'Py는 많은 이미지를 한꺼번에 표시할 수 있도록 스프라이트 시스템을 제공합니다. 각 스프라이트는 디스플레이어블 하나를 담으며 화면 위치와 앞뒤 순서를 바꿀 수 있습니다.
성능을 제외하면 스프라이트 시스템은 개념적으로 Transform()들을 Fixed()로 감싼 것과 비슷합니다. 스프라이트는 트랜스폼보다 훨씬 빠르지만 유연성은 낮습니다. 큰 성능 이점은 같은 디스플레이어블을 여러 스프라이트가 사용해도 프레임마다 한 번만 렌더링한다는 점입니다. 대신 Transform의 다양한 속성을 사용할 수 없고 xoffset과 yoffset만 바꿀 수 있습니다.
스프라이트 시스템을 사용하려면 SpriteManager 객체를 만든 뒤 create 메서드로 새 입자를 만듭니다. 필요에 따라 각 스프라이트의 xoffset, yoffset, zorder 필드를 갱신하여 화면에서 이동합니다. SpriteManager에 update와 event 인수를 전달하면 시간에 따라 변하거나 사용자 입력에 반응하게 할 수 있습니다.
스프라이트 클래스
- class Sprite
SpriteManager가 관리하는 스프라이트입니다. 화면 배치를 제어하는 필드를 가집니다. 직접 생성하지 말고
SpriteManager.create()를 호출하여 만들어야 합니다.스프라이트 객체의 필드는 다음과 같습니다.
- x, y
SpriteManager를 기준으로 한 스프라이트 왼쪽 위 모서리의 x, y 좌표입니다.
- zorder
SpriteManager 안의 다른 스프라이트와 비교한 표시 순서를 제어하는 정수입니다. 값이 클수록 사용자에게 가깝습니다.
- events
True이면 자식에 이벤트를 전달합니다. 기본값인 False이면 자식이 이벤트를 무시하므로 처리 시간도 소모하지 않습니다.
Sprite 객체의 메서드는 다음과 같습니다.
- destroy()
이 스프라이트를 파괴하여 표시되지 않도록 하고 SpriteManager에서 제거합니다.
- set_child(d)
이 스프라이트에 연결된 디스플레이어블을 d로 바꿉니다.
- class SpriteManager(update=None, event=None, predict=None, ignore_time=False, animation=True, **properties)
스프라이트들을 관리하고 가능한 한 빠르게 표시하는 디스플레이어블입니다.
- update
None이 아니면 이 스프라이트 관리자가 스프라이트를 렌더링할 때마다 호출하는 함수입니다. 관리자를 처음 표시한 뒤 지난 초 수를 인수 하나로 받습니다. 함수와 SpriteManager를 다시 호출하고 렌더링할 때까지의 초 수를 반환해야 합니다.
- event
None이 아니면 이벤트 발생 시 호출하는 함수입니다. pygame 이벤트 객체, 이벤트의 x 좌표, y 좌표, 스프라이트 관리자를 처음 표시한 뒤 지난 시간을 인수로 받습니다. None이 아닌 값을 반환하면 상호작용이 끝나고 그 값이 반환됩니다.
- predict
None이 아니면 디스플레이어블 리스트를 반환하는 함수입니다. 스프라이트 관리자를 예측 로딩할 때 이 디스플레이어블들도 예측 로딩합니다.
- ignore_time
True이면 디스플레이어블을 렌더링할 때 시간을 무시합니다. 상대적으로 작은 이미지 집합을 사용하고 이미지가 시간에 따라 변하지 않을 때 사용합니다. SpriteManager가 존재하는 동안 사용한 모든 디스플레이어블을 메모리에 유지하므로 디스플레이어블 수가 적을 때만 사용해야 합니다.
- animation
True이면 애니메이션 시간 기준을 사용합니다. 두 번 표시할 때 상태가 초기화되는 것을 막습니다.
SpriteManager는 한 번 렌더링한 뒤 update 함수를 호출하기 전에 다음 필드를 갖습니다.
- width, height
이 SpriteManager의 너비와 높이로, 픽셀 단위입니다.
SpriteManager의 메서드는 다음과 같습니다.
- create(d)
디스플레이어블 d의 새 Sprite를 만들고 이 SpriteManager에 추가합니다.
- redraw(delay=0)
delay초 뒤에 이 SpriteManager를 다시 그리도록 합니다.
- SnowBlossom(d, count=10, border=50, xspeed=(20, 50), yspeed=(100, 200), start=0, fast=False, horizontal=False, distribution: Callable[[float, float], float] | str = 'linear', animation=False)
snowblossom 효과는 같은 스프라이트의 여러 인스턴스를 화면 위, 아래, 왼쪽 또는 오른쪽으로 이동합니다. 스프라이트가 화면을 벗어나면 시작점으로 되돌립니다.
- d
스프라이트에 사용할 디스플레이어블입니다.
- border
화면 테두리 영역의 크기입니다. 스프라이트가 이 영역을 완전히 벗어날 때까지 화면 안에 있는 것으로 간주하여 갑자기 사라지지 않게 합니다.
- xspeed, yspeed
각각 가로와 세로 이동 속도입니다. 숫자 하나 또는 숫자 두 개의 튜플을 사용할 수 있습니다. 튜플이면 각 입자에 두 숫자 사이의 무작위 속도를 지정합니다. 양수와 음수 모두 가능하지만 튜플의 두 번째 숫자가 첫 번째보다 커야 합니다.
- start
각 입자를 추가하기 전의 지연 시간으로, 초 단위입니다. 입자들이 화면 위쪽에서 시작하더라도 파도처럼 한꺼번에 밀려오는 모양이 되지 않도록 할 수 있습니다.
- fast
참이면 입자들이 가장자리에서만 시작하지 않고 화면 중앙에서도 시작합니다.
- horizontal
참이면 입자들이 위나 아래 대신 왼쪽이나 오른쪽에서 나타납니다.
- distribution
입자의 시작 위치를 정하는 함수 또는 내장 분포 함수의 이름입니다.
문자열이면 다음 중 하나여야 합니다. linear: 축의 모든 위치가 같은 확률을 가집니다. gaussian: 가운데 근처일 확률이 높고 가장자리일 확률은 낮습니다. arcsine: 가장자리일 확률이 높고 가운데일 확률은 낮습니다.
함수이면 float 인수 두 개를 받아 float 하나를 반환해야 합니다.
기본값은 linear입니다.
- animation
True이면 SnowBlossom이 애니메이션 시간 기준을 사용합니다. 두 번 표시할 때 상태가 초기화되는 것을 막습니다.
스프라이트 예제
SnowBlossom 클래스는 화면에 떨어지는 대상을 쉽게 배치하는 방법입니다.
image snow = SnowBlossom("snow.png", count=100)
SpriteManager로 복잡한 동작을 만드는 예제입니다. 입자 400개를 표시하고 마우스를 피하게 합니다.
init python:
import math
def repulsor_update(st):
# If we don't know where the mouse is, give up.
if repulsor_pos is None:
return .01
px, py = repulsor_pos
# For each sprite...
for i in repulsor_sprites:
# Compute the vector between it and the mouse.
vx = i.x - px
vy = i.y - py
# Get the vector length, normalize the vector.
vl = math.hypot(vx, vy)
if vl >= 150:
continue
# Compute the distance to move.
distance = 3.0 * (150 - vl) / 150
# Move
i.x += distance * vx / vl
i.y += distance * vy / vl
# Ensure we stay on the screen.
if i.x < 2:
i.x = 2
if i.x > repulsor.width - 2:
i.x = repulsor.width - 2
if i.y < 2:
i.y = 2
if i.y > repulsor.height - 2:
i.y = repulsor.height - 2
return .01
# On an event, record the mouse position.
def repulsor_event(ev, x, y, st):
store.repulsor_pos = (x, y)
label repulsor_demo:
python:
# Create a sprite manager.
repulsor = SpriteManager(update=repulsor_update, event=repulsor_event)
repulsor_sprites = [ ]
repulsor_pos = None
# Ensure we only have one smile displayable.
smile = Image("smile.png")
# Add 400 sprites.
for i in range(400):
repulsor_sprites.append(repulsor.create(smile))
# Position the 400 sprites.
for i in repulsor_sprites:
i.x = renpy.random.randint(2, 798)
i.y = renpy.random.randint(2, 598)
del smile
del i
# Add the repulsor to the screen.
show expression repulsor as repulsor
"..."
hide repulsor
# Clean up.
python:
del repulsor
del repulsor_sprites
del repulsor_pos