目录
什么是2048
游戏状态机
游戏界面绘制
3.1 界面
3.2 数字的背景颜色
分数逻辑
4.1 加分
4.2 更新最高分
方向控制逻辑
5.1 数组
5.2 随机数
5.3 初始化
5.4 判断数组是否全部填满
5.5 判断方格是否还能移动
5.6 上下左右的监听事件
5.7 移动
完整代码
什么是2048
2048是一款风靡全球的小游戏,具体的玩法就不多说了,最早于2014年Gabriele Cirulli在github发表的版本。
github链接:
https://github.com/claudiopro/2048-react
不过此项目依赖于GULP。
本文就用javascript写出一个较为完整的2048游戏。
以下是本文实现的游戏界面:
代码参考于csdn博客:参考博客
2048的实现可以分为3个部分:游戏界面绘制、分数逻辑和方向控制逻辑。
游戏状态机
游戏界面绘制
3.1 界面
<div id="game">
<span class="container">
<span class="left">
<span class="left-topic">2048</span>
<span class="left-tips">↑上 ↓下 ←左 →右 i重玩</span>
</span>
<span class="right">
<span class="score-box">最高分:<span class="score">0</span></span>
<span class="score-box">得 分:<span class="score">0</span></span>
</span>
</span>
<div id="box">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
3.2 数字的背景颜色
//不同的数字添加不同的背景颜色
function bgcolor(){
for(var i = 0;i <arr.length;i++){
for(var j = 0;j <arr.length;j++){
switch(arr[i][j].innerHTML){
case '2': arr[i][j].style.backgroundColor = "#EEE4DA" ;break;
case '4': arr[i][j].style.backgroundColor = "#EDE0C8" ;break;
case '8': arr[i][j].style.backgroundColor = "#F2B179" ;break;
case '16': arr[i][j].style.backgroundColor = "#F59563" ;break;
case '32': arr[i][j].style.backgroundColor = "#F67C5F" ;break;
case '64': arr[i][j].style.backgroundColor = "#F65E3B" ;break;
case '128': arr[i][j].style.backgroundColor = "#EDCF72" ;break;
case '256': arr[i][j].style.backgroundColor = "#EDCC61" ;break;
case '512': arr[i][j].style.backgroundColor = "#EDC850" ;break;
case '1024': arr[i][j].style.backgroundColor = "yellowgreen" ;break;
case '2048': arr[i][j].style.backgroundColor = "perple" ;
init();
alert('游戏胜利');
break;
default: arr[i][j].style.backgroundColor = "#CDC1B4" ;break;
}
}
}
}
如果出现了2048,就代表游戏胜利。
分数逻辑
//最高分
var high = 0;
//得分
var score = 0;
设两个变量,high和score。
4.1 加分
//加分
function addScore(s) {
score += s;
document.getElementsByClassName('score')[1].innerHTML = score;
}
在每次上下左右操作中,如果存在可以合并的情况,就加上合并的值。
4.2 更新最高分
//更新最高分
if(score>high)
document.getElementsByClassName('score')[0].innerHTML = high = score;
在玩家需要重玩的时候,初始化数组,如果得分比最高分要高的话就更新。
方向控制逻辑
5.1 数组
var divs= document.querySelectorAll("#box>div");
var arr = [[],[],[],[]];
游戏的方格其实对应着一个4*4的二维数组,divs对应着数组的html对象,arr对应着div。
5.2 随机数
//随机产生一个数字
function rand(){
var x=Math.floor(Math.random()*4);
var y=Math.floor(Math.random()*4);
if(arr[x][y].innerHTML == ""){
arr[x][y].innerHTML = Math.random() > 0.5 ? 2 : 4;
}else{
rand();
}
}
随机生成2和4。
5.3 初始化
//初始化
function init(){
for(var i = 0;i <arr.length;i++){
for(var j = 0;j <arr.length;j++){
arr[i][j] = divs[num];
arr[i][j].innerHTML = '';
num++;
}
}
//初始化遍历元素
num = 0;
//更新最高分
if(score>high)
document.getElementsByClassName('score')[0].innerHTML = high = score;
//初始化得分
document.getElementsByClassName('score')[1].innerHTML = score = 0;
//游戏开始产生2个随机数
rand();
rand();
bgcolor();
}
5.4 判断数组是否全部填满
//判断方格是否全部填满
function isFull(){
var bool=true;
for(var i = 0;i <arr.length;i++){
for(var j = 0;j <arr.length;j++){
if(arr[i][j].innerHTML == "" ){
bool = false;
}
}
}
if(bool){
isChange();
}else{
rand();
}
}
设一个布尔值,如果遇到了空就代表游戏可以继续。
5.5 判断方格是否还能移动
//判断方格是否还能移动
function isChange(){
var bool = true;
for(var i = 0;i < arr.length-1 ;i++){
for(var j = 0;j< arr.length-1;j++){
if(arr[i][j].innerHTML == arr[i][j+1].innerHTML || arr[i][j].innerHTML == arr[i+1][j].innerHTML || arr[i+1][j].innerHTML == arr[i+1][j+1].innerHTML || arr[i][j+1].innerHTML == arr[i+1][j+1].innerHTML ){
bool = false;
}
}
}
if(bool){
alert("游戏结束!");
init();
}
}
如果数组中某行某列有相同的就代表可以继续移动。
5.6 上下左右的监听事件
//上下左右的监听事件
window.onkeydown = function(e){
switch(e.keyCode){
case 37 : isFull(); left();bgcolor(); break;//左
case 38 : isFull(); up();bgcolor(); break;//上
case 39 : isFull(); right();bgcolor(); break;//右
case 40 : isFull(); down(); bgcolor(); break;//下
case 73 : init(); break;//初始化
}
}
每执行一个事件,需要判断数组是不是满的,如果未满就一定可以继续游戏,如果满了,则需要判断数组中的元素是否还能继续移动。
5.7 移动
上下左右移动的逻辑都是一样的,这里以右移为例。
//右
function right(){
for(var i = 0;i <4;i++){
for(var j = 0;j <4;j++){
if( j<3&&arr[i][j].innerHTML !=""&& arr[i][j+1].innerHTML==""){
arr[i][j+1].innerHTML = arr[i][j].innerHTML;
arr[i][j].innerHTML="";
right();
}else if(j<3&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i][j+1].innerHTML){
arr[i][j+1].innerHTML *=2;
addScore(arr[i][j+1].innerHTML*1)
arr[i][j].innerHTML ="";
}
}
}
}
对于数组,有的可能没有数据,如果有数据则找出下一个相同的数据进行合并。
完整代码
演示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<style>
.container{
display: flex;
}
.left{
width: 250px;
font-size: 10px;
display: flex;
flex-direction: column;
}
.left-tips{
position: relative;
top: 10px;
font-weight: bold;
color:beige;
}
.left-topic{
font-weight: bold;
color:rgba(172, 130, 75, 0.911);
font-size: 40px;
}
.right{
display: flex;
flex-direction: column;
position: relative;
left: 45px;
color:blanchedalmond;
}
.score-box{
width: 200px;
height: 30px;
border: 1px solid transparent;
border-radius: 5px;
margin-top: 5px;
margin-bottom: 5px;
font-weight: bold;
font-size: 25px;
}
.score{
font-weight: bold;
font-size: 25px;
}
#game{
width: 500px;
height: 530px;
background-color: #BBADA0;
display: flex;
justify-content: space-evenly;
flex-wrap: wrap;
border-radius: 0.5em;
margin: 100px auto;
}
#box{
display: flex;
justify-content: space-evenly;
flex-wrap: wrap;
border-radius: 0.5em;
}
#box div{
width: 100px;
height: 100px;
border: 1px solid transparent;
background-color: #CDC1B4;
font-size: 50px;
text-align: center;
line-height: 100px;
font-weight: bold;
border-radius: 10px;
margin-top: 10px;
color:rgba(172, 141, 101, 0.911);
}
</style>
<body>
<div id="game">
<span class="container">
<span class="left">
<span class="left-topic">2048</span>
<span class="left-tips">↑上 ↓下 ←左 →右 i重玩</span>
</span>
<span class="right">
<span class="score-box">最高分:<span class="score">0</span></span>
<span class="score-box">得 分:<span class="score">0</span></span>
</span>
</span>
<div id="box">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<script >
//最高分
var high = 0;
//得分
var score = 0;
var divs= document.querySelectorAll("#box>div");
var arr = [[],[],[],[]];
var num=0;
/*
主逻辑
*/
//初始化
init();
//上下左右的监听事件
window.onkeydown = function(e){
switch(e.keyCode){
case 37 : isFull(); left();bgcolor(); break;//左
case 38 : isFull(); up();bgcolor(); break;//上
case 39 : isFull(); right();bgcolor(); break;//右
case 40 : isFull(); down(); bgcolor(); break;//下
case 73 : init(); break;//初始化
}
}
//随机产生一个数字
function rand(){
var x=Math.floor(Math.random()*4);
var y=Math.floor(Math.random()*4);
if(arr[x][y].innerHTML == ""){
arr[x][y].innerHTML = Math.random() > 0.5 ? 2 : 4;
}else{
rand();
}
}
//初始化
function init(){
for(var i = 0;i <arr.length;i++){
for(var j = 0;j <arr.length;j++){
arr[i][j] = divs[num];
arr[i][j].innerHTML = '';
num++;
}
}
//初始化遍历元素
num = 0;
//更新最高分
if(score>high)
document.getElementsByClassName('score')[0].innerHTML = high = score;
//初始化得分
document.getElementsByClassName('score')[1].innerHTML = score = 0;
//游戏开始产生2个随机数
rand();
rand();
bgcolor();
}
//加分
function addScore(s) {
score += s;
document.getElementsByClassName('score')[1].innerHTML = score;
}
//判断方格是否全部填满
function isFull(){
var bool=true;
for(var i = 0;i <arr.length;i++){
for(var j = 0;j <arr.length;j++){
if(arr[i][j].innerHTML == "" ){
bool = false;
}
}
}
if(bool){
isChange();
}else{
rand();
}
}
//判断方格是否还能移动
function isChange(){
var bool = true;
for(var i = 0;i < arr.length-1 ;i++){
for(var j = 0;j< arr.length-1;j++){
if(arr[i][j].innerHTML == arr[i][j+1].innerHTML || arr[i][j].innerHTML == arr[i+1][j].innerHTML || arr[i+1][j].innerHTML == arr[i+1][j+1].innerHTML || arr[i][j+1].innerHTML == arr[i+1][j+1].innerHTML ){
bool = false;
}
}
}
if(bool){
alert("游戏结束!");
init();
}
}
//不同的数字添加不同的背景颜色
function bgcolor(){
for(var i = 0;i <arr.length;i++){
for(var j = 0;j <arr.length;j++){
switch(arr[i][j].innerHTML){
case '2': arr[i][j].style.backgroundColor = "#EEE4DA" ;break;
case '4': arr[i][j].style.backgroundColor = "#EDE0C8" ;break;
case '8': arr[i][j].style.backgroundColor = "#F2B179" ;break;
case '16': arr[i][j].style.backgroundColor = "#F59563" ;break;
case '32': arr[i][j].style.backgroundColor = "#F67C5F" ;break;
case '64': arr[i][j].style.backgroundColor = "#F65E3B" ;break;
case '128': arr[i][j].style.backgroundColor = "#EDCF72" ;break;
case '256': arr[i][j].style.backgroundColor = "#EDCC61" ;break;
case '512': arr[i][j].style.backgroundColor = "#EDC850" ;break;
case '1024': arr[i][j].style.backgroundColor = "yellowgreen" ;break;
case '2048': arr[i][j].style.backgroundColor = "perple" ;
init();
alert('游戏胜利');
break;
default: arr[i][j].style.backgroundColor = "#CDC1B4" ;break;
}
}
}
}
//上下左右按下执行的函数
//右
function right(){
for(var i = 0;i <4;i++){
for(var j = 0;j <4;j++){
if( j<3&&arr[i][j].innerHTML !=""&& arr[i][j+1].innerHTML==""){
arr[i][j+1].innerHTML = arr[i][j].innerHTML;
arr[i][j].innerHTML="";
right();
}else if(j<3&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i][j+1].innerHTML){
arr[i][j+1].innerHTML *=2;
addScore(arr[i][j+1].innerHTML*1)
arr[i][j].innerHTML ="";
}
}
}
}
//左
function left(){
for(var i = 0;i <4;i++){
for(var j = 0;j <4;j++){
if( j>0&&arr[i][j].innerHTML !=""&& arr[i][j-1].innerHTML==""){
arr[i][j-1].innerHTML = arr[i][j].innerHTML;
arr[i][j].innerHTML="";
left();
}else if(j>0&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i][j-1].innerHTML){
arr[i][j-1].innerHTML *=2;
addScore(arr[i][j-1].innerHTML*1)
arr[i][j].innerHTML ="";
}
}
}
}
//下
function down(){
for(var i = 0;i <4;i++){
for(var j = 0;j <4;j++){
if( i<3&&arr[i][j].innerHTML !=""&& arr[i+1][j].innerHTML==""){
arr[i+1][j].innerHTML = arr[i][j].innerHTML;
arr[i][j].innerHTML="";
down();
}else if(i<3&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i+1][j].innerHTML){
arr[i+1][j].innerHTML *=2;
addScore(arr[i+1][j].innerHTML*1)
arr[i][j].innerHTML ="";
}
}
}
}
//上
function up(){
for(var i = 0;i <4;i++){
for(var j = 0;j <4;j++){
if( i>0&&arr[i][j].innerHTML !=""&& arr[i-1][j].innerHTML==""){
arr[i-1][j].innerHTML = arr[i][j].innerHTML;
arr[i][j].innerHTML="";
up();
}else if(i>0&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i-1][j].innerHTML){
arr[i-1][j].innerHTML *=2;
addScore(arr[i-1][j].innerHTML*1)
arr[i][j].innerHTML ="";
}
}
}
}
</script>
</body>
</html>