JS和H5编写推箱子游戏

推箱子小游戏是一款多年前很流行的小游戏(即使现在也有很多人玩),游戏目的很简单,就是人推箱子,把所有的箱子推到目的地,就游戏成功:看似跟简单的逻辑,其实还是有一定难度的,我也是依靠了别人的帮助才完成的,现在开始介绍如何用js,html5编写该游戏(方便起见我们把人用一个粉圆形代替):

一.能力要求

JavaScript,HTML画布,面向对象的基本思想,合理的编程逻辑。

二.编写顺序

1.pushBox.html文件

2.pojo.js文件(用来存放所有的对象)

3.paint.js文件(用来写画画的语句)

4.game.js文件(用来写运行逻辑部分)

5.allLevels.js文件(用来存放关卡)

*注:这是我的书写习惯,按内容和功能将个各类分开,如有更好地写法欢迎评论

三.开始编写

1.建立基本的pushBox.html文件:

内容很简单,里面仅仅需要标签,设置id,其后的文件在逻辑部分做完后再加进去:

登录后复制

有引入其他四个.js文件,还有一个调用run()方法:

window.onload = function(){run();}

登录后复制

2.写pojo类:

首先我们需要知道总共有这些类:

人,箱子,目标点,砖块和围墙,很简单,所有的类都有color(颜色),size(边长/半径),x(横坐标),y(纵坐标)这些属性。然后我们要记得,人和砖块可能和目标点重合,所以在箱子和人的类里面要加上isOnTarget(是否和目标点重合)属性,这样就完成了:

//人类function Person(x, y){this.color = 'pink';this.size = 20;this.x = x;this.y = y;//判断这个人是否在目标点上this.isOnTarget = false;}//箱子类function Box(x, y){this.color = 'yellow';this.size = 40;this.x = x;this.y = y;//判断某个箱子是否在目标点上this.isOnTarget = false;}//目标点类function Target(x, y){this.size = 12;this.x = x;this.y = y;this.color = 'lime';}//地砖类function Brick(x, y){this.x = x;this.y = y;this.size = 40;}//围墙类function Wall(x, y){this.x = x;this.y = y;this.size = 40;}

登录后复制

3.编写paint.js类

我们需要对刚刚在pojo.js类中写的所有类写出画的方法:

需要注意一点很重要:我们如果使用确定的x,y坐标,比如说要画箱子:

ctx.fillRect(x, y, size, size);

登录后复制

如果如下面的方式调用的话,我们在allLevels里面这样画这个箱子:

ctx.fillRect(500, 500, 40, 40);

登录后复制

我们就无法确定这个箱子的旁边是什么,不好判断,于是没有办法写逻辑层。

所以,我们这样构思:我们用一个二维数组来构造这个关卡,每一个物块(箱子,人,目标点,砖块或者墙)都放到这个数组当中,arr1[][],像这样:

var arr1 = [['','wall','wall','wall','wall','wall','',''],['','wall','brick','person','wall','wall','wall',''],['','wall','brick','box','brick','brick','wall',''],['wall','wall','wall','brick','wall','brick','wall','wall'],['wall','target','wall','brick','wall','brick','brick','wall'],['wall','target','box','brick','brick','wall','brick','wall'],['wall','target','brick','brick','brick','box','brick','wall'],['wall','wall','wall','wall','wall','wall','wall','wall']];

登录后复制

比如说arr1[0][1]就是墙了,这样一来就能写逻辑层了。而且还有一个优点,就是我们在之后创建新关卡的时候很方便,只需要按照坐标顺序在数组里写出来即可。

所以,我们在paint.js里面这样写,每个方法里面都把x和y进行一些运算,使它能正确地在网页中画出:

