JavaScript實作2048小游戲
作者簡介
作者名:編程界明世隱
簡介:CSDN博客專家,從事軟體開發多年,精通Java、JavaScript,博主也是從零開始一步步把學習成長、深知學習和積累的重要性,喜歡跟廣大ADC一起打野升級,歡迎您關注,期待與您一起學習、成長、起飛!
系列目錄
1. JavaScript 貪吃蛇游戲
2. JavaScript 俄羅斯方塊
3. JavaScript 掃雷小游戲
4. JavaScript 網紅太空人表盤
效果圖

實作思路
- 撰寫頁面和畫布代碼,
- 繪制背景,
- 繪制好全部卡片,
- 隨機生成一個卡片(2或者4),
- 鍵盤事件監聽(上、下、左、右鍵監聽),
- 根據鍵盤的方向,處理數字的移動合并,
- 加入成功、失敗判定,
- 處理其他收尾作業,
代碼實作
撰寫頁面代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2048</title>
<style>
#box{
width:370px;
height:370px;
position:absolute;
margin:0 auto;
left:0;
right:0;
top:1px;
bottom:0;
}
.rebutton{
position: absolute;
top:370px;
left:38%;
}
</style>
</head>
<body>
<div id='box'></div>
<button onclick="restart()" class='rebutton'>重開</button>
</body>
<script src="js/util.js"></script>
<script src="js/2048.js"></script>
<script type="text/javascript">
</script>
</html>
添加畫布
在2048.js撰寫代碼
- 創建函式
function G2048(){
this.renderArr=[];//渲染陣列
this.cards=initCardArray();
//游戲標記
this.flag='start';
}
//初始化陣列
function initCardArray(){
var cards = new Array();
for (var i = 0; i < 4; i++) {
cards[i] = new Array();
for (var j = 0; j < 4; j++) {
//cards[i][j]=null;
}
}
return cards;
}
- 初始化和繪制背景代碼(在2048.js中撰寫)
//初始化
G2048.prototype.init=function(el,musicObj){
if(!el) return ;
this.el=el;
var canvas = document.createElement('canvas');//創建畫布
canvas.style.cssText="background:white;";
var W = canvas.width = 370; //設定寬度
var H = canvas.height = 370;//設定高度
el.appendChild(canvas);//添加到指定的dom物件中
this.ctx = canvas.getContext('2d');
this.draw();
}
//繪制入口
G2048.prototype.draw=function(){
//創建背景
this.drawGB();
//渲染到頁面上
this.render();
}
//創建背景
G2048.prototype.drawGB=function(){
var bg = new _.Rect({x:0,y:0,width:364,height:364,fill:true,fillStyle:'#428853'});
this.renderArr.push(bg);
}
//渲染圖形
G2048.prototype.render=function(){
var context=this.ctx;
this.clearCanvas();
_.each(this.renderArr,function(item){
item && item.render(context);
});
}
//清洗畫布
G2048.prototype.clearCanvas=function() {
this.ctx.clearRect(0,0,parseInt(this.w),parseInt(this.h));
}
- 在頁面代碼中加入以下 js 代碼
var box = document.getElementById('box');
g2048.init(box);

運行效果:

