前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎 点赞 + 收藏 + 关注 哦 💕
(文后附完整代码)html+css+javascript 五子棋项目分析报告
📚 效果展示

📚 本文简介
本文介绍了一个使用HTML、CSS和JavaScript实现的五子棋游戏项目。该项目采用纯原生技术实现,包含15×15标准棋盘、三级AI难度、音效系统和现代化视觉效果。文章详细分析了项目的技术架构、核心功能模块、HTML结构、CSS样式设计以及JavaScript游戏逻辑实现。重点讲解了胜负判定算法、AI系统设计、Web Audio API音效实现等关键技术点。项目具有模块化设计、响应式布局、丰富的交互体验等特点,并提供了完整的代码实现。同时,文章还总结了项目的技术亮点,并提出了改进建议,如优化AI算法、增加多人模式等。该五子棋游戏是一个优秀的前端学习案例,展示了原生JavaScript开发复杂游戏的能力。
目录
- (文后附完整代码)html+css+javascript 五子棋项目分析报告
-
- 📚 效果展示
- 📚 本文简介
- 📚 一、项目架构概述
-
- 📘 1.1 项目文件结构
- 📘 1.2 技术栈分析
- 📘 1.3 核心功能模块
- 📚 二、HTML结构分析:语义化与模块化的界面搭建
-
- 📘 2.1 整体布局设计
- 📘 2.2 关键元素解析
-
- 📖 2.2.1 游戏容器设计
- 📖 2.2.2 棋盘结构
- 📖 2.2.3 游戏信息区
- 📖 2.2.4 控制面板
- 📚 三、CSS样式设计:现代化视觉效果与交互体验
-
- 📘 3.1 整体视觉风格
- 📘 3.2 关键样式解析
-
- 📖 3.2.1 响应式布局
- 📖 3.2.2 棋盘样式
- 📖 3.2.3 棋子样式
- 📖 3.2.4 动画效果
- 📘 3.3 视觉反馈设计
- 📚 四、JavaScript核心逻辑:游戏引擎与AI实现
-
- 📘 4.1 游戏状态管理
- 📘 4.2 棋盘初始化与管理
-
- 📖 4.2.1 棋盘创建
- 📖 4.2.2 落子处理
- 📘 4.3 胜负判定系统
-
- 📖 4.3.1 核心算法
- 📖 4.3.2 位置验证
- 📘 4.4 AI系统设计
-
- 📖 4.4.1 难度等级
- 📖 4.4.2 困难AI实现
- 📘 4.5 音效与特效系统
-
- 📖 4.5.1 音效实现
- 📖 4.5.2 视觉特效
- 📘 4.6 背景音乐系统
-
- 📖 4.6.1 音乐生成
- 📖 4.6.2 音乐控制
- 📚 五、技术特点与创新点
-
- 📘 5.1 技术亮点
- 📘 5.2 游戏体验优化
- 📘 5.3 代码质量分析
- 📚 六、总结与建议
-
- 📘 6.1 项目价值
- 📘 6.2 改进建议
- 📘 6.3 技术拓展可能
- 📚 七、结论
- 📚 完整代码(可直接使用)
-
- 📘 项目目录
- 📘 项目代码
-
- 📖 html代码
- 📖 javascript代码
———— ⬇️·`正文开始`·⬇️————
📚 一、项目架构概述
📘 1.1 项目文件结构
项目采用简洁的文件组织结构,仅包含两个核心文件:
- index.html:主页面文件,包含游戏的完整HTML结构、CSS样式和JavaScript逻辑
- backgroundMusic.js:背景音乐模块,负责生成和管理游戏背景音乐
📘 1.2 技术栈分析
- 前端技术:纯HTML5 + CSS3 + JavaScript
- 音频处理:Web Audio API
- 布局技术:Flexbox布局
- 交互方式:DOM事件监听
- 动画效果:CSS3动画
📘 1.3 核心功能模块
📚 二、HTML结构分析:语义化与模块化的界面搭建
📘 2.1 整体布局设计
项目采用响应式居中布局,通过Flexbox实现页面元素的垂直和水平居中。整体结构分为三个主要部分:
- 游戏标题:位于页面顶部,显示游戏名称
- 游戏信息区:包含玩家信息和难度选择
- 棋盘区域:核心游戏区域
- 控制区域:包含重新开始和音效控制按钮
📘 2.2 关键元素解析
📖 2.2.1 游戏容器设计
使用.game-container作为主容器,采用半透明背景和阴影效果,营造出层次感和现代感。
📖 2.2.2 棋盘结构
棋盘采用动态生成的方式,通过JavaScript在#board容器中创建15×15的单元格网格。每个单元格使用.cell类,通过data-row和data-col属性存储坐标信息。
📖 2.2.3 游戏信息区
包含玩家状态显示和难度选择按钮,通过.player-info类标记玩家状态,.current-player类高亮当前回合的玩家。
📖 2.2.4 控制面板
提供游戏控制功能,包括重新开始和音效开关按钮,使用语义化的按钮元素和图标增强用户体验。
📚 三、CSS样式设计:现代化视觉效果与交互体验
📘 3.1 整体视觉风格
采用现代简约风格,结合渐变背景、半透明效果和阴影,营造出层次感和深度。色彩方案以绿色为主色调,象征胜利和活力,搭配中性色增强可读性。
📘 3.2 关键样式解析
📖 3.2.1 响应式布局
使用Flexbox实现页面元素的灵活布局,确保游戏在不同设备上都能良好显示。通过min-height: 100vh确保游戏容器始终居中显示。
📖 3.2.2 棋盘样式
棋盘采用木质纹理风格,通过#board的背景色和边框模拟真实棋盘效果。单元格使用border属性创建网格线,hover效果提供视觉反馈。
📖 3.2.3 棋子样式
通过CSS伪元素实现棋子效果:
- 黑棋:使用●字符和黑色
- 白棋:使用○字符和白色,配合阴影增强立体感
📖 3.2.4 动画效果
- 落子特效:使用CSS3动画实现棋子放置时的粒子效果
- 胜利消息:实现淡入放大效果
- 按钮交互:添加悬停和点击时的缩放和阴影变化
📘 3.3 视觉反馈设计
- 悬停效果:单元格和按钮在鼠标悬停时提供视觉反馈
- 当前玩家高亮:通过背景色和缩放效果突出显示当前回合的玩家
- 难度按钮状态:使用.active类标记当前选择的难度
📚 四、JavaScript核心逻辑:游戏引擎与AI实现
📘 4.1 游戏状态管理
通过全局变量管理游戏状态:
- board:二维数组存储棋盘状态
- currentPlayer:当前玩家(‘black’或’white’)
- gameOver:游戏是否结束
- difficulty:当前AI难度
- isPlayerTurn:是否为玩家回合
📘 4.2 棋盘初始化与管理
📖 4.2.1 棋盘创建
initBoard()函数负责初始化棋盘:
- 创建15×15的二维数组
- 动态生成DOM元素构建棋盘网格
- 绑定单元格点击事件
- 重置游戏状态
📖 4.2.2 落子处理
handleCellClick()函数处理玩家落子:
- 验证落子合法性
- 更新棋盘状态
- 播放落子音效
- 添加落子特效
- 检查胜负
- 切换到电脑回合
📘 4.3 胜负判定系统
📖 4.3.1 核心算法
checkWin()函数实现胜负判定:
- 检查四个方向(水平、垂直、两个对角线)
- 计算连续相同颜色的棋子数量
- 当连续数量达到5时判定胜利
📖 4.3.2 位置验证
isValidPosition()函数确保坐标在棋盘范围内,防止数组越界。
📘 4.4 AI系统设计
📖 4.4.1 难度等级
实现三级AI难度:
- 简单:随机选择空格落子
- 中等:优先防守,其次进攻
- 困难:基于评分系统的智能落子
📖 4.4.2 困难AI实现
getHardMove()函数采用评估系统:
- 遍历所有空格
- 评估每个位置的落子价值
- 考虑连珠情况和中心位置优势
- 选择评分最高的位置落子
📘 4.5 音效与特效系统
📖 4.5.1 音效实现
使用Web Audio API创建各种音效:
- playDropSound():落子音效
- playWinSound():胜利音效
- playResetSound():重置音效
📖 4.5.2 视觉特效
- addDropEffect():落子特效
- addWinEffect():胜利特效
- showWinMessage():胜利消息显示
📘 4.6 背景音乐系统
📖 4.6.1 音乐生成
backgroundMusic.js模块使用Web Audio API动态生成背景音乐:
- 基于预设旋律生成科幻电子风格音乐
- 使用方波和锯齿波创建激进的音效
- 包含低音增强节奏感
📖 4.6.2 音乐控制
- startBackgroundMusic():开始播放背景音乐
- stopBackgroundMusic():停止播放背景音乐
- 音乐播放状态与游戏状态同步
📚 五、技术特点与创新点
📘 5.1 技术亮点
📘 5.2 游戏体验优化
📘 5.3 代码质量分析
- 代码结构清晰:模块化设计,函数职责明确
- 命名规范:变量和函数命名语义化
- 注释完善:关键逻辑有详细注释
- 错误处理:包含基本的错误捕获
- 性能优化:AI算法效率合理
📚 六、总结与建议
📘 6.1 项目价值
本项目是一个功能完整、体验良好的五子棋游戏,具有以下价值:
- 教育意义:展示了纯原生JavaScript实现复杂游戏的方法
- 技术参考:Web Audio API的实际应用案例
- 游戏体验:提供了一个可玩的五子棋游戏
📘 6.2 改进建议
📘 6.3 技术拓展可能
📚 七、结论
本项目成功实现了一个功能完整、体验良好的五子棋游戏。通过纯原生JavaScript和Web Audio API,开发者展示了如何构建一个具有现代感的网页游戏。项目结构清晰,代码质量高,功能丰富,是一个优秀的前端小型游戏开发案例。
游戏的核心功能包括标准的15×15棋盘、三级AI难度、完整的音效系统和现代化的视觉效果。虽然代码量不大,但实现了五子棋游戏的所有核心要素,同时在用户体验和视觉效果上做了不少优化。
作为一个学习项目,它展示了如何将复杂的游戏逻辑分解为可管理的模块,如何使用Web Audio API创建动态音效,以及如何通过CSS3和JavaScript结合创建流畅的动画效果。这些技术点都值得前端开发者学习和参考。
📚 完整代码(可直接使用)
📘 项目目录