//首先还是清屏function clearScreen(ctx){ctx.clearRect(0,0,1536,750);}//画人function paintPerson(ctx, x, y, size,color){ctx.beginPath();ctx.fillStyle = color;//我们在内部就写好该往哪里画,传过来的x,y坐标值就可以直接在里面计算了ctx.arc(530+x*size*2+20, 180+y*size*2+20, size, 0, 2*Math.PI);ctx.fill();}//画箱子function paintBox(ctx, x, y, size,color){ctx.beginPath();ctx.fillStyle = color;ctx.fillRect(530+x*size, 180+y*size, size, size);ctx.strokeStyle = 'black';ctx.lineWidth = 2;ctx.moveTo(530+x*size, 180+y*size);ctx.lineTo(530+x*size+size, 180+y*size+size);ctx.stroke();ctx.beginPath();ctx.moveTo(530+x*size+size, 180+y*size);ctx.lineTo(530+x*size, 180+y*size+size);ctx.stroke();ctx.strokeRect(530+x*size, 180+y*size, size, size);}//画目标点function paintTarget(ctx, x, y, size,color){ctx.beginPath();ctx.fillStyle = color;ctx.arc(530+x*size*4+20, 180+y*size*4+20, size, 0, 2*Math.PI);ctx.fill();}//画地砖,其中用了for循环简化了代码量function paintBrick(ctx, x, y, size){ctx.beginPath();ctx.fillStyle = 'blue';ctx.fillRect(530+x*size, 180+y*size, size, size);ctx.strokeStyle = 'lightblue';for(var i = 0; i 

然后,我们在调用画的方法时候这样调用,按照每个物块在数组中的位置进行画画:

