도형

Rect, Triangle, Circle, Line, Polyline은 도형 컴포넌트입니다. 엔티티를 생성할 때 하나를 건네주면, 그 엔티티는 파괴될 때까지 매 프레임 그 도형을 그립니다.

from pyxen import *

def start():
    world.spawn(x=110, y=90, shape=Rect(48, 32, fill=(0.4, 0.7, 1.0, 1.0)))
    world.spawn(x=210, y=90, shape=Circle(24, stroke=(1.0, 0.6, 0.3, 1.0), stroke_width=2))

도형은 진짜 엔티티이므로 엔티티가 할 수 있는 모든 것이 그대로 적용됩니다. entity.x와 entity.y로 움직이고, entity.rotation으로 돌리고, 부모를 지정하고, 트윈으로 움직이고, 레이어에 올리고, entity.visible로 숨길 수 있습니다.


도형과 draw 중 무엇을 쓸까

Pyxen은 같은 다섯 가지 기본 도형을 두 가지 방식으로 제공합니다. 화면에서는 똑같아 보이고 차이는 수명뿐입니다. 다른 한쪽은 draw를 참고하세요.

도형 컴포넌트draw
수명엔티티를 파괴할 때까지 유지매 프레임 다시 그림
위치엔티티의 위치·회전·크기직접 전달한 월드 좌표
비용완전한 엔티티(transform, 레이어, 컴포넌트 저장소)프레임 버퍼의 쿼드 몇 개
디버거엔티티로 목록에 나오고 검사됨거슬러 간 각 프레임에 표시
적합한 용도우주선·벽·고정 UI 같은 게임 객체게임 상태를 그린 그림: 잔상, 오버레이, HUD 막대

그것이 게임 속 존재라면 도형 컴포넌트를, 엔티티가 이미 가진 상태를 그림으로 표현한다면 draw를 쓰세요. 시간 여행 디버거에서 프레임을 거슬러 가면 둘 다 그때 모습 그대로 보입니다.


자주 걸리는 세 가지

도형은 생성할 때 정해지며 이후에는 바꿀 수 없습니다. entity.shape는 존재하지 않고, 읽으려 하면 ValueError: component schema does not exist가 발생합니다. 대입이 가능한 sprite나 text와는 다릅니다. 도형을 바꾸려면 엔티티를 파괴하고 새로 생성하세요.

entity.color로는 도형에 색을 입힐 수 없습니다. 스프라이트에는 적용되지만, 도형은 자신의 fill과 stroke로 그려지며 이를 무시합니다. 색은 도형 자체에 지정하세요.

외곽선 두께 인자의 이름이 두 가지입니다. Rect, Triangle, Circle은 stroke_width를, Line과 Polyline은 width를 받습니다. 의미는 같습니다.


색

모든 색 인자는 각 성분이 0.0~1.0인 (r, g, b, a) 튜플 또는 Color를 받습니다.

Rect(40, 20, fill=(1, 0, 0, 1))        # 불투명한 빨강
Rect(40, 20, fill=(1, 0, 0, 0.35))     # 35% 빨강

fill도 stroke도 없는 도형은 아무것도 그리지 않습니다. 둘 다 완전히 투명한 상태로 시작하므로 Rect(40, 40)은 유효하지만 보이지 않는 엔티티입니다. 여기서 가장 흔한 함정입니다. 둘 다 넘기면 외곽선이 있는 채워진 도형이 됩니다.


타입

Rect(width, height, fill=None, stroke=None, stroke_width=1, pivot=None)

직사각형.

인자타입설명
width, heightfloat크기(픽셀).
fill튜플내부 색. 생략하면 채우지 않습니다.
stroke튜플외곽선 색. 생략하면 그리지 않습니다.
stroke_widthfloat외곽선 두께. 기본값은 1.
pivot튜플엔티티 위치가 가리키는 지점을 도형 내부 픽셀로 지정합니다. 기본값은 모서리이며 (width/2, height/2)면 가운데가 됩니다.

pivot을 가진 도형은 Rect뿐이며, 회전의 중심이기도 합니다.

def start():
    world.spawn(x=110, y=90, shape=Rect(48, 32, fill=(0.4, 0.7, 1.0, 1.0)))
    # 자기 위치를 중심으로 하므로 제자리에서 회전합니다.
    world.spawn(name="spinner", x=210, y=90,
                shape=Rect(48, 32, stroke=(1.0, 0.6, 0.3, 1.0), stroke_width=2,
                           pivot=(24, 16)))

def update():
    world.get(name="spinner").rotation += 0.02

Triangle(x1, y1, x2, y2, x3, y3, fill=None, stroke=None, stroke_width=1)

엔티티 위치를 기준으로 한 세 점을 지나는 삼각형.

인자타입설명
x1, y1, x2, y2, x3, y3float세 꼭짓점. 엔티티로부터의 상대 위치.
fill튜플내부 색. 생략하면 채우지 않습니다.
stroke튜플외곽선 색. 생략하면 그리지 않습니다.
stroke_widthfloat외곽선 두께.
world.spawn(x=160, y=90, shape=Triangle(0, -20, 18, 14, -18, 14, fill=(1, 1, 0.3, 1)))

Circle(radius, fill=None, stroke=None, stroke_width=1, segments=12)

엔티티를 중심으로 하는 원.

인자타입설명
radiusfloat반지름(픽셀).
fill튜플내부 색. 생략하면 채우지 않습니다.
stroke튜플외곽선 색. 생략하면 그리지 않습니다.
stroke_widthfloat외곽선 두께.
segmentsint곡선을 근사하는 직선 분할 수. 기본값은 12.

원은 사실 다각형입니다. 작은 크기에서는 12분할이면 둥글게 보입니다. 큰 원에서는 값을 올리고, 일부러 다각형처럼 보이고 싶다면 낮추세요. segments=6이면 육각형입니다.

world.spawn(x=110, y=90, shape=Circle(28, fill=(0.5, 1.0, 0.7, 1.0), segments=6))
world.spawn(x=210, y=90, shape=Circle(28, fill=(1.0, 0.5, 0.7, 1.0), segments=32))

Line(x1, y1, x2, y2, stroke=None, width=1)

엔티티를 기준으로 한 두 점을 잇는 직선.

인자타입설명
x1, y1float시작점. 엔티티로부터의 상대 위치.
x2, y2float끝점.
stroke튜플선 색.
widthfloat선 두께. stroke_width가 아니라 width입니다.
world.spawn(x=60, y=90, shape=Line(0, 0, 80, -40, stroke=(0.3, 1, 0.5, 1), width=2))

Polyline(points, stroke=None, width=1, closed=False, fill=None)

이어진 선분들의 나열.

인자타입설명
points튜플 또는 FloatBuffer(x1, y1, x2, y2, …) 형태의 평탄한 나열. 좌표 쌍의 목록이 아닙니다.
stroke튜플선 색.
widthfloat선 두께. stroke_width가 아니라 width입니다.
closedboolTrue면 마지막 점을 첫 점과 잇습니다.
fill튜플둘러싸인 영역을 채웁니다. closed=True와 함께 쓸 때 특히 유용합니다.

평탄한 나열인 것은 의도된 설계입니다. FloatBuffer가 이미 이 형태이므로, 한 번 계산한 경로를 다시 만들지 않고 그대로 Polyline에 넘길 수 있습니다.

world.spawn(x=250, y=90,
            shape=Polyline((0, 0, 30, -25, 60, 0), stroke=(1, 0.9, 0.2, 1), width=3))