fix: 刺放置方向问题
This commit is contained in:
1 parent
6ba47dfd88
commit
bf0f065432
8 files changed
+580
-120
No files matched your search
+84
-9
@@ -32,21 +32,44 @@ const G = {
|
||||
state: 'menu', // menu | playing | paused | result | editor
|
||||
level: null, player: null, cam: null,
|
||||
data: null, idx: -1,
|
||||
map: null, face: 0, // 多面地图:map=各面 Level 数组,face=当前面下标
|
||||
deaths: 0, ms: 0, hudTick: 0,
|
||||
time: 0,
|
||||
lastLevelId: null,
|
||||
};
|
||||
|
||||
// ---------------- 关卡流程 ----------------
|
||||
// 把一张「面」的数据包装成 Level 可用的 data(门目标来自面自身的 doors)
|
||||
function faceData(map, face, i) {
|
||||
return {
|
||||
id: (map.id || 'map') + '-' + i,
|
||||
name: face.name || ('面' + (i + 1)),
|
||||
type: 'custom',
|
||||
width: face.width || (face.grid[0] ? face.grid[0].length : 25),
|
||||
grid: face.grid,
|
||||
doors: face.doors || [],
|
||||
bg: 'custom', hint: '', messages: [],
|
||||
};
|
||||
}
|
||||
|
||||
function startLevel(data, idx = -1) {
|
||||
unlockAudio();
|
||||
G.data = data; G.idx = idx; G.lastLevelId = data.id;
|
||||
G.level = new Level(data);
|
||||
// 自制多面地图:data.faces 存在则构建每面一个 Level;否则按传统单关处理
|
||||
if (data.faces && data.faces.length) {
|
||||
G.map = data.faces.map((f, i) => { const L = new Level(faceData(data, f, i)); L.faceIndex = i; return L; });
|
||||
G.face = Math.max(0, Math.min(data.startFace || 0, G.map.length - 1));
|
||||
} else {
|
||||
G.map = [new Level(data)]; G.face = 0;
|
||||
}
|
||||
G.level = G.map[G.face];
|
||||
G.player = new Player(G.level);
|
||||
G.cam = new Camera(W, H);
|
||||
G.cam.reset(G.level, G.player);
|
||||
G.player.onDeath = () => { G.deaths++; };
|
||||
G.player.onClear = () => finish();
|
||||
G.player.onPortal = (e) => doPortal(e);
|
||||
G.player.onRespawnFace = () => doRespawnFace();
|
||||
G.level.bosses.forEach(b => { b.onDefeat = () => finish(); });
|
||||
G.deaths = 0; G.ms = 0; G.hudTick = 0;
|
||||
G.state = 'playing';
|
||||
@@ -56,6 +79,53 @@ function startLevel(data, idx = -1) {
|
||||
if (data.hint) UI.toast(data.hint);
|
||||
}
|
||||
|
||||
// 把玩家放到某面某门上(不切面的同面传送也用)
|
||||
function placeOnDoor(dest) {
|
||||
const P = G.player;
|
||||
P.x = dest.x + dest.w / 2 - P.w / 2;
|
||||
P.y = dest.y + dest.h - P.h;
|
||||
P.vx = 0; P.vy = 0; P.jumps = 0;
|
||||
}
|
||||
|
||||
// 踩到门:e.to = {face, door}
|
||||
function doPortal(e) {
|
||||
const to = e.to;
|
||||
const tp = Math.max(0, Math.min(G.map.length - 1, to.face | 0));
|
||||
if (tp === G.face) {
|
||||
const dest = G.map[tp].entities.find(o => o.type === 'warp' && o.doorId === to.door);
|
||||
if (dest) { placeOnDoor(dest); dest.cool = 40; }
|
||||
sfx.warp();
|
||||
} else {
|
||||
switchFace(tp, to.door);
|
||||
}
|
||||
}
|
||||
|
||||
// 切换到第 f 面,并落到该面的目标门上
|
||||
function switchFace(f, doorId) {
|
||||
G.face = f;
|
||||
G.level = G.map[f];
|
||||
G.level.reset(true); // 进入该面时重置其运行时
|
||||
G.player.level = G.level;
|
||||
const dest = G.level.entities.find(o => o.type === 'warp' && o.doorId === doorId);
|
||||
if (dest) { placeOnDoor(dest); dest.cool = 40; }
|
||||
else { const sp = G.level.spawn; G.player.x = sp.x; G.player.y = sp.y; G.player.vx = 0; G.player.vy = 0; }
|
||||
G.cam.reset(G.level, G.player);
|
||||
sfx.warp();
|
||||
G.level.particles.spawn(G.player.cx, G.player.cy, 12, { colors: ['#a86bff', '#fff'], speed: 2.5, life: 24 });
|
||||
}
|
||||
|
||||
// 复活回到存档点所在面(跨面)
|
||||
function doRespawnFace() {
|
||||
const sp = G.player.savePoint;
|
||||
if (sp && typeof sp.face === 'number' && sp.face !== G.face) {
|
||||
G.face = sp.face;
|
||||
G.level = G.map[sp.face];
|
||||
G.level.reset(true);
|
||||
G.player.level = G.level;
|
||||
G.cam.reset(G.level, G.player);
|
||||
}
|
||||
}
|
||||
|
||||
/** 整关从头再来:保留死亡数,丢弃所有存档点进度 */
|
||||
function restart() {
|
||||
if (!G.data) return;
|
||||
@@ -103,26 +173,31 @@ function resume() { if (G.state === 'paused') { G.state = 'playing'; UI.showGame
|
||||
|
||||
// ---------------- 更新 ----------------
|
||||
function update() {
|
||||
const L = G.level, P = G.player;
|
||||
const P = G.player;
|
||||
// R = 自杀回存档点;Backspace = 整关重开
|
||||
if (Input.hit('suicide')) { suicide(); return; }
|
||||
if (Input.hit('restart')) { restart(); return; }
|
||||
if (Input.hit('pause')) { pause(); return; }
|
||||
|
||||
const wasDead = P.dead;
|
||||
L.update(1, P, G.cam);
|
||||
for (const b of L.bosses) b.update(1, P);
|
||||
G.level.update(1, P, G.cam);
|
||||
for (const b of G.level.bosses) b.update(1, P);
|
||||
P.update(1);
|
||||
// 刚从死亡中复活:镜头立刻对准重生点,别慢慢飘过去
|
||||
if (P.justRespawned || (wasDead && !P.dead)) G.cam.snapTo(P, L);
|
||||
P.justRespawned = false;
|
||||
G.cam.update(L, P, 1);
|
||||
// 刚从死亡中复活:若存档点在别的面,先切回该面,再镜头瞬移
|
||||
if (P.justRespawned) {
|
||||
if (P.savePoint && typeof P.savePoint.face === 'number' && P.savePoint.face !== G.face) doRespawnFace();
|
||||
G.cam.snapTo(P, G.level);
|
||||
P.justRespawned = false;
|
||||
}
|
||||
G.cam.update(G.level, P, 1);
|
||||
G.ms += STEP;
|
||||
G.time++;
|
||||
|
||||
if (++G.hudTick % 5 === 0) {
|
||||
const L = G.level;
|
||||
UI.hud({
|
||||
name: G.data.name, deaths: G.deaths, ms: G.ms,
|
||||
name: G.data.name + (G.map.length > 1 ? ` · 面${G.face + 1}/${G.map.length}` : ''),
|
||||
deaths: G.deaths, ms: G.ms,
|
||||
apples: P.apples, totalApples: L.totalApples, hasGun: P.hasGun,
|
||||
save: P.saveIdx || 0, totalSaves: L.totalSaves || 0,
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user