unction getMap(ctx, person){clearScreen(ctx);for(var i = 0; i

在game.js里面的run()调用getMap()方法后,效果就是这样:

360截图20180317162412851.jpg

4.game.js类:

首先我们还是需要创建人和箱子的对象:

var person = new Person(0,0);

登录后复制

var boxLevel1Count = 3;var boxes = new Array(boxLevel1Count);for(var i = 0;i

然后我们要知道人在二维数组中的位置(坐标),以及三个箱子在其中的坐标需要以下两个方法:

//找到人的坐标function findPerson(){for (var i = 0; i 

找到人的坐标之后,我们要把person对象的x,y和二维数组里的i,j关联起来,就是:

//接收person的坐标var position = findPerson();//i是person的横坐标var i = position.personX;//j是person的纵坐标var j = position.personY;//使对象的属性和人在二维数组的坐标关联person.x = i;person.y = j;

登录后复制


登录后复制

然后我们就可以开始写逻辑了,比如说用户按方向键左,要判断左边是什么,如果是箱子的话,还要判断箱子的左边是什么:

正确的逻辑如下所示(我们就拿人往左移动为例,然后上下右都是一样的):

360截图20180317162444157.jpg

具体的语法很简单:比如说,按照第一个为例,左边是砖块,并且人踩的不是目标点:

if(arr1[i][j-1] == 'brick'){arr1[i][j-1] = 'person';arr1[i][j] = 'brick';Audio1.src = '走路emm.wav';}

登录后复制

如果我们下一步,人踩到了目标点,我们就要把person.isOnTarget 设置为true,当人移开时候,我们把这个属性设置为false

当人左边是箱子的时候,比较麻烦,首先必须明白有一点:我们到底推的是哪个箱子?之前已经有了一个存放所有箱子的数组了,所以现在需要一个方法,可以让我们知道我们推的是哪个箱子:

function getBoxIndex(boxes, i,j){var index = 0;for(var k = 0;k

在实际调用中,里面的参数(i,j)就写下一步要走的那个位置,比如说向左走,就是

var index = getBoxIndex(boxes, i,j-1);

登录后复制

这个index就是我们要找的第i个箱子了,接下来就很好办了,我们按照刚才的逻辑一步一步写,一堆的if、else,只需注意两点,当人踩到目标点时,把person.isOnTarget = true,移开之后false;箱子踩到目标点时boxes[index].isOnTarget = true,移开之后false,然后再整理一下,简化代码量,就是:

//玩家操作document.onkeydown = function(ev){var oCan = document.getElementById('can1');var ctx = oCan.getContext('2d');var oEvent = ev || event;var Audio1 = document.getElementById('walk');var Audio2 = document.getElementById('push');//接收person的坐标var position = findPerson();//i是person的横坐标var i = position.personX;//j是person的纵坐标var j = position.personY;//使对象的属性和人在二维数组的坐标关联person.x = i;person.y = j;if(oEvent.keyCode == 37){if(person.isOnTarget){if(arr1[i][j-1] == 'brick'){arr1[i][j-1] = 'person';arr1[i][j] = 'target';person.isOnTarget = false;}else if(arr1[i][j-1] == 'box' && arr1[i][j-2] != 'wall' && arr1[i][j-2] != 'box'){var index = getBoxIndex(boxes, i,j-1);if(!boxes[index].isOnTarget){if(arr1[i][j-2] == 'brick'){arr1[i][j-2] = 'box';arr1[i][j-1] = 'person';arr1[i][j] = 'target';person.isOnTarget = false;}else if(arr1[i][j-2] == 'target'){arr1[i][j-2] = 'box';arr1[i][j-1] = 'person';arr1[i][j] = 'target';person.isOnTarget = false;boxes[index].isOnTarget = true;}}else if(boxes[index].isOnTarget){if(arr1[i][j-2] == 'brick'){arr1[i][j-2] = 'box';arr1[i][j-1] = 'person';arr1[i][j] = 'target';boxes[index].isOnTarget = false;}else if(arr1[i][j-2] == 'target'){arr1[i][j-2] = 'box';arr1[i][j-1] = 'person';arr1[i][j] = 'target';}}boxes[index].y--;}else if(arr1[i][j-1] == 'target'){arr1[i][j-1] = 'person';arr1[i][j] = 'target';}}else if(!person.isOnTarget){if(arr1[i][j-1] == 'brick'){arr1[i][j-1] = 'person';arr1[i][j] = 'brick';}else if(arr1[i][j-1] == 'box' && arr1[i][j-2] != 'wall' && arr1[i][j-2] != 'box'){var index = getBoxIndex(boxes, i,j-1);//箱子踩的不是目标点if(!boxes[index].isOnTarget){//箱子左边是地面if(arr1[i][j-2] == 'brick'){arr1[i][j-2] = 'box';arr1[i][j-1] = 'person';arr1[i][j] = 'brick';}//箱子左边是目标点else if(arr1[i][j-2] == 'target'){arr1[i][j-2] = 'box';arr1[i][j-1] = 'person';arr1[i][j] = 'brick';boxes[index].isOnTarget = true;}}else if(boxes[index].isOnTarget){if(arr1[i][j-2] == 'brick'){arr1[i][j-2] = 'box';arr1[i][j-1] = 'person';arr1[i][j] = 'brick';boxes[index].isOnTarget = false;person.isOnTarget = true;}else if(arr1[i][j-2] == 'target'){arr1[i][j-2] = 'box';arr1[i][j-1] = 'person';arr1[i][j] = 'brick';person.isOnTarget = true;}}boxes[index].y--;}else if(arr1[i][j-1] == 'target'){arr1[i][j-1] = 'person';arr1[i][j] = 'brick';person.isOnTarget = true;}}}

登录后复制

这样,向左走的所有逻辑就完成了,然后是上,右,下,接着else if 就行,照猫画虎,把里面的i和j一更换就完成了。

所有逻辑写完,验证无误后,我们要判断通关条件,这个很简单,当所有的箱子都isOnTarget时候,成功,当然是在每次按完方向键之后都要判断:

function judgeWin(boxes){var count = 0;for(var p = 0;p

通关的画面如下:

360截图20180317162516325.jpg

最后,我们加入音效,主要划分成以下几类:人走到砖块的,人推箱子的,人碰到墙的(和人推箱子碰到墙的),成功后的掌声。

总结:

1.我开始以为这个很简单,和我之前做的那个flappy bird 差不多,没想到这里面的逻辑其实很复杂,我的flappy bird链接如下:点击打开链接。所以,一定要在刚开始的时候要构思好大局,别越写越麻烦,容易产生放弃心里。

2.利用二维数组存放地图,然后在paint()方法里面写画的位置,大小等,调用的时候paint()里面就填坐标,这样有两个好处:(1)可以知道每个物块的上下左右都是什么,易于判断;(2)新建关卡的时候易于创建,只需要按照坐标位置,把wall,brick,person,target,box放进去即可

3.在创建人的对象后,我们需要在地图数组中把人的坐标找出来,然后将对象的x,y属性和坐标关联;在创建箱子的对象数组后,我们需要getIndex()方法,找到人到底推的是哪个箱子,才能使这个箱子的isOnTarget改成true或者false,这两点很关键。

登录后复制

以上就是JS和H5编写推箱子游戏的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2781078.html

(0)
上一篇 2025年3月8日 16:12:46
下一篇 2025年2月19日 13:18:16

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • JavaScript和HTML5编写游戏Flappy Bird简易版

    上一篇文章我们和大家分享了JS和H5编写推箱子游戏,本文主要和大家分享用js和H5标签编写经典游戏:Flappy Bird 简易版,希望能帮助到大家。 声明:本人初学js和h5,本文涉及编写方式以及算法如有更好地改进,请各位大佬提出建议~ …

    2025年3月8日 编程技术
    200
  • JS数组去重方法总结

    本文主要和大家分享JS数组去重方法总结,一共有七种方法,希望能帮助到大家。 最简单的方法: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var arr=[2,8,5,0,5,2,6,7,2]…

    编程技术 2025年3月8日
    200
  • node.js玩转进程实例

    本文主要和大家分享node.js玩转进程实例,node提供了child_process模块,我们再将经典的示例代码存为worker.js文件,如下: let http=require(‘http’);http.createServer(fu…

    2025年3月8日
    200
  • 常用的js读写文件排序详解

    最近写js发现很多规则跟自己想的不一样,毕竟刚上手不就,所以绕了很多弯弯,这里总结记录下,本文主要和大家分享常用的js读写文件排序详解,希望能帮助到大家。 1,由于file标签上传时:onchange方法在再次上传相同文件不在被触发 想要被…

    编程技术 2025年3月8日
    200
  • 通过js异步加载图片实现方法

    本文主要和大家分享通过js异步加载图片实现方法,主要是考虑到网络的限制,为了更好的用户体验,采用异步加载显示的方法为img加载图片,直接贴代码:  标签: 登录后复制登录后复制 js: function getHead(obj,portra…

    编程技术 2025年3月8日
    200
  • js如何制作简单的发布功能

    本文主要和大家分享js如何制作简单的发布功能,主要以代码的形式和大家分享,希望能帮助到大家。 代码如下: nbsp;html>                    demo                         .show…

    编程技术 2025年3月8日
    200
  • js编译语言与解释型语言详解

    本文主要和大家分享js基础知识—编译语言与解释型语言,希望能帮助到大家。 1、原始型类型与引用型1. 编译语言与解释型语言的区别 编译型语言:通篇先编译出一个文件,程序会自动执行这个文件。 优点:快; 缺点:不能跨平台。 服务器…

    2025年3月8日
    200
  • JS混合继承详解

    本文主要和大家分享js混合继承详解,希望能帮助到大家。 window.onload=function(){//混合继承:原型实现继承+借用构造函数继承function Person(name,age,gender,wight){this.n…

    编程技术 2025年3月8日
    200
  • js鼠标事件实例详解

    本文主要和大家分享js鼠标事件实例详解,希望能帮助到大家。 一般事件   事件 浏览器支持 描述 onClick HTML: 2 | 3 | 3.2 | 4Browser: IE3 | N2| O3 鼠标点击事件,多用在某个对象控制的范围内…

    编程技术 2025年3月8日
    200
  • JS为动态创建的元素添加事件

    本文主要和大家介绍了js实现为动态创建的元素添加事件操作,涉及javascript页面元素动态添加及事件响应相关操作技巧,需要的朋友可以参考下,希望能帮助到大家。 html中直接生成的元素,添加事件,我们都知道,但是如何为一个动态生成的元素…

    2025年3月8日
    200

发表回复

登录后才能评论