📘 项目代码
📖 html代码
<!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 {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
overflow: hidden;
}
.game-container {
text-align: center;
background: rgba(255, 255, 255, 0.95);
padding: 20px;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
position: relative;
}
h1 {
color: #333;
margin-bottom: 20px;
font-size: 2.5em;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}
.game-info {
display: flex;
justify-content: space-around;
margin-bottom: 20px;
font-size: 1.2em;
color: #555;
}
.player-info {
padding: 10px 20px;
border-radius: 10px;
transition: all 0.3s ease;
}
.current-player {
background: #4CAF50;
color: white;
transform: scale(1.1);
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.4);
}
#board {
display: inline-block;
background: #d4b996;
border: 10px solid #8b4513;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
position: relative;
}
.row {
display: flex;
}
.cell {
width: 40px;
height: 40px;
border: 1px solid #8b4513;
cursor: pointer;
position: relative;
transition: all 0.2s ease;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
}
.cell:hover {
background: rgba(255, 255, 255, 0.3);
transform: scale(1.05);
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2);
}
.cell.black::before {
content: "●";
color: #000;
font-size: 36px;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
.cell.white::before {
content: "○";
color: #fff;
font-size: 36px;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.5), 0 0 5px #000;
}
.effect {
position: absolute;
font-size: 40px;
pointer-events: none;
z-index: 100;
animation: effect-animation 1s ease-out forwards;
}
@keyframes effect-animation {
0% {
opacity: 1;
transform: scale(1) translateY(0);
}
50% {
opacity: 0.8;
transform: scale(1.5) translateY(-20px);
}
100% {
opacity: 0;
transform: scale(0.5) translateY(-40px);
}
}
.btn {
margin: 10px;
padding: 10px 20px;
font-size: 1.1em;
border: none;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
background: #4CAF50;
color: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.btn:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.btn.reset {
background: #f44336;
}
.btn.sound {
background: #2196F3;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 30px 50px;
border-radius: 20px;
font-size: 2em;
z-index: 200;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
animation: fadeIn 0.5s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translate(-50%, -50%) scale(0.8);
}
to {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
}
.difficulty-selector {
margin: 20px 0;
display: flex;
justify-content: center;
gap: 10px;
}
.difficulty-btn {
padding: 8px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
transition: all 0.3s ease;
background: #2196F3;
color: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.difficulty-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(33, 150, 243, 0.4);
}
.difficulty-btn.active {
background: #4CAF50;
transform: scale(1.1);
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.4);
}
.control-panel {
margin-top: 20px;
}
</style>
</head>
<body>
<div class="game-container">
<h1>🎮 五子棋游戏 🎮</h1>
<div class="game-info">
<div class="player-info current-player" id="player1">
玩家 <span>●</span>
</div>
<div class="player-info" id="player2">
电脑 <span>○</span>
</div>
</div>
<div class="difficulty-selector">
<button class="difficulty-btn active" onclick="setDifficulty('easy')">🧠 简单</button>
<button class="difficulty-btn" onclick="setDifficulty('medium')">🤔 中等</button>
<button class="difficulty-btn" onclick="setDifficulty('hard')">🧠💪 困难</button>
</div>
<div id="board"></div>
<div class="control-panel">
<button class="btn" onclick="resetGame()">🔄 重新开始</button>
<button class="btn sound" onclick="toggleSound()">🔊 音效开关</button>
</div>
</div>
<script src="backgroundMusic.js"></script>
<script>
// 游戏状态
const BOARD_SIZE = 15;
let board = [];
let currentPlayer = 'black';
let gameOver = false;
let soundEnabled = true;
let musicEnabled = true;
let difficulty = 'easy'; // 难度级别:easy, medium, hard
let isPlayerTurn = true; // 是否是玩家回合
// Web Audio API
let audioContext;
let backgroundMusicGain;
let soundGain;
// 初始化游戏
function initGame() {
// 初始化音频上下文
initAudioContext();
// 初始化棋盘
initBoard();
// 开始背景音乐
startMusic();
}
// 初始化音频上下文
function initAudioContext() {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
backgroundMusicGain = audioContext.createGain();
soundGain = audioContext.createGain();
backgroundMusicGain.connect(audioContext.destination);
soundGain.connect(audioContext.destination);
backgroundMusicGain.gain.value = 0.3;
soundGain.gain.value = 0.5;
// 初始化背景音乐模块
initBackgroundMusic(audioContext, backgroundMusicGain);
// 设置游戏状态获取函数
setGameStateGetter(() => ({
gameRunning: true,
gamePaused: false,
gameOver: gameOver
}));
}
// 设置难度
function setDifficulty(level) {
difficulty = level;
// 更新按钮状态
const buttons = document.querySelectorAll('.difficulty-btn');
buttons.forEach(btn => btn.classList.remove('active'));
event.target.classList.add('active');
// 重置游戏
resetGame();
}
// 初始化棋盘
function initBoard() {
const boardElement = document.getElementById('board');
boardElement.innerHTML = '';
board = [];
for (let i = 0; i < BOARD_SIZE; i++) {
const row = [];
const rowElement = document.createElement('div');
rowElement.className = 'row';
for (let j = 0; j < BOARD_SIZE; j++) {
row.push(null);
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.row = i;
cell.dataset.col = j;
cell.addEventListener('click', handleCellClick);
rowElement.appendChild(cell);
}
board.push(row);
boardElement.appendChild(rowElement);
}
// 重置游戏状态
currentPlayer = 'black';
gameOver = false;
isPlayerTurn = true;
updatePlayerInfo();
// 移除游戏结束弹窗
const gameOverElement = document.querySelector('.game-over');
if (gameOverElement) {
gameOverElement.remove();
}
}
// 处理单元格点击
function handleCellClick(e) {
if (gameOver || !isPlayerTurn) return;
const row = parseInt(e.target.dataset.row);
const col = parseInt(e.target.dataset.col);
if (board[row][col]) return;
// 落子
board[row][col] = currentPlayer;
e.target.classList.add(currentPlayer);
// 播放落子音效
playDropSound();
// 添加落子特效
addDropEffect(e.target, row, col);
// 检查胜利
if (checkWin(row, col)) {
gameOver = true;
showWinMessage();
return;
}
// 切换到电脑回合
currentPlayer = 'white';
isPlayerTurn = false;
updatePlayerInfo();
// 电脑思考并落子
setTimeout(() => {
computerMove();
}, 500); // 电脑思考时间
}
// 电脑落子
function computerMove() {
if (gameOver) return;
let move;
// 根据难度选择落子策略
switch (difficulty) {
case 'easy':
move = getEasyMove();
break;
case 'medium':
move = getMediumMove();
break;
case 'hard':
move = getHardMove();
break;
default:
move = getEasyMove();
}
if (move) {
const { row, col } = move;
const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
// 落子
board[row][col] = currentPlayer;
cell.classList.add(currentPlayer);
// 播放落子音效
playDropSound();
// 添加落子特效
addDropEffect(cell, row, col);
// 检查胜利
if (checkWin(row, col)) {
gameOver = true;
showWinMessage();
return;
}
// 切换回玩家回合
currentPlayer = 'black';
isPlayerTurn = true;
updatePlayerInfo();
}
}
// 更新玩家信息
function updatePlayerInfo() {
const player1 = document.getElementById('player1');
const player2 = document.getElementById('player2');
if (currentPlayer === 'black') {
player1.classList.add('current-player');
player2.classList.remove('current-player');
} else {
player1.classList.remove('current-player');
player2.classList.add('current-player');
}
}
// 检查胜利
function checkWin(row, col) {
const directions = [
[0, 1], // 水平
[1, 0], // 垂直
[1, 1], // 对角线
[1, –1] // 反对角线
];
for (const [dx, dy] of directions) {
let count = 1;
// 检查正方向
for (let i = 1; i < 5; i++) {
const newRow = row + dx * i;
const newCol = col + dy * i;
if (isValidPosition(newRow, newCol) && board[newRow][newCol] === currentPlayer) {
count++;
} else {
break;
}
}
// 检查反方向
for (let i = 1; i < 5; i++) {
const newRow = row – dx * i;
const newCol = col – dy * i;
if (isValidPosition(newRow, newCol) && board[newRow][newCol] === currentPlayer) {
count++;
} else {
break;
}
}
if (count >= 5) {
return true;
}
}
return false;
}
// 检查位置是否有效
function isValidPosition(row, col) {
return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;
}
// 获取所有空格
function getEmptyCells() {
const emptyCells = [];
for (let i = 0; i < BOARD_SIZE; i++) {
for (let j = 0; j < BOARD_SIZE; j++) {
if (!board[i][j]) {
emptyCells.push({ row: i, col: j });
}
}
}
return emptyCells;
}
// 简单难度:随机选择空格
function getEasyMove() {
const emptyCells = getEmptyCells();
if (emptyCells.length === 0) return null;
// 随机选择一个空格
const randomIndex = Math.floor(Math.random() * emptyCells.length);
return emptyCells[randomIndex];
}
// 中等难度:优先防守,然后进攻
function getMediumMove() {
const emptyCells = getEmptyCells();
if (emptyCells.length === 0) return null;
// 1. 检查是否有获胜机会
for (const cell of emptyCells) {
board[cell.row][cell.col] = 'white';
if (checkWin(cell.row, cell.col)) {
board[cell.row][cell.col] = null;
return cell;
}
board[cell.row][cell.col] = null;
}
// 2. 检查是否需要防守
for (const cell of emptyCells) {
board[cell.row][cell.col] = 'black';
if (checkWin(cell.row, cell.col)) {
board[cell.row][cell.col] = null;
return cell;
}
board[cell.row][cell.col] = null;
}
// 3. 随机选择
const randomIndex = Math.floor(Math.random() * emptyCells.length);
return emptyCells[randomIndex];
}
// 困难难度:评估所有可能的落子位置
function getHardMove() {
const emptyCells = getEmptyCells();
if (emptyCells.length === 0) return null;
let bestMove = null;
let bestScore = –Infinity;
for (const cell of emptyCells) {
// 计算落子评分
const score = evaluateMove(cell.row, cell.col);
if (score > bestScore) {
bestScore = score;
bestMove = cell;
}
}
return bestMove;
}
// 评估落子位置的分数
function evaluateMove(row, col) {
let score = 0;
// 检查电脑自己的连珠情况
board[row][col] = 'white';
if (checkWin(row, col)) {
board[row][col] = null;
return 10000; // 获胜棋,最高分
}
score += countConsecutive(row, col, 'white') * 10;
board[row][col] = null;
// 检查玩家的连珠情况
board[row][col] = 'black';
if (checkWin(row, col)) {
board[row][col] = null;
return 9000; // 必须防守,高分
}
score += countConsecutive(row, col, 'black') * 15;
board[row][col] = null;
// 中心位置加分
const centerRow = Math.floor(BOARD_SIZE / 2);
const centerCol = Math.floor(BOARD_SIZE / 2);
const distanceToCenter = Math.abs(row – centerRow) + Math.abs(col – centerCol);
score += (20 – distanceToCenter) * 2;
return score;
}
// 计算连珠数量
function countConsecutive(row, col, player) {
let maxCount = 0;
const directions = [
[0, 1], // 水平
[1, 0], // 垂直
[1, 1], // 对角线
[1, –1] // 反对角线
];
for (const [dx, dy] of directions) {
let count = 1;
// 检查正方向
for (let i = 1; i < 5; i++) {
const newRow = row + dx * i;
const newCol = col + dy * i;
if (isValidPosition(newRow, newCol) && board[newRow][newCol] === player) {
count++;
} else {
break;
}
}
// 检查反方向
for (let i = 1; i < 5; i++) {
const newRow = row – dx * i;
const newCol = col – dy * i;
if (isValidPosition(newRow, newCol) && board[newRow][newCol] === player) {
count++;
} else {
break;
}
}
if (count > maxCount) {
maxCount = count;
}
}
return maxCount;
}
// 显示胜利消息
function showWinMessage() {
const winner = currentPlayer === 'black' ? '玩家' : '电脑';
const gameContainer = document.querySelector('.game-container');
const winElement = document.createElement('div');
winElement.className = 'game-over';
winElement.innerHTML = `🎉 ${winner} 获胜! 🎉`;
gameContainer.appendChild(winElement);
// 播放胜利音效
playWinSound();
// 添加胜利特效
addWinEffect();
}
// 重置游戏
function resetGame() {
// 播放重置音效
playResetSound();
initBoard();
}
// 切换音效
function toggleSound() {
soundEnabled = !soundEnabled;
musicEnabled = !musicEnabled;
const btn = document.querySelector('.btn.sound');
btn.textContent = soundEnabled ? '🔊 音效开关' : '🔇 音效关闭';
// 控制音乐
if (musicEnabled) {
startMusic();
} else {
stopBackgroundMusic();
}
}
// 开始音乐
function startMusic() {
if (musicEnabled) {
startBackgroundMusic();
}
}
// 播放落子音效
function playDropSound() {
if (!soundEnabled) return;
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(soundGain);
oscillator.type = 'sine';
oscillator.frequency.value = 800;
const now = audioContext.currentTime;
gainNode.gain.setValueAtTime(0.5, now);
gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.2);
oscillator.start(now);
oscillator.stop(now + 0.2);
}
// 播放胜利音效
function playWinSound() {
if (!soundEnabled) return;
const frequencies = [523, 659, 784, 1047]; // C, E, G, C
frequencies.forEach((freq, index) => {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(soundGain);
oscillator.type = 'sine';
oscillator.frequency.value = freq;
const now = audioContext.currentTime;
const delay = index * 0.2;
gainNode.gain.setValueAtTime(0, now + delay);
gainNode.gain.linearRampToValueAtTime(0.5, now + delay + 0.1);
gainNode.gain.exponentialRampToValueAtTime(0.01, now + delay + 0.3);
oscillator.start(now + delay);
oscillator.stop(now + delay + 0.3);
});
}
// 播放重置音效
function playResetSound() {
if (!soundEnabled) return;
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(soundGain);
oscillator.type = 'sine';
oscillator.frequency.value = 400;
const now = audioContext.currentTime;
gainNode.gain.setValueAtTime(0.5, now);
gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.3);
oscillator.frequency.exponentialRampToValueAtTime(200, now + 0.3);
oscillator.start(now);
oscillator.stop(now + 0.3);
}
// 添加落子特效
function addDropEffect(cell, row, col) {
// 创建emoji特效
const effect = document.createElement('div');
effect.className = 'effect';
// 随机选择特效emoji
const effects = ['✨', '🌟', '💫', '⚡', '🎯'];
effect.textContent = effects[Math.floor(Math.random() * effects.length)];
// 设置位置
const rect = cell.getBoundingClientRect();
const boardRect = document.getElementById('board').getBoundingClientRect();
effect.style.left = `${rect.left – boardRect.left + 20}px`;
effect.style.top = `${rect.top – boardRect.top + 20}px`;
// 添加到棋盘
document.getElementById('board').appendChild(effect);
// 动画结束后移除
setTimeout(() => {
effect.remove();
}, 1000);
}
// 添加胜利特效
function addWinEffect() {
// 在棋盘上随机生成多个庆祝emoji
const effects = ['🎉', '🎊', '🏆', '🎁', '🎈'];
for (let i = 0; i < 20; i++) {
const effect = document.createElement('div');
effect.className = 'effect';
effect.textContent = effects[Math.floor(Math.random() * effects.length)];
// 随机位置
const x = Math.random() * 600;
const y = Math.random() * 600;
effect.style.left = `${x}px`;
effect.style.top = `${y}px`;
// 随机动画时间
effect.style.animationDuration = `${0.5 + Math.random() * 1}s`;
document.getElementById('board').appendChild(effect);
setTimeout(() => {
effect.remove();
}, 1500);
}
}
// 页面加载完成后初始化游戏
window.addEventListener('DOMContentLoaded', initGame);
</script>
</body>
</html>
📖 javascript代码
backgroundMusic.js
// 背景音乐模块
// 使用 Web Audio API 生成背景音乐
let musicInterval = null;
// 注意:audioContext 和 backgroundMusicGain 在主脚本中声明,这里只存储引用
let audioContextRef = null;
let backgroundMusicGainRef = null;
// 初始化背景音乐(需要传入音频上下文和增益节点)
function initBackgroundMusic(audioCtx, musicGain) {
audioContextRef = audioCtx;
backgroundMusicGainRef = musicGain;
}
// 获取游戏状态的函数(由主游戏传入)
let getGameState = null;
// 设置游戏状态获取函数
function setGameStateGetter(getter) {
getGameState = getter;
}
// 生成背景音乐
function startBackgroundMusic() {
if (!audioContextRef || !backgroundMusicGainRef || musicInterval) return;
try {
// 激进快速的旋律循环 – 科幻电子风格
const melody = [
// 第一段:快速上升
{ freq1: 523.25, freq2: 659.25, duration: 0.2, bass: 261.63 }, // C5, E5, C4低音
{ freq1: 659.25, freq2: 783.99, duration: 0.2, bass: 329.63 }, // E5, G5, E4
{ freq1: 783.99, freq2: 987.77, duration: 0.2, bass: 392.00 }, // G5, B5, G4
{ freq1: 987.77, freq2: 1174.66, duration: 0.2, bass: 493.88 }, // B5, D6, B4
// 第二段:跳跃音程
{ freq1: 880.00, freq2: 1318.51, duration: 0.2, bass: 440.00 }, // A5, E6, A4
{ freq1: 1046.50, freq2: 1567.98, duration: 0.2, bass: 523.25 }, // C6, G6, C5
{ freq1: 1174.66, freq2: 1760.00, duration: 0.2, bass: 587.33 }, // D6, A6, D5
// 第三段:快速下降
{ freq1: 1046.50, freq2: 1318.51, duration: 0.2, bass: 523.25 }, // C6, E6, C5
{ freq1: 880.00, freq2: 1108.73, duration: 0.2, bass: 440.00 }, // A5, C#6, A4
{ freq1: 783.99, freq2: 987.77, duration: 0.2, bass: 392.00 }, // G5, B5, G4
{ freq1: 659.25, freq2: 830.61, duration: 0.2, bass: 329.63 }, // E5, G#5, E4
];
let noteIndex = 0;
function playNextNote() {
// 获取当前游戏状态
if (getGameState) {
const state = getGameState();
if (!state.gameRunning || state.gamePaused || state.gameOver) {
return;
}
}
const note = melody[noteIndex];
const currentTime = audioContextRef.currentTime;
// 创建主旋律振荡器(高频,更尖锐)
const osc1 = audioContextRef.createOscillator();
const osc2 = audioContextRef.createOscillator();
const gain1 = audioContextRef.createGain();
const gain2 = audioContextRef.createGain();
osc1.connect(gain1);
osc2.connect(gain2);
gain1.connect(backgroundMusicGainRef);
gain2.connect(backgroundMusicGainRef);
// 使用更激进的波形:方波和锯齿波
osc1.type = 'square'; // 方波更尖锐
osc2.type = 'sawtooth'; // 锯齿波更激进
osc1.frequency.value = note.freq1;
osc2.frequency.value = note.freq2;
// 更快的起音和衰减,营造冲击感
gain1.gain.setValueAtTime(0.12, currentTime);
gain1.gain.exponentialRampToValueAtTime(0.01, currentTime + note.duration);
gain2.gain.setValueAtTime(0.10, currentTime);
gain2.gain.exponentialRampToValueAtTime(0.01, currentTime + note.duration);
osc1.start(currentTime);
osc1.stop(currentTime + note.duration);
osc2.start(currentTime);
osc2.stop(currentTime + note.duration);
// 添加低音增强节奏感(如果有低音频率)
if (note.bass) {
const bassOsc = audioContextRef.createOscillator();
const bassGain = audioContextRef.createGain();
bassOsc.connect(bassGain);
bassGain.connect(backgroundMusicGainRef);
bassOsc.type = 'square'; // 低音使用方波
bassOsc.frequency.value = note.bass;
bassGain.gain.setValueAtTime(0.08, currentTime);
bassGain.gain.exponentialRampToValueAtTime(0.01, currentTime + note.duration);
bassOsc.start(currentTime);
bassOsc.stop(currentTime + note.duration);
}
noteIndex = (noteIndex + 1) % melody.length;
}
// 立即播放第一个音符
playNextNote();
// 设置定时器循环播放 – 更快的节奏(250ms间隔)
musicInterval = setInterval(() => {
if (getGameState) {
const state = getGameState();
if (state.gameRunning && !state.gamePaused && !state.gameOver) {
playNextNote();
}
} else {
playNextNote();
}
}, 250); // 每250ms播放一个音符(比原来快一倍)
} catch (e) {
console.log('背景音乐生成失败:', e);
}
}
// 停止背景音乐
function stopBackgroundMusic() {
if (musicInterval) {
clearInterval(musicInterval);
musicInterval = null;
}
}
———— ⬆️·`正文结束`·⬆️————
到此这篇文章就介绍到这了,更多精彩内容请关注本人以前的文章或继续浏览下面的文章,创作不易,如果能帮助到大家,希望大家多多支持宝码香车~💕,若转载本文,一定注明本文链接。

更多专栏订阅推荐: 👍 html+css+js 绚丽效果 💕 vue ✈️ Electron ⭐️ js 📝 字符串 ✍️ 时间对象(Date())操作
