feat(g20): клик по NPC через pick (как Тир ClickDetector)
Раньше: проверка дистанции до врага при ЛКМ через InputBegan
+ MouseButton1. Никак не работало из-за десятка причин.
Теперь как в Тире:
- BabylonScene._meshToTarget теперь возвращает {kind:'npc', id:N}
для меша с metadata.npcId.
- routeGlobalEvent('click', {target}) — этим уже шлёт в Lua-shim
с target.
- Shim добавлен __rbxl_npc_on_click(ref, fn) — регистрация callback'а.
В fireGlobalEvent при type='click'+target.kind='npc' резолвим
локальный ref и фейерим cb.
- В скрипте игры 20 регистрируем callback на каждого врага.
Клик ЛКМ по NPC (raycast попадает в мешa NPC) → callback → урон.
This commit is contained in:
parent
6aaab1a3f1
commit
9eebbd302e
@ -1763,30 +1763,21 @@ for i, e in ipairs(enemies) do
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Клик по сцене — бьём ближайшего врага в радиусе 4
|
-- Клик по конкретному NPC (как в Тире — pick по 3D-объекту).
|
||||||
UserInputService.InputBegan:Connect(function(input, gp)
|
-- BabylonScene выполняет raycast при ЛКМ и шлёт click с target=NPC.
|
||||||
if gp then return end
|
-- Регистрируем callback для каждого врага по его локальному ref.
|
||||||
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
|
for _, e in ipairs(enemies) do
|
||||||
if won then return end
|
local enemy = e -- замыкание
|
||||||
local px = __rbxl_player_x()
|
__rbxl_npc_on_click(enemy.ref, function()
|
||||||
local pz = __rbxl_player_z()
|
if enemy._dead or won then return end
|
||||||
for _, e in ipairs(enemies) do
|
enemy.hp = enemy.hp - 30
|
||||||
if not e._dead and e.hp > 0 then
|
if enemy.hp < 0 then enemy.hp = 0 end
|
||||||
local dx = e.x - px
|
__rbxl_npc_damage(enemy.ref, 30)
|
||||||
local dz = e.z - pz
|
__rbxl_set_label(enemy.ref, enemy.name .. " HP: " .. enemy.hp, "#ff5555", 3)
|
||||||
local dist = math.sqrt(dx*dx + dz*dz)
|
__rbxl_spawn_particles("sparks", enemy.x, 2, enemy.z, 0.4, 1)
|
||||||
if dist < 4 then
|
hitSound:Play()
|
||||||
e.hp = e.hp - 30
|
end)
|
||||||
if e.hp < 0 then e.hp = 0 end
|
end`,
|
||||||
__rbxl_npc_damage(e.ref, 30)
|
|
||||||
__rbxl_set_label(e.ref, e.name .. " HP: " .. e.hp, "#ff5555", 3)
|
|
||||||
__rbxl_spawn_particles("sparks", e.x, 2, e.z, 0.4, 1)
|
|
||||||
hitSound:Play()
|
|
||||||
break -- бьём только одного за клик
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)`,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════
|
||||||
|
|||||||
@ -3035,6 +3035,7 @@ export class BabylonScene {
|
|||||||
if (md.isBlock) {
|
if (md.isBlock) {
|
||||||
return { kind: 'block', ref: { x: md.gridX, y: md.gridY, z: md.gridZ } };
|
return { kind: 'block', ref: { x: md.gridX, y: md.gridY, z: md.gridZ } };
|
||||||
}
|
}
|
||||||
|
if (md.npcId != null) return { kind: 'npc', id: md.npcId };
|
||||||
if (md.isModel) return { kind: 'model', id: md.instanceId };
|
if (md.isModel) return { kind: 'model', id: md.instanceId };
|
||||||
if (md.isPrimitive) return { kind: 'primitive', id: md.primitiveId };
|
if (md.isPrimitive) return { kind: 'primitive', id: md.primitiveId };
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -1895,6 +1895,10 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
global.set('__rbxl_npc_on_death', (ref, fn) => {
|
global.set('__rbxl_npc_on_death', (ref, fn) => {
|
||||||
if (typeof fn === 'function') _npcDeathCbs.set(String(ref || ''), fn);
|
if (typeof fn === 'function') _npcDeathCbs.set(String(ref || ''), fn);
|
||||||
});
|
});
|
||||||
|
const _npcClickCbs = new Map(); // localRef → fn
|
||||||
|
global.set('__rbxl_npc_on_click', (ref, fn) => {
|
||||||
|
if (typeof fn === 'function') _npcClickCbs.set(String(ref || ''), fn);
|
||||||
|
});
|
||||||
// Инвентарь invUI — паритет с JS game.inventory.add(itemId, count).
|
// Инвентарь invUI — паритет с JS game.inventory.add(itemId, count).
|
||||||
// Сначала определяем итем (один раз), потом добавляем.
|
// Сначала определяем итем (один раз), потом добавляем.
|
||||||
const _localInventory = new Map();
|
const _localInventory = new Map();
|
||||||
@ -2302,6 +2306,20 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
try { equippedTool.Deactivated.Fire(); } catch (_) {}
|
try { equippedTool.Deactivated.Fire(); } catch (_) {}
|
||||||
}
|
}
|
||||||
// Mouse-события из плеера: клики, движение, клавиши при equipped Tool
|
// Mouse-события из плеера: клики, движение, клавиши при equipped Tool
|
||||||
|
// BabylonScene шлёт глобальный 'click' при ЛКМ. Если в payload
|
||||||
|
// target — это попадание по 3D-объекту. Для NPC фейерим cb.
|
||||||
|
if (p.type === 'click' && p.target && p.target.kind === 'npc' && p.target.id != null) {
|
||||||
|
const realRef = 'npc:' + p.target.id;
|
||||||
|
let localRef = null;
|
||||||
|
for (const [k, v] of _localToRealNpc.entries()) {
|
||||||
|
if (v === realRef) { localRef = k; break; }
|
||||||
|
}
|
||||||
|
for (const [ref, fn] of _npcClickCbs.entries()) {
|
||||||
|
if (ref === realRef || ref === localRef) {
|
||||||
|
_pendingHandlerQueue.push({ fn, args: [] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// BabylonScene шлёт глобальный 'click' при ЛКМ — это эквивалент
|
// BabylonScene шлёт глобальный 'click' при ЛКМ — это эквивалент
|
||||||
// mouseButton1Down. Мапим в наши handler-ы.
|
// mouseButton1Down. Мапим в наши handler-ы.
|
||||||
if (p.type === 'click' || p.type === 'mouseButton1Down') {
|
if (p.type === 'click' || p.type === 'mouseButton1Down') {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user