feat(lobby): LobbyNpc(근접·클릭 상호작용)·LobbyMobility(이동 해제) codeblock (P15)
LobbyNpc: 거리 폴링→머리위 마크 토글, TouchEvent/UpArrow→Interact→컨트롤러 OnLobbyNpcInteract. LobbyMobility: 진입 시 pc.Enable·WalkAcceleration=0.7 복원(정찰 확정). 공격 키는 컨트롤러에서 처리. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
92
tools/player/gen-lobby-npc.mjs
Normal file
92
tools/player/gen-lobby-npc.mjs
Normal file
@@ -0,0 +1,92 @@
|
||||
import { writeFileSync } from 'node:fs';
|
||||
|
||||
// 로비 codeblock 2종 emit (맵/엔티티 부착은 tools/map/gen-lobby-map.mjs 소관):
|
||||
// · LobbyNpc — NPC 엔티티에 부착. 근접 폴링→머리위 마크 토글, TouchEvent(클릭)/UpArrow(근접)→Interact→컨트롤러 호출.
|
||||
// · LobbyMobility — 로비 맵 루트에 부착. 진입 시 플레이어 이동 잠금 해제(정찰 확정: WalkAcceleration이 진짜 레버).
|
||||
// 공격 키(LeftControl) 바인딩은 SlayDeckController(/common, 1회 등록·로비 가드)에서 처리 — 여기 두지 않음.
|
||||
const WALK_ACCEL = 0.7; // 정찰: freeze가 0으로 만든 RigidbodyComponent.WalkAcceleration 복원값(이동·점프 정상 확인)
|
||||
const PROX = 1.2; // 근접 임계(맵 NPC 간격 2.5와 분리)
|
||||
|
||||
function prop(Type, Name, DefaultValue = 'nil') {
|
||||
return { Type, DefaultValue, SyncDirection: 0, Attributes: [], Name };
|
||||
}
|
||||
function method(Name, Code, Arguments = [], ExecSpace = 6) {
|
||||
return {
|
||||
Return: { Type: 'void', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: null },
|
||||
Arguments, Code, Scope: 2, ExecSpace, Attributes: [], Name,
|
||||
};
|
||||
}
|
||||
function writeCodeblock(name, properties, methods) {
|
||||
const cb = {
|
||||
Id: '', GameId: '', EntryKey: `codeblock://${name.toLowerCase()}`, ContentType: 'x-mod/codeblock',
|
||||
Content: '', Usage: 0, UsePublish: 1, UseService: 0, CoreVersion: '26.5.0.0', StudioVersion: '', DynamicLoading: 0,
|
||||
ContentProto: { Use: 'Json', Json: {
|
||||
CoreVersion: { Major: 0, Minor: 2 }, ScriptVersion: { Major: 1, Minor: 0 },
|
||||
Description: '', Id: name, Language: 1, Name: name, Type: 1, Source: 0, Target: null,
|
||||
Properties: properties, Methods: methods, EntityEventHandlers: [],
|
||||
} },
|
||||
};
|
||||
writeFileSync(`RootDesk/MyDesk/${name}.codeblock`, JSON.stringify(cb, null, 2) + '\n', 'utf8');
|
||||
}
|
||||
|
||||
// ── LobbyNpc ──────────────────────────────────────────────────────────────
|
||||
const npcInteract = method('Interact', `local c = _EntityService:GetEntityByPath("/common")
|
||||
if c ~= nil and c.SlayDeckController ~= nil then
|
||||
c.SlayDeckController:OnLobbyNpcInteract(self.NpcId)
|
||||
end`);
|
||||
|
||||
const npcBegin = method('OnBeginPlay', `self.InRange = false
|
||||
local mark = _EntityService:GetEntityByPath("/maps/lobby/" .. self.MarkName)
|
||||
if mark ~= nil then mark:SetVisible(false) end
|
||||
self.Entity:ConnectEvent(TouchEvent, function(e)
|
||||
self:Interact()
|
||||
end)
|
||||
_InputService:ConnectEvent(KeyDownEvent, function(e)
|
||||
if self.InRange and e.key == KeyboardKey.UpArrow then
|
||||
self:Interact()
|
||||
end
|
||||
end)
|
||||
local eventId = 0
|
||||
local function tick()
|
||||
local lp = _UserService.LocalPlayer
|
||||
if lp == nil then return end
|
||||
if mark == nil then mark = _EntityService:GetEntityByPath("/maps/lobby/" .. self.MarkName) end
|
||||
local a = lp.TransformComponent.WorldPosition
|
||||
local b = self.Entity.TransformComponent.WorldPosition
|
||||
local d = Vector2.Distance(Vector2(a.x, a.y), Vector2(b.x, b.y))
|
||||
local near = d < ${PROX}
|
||||
if near ~= self.InRange then
|
||||
self.InRange = near
|
||||
if mark ~= nil then mark:SetVisible(near) end
|
||||
end
|
||||
end
|
||||
eventId = _TimerService:SetTimerRepeat(tick, 0.15)`);
|
||||
|
||||
writeCodeblock('LobbyNpc', [
|
||||
prop('string', 'NpcId', '""'),
|
||||
prop('string', 'MarkName', '""'),
|
||||
prop('boolean', 'InRange', 'false'),
|
||||
], [npcBegin, npcInteract]);
|
||||
|
||||
// ── LobbyMobility ─────────────────────────────────────────────────────────
|
||||
const mobBegin = method('OnBeginPlay', `self.Tries = 0
|
||||
local eventId = 0
|
||||
local function apply()
|
||||
self.Tries = self.Tries + 1
|
||||
local lp = _UserService.LocalPlayer
|
||||
if lp ~= nil and lp.PlayerControllerComponent ~= nil then
|
||||
local pc = lp.PlayerControllerComponent
|
||||
pc.Enable = true
|
||||
pc.FixedLookAt = false
|
||||
local rb = lp.RigidbodyComponent
|
||||
if rb ~= nil then rb.WalkAcceleration = ${WALK_ACCEL} end
|
||||
_TimerService:ClearTimer(eventId)
|
||||
elseif self.Tries > 50 then
|
||||
_TimerService:ClearTimer(eventId)
|
||||
end
|
||||
end
|
||||
eventId = _TimerService:SetTimerRepeat(apply, 0.1)`);
|
||||
|
||||
writeCodeblock('LobbyMobility', [prop('number', 'Tries', '0')], [mobBegin]);
|
||||
|
||||
console.log('[gen-lobby-npc] LobbyNpc / LobbyMobility codeblock 생성 완료');
|
||||
Reference in New Issue
Block a user