70 lines
3.1 KiB
Plaintext
70 lines
3.1 KiB
Plaintext
*** Begin Patch ***
|
|||
|
|
--- index.html
|
||
|
|
+++ index.html
|
||
|
|
@@ ... @@
|
||
|
|
const MERGE_DELAY = 80; // 合成视觉延迟 ms(防同一帧连环合)
|
||
|
|
const COMBO_WINDOW = 800; // 连击窗口 ms
|
||
|
|
const NEW_BALL_IMMUNE = 100; // 新球合成免疫期 ms(仅防连环合)
|
||
|
|
+ const MIN_MOVE_THRESHOLD = 3; // 微动阈值:水平位移 < 3px 视为不动
|
||
|
|
const FIXED_STEP = 1000 / 60; // 物理步长 16.67ms
|
||
|
|
const OVER_LINE_GRACE = 700; // 超线宽限 ms
|
||
|
|
const WALL = 6; // 侧墙/地面厚度
|
||
|
|
@@ ... @@
|
||
|
|
// ---------- pointer 事件 ----------
|
||
|
|
canvas.addEventListener('pointerdown', function (e) {
|
||
|
|
if (state !== 'playing') return;
|
||
|
|
canvas.setPointerCapture(e.pointerId);
|
||
|
|
- heldX = toGameX(e.clientX);
|
||
|
|
+ heldX = lastPointerX = toGameX(e.clientX);
|
||
|
|
});
|
||
|
|
canvas.addEventListener('pointermove', function (e) {
|
||
|
|
if (state !== 'playing') return;
|
||
|
|
- heldX = toGameX(e.clientX);
|
||
|
|
+ const newX = toGameX(e.clientX);
|
||
|
|
+ if (Math.abs(newX - lastPointerX) >= MIN_MOVE_THRESHOLD) {
|
||
|
|
+ heldX = newX;
|
||
|
|
+ lastPointerX = newX;
|
||
|
|
+ }
|
||
|
|
});
|
||
|
|
canvas.addEventListener('pointerup', function (e) {
|
||
|
|
if (state !== 'playing') return;
|
||
|
|
@@ ... @@
|
||
|
|
let engine = null;
|
||
|
|
let balls = []; // { body, level, isRemoved, ... }
|
||
|
|
let pendingMerges = [];
|
||
|
|
+ let lastPointerX = -1; // 上次指针位置(防微动)
|
||
|
|
let particles = []; // 爆炸粒子
|
||
|
|
let rings = []; // 冲击环
|
||
|
|
let floaters = []; // 浮动得分文字
|
||
|
|
@@ ... @@
|
||
|
|
function startCelebration() {
|
||
|
|
const colors = ['#E53935', '#FB8C00', '#FDD835', '#43A047', '#1E88E5', '#8E24AA', '#D52B1E', '#1A3C6D', '#FFFFFF'];
|
||
|
|
for (let i = 0; i < 90; i++) {
|
||
|
|
confetti.push({
|
||
|
|
x: Math.random() * W,
|
||
|
|
y: -20 - Math.random() * 120,
|
||
|
|
vx: (Math.random() - 0.5) * 0.5,
|
||
|
|
vy: 0.4 + Math.random() * 1.2,
|
||
|
|
rot: Math.random() * Math.PI * 2,
|
||
|
|
vr: (Math.random() - 0.5) * 0.01,
|
||
|
|
w: 5 + Math.random() * 6,
|
||
|
|
h: 8 + Math.random() * 6,
|
||
|
|
color: colors[i % colors.length],
|
||
|
|
life: 0, maxLife: 2600 + Math.random() * 1200,
|
||
|
|
phase: Math.random() * Math.PI * 2
|
||
|
|
});
|
||
|
|
}
|
||
|
|
+ // 通关动画:大红字渐显
|
||
|
|
+ var titleEl = document.createElement('div');
|
||
|
|
+ titleEl.id = 'passTitle';
|
||
|
|
+ titleEl.textContent = '通关!上海交通大学';
|
||
|
|
+ titleEl.style.cssText = 'position:fixed;top:34%;left:0;width:100%;text-align:center;font:bold 30px "Microsoft YaHei",sans-serif;color:#D52B1E;text-shadow:0 0 20px rgba(255,215,0,0.8),0 0 40px rgba(255,215,0,0.6);opacity:0;transition:opacity 1s ease;pointer-events:none;z-index:1000';
|
||
|
|
+ document.body.appendChild(titleEl);
|
||
|
|
+ requestAnimationFrame(function(){ titleEl.style.opacity = '1'; });
|
||
|
|
+ setTimeout(function(){
|
||
|
|
+ titleEl.style.transition = 'opacity 1.5s ease';
|
||
|
|
+ titleEl.style.opacity = '0';
|
||
|
|
+ setTimeout(function(){ if(titleEl.parentNode) titleEl.parentNode.removeChild(titleEl); }, 1500);
|
||
|
|
+ }, 6000);
|
||
|
|
}
|
||
|
|
*** End Patch ***
|