繪制好全部卡片
- 創建Card
//定義Card
function Card(i,j){
this.i=i;//下標i
this.j=j;//下標j
this.x=0;// x坐標
this.y=0;// y坐標
this.h=80;//高
this.w=80;//寬
this.start=10;//偏移量(固定值)
this.num=0;//顯示數字
this.merge=false;//當前是否被合并過,如果合并了,則不能繼續合并,針對當前輪
//初始化創建
this.obj = this.init();
//創建顯示數字物件
this.numText = this.initNumText();
}
//初始創建
Card.prototype.init=function(){
return new _.Rect({x:this.x,y:this.y,width:this.w,height:this.h,fill:true});
}
//根據i j計算x y坐標
Card.prototype.cal=function(){
this.x = this.start + this.j*this.w + (this.j+1)*5;
this.y = this.start + this.i*this.h + (this.i+1)*5;
//更新給obj
this.obj.x=this.x;
this.obj.y=this.y;
//設定填充顏色
this.obj.fillStyle=this.getColor();
//更新文字的位置
this.numText.x = this.x+40;
this.numText.y = this.y+55;
this.numText.text=this.num;
}
//初始化顯示數字物件
Card.prototype.initNumText=function(){
var font = "34px 思源宋體";
var fillStyle = "#7D4E33";
return new _.Text({x:this.x,y:this.y+50,text:this.num,fill:true,textAlign:'center',font:font,fillStyle:fillStyle});
}
//獲取color
Card.prototype.getColor=function(){
var color;
//根據num設定顏色
switch (this.num) {
case 2:
color = "#EEF4EA";
break;
case 4:
color = "#DEECC8";
break;
case 8:
color = "#AED582";
break;
case 16:
color = "#8EC94B";
break;
case 32:
color = "#6F9430";
break;
case 64:
color = "#4CAE7C";
break;
case 128:
color = "#3CB490";
break;
case 256:
color = "#2D8278";
break;
case 512:
color = "#09611A";
break;
case 1024:
color = "#F2B179";
break;
case 2048:
color = "#DFB900";
break;
default://默認顏色
color = "#5C9775";
break;
}
return color;
}
Card.prototype.render=function(context){
//計算坐標等
this.cal();
//執行繪制
this.obj.render(context);
//是否繪制文字的處理
if(this.num!=0){
this.numText.render(context);
}
}
}
- 創建卡片
//創建卡片
G2048.prototype.drawCard=function(){
var that=this;
var card;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
card = new Card(i,j);
that.cards[i][j]=card;
that.renderArr.push(card);
}
}
}
- 呼叫繪制代碼

運行效果:

- 修改一下卡片的默認數字


隨機生成一個卡片,2或者4
- 先把Card中 num 默認改成0
- 因為2跟4出現的比例是1:4,所以采用隨機出1-5的數字,當是1的時候就表示,當得到2、3、4、5的時候就表示要出現數字2.
- 隨機獲取i,j 就可以得到卡片的位置,割接i,j取到card實體,如果卡片沒有數字,就表示可以,否則就遞回繼續取,取到為止,
- 把剛才取到的數字,設定到card實體物件中就好了,
代碼如下:
//隨機創建一個卡片
G2048.prototype.createRandomNumber=function(){
var num = 0;
var index = _.getRandom(1,6);//這樣取出來的就是1-5 之間的亂數
//因為2和4出現的概率是1比4,所以如果index是1,則創建數字4,否則創建數字2(1被隨機出來的概率就是1/5,而其他就是4/5 就是1:4的關系)
console.log('index==='+index)
if(index==1){
num = 4;
}else {
num = 2;
}
//判斷如果格子已經滿了,則不再獲取,退出
if(this.cardFull()){
return ;
}
//獲取隨機卡片,不為空的
var card = this.getRandomCard();
//給card物件設定數字
if(card!=null){
card.num=num;
}
}
//獲取隨機卡片,不為空的
G2048.prototype.getRandomCard=function(){
var i = _.getRandom(0,4);
var j = _.getRandom(0,4);
var card = this.cards[i][j];
if(card.num==0){//如果是空白的卡片,則找到了,直接回傳
return card;
}
//沒找到空白的,就遞回,繼續尋找
return this.getRandomCard();
}
//判斷格子滿了
G2048.prototype.cardFull=function() {
var card;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
card = this.cards[i][j];
if(card.num==0){//有一個為空,則沒滿
return false;
}
}
}
return true;
}
draw方法中呼叫,表示打開游戲默認一個數字

運行效果:

