803 lines
18 KiB
JavaScript
803 lines
18 KiB
JavaScript
// pages/game/index.js - 游戏主逻辑(纯原生实现)
|
||
const app = getApp();
|
||
const audioManager = require('../../utils/AudioManager');
|
||
|
||
// 水果配置
|
||
const FRUIT_CONFIGS = [
|
||
{ level: 1, name: '果切丁', radius: 18, color: '#FF6B6B', score: 1 },
|
||
{ level: 2, name: '西瓜片', radius: 25, color: '#4ECDC4', score: 3 },
|
||
{ level: 3, name: '紫葡萄', radius: 32, color: '#9B59B6', score: 9 },
|
||
{ level: 4, name: '黄柠檬', radius: 40, color: '#F1C40F', score: 27 },
|
||
{ level: 5, name: '红苹果', radius: 48, color: '#E74C3C', score: 81 },
|
||
{ level: 6, name: '甜橙', radius: 56, color: '#F39C12', score: 243 },
|
||
{ level: 7, name: '粉桃子', radius: 64, color: '#FF69B4', score: 729 },
|
||
{ level: 8, name: '金菠萝', radius: 76, color: '#FFD700', score: 2187 },
|
||
{ level: 9, name: '报恩榴莲', radius: 90, color: '#FFA500', score: 6561 }
|
||
];
|
||
|
||
// 关卡配置
|
||
const LEVEL_CONFIGS = [
|
||
{ level: 1, bossName: '贪吃喵星人', targetLevel: 3, feedCount: 3, dropMin: 1, dropMax: 2 },
|
||
{ level: 2, bossName: '吃货柴犬', targetLevel: 4, feedCount: 4, dropMin: 1, dropMax: 3 },
|
||
{ level: 3, bossName: '美食家熊猫', targetLevel: 5, feedCount: 5, dropMin: 2, dropMax: 4 },
|
||
// ... 更多关卡可后续添加
|
||
];
|
||
|
||
Page({
|
||
data: {
|
||
currentLevel: 1,
|
||
score: 0,
|
||
combo: 0,
|
||
bossName: '',
|
||
fedCount: 0,
|
||
targetFeed: 0,
|
||
feedProgress: 0,
|
||
items: {
|
||
bomb: 3,
|
||
freeze: 2
|
||
},
|
||
showReviveBtn: false,
|
||
isPaused: false,
|
||
showResult: false,
|
||
isClear: false,
|
||
finalScore: 0,
|
||
finalCombo: 0,
|
||
finalTime: 0,
|
||
showGoldenEffect: false
|
||
},
|
||
|
||
// 游戏状态
|
||
gameState: {
|
||
fruits: [], // 场上的水果数组
|
||
nextFruitLevel: 1, // 下一个掉落的水果等级
|
||
fruitIdCounter: 0, // 水果ID计数器
|
||
dropCooldown: 0, // 掉落冷却时间
|
||
failTimer: 0, // 失败计时器
|
||
startTime: 0, // 游戏开始时间
|
||
sessionMaxCombo: 0, // 本局最高连击
|
||
mergeCore: null // 合成核心引擎
|
||
},
|
||
|
||
// Canvas 上下文
|
||
gameCanvas: null,
|
||
previewCanvas: null,
|
||
ctx: null,
|
||
previewCtx: null,
|
||
|
||
onLoad() {
|
||
// 初始化音频管理器
|
||
audioManager.init();
|
||
|
||
// 初始化游戏
|
||
this.initGame();
|
||
|
||
// 获取 Canvas 上下文
|
||
this.gameCanvas = wx.createCanvasContext('gameCanvas', this);
|
||
this.previewCanvas = wx.createCanvasContext('previewCanvas', this);
|
||
},
|
||
|
||
onReady() {
|
||
// 页面渲染完成后启动游戏循环
|
||
this.startGameLoop();
|
||
},
|
||
|
||
/**
|
||
* 初始化游戏
|
||
*/
|
||
initGame() {
|
||
const levelConfig = LEVEL_CONFIGS[this.data.currentLevel - 1] || LEVEL_CONFIGS[0];
|
||
|
||
this.setData({
|
||
bossName: levelConfig.bossName,
|
||
targetFeed: levelConfig.feedCount,
|
||
fedCount: 0,
|
||
feedProgress: 0
|
||
});
|
||
|
||
// 重置游戏状态
|
||
this.gameState = {
|
||
fruits: [],
|
||
nextFruitLevel: levelConfig.dropMin,
|
||
fruitIdCounter: 0,
|
||
dropCooldown: 0,
|
||
failTimer: 0,
|
||
startTime: Date.now(),
|
||
sessionMaxCombo: 0,
|
||
mergeCore: new MergeCore()
|
||
};
|
||
|
||
// 生成第一个预览水果
|
||
this.generateNextFruit();
|
||
|
||
// 更新预览
|
||
this.drawPreview();
|
||
|
||
// 播放背景音乐
|
||
this.playBGM();
|
||
},
|
||
|
||
/**
|
||
* 生成下一个水果
|
||
*/
|
||
generateNextFruit() {
|
||
const levelConfig = LEVEL_CONFIGS[this.data.currentLevel - 1] || LEVEL_CONFIGS[0];
|
||
const min = levelConfig.dropMin;
|
||
const max = levelConfig.dropMax;
|
||
this.gameState.nextFruitLevel = Math.floor(Math.random() * (max - min + 1)) + min;
|
||
this.drawPreview();
|
||
},
|
||
|
||
/**
|
||
* 绘制预览水果
|
||
*/
|
||
drawPreview() {
|
||
if (!this.previewCtx) return;
|
||
|
||
const config = FRUIT_CONFIGS[this.gameState.nextFruitLevel - 1];
|
||
const centerX = 30;
|
||
const centerY = 30;
|
||
const radius = Math.min(config.radius, 25); // 限制预览大小
|
||
|
||
// 清空画布
|
||
this.previewCtx.clearRect(0, 0, 60, 60);
|
||
|
||
// 绘制水果
|
||
this.previewCtx.beginPath();
|
||
this.previewCtx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
|
||
this.previewCtx.fillStyle = config.color;
|
||
this.previewCtx.fill();
|
||
|
||
// 绘制边框
|
||
this.previewCtx.strokeStyle = '#333';
|
||
this.previewCtx.lineWidth = 2;
|
||
this.previewCtx.stroke();
|
||
|
||
// 绘制等级
|
||
this.previewCtx.fillStyle = 'white';
|
||
this.previewCtx.font = 'bold 16px Arial';
|
||
this.previewCtx.textAlign = 'center';
|
||
this.previewCtx.textBaseline = 'middle';
|
||
this.previewCtx.fillText(config.level.toString(), centerX, centerY);
|
||
|
||
this.previewCtx.draw();
|
||
},
|
||
|
||
/**
|
||
* 触摸开始事件 - 掉落水果
|
||
*/
|
||
onTouchStart(e) {
|
||
if (this.data.isPaused) return;
|
||
if (this.gameState.dropCooldown > 0) return;
|
||
|
||
const touch = e.touches[0];
|
||
const x = touch.x;
|
||
|
||
// 限制在容器范围内
|
||
const clampedX = this.clampToContainer(x);
|
||
|
||
// 掉落水果
|
||
this.dropFruit(clampedX, this.gameState.nextFruitLevel);
|
||
|
||
// 设置冷却
|
||
this.gameState.dropCooldown = 300; // 300ms
|
||
|
||
// 生成下一个
|
||
this.generateNextFruit();
|
||
},
|
||
|
||
/**
|
||
* 掉落水果
|
||
*/
|
||
dropFruit(x, level) {
|
||
const config = FRUIT_CONFIGS[level - 1];
|
||
const fruitId = `fruit_${++this.gameState.fruitIdCounter}`;
|
||
|
||
// 创建水果对象
|
||
const fruit = {
|
||
id: fruitId,
|
||
level: level,
|
||
x: x,
|
||
y: 50, // 从顶部开始
|
||
vx: 0,
|
||
vy: 0,
|
||
radius: config.radius,
|
||
color: config.color,
|
||
score: config.score,
|
||
isMerging: false
|
||
};
|
||
|
||
this.gameState.fruits.push(fruit);
|
||
|
||
// 播放音效(可选)
|
||
this.playSound('drop');
|
||
},
|
||
|
||
/**
|
||
* 限制X坐标到容器内
|
||
*/
|
||
clampToContainer(x) {
|
||
const containerWidth = 360; // 容器宽度
|
||
const halfWidth = containerWidth / 2;
|
||
return Math.max(halfWidth - 20, Math.min(halfWidth + 20, x));
|
||
},
|
||
|
||
/**
|
||
* 游戏主循环
|
||
*/
|
||
startGameLoop() {
|
||
const loop = () => {
|
||
if (!this.data.isPaused) {
|
||
this.update();
|
||
this.render();
|
||
}
|
||
|
||
requestAnimationFrame(loop);
|
||
};
|
||
|
||
loop();
|
||
},
|
||
|
||
/**
|
||
* 更新游戏逻辑
|
||
*/
|
||
update() {
|
||
const dt = 16; // 假设60fps,每帧约16ms
|
||
|
||
// 更新掉落冷却
|
||
if (this.gameState.dropCooldown > 0) {
|
||
this.gameState.dropCooldown -= dt;
|
||
}
|
||
|
||
// 更新水果物理
|
||
this.updateFruits(dt);
|
||
|
||
// 检测合成
|
||
this.checkMerges();
|
||
|
||
// 检测失败条件
|
||
this.checkFailCondition(dt);
|
||
},
|
||
|
||
/**
|
||
* 更新水果物理
|
||
*/
|
||
updateFruits(dt) {
|
||
const gravity = 0.5;
|
||
const damping = 0.98;
|
||
const bounce = 0.3;
|
||
const groundY = 600; // 地面Y坐标
|
||
|
||
for (let i = this.gameState.fruits.length - 1; i >= 0; i--) {
|
||
const fruit = this.gameState.fruits[i];
|
||
|
||
if (fruit.isMerging) continue;
|
||
|
||
// 应用重力
|
||
fruit.vy += gravity;
|
||
|
||
// 更新位置
|
||
fruit.y += fruit.vy;
|
||
fruit.x += fruit.vx;
|
||
|
||
// 地面碰撞
|
||
if (fruit.y + fruit.radius > groundY) {
|
||
fruit.y = groundY - fruit.radius;
|
||
fruit.vy *= -bounce;
|
||
fruit.vx *= damping;
|
||
|
||
// 如果速度很小,停止弹跳
|
||
if (Math.abs(fruit.vy) < 1) {
|
||
fruit.vy = 0;
|
||
}
|
||
}
|
||
|
||
// 墙壁碰撞
|
||
if (fruit.x - fruit.radius < 0) {
|
||
fruit.x = fruit.radius;
|
||
fruit.vx *= -bounce;
|
||
} else if (fruit.x + fruit.radius > 360) {
|
||
fruit.x = 360 - fruit.radius;
|
||
fruit.vx *= -bounce;
|
||
}
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 检测并处理合成
|
||
*/
|
||
checkMerges() {
|
||
const fruits = this.gameState.fruits;
|
||
const merged = new Set();
|
||
|
||
for (let i = 0; i < fruits.length; i++) {
|
||
if (merged.has(i) || fruits[i].isMerging) continue;
|
||
|
||
for (let j = i + 1; j < fruits.length; j++) {
|
||
if (merged.has(j) || fruits[j].isMerging) continue;
|
||
|
||
const f1 = fruits[i];
|
||
const f2 = fruits[j];
|
||
|
||
// 检查是否相同等级且距离足够近
|
||
if (f1.level === f2.level && !f1.isMerging && !f2.isMerging) {
|
||
const dx = f1.x - f2.x;
|
||
const dy = f1.y - f2.y;
|
||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||
|
||
if (distance < f1.radius + f2.radius - 5) {
|
||
// 触发合成
|
||
this.mergeFruits(i, j);
|
||
merged.add(i);
|
||
merged.add(j);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 合并两个水果
|
||
*/
|
||
mergeFruits(index1, index2) {
|
||
const f1 = this.gameState.fruits[index1];
|
||
const f2 = this.gameState.fruits[index2];
|
||
|
||
// 计算新等级
|
||
const newLevel = f1.level + 1;
|
||
|
||
if (newLevel > 9) {
|
||
// 已经是最高级,不合成
|
||
return;
|
||
}
|
||
|
||
// 标记为正在合成
|
||
f1.isMerging = true;
|
||
f2.isMerging = true;
|
||
|
||
// 计算质心位置
|
||
const newX = (f1.x + f2.x) / 2;
|
||
const newY = (f1.y + f2.y) / 2;
|
||
|
||
// 移除旧水果
|
||
this.gameState.fruits = this.gameState.fruits.filter((f, idx) =>
|
||
idx !== index1 && idx !== index2
|
||
);
|
||
|
||
// 创建新水果
|
||
const config = FRUIT_CONFIGS[newLevel - 1];
|
||
const newFruit = {
|
||
id: `merged_${++this.gameState.fruitIdCounter}`,
|
||
level: newLevel,
|
||
x: newX,
|
||
y: newY,
|
||
vx: 0,
|
||
vy: -2, // 轻微向上弹起
|
||
radius: config.radius,
|
||
color: config.color,
|
||
score: config.score,
|
||
isMerging: false
|
||
};
|
||
|
||
this.gameState.fruits.push(newFruit);
|
||
|
||
// 更新分数
|
||
const addScore = f1.score + f2.score + config.score;
|
||
this.setData({
|
||
score: this.data.score + addScore
|
||
});
|
||
|
||
// 更新连击
|
||
const newCombo = this.gameState.mergeCore.incrementCombo();
|
||
this.setData({
|
||
combo: newCombo
|
||
});
|
||
|
||
if (newCombo > this.gameState.sessionMaxCombo) {
|
||
this.gameState.sessionMaxCombo = newCombo;
|
||
}
|
||
|
||
// 播放音效
|
||
this.playSound('merge');
|
||
|
||
// 检查是否为金色传说(合成出Lv9)
|
||
if (newLevel === 9) {
|
||
this.triggerGoldenLegend();
|
||
}
|
||
|
||
// 尝试投喂Boss
|
||
this.tryFeedBoss(newLevel);
|
||
},
|
||
|
||
/**
|
||
* 投喂Boss
|
||
*/
|
||
tryFeedBoss(fruitLevel) {
|
||
const levelConfig = LEVEL_CONFIGS[this.data.currentLevel - 1];
|
||
if (!levelConfig) return;
|
||
|
||
if (fruitLevel >= levelConfig.targetLevel) {
|
||
const newFedCount = this.data.fedCount + 1;
|
||
const progress = (newFedCount / levelConfig.feedCount) * 100;
|
||
|
||
this.setData({
|
||
fedCount: newFedCount,
|
||
feedProgress: progress
|
||
});
|
||
|
||
// 检查是否通关
|
||
if (newFedCount >= levelConfig.feedCount) {
|
||
this.handleLevelClear();
|
||
}
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 处理通关
|
||
*/
|
||
handleLevelClear() {
|
||
console.log('[Game] 通关!');
|
||
|
||
const elapsed = (Date.now() - this.gameState.startTime) / 1000;
|
||
|
||
this.setData({
|
||
isClear: true,
|
||
finalScore: this.data.score,
|
||
finalCombo: this.gameState.sessionMaxCombo,
|
||
finalTime: elapsed.toFixed(1),
|
||
showResult: true
|
||
});
|
||
|
||
// 保存进度
|
||
app.saveGameData();
|
||
|
||
// 播放通关音效
|
||
this.playSound('clear');
|
||
},
|
||
|
||
/**
|
||
* 触发金色传说特效
|
||
*/
|
||
triggerGoldenLegend() {
|
||
console.log('[Game] ✨ 金色传说!✨');
|
||
|
||
this.setData({
|
||
showGoldenEffect: true
|
||
});
|
||
|
||
// 播放金色传说音效
|
||
this.playSound('golden');
|
||
|
||
// 3秒后隐藏特效
|
||
setTimeout(() => {
|
||
this.setData({
|
||
showGoldenEffect: false
|
||
});
|
||
}, 3000);
|
||
},
|
||
|
||
/**
|
||
* 检测失败条件
|
||
*/
|
||
checkFailCondition(dt) {
|
||
const warningY = 150; // 警戒线Y坐标
|
||
let hasFruitAboveWarning = false;
|
||
|
||
for (const fruit of this.gameState.fruits) {
|
||
if (fruit.isMerging) continue;
|
||
|
||
if (fruit.y - fruit.radius < warningY) {
|
||
hasFruitAboveWarning = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (hasFruitAboveWarning) {
|
||
this.gameState.failTimer += dt;
|
||
if (this.gameState.failTimer >= 3000) { // 3秒后失败
|
||
this.handleGameOver();
|
||
}
|
||
} else {
|
||
this.gameState.failTimer = 0;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 处理游戏失败
|
||
*/
|
||
handleGameOver() {
|
||
console.log('[Game] 游戏失败');
|
||
|
||
const elapsed = (Date.now() - this.gameState.startTime) / 1000;
|
||
|
||
this.setData({
|
||
isClear: false,
|
||
finalScore: this.data.score,
|
||
finalCombo: this.gameState.sessionMaxCombo,
|
||
finalTime: elapsed.toFixed(1),
|
||
showResult: true,
|
||
showReviveBtn: true
|
||
});
|
||
|
||
// 播放失败音效
|
||
this.playSound('gameover');
|
||
},
|
||
|
||
/**
|
||
* 渲染游戏画面
|
||
*/
|
||
render() {
|
||
if (!this.gameCanvas) return;
|
||
|
||
const ctx = this.gameCanvas;
|
||
const width = 360;
|
||
const height = 600;
|
||
|
||
// 清空画布
|
||
ctx.clearRect(0, 0, width, height);
|
||
|
||
// 绘制背景
|
||
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
|
||
ctx.fillRect(0, 0, width, height);
|
||
|
||
// 绘制警戒线
|
||
ctx.strokeStyle = '#ff4444';
|
||
ctx.lineWidth = 3;
|
||
ctx.setLineDash([10, 5]);
|
||
ctx.beginPath();
|
||
ctx.moveTo(0, 150);
|
||
ctx.lineTo(width, 150);
|
||
ctx.stroke();
|
||
ctx.setLineDash([]);
|
||
|
||
// 绘制地面
|
||
ctx.strokeStyle = '#4CAF50';
|
||
ctx.lineWidth = 4;
|
||
ctx.beginPath();
|
||
ctx.moveTo(0, 600);
|
||
ctx.lineTo(width, 600);
|
||
ctx.stroke();
|
||
|
||
// 绘制所有水果
|
||
for (const fruit of this.gameState.fruits) {
|
||
if (fruit.isMerging) continue;
|
||
|
||
// 绘制水果圆形
|
||
ctx.beginPath();
|
||
ctx.arc(fruit.x, fruit.y, fruit.radius, 0, 2 * Math.PI);
|
||
ctx.fillStyle = fruit.color;
|
||
ctx.fill();
|
||
|
||
// 绘制边框
|
||
ctx.strokeStyle = '#333';
|
||
ctx.lineWidth = 2;
|
||
ctx.stroke();
|
||
|
||
// 绘制等级数字
|
||
ctx.fillStyle = 'white';
|
||
ctx.font = `bold ${Math.max(12, fruit.radius / 3)}px Arial`;
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'middle';
|
||
ctx.fillText(fruit.level.toString(), fruit.x, fruit.y);
|
||
}
|
||
|
||
ctx.draw();
|
||
},
|
||
|
||
/**
|
||
* 播放音效
|
||
*/
|
||
playSound(type) {
|
||
audioManager.playSFX(type);
|
||
},
|
||
|
||
/**
|
||
* 播放背景音乐
|
||
*/
|
||
playBGM() {
|
||
audioManager.playBGM('bgm_main');
|
||
},
|
||
|
||
/**
|
||
* 停止背景音乐
|
||
*/
|
||
stopBGM() {
|
||
audioManager.stopBGM();
|
||
},
|
||
|
||
/**
|
||
* 使用道具 - 炸弹
|
||
*/
|
||
useBomb() {
|
||
if (this.data.items.bomb <= 0) {
|
||
wx.showToast({
|
||
title: '炸弹不足',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 移除最低等级的水果
|
||
let lowestLevel = 999;
|
||
let lowestIndex = -1;
|
||
|
||
for (let i = 0; i < this.gameState.fruits.length; i++) {
|
||
if (this.gameState.fruits[i].level < lowestLevel && !this.gameState.fruits[i].isMerging) {
|
||
lowestLevel = this.gameState.fruits[i].level;
|
||
lowestIndex = i;
|
||
}
|
||
}
|
||
|
||
if (lowestIndex >= 0) {
|
||
this.gameState.fruits.splice(lowestIndex, 1);
|
||
|
||
this.setData({
|
||
'items.bomb': this.data.items.bomb - 1
|
||
});
|
||
|
||
wx.showToast({
|
||
title: '使用炸弹',
|
||
icon: 'success'
|
||
});
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 使用道具 - 冰冻
|
||
*/
|
||
useFreeze() {
|
||
if (this.data.items.freeze <= 0) {
|
||
wx.showToast({
|
||
title: '冰冻不足',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 暂停所有水果运动3秒
|
||
for (const fruit of this.gameState.fruits) {
|
||
fruit.vx = 0;
|
||
fruit.vy = 0;
|
||
}
|
||
|
||
this.setData({
|
||
'items.freeze': this.data.items.freeze - 1
|
||
});
|
||
|
||
wx.showToast({
|
||
title: '冰冻3秒',
|
||
icon: 'success'
|
||
});
|
||
|
||
setTimeout(() => {
|
||
// 恢复物理
|
||
}, 3000);
|
||
},
|
||
|
||
/**
|
||
* 看视频复活
|
||
*/
|
||
revive() {
|
||
app.showRewardedAd(() => {
|
||
// 奖励:移除最上层30%的水果
|
||
const fruits = this.gameState.fruits;
|
||
fruits.sort((a, b) => a.y - b.y);
|
||
const removeCount = Math.ceil(fruits.length * 0.3);
|
||
|
||
this.gameState.fruits.splice(0, removeCount);
|
||
|
||
this.setData({
|
||
showReviveBtn: false,
|
||
showResult: false
|
||
});
|
||
|
||
wx.showToast({
|
||
title: '复活成功',
|
||
icon: 'success'
|
||
});
|
||
}, (success) => {
|
||
if (!success) {
|
||
wx.showToast({
|
||
title: '广告未看完',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 下一关
|
||
*/
|
||
nextLevel() {
|
||
if (this.data.currentLevel < 20) {
|
||
this.setData({
|
||
currentLevel: this.data.currentLevel + 1,
|
||
showResult: false,
|
||
score: 0,
|
||
combo: 0
|
||
});
|
||
|
||
this.initGame();
|
||
} else {
|
||
wx.showToast({
|
||
title: '恭喜通关全部关卡!',
|
||
icon: 'success'
|
||
});
|
||
this.returnHome();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 重新开始
|
||
*/
|
||
restart() {
|
||
this.setData({
|
||
showResult: false,
|
||
score: 0,
|
||
combo: 0
|
||
});
|
||
|
||
this.initGame();
|
||
},
|
||
|
||
/**
|
||
* 返回主页
|
||
*/
|
||
returnHome() {
|
||
wx.navigateBack({
|
||
delta: 1
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 暂停/继续
|
||
*/
|
||
togglePause() {
|
||
const isPaused = !this.data.isPaused;
|
||
this.setData({
|
||
isPaused: isPaused
|
||
});
|
||
|
||
// 暂停时停止BGM,继续时恢复播放
|
||
if (isPaused) {
|
||
this.stopBGM();
|
||
} else {
|
||
this.playBGM();
|
||
}
|
||
},
|
||
|
||
onUnload() {
|
||
// 页面卸载时保存游戏数据并停止音频
|
||
app.saveGameData();
|
||
audioManager.destroy();
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 简单的合成核心引擎
|
||
*/
|
||
class MergeCore {
|
||
constructor() {
|
||
this.combo = 0;
|
||
this.lastMergeTime = 0;
|
||
}
|
||
|
||
incrementCombo() {
|
||
const now = Date.now();
|
||
if (now - this.lastMergeTime < 2000) {
|
||
// 2秒内连续合成,连击+1
|
||
this.combo++;
|
||
} else {
|
||
// 超过2秒,重置连击
|
||
this.combo = 1;
|
||
}
|
||
this.lastMergeTime = now;
|
||
return this.combo;
|
||
}
|
||
|
||
reset() {
|
||
this.combo = 0;
|
||
this.lastMergeTime = 0;
|
||
}
|
||
}
|