pyxen.Entity

Entity는 경량 핸들 — 컴포넌트를 위한 컨테이너입니다.

엔티티-컴포넌트 시스템의 소개는 엔티티 및 컴포넌트를 참조하세요.


내장 컴포넌트

컴포넌트접근
Transforme.x, e.y, e.rotation, e.scale
Spritee.sprite, e.color
Animatione.animation
Sounde.sound
Musice.music
GridBodye.body
GridMape.map
Nodee.parent, e.children
Layere.layer
Namee.name
Camerae.camera

Transform

e.x = 100
e.y = 50
e.rotation = 45
e.scale = (2, 2)

scale을 읽으면 Vector2를 반환합니다:

s = e.scale
print(s.x, s.y)

Sprite

e.sprite = sprite
e.color = (1.0, 0.5, 0.5, 1.0)

color를 읽으면 Color를 반환합니다:

c = e.color
print(c.r, c.g, c.b, c.a)

스프라이트 애니메이션

animation 매개변수로 스프라이트를 생성하면 엔진이 자동으로 애니메이션을 재생합니다. e.animation을 통해 애니메이션 상태를 읽을 수 있습니다:

player.sprite = Sprite("hero", animation="walk")

속성

속성타입설명
namestr현재 애니메이션 클립의 이름
frameint클립 내 현재 프레임 인덱스
playingbool애니메이션이 재생 중이면 True
finishedbool원샷 애니메이션이 완료되면 True
anim = player.animation
if anim:
    print(anim.name)      # "walk"
    print(anim.frame)     # 2
    print(anim.playing)   # True
    print(anim.finished)  # False

애니메이션이 활성화되지 않은 경우 e.animationNone을 반환합니다:

player.sprite = Sprite("hero", tile=(0, 0, 16, 16))
print(player.animation)  # None

취소

e.animationNone을 할당하여 재생을 중지합니다:

player.animation = None

새 스프라이트를 할당하면 기존 애니메이션이 자동으로 취소됩니다.

원샷 애니메이션

한 번만 재생되는 애니메이션에는 loop=False를 사용합니다:

player.sprite = Sprite("hero", animation="attack", loop=False)

def update():
    if player.animation and player.animation.finished:
        player.sprite = Sprite("hero", animation="idle")

Tweens

Tweens는 엔티티의 속성을 시간에 따라 부드럽게 애니메이션합니다. 엔진이 자동으로 보간을 처리하므로 프레임별 코드가 필요 없습니다.

entity.tween()

# 속성 이름 지정 형식
entity.tween("x", to=200, duration=1.0)
entity.tween("alpha", to=0, duration=0.5, ease="out_quad")

# 키워드 축약 형식 — 여러 속성을 동시에 애니메이션
entity.tween(x=200, y=100, duration=1.0, ease="out_quad")
매개변수타입기본값설명
propertystr속성 이름 (위치 인수 또는 키워드 형식)
tofloat목표 값
byfloat상대 오프셋 (to의 대안)
startfloat현재 값시작 값 (기본값은 현재 값)
durationfloat1.0초 단위 지속 시간
easestr"linear"이징 함수 이름

to로 절대 목표를, by로 상대 오프셋을 지정합니다:

entity.tween("x", to=200, duration=1.0)    # x=200으로 이동
entity.tween("x", by=50, duration=0.5)     # 오른쪽으로 50픽셀 이동

start로 시작 값을 재지정합니다:

entity.tween("x", to=200, start=0, duration=1.0)  # 항상 0에서 시작

애니메이션 가능한 속성

컴포넌트속성
Transformx, y, rotation, sx, sy
Spriter, g, b, alpha
Camerazoom

이징 함수

이름곡선
linear일정 속도 (기본값)
in_quad느린 시작, 가속
out_quad빠른 시작, 감속
in_out_quad느린 시작과 끝
in_cubicquad보다 느린 시작
out_cubicquad보다 빠른 시작
in_out_cubic부드러운 시작과 끝
in_expo매우 느린 시작, 폭발적 가속
in_out_expo폭발적 중간
out_expo매우 빠른 시작, 부드러운 정지
in_back전진하기 전에 뒤로 당김
out_back목표를 초과한 후 안정
in_out_back뒤로 당김과 초과
in_elastic탄성 감기
out_elastic탄성 초과와 바운스
in_out_elastic양쪽 끝에서 탄성

entity.tweens.cancel()

엔티티의 트윈을 취소합니다. 속성 이름을 전달하면 하나의 트윈을 취소하고, 인수 없이 호출하면 모든 트윈을 취소합니다. 값은 현재 위치에서 고정됩니다.

entity.tweens.cancel("x")   # 하나의 속성 취소
entity.tweens.cancel()       # 모두 취소

충돌 해결

같은 엔티티와 속성에 새로운 트윈을 시작하면 이전 것이 교체됩니다. 서로 다른 속성의 트윈은 독립적으로 실행됩니다.

entity.tween("x", to=100, duration=1.0)
entity.tween("x", to=200, duration=0.5)  # 첫 번째 트윈을 교체
entity.tween("y", to=50, duration=1.0)   # x 트윈과 함께 실행

파괴된 엔티티의 트윈은 자동으로 정리됩니다.

속성에서 animate()를 시작하면 해당 속성의 활성 tween()이 취소되며, 그 반대도 마찬가지입니다.


애니메이션

무한히 실행되는 연속 애니메이션 — 사인파 진동(펄스, 호흡, 흔들림)과 일정 속도 회전.

entity.animate() — 진동

사인파로 중심 값 주위로 속성을 진동시킵니다.

entity.animate("sx", "sy", by=0.15, speed=6.0)     # coin pulse
entity.animate("alpha", by=0.3, center=0.7, speed=4.0)  # flicker 0.4–1.0

