本文详细讲解如何使用JavaScript开发一个4x5格子的数字配对游戏。文章涵盖游戏规则设定、核心数据结构设计(包括隐藏、暂显、永久显示三种状态)、随机数生成与洗牌算法,以及点击事件处理逻辑。通过完整的代码示例,展示如何利用数组和DOM操作实现游戏计时、状态同步与胜负判定,适合前端初学者理解复杂交互逻辑的实现。
游戏效果展示
游戏运行界面效果如下图所示:

游戏规则说明
游戏规则如下:
游戏界面为一个4行5列的网格,共20个格子。系统随机生成10个互不相同的整数,每个整数复制一份,共20个数字,形成10对相等的数字。这20个数字随机分布在20个格子中。游戏启动后,会弹出包含这20个数字的序列提示。玩家每次点击一个格子,该格子显示其对应的数字并暂时保持可见状态,直到玩家进行下一次点击。若第二次点击的格子数字与第一次不同,则第一次点击的数字会重新隐藏(数据仍存在于格子中但视觉上不可见)。若连续两次点击的数字相同,则这两个数字将永久显示在界面上,不再隐藏。
当所有格子中的数字都通过连续点击相同数字的方式被永久显示出来时,游戏结束,系统会提示游戏耗时。此时玩家可以点击“开始游戏”或“刷新”按钮重新开始一局。
逻辑分析与状态设计
逻辑分析:
1. 网格包含20个格子,对应20个数据。系统需生成两组相等的10个随机数,存入数组中,数组的下标决定数字在网格中的显示位置。
2. 每个格子存在三种状态:数据隐藏、暂时保留显示、永久显示。处于“数据隐藏”状态的格子,被点击后状态变为“暂时保留”;处于“暂时保留”状态的格子,再次被点击后,若两次获取的数字相同,则状态变为“永久显示”;若不同,则前一个格子状态恢复为“数据隐藏”,新点击的格子变为“暂时保留”。一旦状态变为“永久显示”,该状态不可逆,后续点击无效。
3. 计时器从点击“开始游戏”按钮后,玩家首次点击网格中任意一个格子时正式启动。计时过程持续进行,直到游戏完成或玩家点击“刷新”按钮重新开始,期间计时器不得暂停。
4. 需要一个布尔变量来记录游戏是否已开始。若游戏已开始,再次点击“开始游戏”按钮应被拒绝响应。计时器运行直至游戏完成,此时修改布尔变量,停止计时器,显示总用时,并使“开始游戏”按钮重新可用。
核心代码实现
代码实现思路:
表格通过JavaScript动态创建,初始时表格单元格内容默认为空字符串。具体显示内容通过点击事件触发更新。CSS样式可根据需求自行定义。
<table border:1>
<script>
var rowlength = 4;
var collength = 5;
var str = '';
for (var i = 0; i < rowlength; i++) {
str += '<tr>'
for (var j = 0; j < collength; j++) {
//这里将每个td的id拼接为imgxx xx为元素索引
var index = i * collength + j;
var id = "img" + index;
//注意这里字符串 每个''是一个字符串进行输出
str += '<td id="' + id + '" onclick="showImg(' + index + ')">';
str += '</td>';
}
str += '</tr>'
}
document.write(str);
</script>
</table>
变量NEW_START用于记录游戏是否允许开始,初始值为true。
变量times用于记录游戏已用的时间(秒)。
数组trans用于记录每个格子的翻转状态。数组中每个元素对应一个格子,其值仅有三种可能:0表示隐藏,1表示显示(仍可翻转),2表示显示(不可翻转,即永久显示)。
数组numArr用于存储生成的30个数的随机序列(注:根据上下文实际应为20个数,此处保留原文描述或指代生成逻辑中的中间变量,实际有效数据为20个)。
var NEW_START = true;
var times = 0;
var trans = [];
var numArr = [];
通过ID获取DOM元素的方法封装如下:
function $(id) {
return document.getElementById(id);
}
接下来通过函数生成20个随机数,确保这20个数由10对相等的数字组成(具体生成逻辑可参考生成指定范围随机数的方法)。
function getNum() {
var index = 0;
var arrLength = rowlength * collength / 2;
var arr = new Array();
while (index < arrLength) {
var flag = true;
var num = parseInt(Math.random() * 100);
for (var i in arr) {
if (arr[i] == num || arr[i] < 1) {
flag = false;
}
}
if (flag == true) {
arr[index] = num;
index++;
}
}
//alert(arr.length);
//arr是十个互不相等的随机数
// newArr数组就是每个随机数都有两个的数组
var newArr = new Array();
for (var i = 0; i < arrLength; i++) {
newArr[i] = arr[i];
newArr[arrLength + i] = arr[i];
}
return newArr;
}
创建表格结构和生成随机数数组属于游戏初始化前的准备工作。
以下是游戏核心逻辑的具体实现:
“开始游戏”按钮的点击处理函数。
<input type="button"
id="startButton"
value="开始游戏"
onclick="init()">
点击“开始游戏”时,需初始化游戏相关参数。若游戏已经开始(NEW_START为false),则拒绝执行初始化。通过排序函数打乱数组元素,确保数字分布的随机性。
function init() {
//如果已经开始 拒绝点击
if (NEW_START == false) {
return;
}
//结束时用于显示时间的h4标签
$('end').innerHTML = '';
var count = rowlength * collength;
//将每个格子的数据隐藏 初始化每个格子的翻转状态
for (var i = 0; i < count; i++) {
$('img' + i).innerHTML = '';
trans[i] = 0;
}
//将游戏用时置为0
times = 0;
$('gametime').innerHTML = times + '秒';
//获取随机的三十个数的随机序列数组 注意排序函数的使用
numArr = getNum().sort(function () {
return Math.random() - 0.5;
});
alert("已生成随机数,按表格顺序排列:" + numArr);
}
计时函数实现。
当玩家点击第一个格子时,启动计时器。若NEW_START为false,表示游戏已进行,需确保仅在游戏进行中时执行计时。该函数每秒调用自身一次,并通过innerHTML实时更新界面上显示的游戏用时。
用时:<span id="gametime">0秒</span>
function countTime() {
if (NEW_START == false) {
setTimeout('countTime()', 1000);
$('gametime').innerHTML = times + "秒";
times++;
}
}
每个网格单元格的点击处理函数(核心逻辑)。
若游戏尚未开始,拒绝处理格子点击事件(无效果)。当玩家首次点击格子进入游戏时,更新状态,将NEW_START设为false,表示游戏已开始且不可再创建新游戏。同时启动计时器。
后续的点击事件需根据当前点击的格子状态执行不同的逻辑判断:
若点击的是已永久显示的格子,直接返回,不执行任何操作。
若点击的是刚显示但尚未永久显示的格子(即暂时保留状态),且该格子是第二次被点击,则根据前一次点击的数字是否相同来判断后续状态;若只是单纯点击已暂时显示的格子且未匹配,则不处理或视为无效操作(具体逻辑见下文)。
注意:判断是否为同一元素是通过状态数组trans中的索引index查找并对比状态值来实现的。
若点击的是未显示(隐藏状态)的元素,获取该格子的数值,并与前一个暂时显示的格子数值进行对比:
若两个数值相等,则将trans数组中对应索引的状态值修改为2,表示这两个格子已永久显示。
若两个数值不相等,则将新点击元素在trans数组中对应索引的状态值设为1(保持暂时显示),而前一个点击的元素索引状态值设为0(重新隐藏)。
状态值设置完成后,立即调用refreshUI函数更新界面显示。该函数根据trans数组中记录的状态值来操作DOM,决定每个格子是否显示数字。
function showImg(index) {
//未点击开始,还未初始化,退出
if (numArr[0] == undefined) {
return;
}
//初次点击进入,开启计时
if (NEW_START) {
NEW_START = false;
countTime();
}
//1-点击已经彻底显示的元素 退出
if (trans[index] == 2) {
return;
}
//将点击的格子的元素显示出来,并改变翻转状态
//alert(index);
//alert(numArr)
var clickEle = $('img' + index);
clickEle.innerHTML = numArr[index];
//已点击元素的index
var transIndex;
for (var i in trans) {
if (trans[i] == 1) {
transIndex = i;
}
}
//2-如果点击的是刚刚已显示元素
if (transIndex == index) {
trans[index] = 1;
return;
}
//3-点击新元素 与先前显示元素对比 两种情况-相等 不等
else {
if (numArr[transIndex] == numArr[index]) {
trans[transIndex] = 2;
trans[index] = 2;
} else {
trans[transIndex] = 0;
trans[index] = 1;
}
}
refreshUI();
}
根据状态值设置显示的函数refreshUI实现。
遍历trans数组,根据每个元素的值改变对应索引格子的innerHTML。若格子状态为永久显示(值为2),需记录已永久显示的格子数量。当该数量等于总格子数(20)时,判定游戏结束,显示总用时,并停止计时。
function refreshUI() {
//此处用fore循环会最后存在一个undefined
//count记录已经被彻底显示的个数
var count = 0;
for (var i = 0; i < trans.length; i++) {
if (trans[i] == 0) {
$('img' + i).innerHTML = '';
}
if (trans[i] == 1) {
$('img' + i).innerHTML = numArr[i];
}
if (trans[i] == 2) {
$('img' + i).innerHTML = numArr[i]
count++;
}
}
if (count == collength * rowlength) {
NEW_START = true;
var endTime = times;
$('end').innerHTML = '用时' + endTime + '秒!!游戏结束,点击开始游戏继续';
$('gametime').innerHTML = endTime + "秒";
}
}
通过数组与表格的配合实现配对游戏,旨在加深对表格动态创建和数组状态管理的理解。处理逻辑与数据显示分离,依据状态值实现不同的显示效果。
以上关于JavaScript实现数字配对游戏的实例讲解内容到此结束,希望能为读者提供有价值的参考,也欢迎大家继续支持本站。