jQuery版推箱子游戏详解和源码

前言

偶然间看到很多用js写游戏的感觉很炫酷的样子,所以就想试试,就看了一些资料和某前端站点的视屏。于是乎就自己动手实践了一下,上推箱子截图

pushbox

感觉很丑陋,但是功能是实现了。再说貌似大多都是这样的吧,这一关其实还是有点难度的,我做完之后想检测一下下一关正确么,居然玩了20分钟才通关。

如果你看到这张图让你想起了你童年的回忆,说明你老了,这里可以试玩一下(很遗憾没有链接地址,最后又源码可以下载)。

css布局

主要考虑的是地图是怎么动态生成的,地图中有灰色的,还有墙,箱子,蓝色,红色背景,人物。先看css代码吧

 

* {
            padding: 0;
            margin: 0;
        }

        img {
            border: 0;
        }

        #container {
            position: relative;
            margin: 20px auto;
        }

        .pos1 {
            width: 50px;
            height: 50px;
            float: left;
            background: #666;
        }

        .pos2 {
            width: 50px;
            height: 50px;
            float: left;
            background: url(images/wall.png);
        }

        .pos3 {
            width: 50px;
            height: 50px;
            float: left;
            background: red;
        }

        .pos0 {
            width: 50px;
            height: 50px;
            float: left;
            background: blue;
        }

        .box {
            width: 50px;
            height: 50px;
            position: absolute;
            background: url(images/box.png);
        }

        .person {
            width: 50px;
            height: 50px;
            position: absolute;
            background: url(images/person.png);
        }

代码中的pos0/pos1/pos2/pos3/主要是墙,箱子,蓝色红色背景的样式,其中person和box就是人物和箱子的样式,

这里用样式下标来节省部分js代码

其次body中html布局,这里就很简单了,就是一个带id的div,其余的内容均动态生成,因为每个关卡的地图数据都是不一样的。