값은 다음을 따릅니다: center + sin(elapsed * speed) * by

entity.animate() — 스핀

일정한 속도로 값을 누적합니다. 스핀 모드를 사용하려면 by=를 생략합니다.

entity.animate("rotation", speed=180)   # 180°/sec clockwise

매개변수

매개변수타입기본값설명
*propsstr하나 이상의 속성 이름 (위치 인수)
byfloat진폭 (진동 모드). 스핀의 경우 생략.
centerfloat현재값진동의 중심 값
speedfloat1.0각 주파수 (진동) 또는 단위/초 (스핀)

트윈과 동일한 10개 속성: x, y, rotation, sx, sy, r, g, b, alpha, zoom.

entity.animations.cancel()

엔티티의 애니메이션을 취소합니다. 속성 이름을 전달하면 하나의 애니메이션을 취소하고, 인수 없이 호출하면 모든 애니메이션을 취소합니다.

entity.animations.cancel("rotation")   # 하나의 속성 취소
entity.animations.cancel()             # 모두 취소

부모 / 자식

child.parent = parent

자식에 접근:

for c in parent.children:
    print(c.name)

자식 수 확인:

parent.children.count

커스텀 컴포넌트

컴포넌트는 할당으로 생성됩니다:

  • 딕셔너리 — 구조화된 컴포넌트
  • 불리언 — 마커 컴포넌트
e.cell = {
    'row': 0,
    'col': 0
}

첫 번째 할당이 스키마를 생성합니다. 필드 타입이 추론되며 스키마가 고정됩니다 — 이후에 새 필드를 추가할 수 없습니다.


시스템에서 컴포넌트 사용

for cell in world.all("cell"):
    ...

참조: pyxen.world.all()


마커 컴포넌트

e.alive = True

마커는 데이터를 저장하지 않습니다 — 존재만 나타냅니다. 일반 컴포넌트처럼 쿼리합니다:

for e in world.all("alive"):
    ...

컴포넌트 필드 접근

e.cell.row
e.cell.col
e.cell.row = 5

지원되는 필드 타입

Python 타입저장 형태
int32비트 정수
float32비트 부동소수점
bool불리언
str고정 문자열 (최대 31자)
Entity엔티티 참조

잘못된 타입은 에러를 발생시킵니다:

TypeError: invalid value type in dict

스키마 규칙

  • 최대 컴포넌트 크기: 256바이트
  • 문자열 최대: 31자
  • 딕셔너리 키는 문자열이어야 함
  • 스키마 생성 후 새 필드 추가 불가
e.cell = {'row': 0}
e.cell = {'row': 0, 'new_field': 5}
ValueError: cannot create new fields after schema is complete

이후 할당에서 필드를 생략하는 것은 유효합니다 — 0, 0.0, False, "" 등으로 기본값이 설정됩니다.


컴포넌트 확인

e.has("cell")

엔티티에 해당 컴포넌트가 있으면 True, 없으면 False를 반환합니다.

커스텀과 내장 컴포넌트 이름 모두 작동합니다:

e.has("sprite")   # 엔티티에 스프라이트가 있으면 True
e.has("body")     # 엔티티에 그리드 바디가 있으면 True

자손 쿼리

entity.all(*components, without=(), include_self=False)

주어진 컴포넌트 필터와 일치하는 엔티티의 모든 자손 (씬 그래프 계층을 통한 깊이 우선)에 대한 이터레이터를 반환합니다.

world.all()과 동일하게 작동하지만, 전체 월드 대신 하위 트리로 범위가 제한됩니다.

# "enemy" 컴포넌트를 가진 모든 자손
for e in parent.all("enemy"):
    ...

# 제외 조건 포함
for e in parent.all("enemy", without=("boss",)):
    ...

# 부모 엔티티 자체도 포함
for e in parent.all("tag", include_self=True):
    ...
매개변수타입기본값설명
*componentsstr필요한 컴포넌트 이름
withouttuple()제외할 컴포넌트 이름
include_selfboolFalse엔티티 자체를 포함할지 여부

내장 및 커스텀 컴포넌트 이름 모두 지원됩니다.


컴포넌트 제거

del 또는 None 할당으로 엔티티에서 컴포넌트를 제거합니다:

# 둘 다 동일합니다:
del entity.health
entity.health = None

제거 후, entity.has("health")False를 반환하며 해당 엔티티는 더 이상 해당 컴포넌트에 대한 쿼리에 매칭되지 않습니다.

e = world.spawn()
e.health = {'hp': 100}

del e.health

e.has("health")         # False
# world.all("health")에 e가 포함되지 않음

제거 후 컴포넌트를 다시 추가할 수 있습니다:

del e.health
e.health = {'hp': 50}   # 정상 작동

내장 컴포넌트

모든 내장 컴포넌트를 제거할 수 있습니다:

del e.sprite    # 스프라이트 데이터 초기화
del e.body      # 물리 바디 초기화
del e.camera    # 카메라 제거
del e.text      # 텍스트 제거
del e.sound     # 사운드 제거
del e.music     # 음악 제거
del e.map       # 그리드 맵 제거

스프라이트와 바디는 0으로 초기화됩니다 (엔티티는 여전히 저장소를 가지지만 데이터는 비어 있습니다). 카메라, 텍스트, 사운드, 음악, 맵은 완전히 삭제됩니다.

마커

e.enemy = True
del e.enemy      # 또는: e.enemy = None
e.has("enemy")   # False

엔티티 생명주기

  • world.spawn()으로 생성
  • 컴포넌트 할당으로 수정
  • del 또는 = None으로 컴포넌트 제거
  • world.destroy()로 제거

참조: pyxen.world.spawn() | pyxen.world.destroy()