加入鍵盤事件
同樣要在draw方法中呼叫哦
//按鍵的控制
G2048.prototype.control=function(){
var that=this;
global.addEventListener('keydown',function(e){
console.log(that.flag)
if(that.flag!='start') return ;
var dir;
switch (e.keyCode){
case 87://w
case 38://上
dir=1;//上移動
break;
case 68://d
case 39://右
dir=2;//右移動
break;
case 83://s
case 40://下
dir=3;//下移動
break;
case 65://a
case 37://左
dir=4;//左移動
break;
}
//卡片移動的方法
that.moveCard(dir);
});
}
- 加入移動邏輯處理代碼
//卡片移動的方法
G2048.prototype.moveCard=function(dir) {
//將卡片清理一遍,因為每輪移動會設定合并標記,需重置
this.clearCard();
if(dir==1){//向上移動
this.moveCardTop(true);
}else if(dir==2){//向右移動
this.moveCardRight(true);
}else if(dir==3){//向下移動
this.moveCardBottom(true);
}else if(dir==4){//向左移動
this.moveCardLeft(true);
}
//移動后要創建新的卡片
this.createRandomNumber();
//重繪
this.render();
//判斷游戲是否結束
this.gameOverOrNot();
}
//將卡片清理一遍,因為每輪移動會設定合并標記,需重置
G2048.prototype.clearCard=function() {
var card;
for (var i = 0; i < 4; i++) {//i從1開始,因為i=0不需要移動
for (var j = 0; j < 4; j++) {
card = this.cards[i][j];
card.merge=false;
}
}
}
- 加入上下左右處理邏輯
//向上移動
G2048.prototype.moveCardTop=function(bool) {
var res = false;
var card;
for (var i = 1; i < 4; i++) {//i從1開始,因為i=0不需要移動
for (var j = 0; j < 4; j++) {
card = this.cards[i][j];
if(card.num!=0){//只要卡片不為空,要移動
if(card.moveTop(this.cards,bool)){//向上移動
res = true;//有一個為移動或者合并了,則res為true
}
}
}
}
return res;
}
//向右移動
G2048.prototype.moveCardRight=function(bool) {
var res = false;
var card;
for (var i = 0; i < 4; i++) {
for (var j = 3; j >=0 ; j--) {//j從COLS-1開始,從最右邊開始移動遞減
card = this.cards[i][j];
if(card.num!=0){//只要卡片不為空,要移動
if(card.moveRight(this.cards,bool)){//向右移動
res = true;//有一個為移動或者合并了,則res為true
}
}
}
}
return res;
}
//向下移動
G2048.prototype.moveCardBottom=function(bool) {
var res = false;
var card;
for (var i = 3; i >=0; i--) {//i從ROWS-1開始,往下遞減移動
for (var j = 0; j < 4; j++) {
card = this.cards[i][j];
if(card.num!=0){//只要卡片不為空,要移動
if(card.moveBottom(this.cards,bool)){//下移動
res = true;//有一個為移動或者合并了,則res為true
}
}
}
}
return res;
}
//向左移動
G2048.prototype.moveCardLeft=function(bool) {
var res = false;
var card;
for (var i = 0; i < 4; i++) {
for (var j = 1; j < 4 ; j++) {//j從1開始,從最左邊開始移動
card = this.cards[i][j];
if(card.num!=0){//只要卡片不為空,要移動
if(card.moveLeft(this.cards,bool)){//向左移動
res = true;//有一個為移動或者合并了,則res為true
}
}
}
}
return res;
}
- 在Card中加入向上移動的處理邏輯
- 從第2行開始移動,因為第一行不需要移動,
- 只要卡片的數字不是0,就表示要移動,
- 根據 i-1 可以獲取到上一個卡片,如果上一個卡片是空,則把當前卡片交換上去,并且遞回,因為可能要繼續往上移動,
- 如果當前卡片與上一個卡片是相同數字的,則要合并,
- 以上兩種都不是,則不做操作,
//卡片向上移動
Card.prototype.moveTop=function(cards,bool) {
var i=this.i;
var j=this.j;
//設定退出條件
if(i==0){//已經是最上面了
return false;
}
//上面一個卡片
var prev = cards[i-1][j];
if(prev.num==0){//上一個卡片是空
//移動,本質就是設定數字
if(bool){//bool為true才執行,因為flase只是用來判斷能否移動
prev.num=this.num;
this.num=0;
//遞回操作(注意這里是要 prev 來 move了)
prev.moveTop(cards,bool);
}
return true;
}else if(prev.num==this.num && !prev.merge){//合并操作(如果已經合并了,則不運行再次合并,針對當然輪)
if(bool){bool為true才執行
prev.merge=true;
prev.num=this.num*2;
this.num=0;
}
return true;
}else {//上一個的num與當前num不同,無法移動,并退出
return false;
}
}

