도형
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, height | float | 크기(픽셀). |
fill | 튜플 | 내부 색. 생략하면 채우지 않습니다. |
stroke | 튜플 | 외곽선 색. 생략하면 그리지 않습니다. |
stroke_width | float | 외곽선 두께. 기본값은 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, y3 | float | 세 꼭짓점. 엔티티로부터의 상대 위치. |
fill | 튜플 | 내부 색. 생략하면 채우지 않습니다. |
stroke | 튜플 | 외곽선 색. 생략하면 그리지 않습니다. |
stroke_width | float | 외곽선 두께. |
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)
엔티티를 중심으로 하는 원.
| 인자 | 타입 | 설명 |
|---|---|---|
radius | float | 반지름(픽셀). |
fill | 튜플 | 내부 색. 생략하면 채우지 않습니다. |
stroke | 튜플 | 외곽선 색. 생략하면 그리지 않습니다. |
stroke_width | float | 외곽선 두께. |
segments | int | 곡선을 근사하는 직선 분할 수. 기본값은 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, y1 | float | 시작점. 엔티티로부터의 상대 위치. |
x2, y2 | float | 끝점. |
stroke | 튜플 | 선 색. |
width | float | 선 두께. 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 | 튜플 | 선 색. |
width | float | 선 두께. stroke_width가 아니라 width입니다. |
closed | bool | True면 마지막 점을 첫 점과 잇습니다. |
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))