js代码部分

 

  1 $(function () {
  2             Game.init($("#container"));//初始化容器
  3         });
  4         var Game = {
  5             gk: [{//关卡
  6                 map: [//地图数据 按照坐标呈现的数组格式
  7                 1, 1, 2, 2, 2, 2, 1, 1,
  8                 1, 1, 2, 3, 3, 2, 1, 1,
  9                 1, 2, 2, 0, 3, 2, 2, 1,
 10                 1, 2, 0, 0, 0, 3, 2, 1,
 11                 2, 2, 0, 0, 0, 0, 2, 2,
 12                 2, 0, 0, 2, 0, 0, 0, 2,
 13                 2, 0, 0, 0, 0, 0, 0, 2,
 14                 2, 2, 2, 2, 2, 2, 2, 2
 15                 ],
 16                 box: [//箱子 坐标点对象
 17                     { x: 4, y: 3 },
 18                     { x: 3, y: 4 },
 19                     { x: 4, y: 5 },
 20                     { x: 5, y: 5 }
 21                 ],
 22                 person: { x: 3, y: 6 }//人物 坐标点对象
 23             },
 24             {
 25                 map: [
 26                 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1,
 27                 1, 1, 1, 1, 2, 0, 2, 2, 0, 0, 2, 1,
 28                 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 2, 1,
 29                 2, 2, 2, 2, 0, 0, 2, 0, 0, 0, 2, 1,
 30                 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 2, 2,
 31                 3, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2,
 32                 3, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2,
 33                 3, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2,
 34                 3, 3, 3, 2, 2, 2, 0, 0, 2, 0, 0, 2,
 35                 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 1,
 36                 1, 1, 1, 1, 2, 0, 0, 2, 0, 0, 2, 1,
 37                 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1,
 38                 ],
 39                 box: [
 40                     { x: 8, y: 3 },
 41                     { x: 9, y: 3 },
 42                     { x: 7, y: 4 },
 43                     { x: 6, y: 7 },
 44                     { x: 7, y: 5 },
 45                     { x: 7, y: 8 },
 46                     { x: 8, y: 9 },
 47                     { x: 4, y: 5 },
 48                     { x: 6, y: 6 }
 49 
 50                 ],
 51                 person: { x: 3, y: 6 }
 52             }
 53             ],
 54             init: function (oParent) {
 55                 this.oParent = oParent;//此处将外层的对象引进来 
 56                 this.iNow = 0;
 57                 this.createMap(this.iNow);
 58             },
 59             createMap: function (iNow) {
 60                 //创建地图 很关键的是 将元素的样式下标和地图的坐标点关联
 61  this.oParent.empty(); document.title = "第" + (iNow + 1) + "关";
 62                 this.newJson = this.gk[iNow];
 63 
 64                 this.oParent.css("width", Math.sqrt(this.newJson.map.length) * 50);
 65                 var tempHtml = '';
 66                 $.each(this.newJson.map, $.proxy(function (i, elem) {
 67                     tempHtml += '<div class="pos' + elem + '"></div>';
 68                 }, this));
 69                 this.oParent.append(tempHtml);
 70                 this.createBox();
 71                 this.createPerson();
 72             },
 73             createBox: function () {//布局箱子所在的位置
 74                 $.each(this.newJson.box, $.proxy(function (i, elem) {
 75                     var oBox = $('<div class="box"></div>');
 76                     oBox.css({ 'left': elem.x * 50, 'top': elem.y * 50 });
 77                     this.oParent.append(oBox);
 78                 }, this));
 79             },
 80             createPerson: function () {//布局人物所在的位置
 81                 var oPerson = $('<div class="person"></div>');
 82                 var pos = this.newJson.person;
 83                 oPerson.css({ 'left': pos.x * 50, 'top': pos.y * 50 });
 84                 oPerson.data('x', pos.x);//缓存在oPerson上的数据
 85                 oPerson.data('y', pos.y);
 86                 this.oParent.append(oPerson);
 87                 this.bindPerson(oPerson);
 88             },
 89             bindPerson: function (oPerson) {//绑定对人物←↑→↓操作
 90                 $(document).keydown($.proxy(function (ev) {
 91                     switch (ev.which) {
 92                         case 37: //
 93                             oPerson.css('backgroundPosition', '-150px 0');
 94                             this.movePerson(oPerson, { x: -1 });
 95                             break;
 96                         case 38: //
 97                             oPerson.css("backgroundPosition", "0 0");
 98                             this.movePerson(oPerson, { y: -1 });
 99                             break;
100                         case 39: //
101                             oPerson.css("backgroundPosition", "-50px 0");
102                             this.movePerson(oPerson, { x: 1 });
103                             break;
104                         case 40: //
105                             oPerson.css("backgroundPosition", "100px 0");
106                             this.movePerson(oPerson, { y: 1 });
107                             break;
108                         default:
109                     }
110                 }, this));
111             },
112             movePerson: function (oP, opt) {//移动人物
113                 var xValue = opt.x || 0;
114                 var yValue = opt.y || 0;
115                 var length = Math.sqrt(this.newJson.map.length);
116                 var currentMapIndex = (oP.data('x') + xValue) + (oP.data('y') + yValue) * length;
117                 if (this.newJson.map[currentMapIndex] != 2) {//遇到墙的判断
118                     oP.data('x', oP.data('x') + xValue);
119                     oP.data('y', oP.data('y') + yValue);
120                     oP.css({ "left": oP.data("x") * 50, "top": oP.data("y") * 50 });
121                     $(".box").each($.proxy(function (i, elem) {
122                         //当和箱子发生碰撞时遇到墙的判断
123                         if (this.pz(oP, $(elem)) && this.newJson.map[(oP.data('x') + xValue) + (oP.data('y') + yValue) * length] != 2) {
124                             $(elem).css({ 'left': (oP.data('x') + xValue) * 50, 'top': (oP.data('y') + yValue) * 50 });
125                             $(".box").each($.proxy(function (j, elem2) {
126                                 if (this.pz($(elem), $(elem2)) && elem != elem2) {
127                                     //当遇到箱子和箱子的的碰撞时同时前面也不是强的判断
128                                     $(elem).css({ 'left': oP.data('x') * 50, 'top': oP.data('y') * 50 });
129                                     oP.data('x', oP.data('x') - xValue);
130                                     oP.data('y', oP.data('y') - yValue);
131                                     oP.css({ "left": oP.data("x") * 50, "top": oP.data("y") * 50 });
132                                 }
133                             }, this));
134                         }
135                         else if (this.pz(oP, $(elem))) {//和墙之间的碰撞
136                             oP.data('x', oP.data('x') - xValue);
137                             oP.data('y', oP.data('y') - yValue);
138                             oP.css({ "left": oP.data("x") * 50, "top": oP.data("y") * 50 });
139                         }
140                     }, this));
141                 }
142                 this.nextShow();
143             },
144             nextShow: function () {//判断是否赢
145                 var iNum = 0;
146                 //红色区域所在的位置是否全部被箱子所占据
147                 $(".box").each($.proxy(function (i, elem) {
148                     $(".pos3").each($.proxy(function (j, elem1) {
149                         if (this.pz($(elem), $(elem1))) {
150                             iNum++;
151                         }
152                     }, this));
153                 }, this));
154                 if (iNum == this.newJson.box.length) {
155                     this.iNow++;
156                     this.createMap(this.iNow);
157                 }
158             },
159             pz: function (obj1, obj2) { //碰撞检测
160                 var L1 = obj1.offset().left;
161                 var R1 = obj1.offset().left + obj1.width();
162                 var T1 = obj1.offset().top;
163                 var B1 = obj1.offset().top + obj1.height();
164 
165                 var L2 = obj2.offset().left;
166                 var R2 = obj2.offset().left + obj2.width();
167                 var T2 = obj2.offset().top;
168                 var B2 = obj2.offset().top + obj2.height();
169                 if (L1 >= R2 || B2 <= T1 || T2 >= B1 || R1 <= L2)
170                 { return false; }
171                 else
172                 { return true; }
173             }
174         };


