feat(rogue-map): 로그라이크 절차 생성 맵·층 시스템·유물 방 (배포 퀄리티 P8) #41
File diff suppressed because one or more lines are too long
@@ -1454,23 +1454,28 @@ function upsertUi() {
|
|||||||
text({ value: '다음 노드 선택', fontSize: 40, bold: true, color: GOLD, alignment: 4 }),
|
text({ value: '다음 노드 선택', fontSize: 40, bold: true, color: GOLD, alignment: 4 }),
|
||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
|
// 절차 생성 맵용 정적 그리드 — 노드 7행×4열 + 보스, 점선 도트. RenderMap이 런타임 토글.
|
||||||
|
const nodeX = (c) => -270 + (c - 1) * 180;
|
||||||
|
const nodeY = (r) => -330 + (r - 1) * 105;
|
||||||
|
const BOSS_POS = { x: 0, y: 405 };
|
||||||
let mapN = 2;
|
let mapN = 2;
|
||||||
for (const [id, node] of Object.entries(MAP.nodes)) {
|
const pushMapNode = (id, pos, size, label) => {
|
||||||
const nodePath = `/ui/DefaultGroup/MapHud/Node_${id}`;
|
const nodePath = `/ui/DefaultGroup/MapHud/Node_${id}`;
|
||||||
const pos = { x: node.col * 180, y: (node.row - (MAX_ROW + 1) / 2) * 140 };
|
const nodeEnt = entity({
|
||||||
map.push(entity({
|
|
||||||
id: guid('map', mapN++),
|
id: guid('map', mapN++),
|
||||||
path: nodePath,
|
path: nodePath,
|
||||||
modelId: 'uisprite',
|
modelId: 'uisprite',
|
||||||
entryId: 'UISprite',
|
entryId: 'UISprite',
|
||||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.ButtonComponent',
|
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.ButtonComponent',
|
||||||
displayOrder: node.row,
|
displayOrder: 5,
|
||||||
components: [
|
components: [
|
||||||
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 150, y: 80 }, pos }),
|
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size, pos }),
|
||||||
sprite({ color: { r: 0.3, g: 0.55, b: 0.85, a: 1 }, type: 1, raycast: true }),
|
sprite({ color: { r: 0.2, g: 0.22, b: 0.26, a: 1 }, type: 1, raycast: true }),
|
||||||
button(),
|
button(),
|
||||||
],
|
],
|
||||||
}));
|
});
|
||||||
|
nodeEnt.jsonString.enable = false;
|
||||||
|
map.push(nodeEnt);
|
||||||
map.push(entity({
|
map.push(entity({
|
||||||
id: guid('map', mapN++),
|
id: guid('map', mapN++),
|
||||||
path: `${nodePath}/Label`,
|
path: `${nodePath}/Label`,
|
||||||
@@ -1479,11 +1484,47 @@ function upsertUi() {
|
|||||||
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent',
|
||||||
displayOrder: 0,
|
displayOrder: 0,
|
||||||
components: [
|
components: [
|
||||||
transform({ parentW: 150, parentH: 80, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 144, y: 72 }, pos: { x: 0, y: 0 } }),
|
transform({ parentW: size.x, parentH: size.y, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: size.x + 20, y: 30 }, pos: { x: 0, y: 0 } }),
|
||||||
sprite({ color: TRANSPARENT }),
|
sprite({ color: TRANSPARENT }),
|
||||||
text({ value: node.enemy ? `${TYPE_KO[node.type]}\n${ENEMIES.enemies[node.enemy].name}` : TYPE_KO[node.type], fontSize: 20, bold: true }),
|
text({ value: label, fontSize: id === 'boss' ? 18 : 15, bold: true, color: { r: 1, g: 1, b: 1, a: 1 }, alignment: 4 }),
|
||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
|
};
|
||||||
|
for (let r = 1; r <= MAP_ROWS; r++) {
|
||||||
|
for (let c = 1; c <= MAP_COLS; c++) {
|
||||||
|
pushMapNode(`r${r}c${c}`, { x: nodeX(c), y: nodeY(r) }, { x: 56, y: 56 }, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushMapNode('boss', BOSS_POS, { x: 72, y: 72 }, '보스');
|
||||||
|
const pushDots = (dotId, from, to) => {
|
||||||
|
for (let k = 1; k <= 3; k++) {
|
||||||
|
const t = k / 4;
|
||||||
|
const dot = entity({
|
||||||
|
id: guid('map', mapN++),
|
||||||
|
path: `/ui/DefaultGroup/MapHud/Dot_${dotId}_${k}`,
|
||||||
|
modelId: 'uisprite',
|
||||||
|
entryId: 'UISprite',
|
||||||
|
componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent',
|
||||||
|
displayOrder: 1,
|
||||||
|
components: [
|
||||||
|
transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 8, y: 8 }, pos: { x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t } }),
|
||||||
|
sprite({ color: { r: 0.5, g: 0.5, b: 0.55, a: 0.8 }, type: 1 }),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
dot.jsonString.enable = false;
|
||||||
|
map.push(dot);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (let r = 1; r < MAP_ROWS; r++) {
|
||||||
|
for (let c = 1; c <= MAP_COLS; c++) {
|
||||||
|
for (let c2 = c - 1; c2 <= c + 1; c2++) {
|
||||||
|
if (c2 < 1 || c2 > MAP_COLS) continue;
|
||||||
|
pushDots(`r${r}c${c}_${c2}`, { x: nodeX(c), y: nodeY(r) }, { x: nodeX(c2), y: nodeY(r + 1) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let c = 1; c <= MAP_COLS; c++) {
|
||||||
|
pushDots(`r${MAP_ROWS}c${c}_b`, { x: nodeX(c), y: nodeY(MAP_ROWS) }, BOSS_POS);
|
||||||
}
|
}
|
||||||
emit('MapHud', map);
|
emit('MapHud', map);
|
||||||
|
|
||||||
@@ -3570,22 +3611,114 @@ for i = 1, #list do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'id' }], 0, 'boolean'),
|
return false`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'id' }], 0, 'boolean'),
|
||||||
method('RenderMap', `for id, node in pairs(self.MapNodes) do
|
method('RenderMapNode', `local base = "/ui/DefaultGroup/MapHud/Node_" .. id
|
||||||
local e = _EntityService:GetEntityByPath("/ui/DefaultGroup/MapHud/Node_" .. id)
|
local e = _EntityService:GetEntityByPath(base)
|
||||||
if e ~= nil then
|
if e == nil then
|
||||||
local reachable = self:IsReachable(id)
|
return
|
||||||
if e.SpriteGUIRendererComponent ~= nil then
|
end
|
||||||
if reachable then
|
local node = self.MapNodes[id]
|
||||||
e.SpriteGUIRendererComponent.Color = Color(0.3, 0.55, 0.85, 1)
|
if node == nil then
|
||||||
|
e.Enable = false
|
||||||
|
return
|
||||||
|
end
|
||||||
|
e.Enable = true
|
||||||
|
local tname = "전투"
|
||||||
|
local r0 = 0.78
|
||||||
|
local g0 = 0.36
|
||||||
|
local b0 = 0.32
|
||||||
|
if node.type == "elite" then
|
||||||
|
tname = "엘리트"
|
||||||
|
r0 = 0.62
|
||||||
|
g0 = 0.4
|
||||||
|
b0 = 0.85
|
||||||
|
elseif node.type == "shop" then
|
||||||
|
tname = "상점"
|
||||||
|
r0 = 0.9
|
||||||
|
g0 = 0.75
|
||||||
|
b0 = 0.35
|
||||||
|
elseif node.type == "rest" then
|
||||||
|
tname = "휴식"
|
||||||
|
r0 = 0.4
|
||||||
|
g0 = 0.75
|
||||||
|
b0 = 0.45
|
||||||
|
elseif node.type == "treasure" then
|
||||||
|
tname = "보물"
|
||||||
|
r0 = 0.35
|
||||||
|
g0 = 0.7
|
||||||
|
b0 = 0.75
|
||||||
|
elseif node.type == "boss" then
|
||||||
|
tname = "보스"
|
||||||
|
r0 = 0.85
|
||||||
|
g0 = 0.25
|
||||||
|
b0 = 0.25
|
||||||
|
end
|
||||||
|
self:SetText(base .. "/Label", tname)
|
||||||
|
local reachable = self:IsReachable(id)
|
||||||
|
local visited = false
|
||||||
|
if self.VisitedNodes ~= nil then
|
||||||
|
for i = 1, #self.VisitedNodes do
|
||||||
|
if self.VisitedNodes[i] == id then visited = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if e.SpriteGUIRendererComponent ~= nil then
|
||||||
|
if id == self.CurrentNodeId then
|
||||||
|
e.SpriteGUIRendererComponent.Color = Color(0.95, 0.8, 0.3, 1)
|
||||||
|
elseif visited == true then
|
||||||
|
e.SpriteGUIRendererComponent.Color = Color(0.18, 0.19, 0.22, 0.9)
|
||||||
|
elseif reachable == true then
|
||||||
|
e.SpriteGUIRendererComponent.Color = Color(r0, g0, b0, 1)
|
||||||
|
else
|
||||||
|
e.SpriteGUIRendererComponent.Color = Color(r0 * 0.45, g0 * 0.45, b0 * 0.45, 0.55)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if e.ButtonComponent ~= nil then
|
||||||
|
e.ButtonComponent.Enable = reachable
|
||||||
|
end`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'id' }]),
|
||||||
|
method('RenderMapDots', `local node = self.MapNodes[fromId]
|
||||||
|
local has = false
|
||||||
|
if node ~= nil then
|
||||||
|
for i = 1, #node.next do
|
||||||
|
if node.next[i] == toId then has = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for k = 1, 3 do
|
||||||
|
local d = _EntityService:GetEntityByPath("/ui/DefaultGroup/MapHud/Dot_" .. dotId .. "_" .. tostring(k))
|
||||||
|
if d ~= nil then
|
||||||
|
d.Enable = has
|
||||||
|
if has == true and d.SpriteGUIRendererComponent ~= nil then
|
||||||
|
if fromId == self.CurrentNodeId then
|
||||||
|
d.SpriteGUIRendererComponent.Color = Color(0.95, 0.8, 0.3, 1)
|
||||||
else
|
else
|
||||||
e.SpriteGUIRendererComponent.Color = Color(0.2, 0.22, 0.26, 0.6)
|
d.SpriteGUIRendererComponent.Color = Color(0.5, 0.5, 0.55, 0.8)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if e.ButtonComponent ~= nil then
|
end
|
||||||
e.ButtonComponent.Enable = reachable
|
end`, [
|
||||||
|
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'dotId' },
|
||||||
|
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'fromId' },
|
||||||
|
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'toId' },
|
||||||
|
]),
|
||||||
|
method('RenderMap', `for r = 1, ${MAP_ROWS} do
|
||||||
|
for c = 1, ${MAP_COLS} do
|
||||||
|
self:RenderMapNode("r" .. tostring(r) .. "c" .. tostring(c))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:RenderMapNode("boss")
|
||||||
|
for r = 1, ${MAP_ROWS} - 1 do
|
||||||
|
for c = 1, ${MAP_COLS} do
|
||||||
|
local fid = "r" .. tostring(r) .. "c" .. tostring(c)
|
||||||
|
for c2 = c - 1, c + 1 do
|
||||||
|
if c2 >= 1 and c2 <= ${MAP_COLS} then
|
||||||
|
self:RenderMapDots(fid .. "_" .. tostring(c2), fid, "r" .. tostring(r + 1) .. "c" .. tostring(c2))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end`),
|
end
|
||||||
|
for c = 1, ${MAP_COLS} do
|
||||||
|
local fid = "r" .. tostring(${MAP_ROWS}) .. "c" .. tostring(c)
|
||||||
|
self:RenderMapDots(fid .. "_b", fid, "boss")
|
||||||
|
end
|
||||||
|
`),
|
||||||
method('PickNode', `if self.RunActive ~= true then
|
method('PickNode', `if self.RunActive ~= true then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
35750
ui/DefaultGroup.ui
35750
ui/DefaultGroup.ui
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user