前言
前段时间发现网上有很多收费或公开课都有教用 js 做 2048 小游戏的,然后自己就也想动手做一个,做这个小游戏主要是为了锻炼自己的逻辑能力,也算是对之前一些学习的总结吧
注:
- 实现方法完全是自己边玩 2048 边想的,所有些乱还请见谅
- 另外配色方案是在某个 2048 游戏截屏,然后用 ps 吸取的,非本人原创
- 代码中有很多都可以使用数组相关的方法来代替,这里是为了自己理解数组方法是什么原理
- 由于时间关系本次不做详解
游戏逻辑
- 随机位置生成数字 2 或 4
- 按方向键,有挨着的相同的数字就合并成新的数字
- 按方向键,数字会移动到对应方向的最边上(按左,数字全部移动到左边)
- 每次按方向键,合并完成后,会在没有数字的随机位置都会生成新的数字 2 或 4
- 当前分数等于当前所有数字相加
- 当有数字达到 2048 游戏结束
项目相关
这个版本是用原生 ES6 写的,只实现了游戏逻辑中的 1,2,3,4;
第一版地址:github.com/yhtx1997/Sm…
之后是打算用 vue 重新写一遍,并且完善下,因为长时间用原生,导致 vue 有些生疏,借此机会重新温习下
项目代码
采用二维数组进行数据的管理,默认全部为零
let arr = [
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
];
复制代码
随机创建数字
let s = 0;
let create = () => {
let x = Math.floor(Math.random() * 4);
let y = Math.floor(Math.random() * 4);
// console.log(s)
if (s > 100) {
s = 0;
return;
}
if (arr[x][y] == 0) {
if (Math.floor(Math.random() * 10) % 2 == 0) {
arr[x][y] = 2;
} else {
arr[x][y] = 4;
}
s = 0;
return;
} else {
s++;
return create();
}
}
复制代码
渲染页面
let updateHtml = () => {
//获取元素
let warp = document.getElementById('warp');
let html = '';
//将数据转换为 HTML
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
html += `'c c-${arr[i][j]}'>${arr[i][j]==0?'':arr[i][j]}`;
}
}
//将 数据转换的 HTML 渲染到页面
warp.innerHTML = html;
}
复制代码
事件监听
window.onkeydown = (e) => {
switch (e.keyCode) {
case 37:
// ←
console.log('←');
arr = new move(arr).moveLeft();
create(); //随机位置新建
updateHtml(); //更新数据到页面
break;
case 38:
// ↑
console.log('↑');
arr = new move(arr).moveUp();
create(); //随机位置新建
updateHtml(); //更新数据到页面
break;
case 39:
// →
console.log('→');
arr = new move(arr).moveRight();
create(); //随机位置新建
updateHtml(); //更新数据到页面
break;
case 40:
// ↓
console.log('↓');
arr = new move(arr).moveDown();
create(); //随机位置新建
updateHtml(); //更新数据到页面
break;
}
}
复制代码
具体处理函数
先提取非零数字
export default function ClearZero (arr){//去零
let clearZero = [[],[],[],[]];
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
if (arr[i][j] != 0) {
clearZero[i].push(arr[i][j])
}
}
}
return clearZero;
}
复制代码
将挨着的相等数字分组并相加
分组
import Deduplication from './deduplication';//将相邻且相同的数字相加
export default class Grouping{//将相邻的相同数字分组
constructor(clearZero){
this.clearZero = clearZero;
}
left(){
let newarr = [[],[],[],[]];
for (let j = 0; j < this.clearZero.length; j++) {
let grouping = [];
let i = 0;
//将重复的 分到一组
while (i < this.clearZero[j].length) {
if (this.clearZero[j][i] == this.clearZero[j][i + 1]) {
grouping.push([this.clearZero[j][i], this.clearZero[j][i + 1]]);
i += 2;
} else {
grouping.push(this.clearZero[j][i]);
i++;
}
}
//去重复
newarr[j] = Deduplication(grouping);
}
return newarr;
}
right(){
let newarr = [[],[],[],[]];
for (let i = 0; i < this.clearZero.length; i++) {
let grouping = [];
let j = this.clearZero[i].length - 1;
//将重复的 分到一组
while (j >= 0) {
if (this.clearZero[i][j] == this.clearZero[i][j - 1]) {
grouping.unshift([this.clearZero[i][j], this.clearZero[i][j - 1]]);
j -= 2;
} else {
grouping.unshift(this.clearZero[i][j]);
j--;
}
}
//将重复的进行计算
newarr[i] = Deduplication(grouping);
}
return newarr;
}
}
复制代码
相加
export default function Deduplication (grouping){//将相邻且相同的数字相加
for (let i = 0; i < grouping.length; i++) {
if (typeof grouping[i] == 'object') {
grouping[i] = grouping[i][0] + grouping[i][1];
}
}
return grouping;
}
复制代码
添加占位用的零
export default function AddZero (newarr,w){//加零
for (let i = 0; i < newarr.length; i++) {
while (newarr[i].length != 4) {
if(w == 'l'){
newarr[i].push(0);
}else if(w == 'r'){
newarr[i].unshift(0);
}
}
}
return newarr;
}
复制代码
上下的处理
将 Y 轴的处理转换成 X 轴的处理
export default function turn(arr) {//将数组转一下
let clearZero = [[],[],[],[]];
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
clearZero[i][j] = arr[j][i]
}
}
return clearZero;
}
复制代码
等处理完成后再调用上边的函数,将 X 轴的处理结果转换回 Y 轴的表现方式