基本代码中都有注释,应该是可以理解的,具体如果你有疑问那么请留言,我定会回复。

我个人认为其中的精华部分就是首先地图数据的构造用一维数组来确定地图坐标,其中的内容的数据和样式中pos的下标的数据对应起来感觉很赞。

其次是逻辑判断,比如当人物推箱子是发现前面是墙,推箱子遇到箱子时前面也是箱子,此时如果又遇到了墙怎么处理。最后判断输赢就是如果红色区域的位置全部被箱子所占据那么也就

表示通过,进入下一关,当然下一关的数据我是自己随意填充的。如果你有兴趣请自行解决。

结论

这种类似的小游戏重在思路,如果复杂的话就要考虑架构性能等问题了,我猜的。因为没有做大的游戏,如有错误请指出。如果你觉得不错就支持推荐一下。

download PushBox

转载于:https://www.cnblogs.com/miniyk/p/3873892.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴为您介绍Python推箱子游戏的源代码。由于推箱子游戏的实现方式有很多种,我将为您提供一种基于Python的实现方式。 ```python # 定义地图类 class Map: def __init__(self, map_list): self.map_list = map_list self.row = len(map_list) self.col = len(map_list[0]) self.player_pos = None self.box_pos = [] self.target_pos = [] for i in range(self.row): for j in range(self.col): if map_list[i][j] == 'P': self.player_pos = (i, j) elif map_list[i][j] == 'B': self.box_pos.append((i, j)) elif map_list[i][j] == 'T': self.target_pos.append((i, j)) # 判断是否胜利 def is_win(self): for pos in self.box_pos: if pos not in self.target_pos: return False return True # 移动箱子 def move_box(self, box_pos, direction): new_box_pos = (box_pos[0] + direction[0], box_pos[1] + direction[1]) if self.map_list[new_box_pos[0]][new_box_pos[1]] == '#': return False if new_box_pos in self.box_pos: return False self.box_pos.remove(box_pos) self.box_pos.append(new_box_pos) return True # 移动玩家 def move_player(self, direction): new_player_pos = (self.player_pos[0] + direction[0], self.player_pos[1] + direction[1]) if self.map_list[new_player_pos[0]][new_player_pos[1]] == '#': return False for box_pos in self.box_pos: if new_player_pos == box_pos: if not self.move_box(box_pos, direction): return False break self.player_pos = new_player_pos return True # 打印地图 def print_map(self): for i in range(self.row): for j in range(self.col): if (i, j) == self.player_pos: print('P', end='') elif (i, j) in self.box_pos: print('B', end='') elif (i, j) in self.target_pos: print('T', end='') elif self.map_list[i][j] == '#': print('#', end='') else: print(' ', end='') print() # 定义主函数 def main(): map_list = [ ['#', '#', '#', '#', '#', '#', '#', '#', '#', '#'], ['#', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', '#'], ['#', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', '#'], ['#', ' ', ' ', ' ', ' ', ' ', 'B', ' ', ' ', '#'], ['#', ' ', ' ', ' ', ' ', ' ', '#', ' ', ' ', '#'], ['#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#'], ['#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#'], ['#', ' ', ' ', ' ', ' ', ' ', ' ', 'T', ' ', '#'], ['#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#'], ['#', '#', '#', '#', '#', '#', '#', '#', '#', '#'] ] game_map = Map(map_list) game_map.print_map() while not game_map.is_win(): direction = input('请输入移动方向(w:上 s:下 a:左 d:右):') if direction == 'w': if not game_map.move_player((-1, 0)): print('移动失败,请重新输入') elif direction == 's': if not game_map.move_player((1, 0)): print('移动失败,请重新输入') elif direction == 'a': if not game_map.move_player((0, -1)): print('移动失败,请重新输入') elif direction == 'd': if not game_map.move_player((0, 1)): print('移动失败,请重新输入') else: print('输入有误,请重新输入') game_map.print_map() print('恭喜你,游戏胜利!') if __name__ == '__main__': main() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值