这两天写了个2048小游戏先看效果图:
现在分享一下它的逻辑:
首先要关注的就是它的页面结构:
容器中放置16个div用于,初始页背景的16个格子,注意class命名方式,这样命名可以用函数方便的进行布局,和其他功能操作。
<div class="container">
<div class="box--0-0"></div>
<div class="box--0-1"></div>
<div class="box--0-2"></div>
<div class="box--0-3"></div>
<div class="box--1-0"></div>
<div class="box--1-1"></div>
<div class="box--1-2"></div>
<div class="box--1-3"></div>
<div class="box--2-0"></div>
<div class="box--2-1"></div>
<div class="box--2-2"></div>
<div class="box--2-3"></div>
<div class="box--3-0"></div>
<div class="box--3-1"></div>
<div class="box--3-2"></div>
<div class="box--3-3"></div>
</div>
其次 数字所在的div并不是这16个div,而是在通过方向键移动的过程中另外动态生成的。这里我先用一个值为0的4 *4的二维数组来标记初始的16个div,然后移动过程中生成的数字根据坐标放到这个数组的相应位置。而动态div就是根据这个数组的值来生成的,值不为0,则生成div,值为0,相应位置不生成div
//1:二维数组生成函数
function getArr () {
var arr =[];
for( var i = 0; i < 4; i++){
arr[i]=[];
for( var j = 0; j < 4; j++){
arr[i][j]=0
}
}
return arr;
}
// 2: 创建16个容纳数字的方格函数
function getBoxs(arr1) {
//重新开始先移除包含数字的格子
if(getChild(parents)>16){
removeClassEle('news');
}
for( var i = 0; i < arr1.length; i++){
for( var j = 0; j < arr1[0].length; j++){
if(arr1[i][j]===0){
continue;
}else{
var divs = document.createElement('div');
divs.setAttribute('id','news--'+i+'-'+j);
divs.setAttribute('class','news');
divs.style.left=20+j*120+'px';
divs.style.top=20+i*120+'px';
divs.innerText=arr1[i][j]
parents.appendChild(divs);
}
}
}
}
第三点就是上下左右移动的逻辑
以向左移动为例:
向左移动=>首先判断能否向左移动(条件:向左移动列的左侧有空间或者移动列与它相邻的左侧列值相等 xx24||x224)=>移动完成改变之前定义的数组的值,然后再重新根据该数组动态布局,=>检测数组的剩余空间,然后在剩余的空间位置中随机添加一个值=》在根据数组动态布局
//判断能否向左移动,可以向左移动的条件,1:存在数字的方格左侧不存在数字,2:存在数字但两者相同。x 1 xx | 1,1 xx | 1 x 1 x
function canLeft(arr){
//我通过arr2来判断
for(var i=0;i<arr.length;i++){
//这里j等于1是因为第一列没必要判断,不用左移了
for(var j=1;j<arr[0].length;j++){
for(var k=j-1; k>=0;k--){ //循环判断数字左侧的格子
if(arr[i][k]===0){
arr[i][k]=arr[i][k+1];
arr[i][k+1]=0;
}
else if(arr[i][k]===arr[i][k+1]){
arr[i][k]=arr[i][k]*2;
arr[i][k+1]=0;
}
}
}
}
return arr
}
//随机生成一个Box
function productRandomBox (arr){
//首先盘算是否有空间
var arr3 =[]; //放剩余空间
var objs;
for (var i=0;i<arr.length;i++){
for (var j=0;j<arr[0].length;j++){
if(arr[i][j]===0){
arr3.push({"x":i,"y":j});
}
}
}
if(arr3.length>0){ //随机生成box的逻辑
objs=Math.floor(Math.random()*(arr3.length));
arr[arr3[objs].x][arr3[objs].y]=getNum()
return arr
}else{
alert('GG思密达')
}
}
//左移事件,首先判断能否左移,然后随机生成数组,左移后,重新设定样式
function goLeft (){
getBoxs(canLeft(arr2));
getBoxs( productRandomBox(arr2));
getColor();
}
主要逻辑就是这些,写完后发现还是很简单的,下面附上完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>2048哈哈</title>
<style>
.parent{ text-align:center;}
.restart{ cursor: pointer; background: bisque; width: 100px; height: 30px; line-height: 30px; margin: auto; border-radius: 5px;}
div[class|='box']{ width: 100px; height: 100px; background: #ccc0b3; position: absolute;}
.news{ width: 100px; height: 100px; background-color: rgb(238, 228, 218); position: absolute; text-align:center; line-height: 100px;}
.container { background:#bbada0; width: 500px; height: 500px; margin: 20px auto; position: relative;}
</style>
</head>
<body>
<div class="parent">
<h1>唯美JS2048</h1>
<p class="restart">new game</p>
<span><strong>score:</strong><span class="score">0</span></span>
<div class="container">
<div class="box--0-0"></div>
<div class="box--0-1"></div>
<div class="box--0-2"></div>
<div class="box--0-3"></div>
<div class="box--1-0"></div>
<div class="box--1-1"></div>
<div class="box--1-2"></div>
<div class="box--1-3"></div>
<div class="box--2-0"></div>
<div class="box--2-1"></div>
<div class="box--2-2"></div>
<div class="box--2-3"></div>
<div class="box--3-0"></div>
<div class="box--3-1"></div>
<div class="box--3-2"></div>
<div class="box--3-3"></div>
</div>
</div>
<script>
window.onload=function (){
var games = document.getElementsByClassName('restart')[0];
//设置16个方格样式函数
function setStyle (box) {
for (var i = 0; i < 4; i++){
for (var j = 0; j < 4; j++){
var el = document.getElementsByClassName(box+'--'+i+'-'+j)[0];
el.style.left=20+j*120+'px';
el.style.top=20+i*120+'px';
}
}
};
setStyle('box');
//接着创建另一组16个方格容纳数字---想想,当某位置数字不存在时,容纳数字的方格也不应该存在,所以应该设置一标记来判断数字是否存在,
//例如:当我们初始化开始游戏时只有两个位置有方格,那就意味着只能创建两个方格
// 我们用一个数组标记,初始值都为0;当出现数字,就把值赋给它,然后通过该数组判断。
//1:二维数组生成函数
function getArr () {
var arr =[];
for( var i = 0; i < 4; i++){
arr[i]=[];
for( var j = 0; j < 4; j++){
arr[i][j]=0
}
}
return arr;
}
//标记
var arr1=getArr();
var parents = document.getElementsByClassName('container')[0];
// 2: 创建16个容纳数字的方格函数
function getBoxs(arr1) {
//重新开始先移除包含数字的格子
if(getChild(parents)>16){
removeClassEle('news');
}
for( var i = 0; i < arr1.length; i++){
for( var j = 0; j < arr1[0].length; j++){
if(arr1[i][j]===0){
continue;
}else{
var divs = document.createElement('div');
divs.setAttribute('id','news--'+i+'-'+j);
divs.setAttribute('class','news');
divs.style.left=20+j*120+'px';
divs.style.top=20+i*120+'px';
divs.innerText=arr1[i][j]
parents.appendChild(divs);
}
}
}
}
//点击new game 随机位置生成数字赋予arr1
function randoms(arr) {
var random1 = Math.floor(Math.random()*4);
var random3 = Math.floor(Math.random()*4);
var random4 = Math.floor(Math.random()*4);
var random5 = Math.floor(Math.random()*4);
var random2 = Math.random()>0.5?2:4;
arr[random1][random3]=random2;
arr[random4][random5]=random2;
return arr
}
var arr2=getArr()
//new game点击事件
games.addEventListener('click',function(){
arr2 =randoms(arrval(arr1))
//生成两个随机的包含数字的box
getBoxs(arr2);
})
// 清除数组数据的函数
function arrval(arr){
for( var i = 0; i < arr.length; i++){
for( var j = 0; j < arr[0].length; j++){
arr[i][j]=0
}
}
return arr
}
//清除指定class的元素集合
function removeClassEle(cls){
var arr = document.getElementsByClassName(cls);
var c=arr.length;
var parents = arr[0].parentNode;
for(var i = 0; i<c; i++){
parents.removeChild(arr[0]); //这里有些不明白,为什么移除子元素后arr长度会变呢?arr不是之前读取的吗
}
}
//获取元素的所有子元素的长度
function getChild(pa) {
var arr=[];
var child = pa.childNodes;
for ( var i=0; i<child.length;i++){
if(child[i].nodeType===1){
arr.push(child[i])
}
}
return arr.length;
}
//判断能否向左移动,可以向左移动的条件,1:存在数字的方格左侧不存在数字,2:存在数字但两者相同。x 1 xx | 1,1 xx | 1 x 1 x
function canLeft(arr){
//我通过arr2来判断
for(var i=0;i<arr.length;i++){
//这里j等于1是因为第一列没必要判断,不用左移了
for(var j=1;j<arr[0].length;j++){
for(var k=j-1; k>=0;k--){ //循环判断数字左侧的格子
if(arr[i][k]===0){
arr[i][k]=arr[i][k+1];
arr[i][k+1]=0;
}
else if(arr[i][k]===arr[i][k+1]){
arr[i][k]=arr[i][k]*2;
arr[i][k+1]=0;
}
}
}
}
return arr
}
function canRight(arr){
for(var i=0;i<arr.length;i++){
for (var j=0;j<arr[0].length-1;j++){
for(var k=j+1;k<arr[0].length;k++){
if(arr[i][k]===0){
arr[i][k]=arr[i][k-1];
arr[i][k-1]=0;
} else if(arr[i][k]===arr[i][k-1]){
arr[i][k]=arr[i][k]*2;
arr[i][k-1]=0;
}
}
}
}
return arr;
}
function canUp(arr){
for(var i=1;i<arr.length;i++){
for(var j=0;j<arr[0].length;j++){
for(var k=i-1; k>=0;k--){
if(arr[k][j]===0){
arr[k][j]=arr[k+1][j];
arr[k+1][j]=0;
}else if(arr[k][j]===arr[k+1][j]){
arr[k][j]=arr[k][j]*2;
arr[k+1][j]=0;
}
}
}
}
return arr;
}
function canDown(arr){
for(var i=0;i<arr.length-1;i++){
for(var j=0;j<arr[0].length;j++){
for(var k=i+1; k<arr.length;k++){
if(arr[k][j]===0){
arr[k][j]=arr[k-1][j];
arr[k-1][j]=0;
}else if(arr[k][j]===arr[k-1][j]){
arr[k][j]=arr[k][j]*2;
arr[k-1][j]=0;
}
}
}
}
return arr;
}
//左移事件,首先判断能否左移,然后随机生成数组,左移后,重新设定样式
function goLeft (){
getBoxs(canLeft(arr2));
getBoxs( productRandomBox(arr2));
getColor();
}
//右移事件
function goRight() {
getBoxs(canRight(arr2));
getBoxs( productRandomBox(arr2));
getColor();
}
//上移事件
function goUp() {
getBoxs(canUp(arr2));
getBoxs( productRandomBox(arr2));
getColor();
}
//下移事件
function goDowm (){
getBoxs(canDown(arr2));
getBoxs( productRandomBox(arr2));
getColor();
}
//键盘绑定事件
document.addEventListener('keydown',function(e){
var codes = window.event ? e.keyCode: e.which;
switch (codes) {
case 37 :
goLeft();
break;
case 38:
goUp();
break;
case 39 :
goRight();
break;
case 40:
goDowm();
break;
default :
}
})
//随机生成一个Box
function productRandomBox (arr){
//首先盘算是否有空间
var arr3 =[]; //放剩余空间
var objs;
for (var i=0;i<arr.length;i++){
for (var j=0;j<arr[0].length;j++){
if(arr[i][j]===0){
arr3.push({"x":i,"y":j});
}
}
}
if(arr3.length>0){ //随机生成box的逻辑
objs=Math.floor(Math.random()*(arr3.length));
arr[arr3[objs].x][arr3[objs].y]=getNum()
return arr
}else{
alert('GG思密达')
}
}
//随机生成一个2或者4的数字
function getNum(){
return Math.random()>0.5 ? 2 : 4;
}
}
function setColor(number) {
switch (number) {
case 2:
return "#eee4da";
break;
case 4:
return "#eee4da";
break;
case 8:
return "#f26179";
break;
case 16:
return "#f59563";
break;
case 32:
return "#f67c5f";
break;
case 64:
return "#f65e36";
break;
case 128:
return "#edcf72";
break;
case 256:
return "#edcc61";
break;
case 512:
return "#9c0";
break;
case 1024:
return "#3365a5";
break;
case 2048:
return "#09c";
break;
case 4096:
return "#a6bc";
break;
case 8192:
return "#93c";
break;
}
return "black";
}
//设置颜色的函数
function getColor (){
var arr = document.getElementsByClassName('news');
for(var i=0;i<arr.length;i++){
arr[i].style.backgroundColor=setColor(parseInt(arr[i].innerText));
}
}
</script>
</body>
</html>