feat: 添加贪吃蛇和记忆配对纸牌游戏
- 贪吃蛇游戏: Canvas渲染、方向控制、碰撞检测、计分系统 - 记忆配对纸牌: 3D翻转动画、配对消除、计时器、胜利判定
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
class SnakeGame {
|
||||
constructor(canvasId, scoreId) {
|
||||
this.canvas = document.getElementById(canvasId);
|
||||
this.ctx = this.canvas.getContext('2d');
|
||||
this.scoreElement = document.getElementById(scoreId);
|
||||
|
||||
this.gridSize = 20;
|
||||
this.tileCount = this.canvas.width / this.gridSize;
|
||||
|
||||
this.reset();
|
||||
|
||||
window.addEventListener('keydown', this.handleKeyDown.bind(this));
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.snake = [
|
||||
{ x: 10, y: 10 },
|
||||
{ x: 10, y: 11 },
|
||||
{ x: 10, y: 12 }
|
||||
];
|
||||
this.food = this.getRandomFood();
|
||||
this.dx = 0;
|
||||
this.dy = -1;
|
||||
this.score = 0;
|
||||
this.updateScore();
|
||||
this.gameOver = false;
|
||||
}
|
||||
|
||||
getRandomFood() {
|
||||
let newFood;
|
||||
while (true) {
|
||||
newFood = {
|
||||
x: Math.floor(Math.random() * this.tileCount),
|
||||
y: Math.floor(Math.random() * this.tileCount)
|
||||
};
|
||||
// 确保食物不生成在蛇身上
|
||||
let collision = this.snake.some(segment => segment.x === newFood.x && segment.y === newFood.y);
|
||||
if (!collision) break;
|
||||
}
|
||||
return newFood;
|
||||
}
|
||||
|
||||
handleKeyDown(e) {
|
||||
switch (e.key) {
|
||||
case 'ArrowUp':
|
||||
if (this.dy === 0) { this.dx = 0; this.dy = -1; }
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
if (this.dy === 0) { this.dx = 0; this.dy = 1; }
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
if (this.dx === 0) { this.dx = -1; this.dy = 0; }
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
if (this.dx === 0) { this.dx = 1; this.dy = 0; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this.gameOver) return;
|
||||
|
||||
const head = { x: this.snake[0].x + this.dx, y: this.snake[0].y + this.dy };
|
||||
|
||||
// 碰撞墙壁检测
|
||||
if (head.x < 0 || head.x >= this.tileCount || head.y < 0 || head.y >= this.tileCount) {
|
||||
this.endGame();
|
||||
return;
|
||||
}
|
||||
|
||||
// 碰撞自身检测
|
||||
if (this.snake.some(segment => segment.x === head.x && segment.y === head.y)) {
|
||||
this.endGame();
|
||||
return;
|
||||
}
|
||||
|
||||
this.snake.unshift(head);
|
||||
|
||||
// 进食检测
|
||||
if (head.x === this.food.x && head.y === this.food.y) {
|
||||
this.score += 10;
|
||||
this.updateScore();
|
||||
this.food = this.getRandomFood();
|
||||
} else {
|
||||
this.snake.pop();
|
||||
}
|
||||
}
|
||||
|
||||
draw() {
|
||||
// 清屏
|
||||
this.ctx.fillStyle = '#1a1a1a';
|
||||
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
// 画网格背景 (可选)
|
||||
this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.03)';
|
||||
this.ctx.lineWidth = 1;
|
||||
for (let i = 0; i <= this.tileCount; i++) {
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(i * this.gridSize, 0);
|
||||
this.ctx.lineTo(i * this.gridSize, this.canvas.height);
|
||||
this.ctx.stroke();
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(0, i * this.gridSize);
|
||||
this.ctx.lineTo(this.canvas.width, i * this.gridSize);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
// 画食物
|
||||
const foodX = this.food.x * this.gridSize + this.gridSize / 2;
|
||||
const foodY = this.food.y * this.gridSize + this.gridSize / 2;
|
||||
const foodRadius = this.gridSize / 2 - 2;
|
||||
|
||||
const gradient = this.ctx.createRadialGradient(foodX, foodY, 2, foodX, foodY, foodRadius);
|
||||
gradient.addColorStop(0, '#ff7675');
|
||||
gradient.addColorStop(1, '#d63031');
|
||||
|
||||
this.ctx.fillStyle = gradient;
|
||||
this.ctx.shadowBlur = 15;
|
||||
this.ctx.shadowColor = '#d63031';
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(foodX, foodY, foodRadius, 0, Math.PI * 2);
|
||||
this.ctx.fill();
|
||||
this.ctx.shadowBlur = 0;
|
||||
|
||||
// 画蛇
|
||||
this.snake.forEach((segment, index) => {
|
||||
const isHead = index === 0;
|
||||
const x = segment.x * this.gridSize;
|
||||
const y = segment.y * this.gridSize;
|
||||
const size = this.gridSize - 2;
|
||||
const radius = isHead ? 8 : 4;
|
||||
|
||||
this.ctx.fillStyle = isHead ? '#55efc4' : '#00b894';
|
||||
|
||||
// 蛇头阴影
|
||||
if (isHead) {
|
||||
this.ctx.shadowBlur = 10;
|
||||
this.ctx.shadowColor = '#55efc4';
|
||||
}
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.roundRect(x + 1, y + 1, size, size, radius);
|
||||
this.ctx.fill();
|
||||
this.ctx.shadowBlur = 0;
|
||||
|
||||
// 眼睛
|
||||
if (isHead) {
|
||||
this.ctx.fillStyle = '#2d3436';
|
||||
const eyeSize = 3;
|
||||
const offset = 5;
|
||||
|
||||
// 根据方向画眼睛
|
||||
if (this.dy === -1) { // Up
|
||||
this.ctx.fillRect(x + offset, y + offset, eyeSize, eyeSize);
|
||||
this.ctx.fillRect(x + size - offset - eyeSize, y + offset, eyeSize, eyeSize);
|
||||
} else if (this.dy === 1) { // Down
|
||||
this.ctx.fillRect(x + offset, y + size - offset - eyeSize, eyeSize, eyeSize);
|
||||
this.ctx.fillRect(x + size - offset - eyeSize, y + size - offset - eyeSize, eyeSize, eyeSize);
|
||||
} else if (this.dx === -1) { // Left
|
||||
this.ctx.fillRect(x + offset, y + offset, eyeSize, eyeSize);
|
||||
this.ctx.fillRect(x + offset, y + size - offset - eyeSize, eyeSize, eyeSize);
|
||||
} else { // Right
|
||||
this.ctx.fillRect(x + size - offset - eyeSize, y + offset, eyeSize, eyeSize);
|
||||
this.ctx.fillRect(x + size - offset - eyeSize, y + size - offset - eyeSize, eyeSize, eyeSize);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (this.gameOver) {
|
||||
this.ctx.fillStyle = 'rgba(0, 0, 0, 0.75)';
|
||||
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
this.ctx.shadowBlur = 20;
|
||||
this.ctx.shadowColor = 'rgba(255, 255, 255, 0.5)';
|
||||
this.ctx.fillStyle = 'white';
|
||||
this.ctx.textAlign = 'center';
|
||||
this.ctx.font = 'bold 40px Segoe UI';
|
||||
this.ctx.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2);
|
||||
|
||||
this.ctx.font = '20px Segoe UI';
|
||||
this.ctx.fillStyle = '#bdc3c7';
|
||||
this.ctx.fillText('按空格重新开始', this.canvas.width / 2, this.canvas.height / 2 + 50);
|
||||
this.ctx.shadowBlur = 0;
|
||||
this.ctx.textAlign = 'start';
|
||||
}
|
||||
}
|
||||
|
||||
updateScore() {
|
||||
this.scoreElement.innerText = this.score;
|
||||
}
|
||||
|
||||
endGame() {
|
||||
this.gameOver = true;
|
||||
}
|
||||
|
||||
run() {
|
||||
this.update();
|
||||
this.draw();
|
||||
}
|
||||
}
|
||||
|
||||
const game = new SnakeGame('snakeGame', 'score');
|
||||
setInterval(() => game.run(), 100);
|
||||
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.code === 'Space' && game.gameOver) {
|
||||
game.reset();
|
||||
}
|
||||
});
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>贪吃蛇大作战</title>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
background: radial-gradient(circle, #2c3e50, #000);
|
||||
color: white;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
overflow: hidden;
|
||||
}
|
||||
#game-container {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 0 30px rgba(0, 0, 0, 0.5), inset 0 0 10px rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
canvas {
|
||||
border-radius: 8px;
|
||||
display: block;
|
||||
}
|
||||
#score-board {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
text-shadow: 0 0 10px rgba(0, 255, 0, 0.5);
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
#score {
|
||||
color: #2ecc71;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="score-board">分数: <span id="score">0</span></div>
|
||||
<div id="game-container">
|
||||
<canvas id="snakeGame" width="400" height="400"></canvas>
|
||||
</div>
|
||||
<script src="game.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>记忆配对纸牌</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 20px;
|
||||
text-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
|
||||
background: linear-gradient(90deg, #00ffff, #ff00ff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
#stats {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.stat {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
padding: 10px 25px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
.stat-value {
|
||||
color: #00ffcc;
|
||||
font-weight: bold;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
#game-board {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 100px);
|
||||
gap: 15px;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.card {
|
||||
width: 100px;
|
||||
height: 140px;
|
||||
position: relative;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.6s ease, opacity 0.5s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
.card.flipped {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
.card.matched {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transform: rotateY(180deg) scale(0.8);
|
||||
}
|
||||
.card-face {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
backface-visibility: hidden;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 3rem;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.card-back {
|
||||
background: linear-gradient(145deg, #e94560, #c23a51);
|
||||
border: 3px solid #ff6b6b;
|
||||
}
|
||||
.card-back::before {
|
||||
content: '?';
|
||||
font-size: 3rem;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
font-weight: bold;
|
||||
}
|
||||
.card-front {
|
||||
background: linear-gradient(145deg, #f8f9fa, #e9ecef);
|
||||
transform: rotateY(180deg);
|
||||
border: 3px solid #ddd;
|
||||
}
|
||||
.card:hover:not(.flipped):not(.matched) {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
#restart-btn {
|
||||
margin-top: 25px;
|
||||
padding: 15px 40px;
|
||||
font-size: 1.2rem;
|
||||
background: linear-gradient(90deg, #00b894, #00cec9);
|
||||
border: none;
|
||||
border-radius: 30px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(0, 206, 201, 0.4);
|
||||
}
|
||||
#restart-btn:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 20px rgba(0, 206, 201, 0.6);
|
||||
}
|
||||
#win-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
.modal-content {
|
||||
background: linear-gradient(145deg, #2d3436, #1e272e);
|
||||
padding: 50px;
|
||||
border-radius: 20px;
|
||||
text-align: center;
|
||||
box-shadow: 0 0 50px rgba(0, 255, 255, 0.3);
|
||||
border: 2px solid rgba(0, 255, 255, 0.3);
|
||||
}
|
||||
.modal-content h2 {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 20px;
|
||||
background: linear-gradient(90deg, #f1c40f, #e74c3c);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
.modal-content p {
|
||||
font-size: 1.3rem;
|
||||
margin-bottom: 30px;
|
||||
color: #bdc3c7;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>记忆配对纸牌</h1>
|
||||
<div id="stats">
|
||||
<div class="stat">步数: <span id="moves" class="stat-value">0</span></div>
|
||||
<div class="stat">时间: <span id="timer" class="stat-value">0:00</span></div>
|
||||
<div class="stat">配对: <span id="pairs" class="stat-value">0/8</span></div>
|
||||
</div>
|
||||
<div id="game-board"></div>
|
||||
<button id="restart-btn">重新开始</button>
|
||||
|
||||
<div id="win-modal">
|
||||
<div class="modal-content">
|
||||
<h2>🎉 恭喜胜利!</h2>
|
||||
<p>你用了 <span id="final-moves">0</span> 步,耗时 <span id="final-time">0:00</span></p>
|
||||
<button id="play-again-btn" style="padding: 15px 40px; font-size: 1.2rem; background: linear-gradient(90deg, #00b894, #00cec9); border: none; border-radius: 30px; color: white; cursor: pointer; font-weight: bold;">再来一局</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="memory.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,192 @@
|
||||
class MemoryGame {
|
||||
constructor() {
|
||||
this.symbols = ['🍎', '🍊', '🍋', '🍇', '🍓', '🍒', '🥝', '🍑'];
|
||||
this.cards = [];
|
||||
this.flippedCards = [];
|
||||
this.matchedPairs = 0;
|
||||
this.moves = 0;
|
||||
this.timer = null;
|
||||
this.seconds = 0;
|
||||
this.isLocked = false;
|
||||
this.gameStarted = false;
|
||||
|
||||
this.boardEl = document.getElementById('game-board');
|
||||
this.movesEl = document.getElementById('moves');
|
||||
this.timerEl = document.getElementById('timer');
|
||||
this.pairsEl = document.getElementById('pairs');
|
||||
this.winModal = document.getElementById('win-modal');
|
||||
this.finalMovesEl = document.getElementById('final-moves');
|
||||
this.finalTimeEl = document.getElementById('final-time');
|
||||
|
||||
document.getElementById('restart-btn').addEventListener('click', () => this.init());
|
||||
document.getElementById('play-again-btn').addEventListener('click', () => {
|
||||
this.winModal.style.display = 'none';
|
||||
this.init();
|
||||
});
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
// 重置状态
|
||||
this.cards = [];
|
||||
this.flippedCards = [];
|
||||
this.matchedPairs = 0;
|
||||
this.moves = 0;
|
||||
this.seconds = 0;
|
||||
this.isLocked = false;
|
||||
this.gameStarted = false;
|
||||
|
||||
// 清除计时器
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
|
||||
// 更新UI
|
||||
this.movesEl.textContent = '0';
|
||||
this.timerEl.textContent = '0:00';
|
||||
this.pairsEl.textContent = '0/8';
|
||||
|
||||
// 生成卡牌
|
||||
this.generateCards();
|
||||
this.renderBoard();
|
||||
}
|
||||
|
||||
generateCards() {
|
||||
// 创建配对卡牌
|
||||
const cardPairs = [...this.symbols, ...this.symbols];
|
||||
// 洗牌 (Fisher-Yates shuffle)
|
||||
for (let i = cardPairs.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[cardPairs[i], cardPairs[j]] = [cardPairs[j], cardPairs[i]];
|
||||
}
|
||||
this.cards = cardPairs.map((symbol, index) => ({
|
||||
id: index,
|
||||
symbol: symbol,
|
||||
isFlipped: false,
|
||||
isMatched: false
|
||||
}));
|
||||
}
|
||||
|
||||
renderBoard() {
|
||||
this.boardEl.innerHTML = '';
|
||||
this.cards.forEach(card => {
|
||||
const cardEl = document.createElement('div');
|
||||
cardEl.className = 'card';
|
||||
cardEl.dataset.id = card.id;
|
||||
cardEl.innerHTML = `
|
||||
<div class="card-face card-back"></div>
|
||||
<div class="card-face card-front">${card.symbol}</div>
|
||||
`;
|
||||
cardEl.addEventListener('click', () => this.flipCard(card.id));
|
||||
this.boardEl.appendChild(cardEl);
|
||||
});
|
||||
}
|
||||
|
||||
flipCard(id) {
|
||||
const card = this.cards[id];
|
||||
const cardEl = this.boardEl.querySelector(`[data-id="${id}"]`);
|
||||
|
||||
// 防止重复点击或锁定状态
|
||||
if (this.isLocked || card.isFlipped || card.isMatched) return;
|
||||
|
||||
// 开始计时
|
||||
if (!this.gameStarted) {
|
||||
this.gameStarted = true;
|
||||
this.startTimer();
|
||||
}
|
||||
|
||||
// 翻牌
|
||||
card.isFlipped = true;
|
||||
cardEl.classList.add('flipped');
|
||||
this.flippedCards.push(card);
|
||||
|
||||
// 检查是否翻了两张
|
||||
if (this.flippedCards.length === 2) {
|
||||
this.moves++;
|
||||
this.movesEl.textContent = this.moves;
|
||||
this.checkMatch();
|
||||
}
|
||||
}
|
||||
|
||||
checkMatch() {
|
||||
const [card1, card2] = this.flippedCards;
|
||||
|
||||
if (card1.symbol === card2.symbol) {
|
||||
// 配对成功
|
||||
this.matchSuccess(card1, card2);
|
||||
} else {
|
||||
// 配对失败
|
||||
this.matchFail(card1, card2);
|
||||
}
|
||||
}
|
||||
|
||||
matchSuccess(card1, card2) {
|
||||
card1.isMatched = true;
|
||||
card2.isMatched = true;
|
||||
this.matchedPairs++;
|
||||
this.pairsEl.textContent = `${this.matchedPairs}/8`;
|
||||
|
||||
const cardEl1 = this.boardEl.querySelector(`[data-id="${card1.id}"]`);
|
||||
const cardEl2 = this.boardEl.querySelector(`[data-id="${card2.id}"]`);
|
||||
|
||||
// 延迟消除动画
|
||||
setTimeout(() => {
|
||||
cardEl1.classList.add('matched');
|
||||
cardEl2.classList.add('matched');
|
||||
}, 500);
|
||||
|
||||
this.flippedCards = [];
|
||||
|
||||
// 检查胜利
|
||||
if (this.matchedPairs === 8) {
|
||||
this.win();
|
||||
}
|
||||
}
|
||||
|
||||
matchFail(card1, card2) {
|
||||
this.isLocked = true;
|
||||
|
||||
// 延迟翻回
|
||||
setTimeout(() => {
|
||||
card1.isFlipped = false;
|
||||
card2.isFlipped = false;
|
||||
|
||||
const cardEl1 = this.boardEl.querySelector(`[data-id="${card1.id}"]`);
|
||||
const cardEl2 = this.boardEl.querySelector(`[data-id="${card2.id}"]`);
|
||||
cardEl1.classList.remove('flipped');
|
||||
cardEl2.classList.remove('flipped');
|
||||
|
||||
this.flippedCards = [];
|
||||
this.isLocked = false;
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
startTimer() {
|
||||
this.timer = setInterval(() => {
|
||||
this.seconds++;
|
||||
const mins = Math.floor(this.seconds / 60);
|
||||
const secs = this.seconds % 60;
|
||||
this.timerEl.textContent = `${mins}:${secs.toString().padStart(2, '0')}`;
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
win() {
|
||||
clearInterval(this.timer);
|
||||
|
||||
const mins = Math.floor(this.seconds / 60);
|
||||
const secs = this.seconds % 60;
|
||||
const timeStr = `${mins}:${secs.toString().padStart(2, '0')}`;
|
||||
|
||||
this.finalMovesEl.textContent = this.moves;
|
||||
this.finalTimeEl.textContent = timeStr;
|
||||
|
||||
setTimeout(() => {
|
||||
this.winModal.style.display = 'flex';
|
||||
}, 800);
|
||||
}
|
||||
}
|
||||
|
||||
// 启动游戏
|
||||
new MemoryGame();
|
||||
Reference in New Issue
Block a user