- 在Card中加入其他3個方向的代碼
//向下移動
Card.prototype.moveBottom=function(cards,bool) {
var i=this.i;
var j=this.j;
//設定退出條件
if(i==3){//已經是最下面了
return false;
}
//上面一個卡片
var prev = cards[i+1][j];
if(prev.num==0){//上一個卡片是空
//移動,本質就是設定數字
if(bool){//bool為true才執行,因為flase只是用來判斷能否移動
prev.num=this.num;
this.num=0;
//遞回操作(注意這里是要 prev 來 move了)
prev.moveBottom(cards,bool);
}
return true;
}else if(prev.num==this.num && !prev.merge){//合并操作(如果已經合并了,則不運行再次合并,針對當然輪)
if(bool){bool為true才執行
prev.merge=true;
prev.num=this.num*2;
this.num=0;
}
return true;
}else {//上一個的num與當前num不同,無法移動,并退出
return false;
}
}
//向右移動
Card.prototype.moveRight=function(cards,bool) {
var i=this.i;
var j=this.j;
//設定退出條件
if(j==3){//已經是最右邊了
return false;
}
//上面一個卡片
var prev = cards[i][j+1];
if(prev.num==0){//上一個卡片是空
//移動,本質就是設定數字
if(bool){//bool為true才執行,因為flase只是用來判斷能否移動
prev.num=this.num;
this.num=0;
//遞回操作(注意這里是要 prev 來 move了)
prev.moveRight(cards,bool);
}
return true;
}else if(prev.num==this.num && !prev.merge){//合并操作(如果已經合并了,則不運行再次合并,針對當然輪)
if(bool){bool為true才執行
prev.merge=true;
prev.num=this.num*2;
this.num=0;
}
return true;
}else {//上一個的num與當前num不同,無法移動,并退出
return false;
}
}
//向左移動
Card.prototype.moveLeft=function(cards,bool) {
var i=this.i;
var j=this.j;
//設定退出條件
if(j==0){//已經是最左邊了
return false;
}
//上面一個卡片
var prev = cards[i][j-1];
if(prev.num==0){//上一個卡片是空
//移動,本質就是設定數字
if(bool){//bool為true才執行,因為flase只是用來判斷能否移動
prev.num=this.num;
this.num=0;
//遞回操作(注意這里是要 prev 來 move了)
prev.moveLeft(cards,bool);
}
return true;
}else if(prev.num==this.num && !prev.merge){//合并操作(如果已經合并了,則不運行再次合并,針對當然輪)
if(bool){bool為true才執行
prev.merge=true;
prev.num=this.num*2;
this.num=0;
}
return true;
}else {//上一個的num與當前num不同,無法移動,并退出
return false;
}
}
運行效果:

做到這里就基本完成了,加入其他一下輔助的東西就行了,比如重新開始、游戲勝利,游戲結束等,也就不多說了,
看到這里的大佬,動動發財的小手 點贊 + 回復 + 收藏,能【 關注 】一波就更好了,
代碼獲取方式:
幫忙文章【點贊】 +【 收藏】+【關注】+【評論】 后,加我主頁左邊的微信 或者 私聊我,我發給你!
更多精彩
1. Java俄羅斯方塊
2. Java五子棋小游戲
3. 老Java程式員花一天時間寫了個飛機大戰
4. Java植物大戰僵尸
5. 老Java程式員花2天寫了個連連看
6. Java消消樂(天天愛消除)
7. Java貪吃蛇小游戲
8. Java掃雷小游戲
9. Java坦克大戰
10. Java迷宮小游戲
相關閱讀
1. JavaWeb圖書管理系統
2. JavaWeb學生宿舍管理系統
3. JavaWeb在線考試系統
另外
為了幫助更多小白從零進階 Java 工程師,從CSDN官方那邊搞來了一套 《Java 工程師學習成長知識圖譜》,尺寸 870mm x 560mm,展開后有一張辦公桌大小,也可以折疊成一本書的尺寸,原件129元現價 29 元,先到先得,有興趣的小伙伴可以了解一下!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/300463.html
標籤:java
上一篇:??高級JAVA開發必備技能??java8 JSR-310判斷是否閏年實作,發現原作者的代碼可能有問題(JAVA 小虛竹,建議收藏)
下一篇:2021-09-15
