몹 모델
몹의 모양을 코드에서 상자 모델로 정의합니다. 모델을 지정하지 않으면 플레이어 모양 모델에 64×64 스킨 텍스처를 입혀 그립니다.
mod.content().entity("wisp", EntityDefinition.builder(ResourceId.of("my_mod", "textures/entity/wisp.png"))
.size(0.6f, 0.8f)
.maxHealth(6)
.noGravity()
.spawnEgg(CreativeTab.SPAWN_EGGS)
.model(EntityModelDefinition.builder(32, 32) // 텍스처 크기
.part("body", part -> part.pivot(0, 16, 0)
.box(0, 0, -3, -3, -3, 6, 6, 6) // u, v, x, y, z, 너비, 높이, 깊이
.animation(PartAnimation.BOB))
.part("ring", part -> part.parent("body")
.pivot(0, 0, 0)
.box(0, 12, -4, 0, -4, 8, 1, 8)
.animation(PartAnimation.SPIN))
.build())
.build());
좌표
- 좌표는 게임의 모델 공간을 기준으로 합니다. 단위는 픽셀(1/16블록)이고, y는 아래쪽으로 커지며, 땅은 y=24입니다.
- Blockbench의 "Modded Entity" 형식과 같은 좌표계입니다.
box(u, v, x, y, z, width, height, depth)는 텍스처 위치(u, v)와 상자의 모서리 좌표 및 크기를 받습니다.mirroredBox는 텍스처를 좌우로 뒤집습니다.pivot(x, y, z)는 회전 중심,rotation(x, y, z)는 기본 회전,parent(name)은 부모 부품을 지정합니다.
부품 애니메이션
PartAnimation | 동작 |
|---|---|
NONE | 움직이지 않음 |
HEAD | 시선을 따라 돌아감 |
WALK_SWING, WALK_SWING_OPPOSITE | 걸을 때 앞뒤로 흔들림(서로 반대 위상) |
BOB | 위아래로 오르내림 |
SPIN | 회전 |
키프레임 애니메이션
Blockbench 애니메이션처럼 부품마다 시간별 값(키프레임)을 지정하면 그 사이를 이어서 움직입니다. 이 값은 부품의 기본 자세에 더해지며, 그리기는 게임의 키프레임 애니메이션 엔진이 맡습니다.
.model(EntityModelDefinition.builder(32, 32)
.part("body", part -> part.pivot(0, 16, 0).box(0, 0, -3, -3, -3, 6, 6, 6))
.part("ring", part -> part.parent("body").box(0, 12, -4, 0, -4, 8, 1, 8))
// 계속 반복: 2초 동안 부드럽게 커졌다 작아짐
.animation("pulse", KeyframeAnimation.builder(2)
.looping()
.trigger(KeyframeAnimation.Trigger.ALWAYS)
.smooth()
.scale("body", 0, 1, 1, 1)
.scale("body", 1, 1.15f, 1.15f, 1.15f)
.scale("body", 2, 1, 1, 1)
.build())
// 서버가 시작할 때만 재생: 1초 동안 고리를 들어 올림
.animation("wave", KeyframeAnimation.builder(1)
.rotation("ring", 0, 0, 0, 0)
.rotation("ring", 0.5f, 45, 0, 0)
.rotation("ring", 1, 0, 0, 0)
.build())
.build())
재생 시점(Trigger) | 뜻 |
|---|---|
ALWAYS | 몹이 보이는 동안 계속 재생(숨쉬기, 회전) |
WHILE_MOVING | 움직이는 동안 재생하며, 빠르게 움직일수록 빨라짐(걷기, 날갯짓, 꼬리) |
ON_DEMAND(기본) | 서버가 MobView.playAnimation(name)으로 시작할 때 재생. 그 몹을 보는 모든 클라이언트에서 처음부터 재생됨 |
| 키프레임 | 단위 |
|---|---|
rotation(part, time, x, y, z) | 도(degree) |
position(part, time, x, y, z) | 모델 픽셀 단위, y는 위쪽이 양수(Blockbench와 같음) |
scale(part, time, x, y, z) | 배율, 1이 원래 크기 |
time은 초 단위이며0..길이범위 안이어야 합니다.smooth()뒤에 추가한 키프레임은 곡선(Catmull-Rom)으로, 그 전에 추가한 키프레임은 직선으로 이어집니다.looping()을 지정하지 않은ON_DEMAND애니메이션은 끝나면 멈춥니다. 다른 트리거에서는 마지막 값을 유지합니다.
서버에서 재생하는 방법은 다음과 같습니다.
MobView wisp = (MobView) world.spawnEntity(WISP, x, y, z);
world.schedule(10, () -> wisp.playAnimation("wave")); // 클라이언트가 몹을 받은 뒤에 재생
wisp.stopAnimation("wave"); // 반복 애니메이션 멈춤
- 모델에 없는 부품을 움직이거나 이름이
[a-z0-9_]+형식이 아니면 정의할 때IllegalArgumentException이 발생합니다. ON_DEMAND애니메이션은 모델마다 64개까지 둘 수 있습니다.- 모드 몹이 아니거나 해당
ON_DEMAND애니메이션이 없으면playAnimation이IllegalArgumentException을 던집니다.
사람 확인 필요
그린 결과가 올바르게 보이는지는 사람이 직접 확인해야 합니다. 자동 검증은 그리기 경로가 실행되는지만 확인합니다.