优化结果
This commit is contained in:
424
InfoGenie-frontend/public/smallgame/2048/game-logic.js
Normal file
424
InfoGenie-frontend/public/smallgame/2048/game-logic.js
Normal file
@@ -0,0 +1,424 @@
|
||||
// 2048游戏核心逻辑
|
||||
class Game2048 {
|
||||
constructor() {
|
||||
this.size = 4;
|
||||
this.grid = [];
|
||||
this.score = 0;
|
||||
this.bestScore = parseInt(localStorage.getItem('2048-best-score')) || 0;
|
||||
this.gameWon = false;
|
||||
this.gameOver = false;
|
||||
this.moved = false;
|
||||
|
||||
// 游戏统计数据
|
||||
this.stats = {
|
||||
moves: 0,
|
||||
startTime: null,
|
||||
gameTime: 0,
|
||||
maxTile: 2,
|
||||
mergeCount: 0
|
||||
};
|
||||
|
||||
this.initializeGrid();
|
||||
this.updateDisplay();
|
||||
this.addRandomTile();
|
||||
this.addRandomTile();
|
||||
this.updateDisplay();
|
||||
|
||||
// 绑定事件
|
||||
this.bindEvents();
|
||||
|
||||
// 开始计时
|
||||
this.startTimer();
|
||||
}
|
||||
|
||||
initializeGrid() {
|
||||
this.grid = [];
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
this.grid[i] = [];
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
this.grid[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addRandomTile() {
|
||||
const emptyCells = [];
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
if (this.grid[i][j] === 0) {
|
||||
emptyCells.push({x: i, y: j});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (emptyCells.length > 0) {
|
||||
const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
|
||||
const value = Math.random() < 0.9 ? 2 : 4;
|
||||
this.grid[randomCell.x][randomCell.y] = value;
|
||||
|
||||
// 创建新方块动画
|
||||
this.createTileElement(randomCell.x, randomCell.y, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
createTileElement(x, y, value, isNew = false) {
|
||||
const container = document.getElementById('tile-container');
|
||||
const tile = document.createElement('div');
|
||||
tile.className = `tile tile-${value}`;
|
||||
if (isNew) tile.classList.add('tile-new');
|
||||
|
||||
tile.textContent = value;
|
||||
tile.style.left = `${y * (100/4)}%`;
|
||||
tile.style.top = `${x * (100/4)}%`;
|
||||
tile.dataset.x = x;
|
||||
tile.dataset.y = y;
|
||||
tile.dataset.value = value;
|
||||
|
||||
container.appendChild(tile);
|
||||
|
||||
// 移除动画类
|
||||
setTimeout(() => {
|
||||
tile.classList.remove('tile-new');
|
||||
}, 200);
|
||||
}
|
||||
|
||||
updateDisplay() {
|
||||
// 清除所有方块
|
||||
const container = document.getElementById('tile-container');
|
||||
container.innerHTML = '';
|
||||
|
||||
// 重新创建所有方块
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
if (this.grid[i][j] !== 0) {
|
||||
this.createTileElement(i, j, this.grid[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新分数
|
||||
document.getElementById('score').textContent = this.score;
|
||||
document.getElementById('best-score').textContent = this.bestScore;
|
||||
|
||||
// 更新统计数据显示
|
||||
if (window.gameStats) {
|
||||
window.gameStats.updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
move(direction) {
|
||||
if (this.gameOver) return;
|
||||
|
||||
this.moved = false;
|
||||
const previousGrid = this.grid.map(row => [...row]);
|
||||
|
||||
switch (direction) {
|
||||
case 'up':
|
||||
this.moveUp();
|
||||
break;
|
||||
case 'down':
|
||||
this.moveDown();
|
||||
break;
|
||||
case 'left':
|
||||
this.moveLeft();
|
||||
break;
|
||||
case 'right':
|
||||
this.moveRight();
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.moved) {
|
||||
this.stats.moves++;
|
||||
this.addRandomTile();
|
||||
this.updateDisplay();
|
||||
|
||||
if (this.isGameWon() && !this.gameWon) {
|
||||
this.gameWon = true;
|
||||
this.showGameWon();
|
||||
} else if (this.isGameOver()) {
|
||||
this.gameOver = true;
|
||||
this.showGameOver();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moveLeft() {
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
const row = this.grid[i].filter(val => val !== 0);
|
||||
const merged = [];
|
||||
|
||||
for (let j = 0; j < row.length - 1; j++) {
|
||||
if (row[j] === row[j + 1] && !merged[j] && !merged[j + 1]) {
|
||||
row[j] *= 2;
|
||||
this.score += row[j];
|
||||
this.stats.mergeCount++;
|
||||
this.stats.maxTile = Math.max(this.stats.maxTile, row[j]);
|
||||
row[j + 1] = 0;
|
||||
merged[j] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const newRow = row.filter(val => val !== 0);
|
||||
while (newRow.length < this.size) {
|
||||
newRow.push(0);
|
||||
}
|
||||
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
if (this.grid[i][j] !== newRow[j]) {
|
||||
this.moved = true;
|
||||
}
|
||||
this.grid[i][j] = newRow[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moveRight() {
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
const row = this.grid[i].filter(val => val !== 0);
|
||||
const merged = [];
|
||||
|
||||
for (let j = row.length - 1; j > 0; j--) {
|
||||
if (row[j] === row[j - 1] && !merged[j] && !merged[j - 1]) {
|
||||
row[j] *= 2;
|
||||
this.score += row[j];
|
||||
this.stats.mergeCount++;
|
||||
this.stats.maxTile = Math.max(this.stats.maxTile, row[j]);
|
||||
row[j - 1] = 0;
|
||||
merged[j] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const newRow = row.filter(val => val !== 0);
|
||||
while (newRow.length < this.size) {
|
||||
newRow.unshift(0);
|
||||
}
|
||||
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
if (this.grid[i][j] !== newRow[j]) {
|
||||
this.moved = true;
|
||||
}
|
||||
this.grid[i][j] = newRow[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moveUp() {
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
const column = [];
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
if (this.grid[i][j] !== 0) {
|
||||
column.push(this.grid[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
const merged = [];
|
||||
for (let i = 0; i < column.length - 1; i++) {
|
||||
if (column[i] === column[i + 1] && !merged[i] && !merged[i + 1]) {
|
||||
column[i] *= 2;
|
||||
this.score += column[i];
|
||||
this.stats.mergeCount++;
|
||||
this.stats.maxTile = Math.max(this.stats.maxTile, column[i]);
|
||||
column[i + 1] = 0;
|
||||
merged[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const newColumn = column.filter(val => val !== 0);
|
||||
while (newColumn.length < this.size) {
|
||||
newColumn.push(0);
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
if (this.grid[i][j] !== newColumn[i]) {
|
||||
this.moved = true;
|
||||
}
|
||||
this.grid[i][j] = newColumn[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moveDown() {
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
const column = [];
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
if (this.grid[i][j] !== 0) {
|
||||
column.push(this.grid[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
const merged = [];
|
||||
for (let i = column.length - 1; i > 0; i--) {
|
||||
if (column[i] === column[i - 1] && !merged[i] && !merged[i - 1]) {
|
||||
column[i] *= 2;
|
||||
this.score += column[i];
|
||||
this.stats.mergeCount++;
|
||||
this.stats.maxTile = Math.max(this.stats.maxTile, column[i]);
|
||||
column[i - 1] = 0;
|
||||
merged[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const newColumn = column.filter(val => val !== 0);
|
||||
while (newColumn.length < this.size) {
|
||||
newColumn.unshift(0);
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
if (this.grid[i][j] !== newColumn[i]) {
|
||||
this.moved = true;
|
||||
}
|
||||
this.grid[i][j] = newColumn[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isGameWon() {
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
if (this.grid[i][j] === 2048) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isGameOver() {
|
||||
// 检查是否有空格
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
if (this.grid[i][j] === 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否可以合并
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
const current = this.grid[i][j];
|
||||
if (
|
||||
(i > 0 && this.grid[i - 1][j] === current) ||
|
||||
(i < this.size - 1 && this.grid[i + 1][j] === current) ||
|
||||
(j > 0 && this.grid[i][j - 1] === current) ||
|
||||
(j < this.size - 1 && this.grid[i][j + 1] === current)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
showGameWon() {
|
||||
const message = document.getElementById('game-message');
|
||||
message.className = 'game-message game-won';
|
||||
message.style.display = 'flex';
|
||||
message.querySelector('p').textContent = '你赢了!';
|
||||
}
|
||||
|
||||
showGameOver() {
|
||||
const message = document.getElementById('game-message');
|
||||
message.className = 'game-message game-over';
|
||||
message.style.display = 'flex';
|
||||
message.querySelector('p').textContent = '游戏结束!';
|
||||
|
||||
// 显示最终统计
|
||||
setTimeout(() => {
|
||||
if (window.gameStats) {
|
||||
window.gameStats.showFinalStats();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
restart() {
|
||||
this.score = 0;
|
||||
this.gameWon = false;
|
||||
this.gameOver = false;
|
||||
this.moved = false;
|
||||
|
||||
// 重置统计数据
|
||||
this.stats = {
|
||||
moves: 0,
|
||||
startTime: null,
|
||||
gameTime: 0,
|
||||
maxTile: 2,
|
||||
mergeCount: 0
|
||||
};
|
||||
|
||||
this.initializeGrid();
|
||||
this.addRandomTile();
|
||||
this.addRandomTile();
|
||||
this.updateDisplay();
|
||||
|
||||
// 隐藏游戏消息
|
||||
document.getElementById('game-message').style.display = 'none';
|
||||
|
||||
// 重新开始计时
|
||||
this.startTimer();
|
||||
}
|
||||
|
||||
keepPlaying() {
|
||||
document.getElementById('game-message').style.display = 'none';
|
||||
}
|
||||
|
||||
startTimer() {
|
||||
this.stats.startTime = Date.now();
|
||||
|
||||
if (this.timerInterval) {
|
||||
clearInterval(this.timerInterval);
|
||||
}
|
||||
|
||||
this.timerInterval = setInterval(() => {
|
||||
if (!this.gameOver && this.stats.startTime) {
|
||||
this.stats.gameTime = Math.floor((Date.now() - this.stats.startTime) / 1000);
|
||||
if (window.gameStats) {
|
||||
window.gameStats.updateDisplay();
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
// 重新开始按钮
|
||||
document.getElementById('restart-btn').addEventListener('click', () => {
|
||||
this.restart();
|
||||
});
|
||||
|
||||
// 继续游戏按钮
|
||||
document.getElementById('keep-playing').addEventListener('click', () => {
|
||||
this.keepPlaying();
|
||||
});
|
||||
|
||||
// 重试按钮
|
||||
document.getElementById('retry-btn').addEventListener('click', () => {
|
||||
this.restart();
|
||||
});
|
||||
}
|
||||
|
||||
updateBestScore() {
|
||||
if (this.score > this.bestScore) {
|
||||
this.bestScore = this.score;
|
||||
localStorage.setItem('2048-best-score', this.bestScore.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 游戏实例
|
||||
let game;
|
||||
|
||||
// 页面加载完成后初始化游戏
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
game = new Game2048();
|
||||
|
||||
// 监听分数变化以更新最高分
|
||||
const originalUpdateDisplay = game.updateDisplay.bind(game);
|
||||
game.updateDisplay = function() {
|
||||
originalUpdateDisplay();
|
||||
this.updateBestScore();
|
||||
};
|
||||
|
||||
// 导出游戏实例供其他模块使用
|
||||
window.game2048 = game;
|
||||
});
|
||||
Reference in New Issue
Block a user