맵과 몸
맵을 연다
local main = Chain2D.Map.load("main") -- 없으면 만들고, 있으면 그것을 줍니다
local same = Chain2D.Map.get("main") -- 이미 있는 것만
local names = Chain2D.Map.list() -- 지금 열려 있는 맵 이름들
Chain2D.Map.define("dungeon", function(map) end) -- 처음 열릴 때 할 일
맵은 이름으로 다룹니다. 손잡이를 오래 들고 있지 마세요 — 언로드된 맵의 손잡이는 더 이상 존재하지 않는 세계를 가리키고, 이름은 그 사이에도 참입니다.
바닥을 놓는다
local town = main.loadTiles("town")
print(town.width, town.height, town.tileSize)
local spawn = town.point("spawn") -- 문서가 이름 붙인 자리
local door = town.area("to-dungeon") -- 문서가 이름 붙인 구역
local bridge = town.tile("bridge") -- 타일셋이 이름 붙인 타일
loadTiles 는 shared/maps/<이름>.json 을 읽습니다. 없는 이름을 부르면 그 자리에서
오류가 납니다 — 조용히 비어 있으면 바닥 없는 게임이 되고, 그것은 파일이 빠졌다는
사실이 아니라 물리 버그처럼 읽힙니다.
문서 없이 직접 칠할 수도 있습니다:
main.setMap(width, height, tileSize, tiles) -- tiles 는 판정 플래그 배열
세계를 바꾼다
main.setTile(x, y, bridge) -- 타일 하나를 바꿉니다
main.setMoverRate(0, 0) -- 0번 움직이는 발판을 멈춥니다 (1 = 정상, -1 = 역방향)
main.setViewDistance(900) -- 한 사람에게 알려줄 거리. 0 이면 전부
setTile 은 지금 바꾸는 것처럼 보이지만 엔진이 0.2초 뒤로 예약합니다. 그 사이에
모든 클라이언트가 소식을 받으므로, 아무도 모르는 채로 그 틱을 굴린 적이 없고
따라서 되돌릴 것도 없습니다. 스크립트는 그 지연을 볼 일이 없습니다.
몸
local body = main.spawn({
-- 무엇으로 그려지는지. client/sprites/hero.json 입니다.
sprite = "hero",
halfWidth = 8, halfHeight = 14,
maxSpeed = 220, jumpHeight = 64,
wallJump = true, dash = true,
}, x, y)
main.setOwner(body, player.id) -- 이 사람의 입력이 이 몸을 움직입니다
main.setInput(body, { moveX = 1, jumpPressed = true }) -- 서버가 직접 모는 몸
local state = main.stateOf(body) -- 위치, 속도, 땅에 붙었는지
main.despawn(body)
주인이 없는 몸은 서버가 몹니다. 주인이 있는 몸은 그 사람의 입력 패킷이 움직이고, 그 사람의 클라이언트가 예측합니다.
main.bodyOf(player) -- 이 사람의 몸
main.bodyCount() -- 이 맵의 몸 수
main.playerCount() -- 이 맵의 사람 수
main.setCapacity(50) -- 이 맵에 들어올 수 있는 사람 수
main.tick() -- 이 맵이 지금까지 돈 틱
사람을 옮긴다
Chain2D.Map.move(player, "dungeon", x, y)
Chain2D.Map.of(player) -- 이 사람이 지금 어느 맵에 있는지
Chain2D.Map.stateOf(player) -- 그 몸의 상태
움직임 모듈
shared/motion.luau 를 두면 서버와 모든 클라이언트가 같은 파일을 돌립니다.
줄, 갈고리, 중력 반전처럼 기본 움직임에 없는 것을 여기에 쓰면, 클라이언트는
서버가 무엇을 할지 짐작하는 대신 같은 것을 실행합니다.
main.moduleStateOf(body) -- 모듈이 그 몸에 대해 들고 있는 값