地图游戏初尝

《迷宫游戏》

  今天第一次做移动端地图游戏,游戏虽简,获益匪浅。

  以前没做过地图游戏,一直不懂怎么构造地图和检测路径,我想这就是做web地图游戏的关键吧。慢慢地有了思路,有了常用方案,那么就算换了一个很复杂的图也不怕实现不了了。不过web app一直离不开性能问题,尤其在移动端。假如使用标签元素来构图的话(像本例),当操作的数量达到一定后,流畅度就好大打折扣。因为web app一般是无法得到硬件加速的,所以性能远不如native app。除非开启3D加速(GPU),如移动大图时使用translate3D,否则就会有明显的卡顿感。

  还好,由于本例只用了几百个块,操作简单,所以暂时不会有卡顿感。下面我就分部讲讲如何实现一个web地图小游戏吧,有了这个基础,就算换上复杂的图也知道怎么实现了。

  1、建图拿数据

  首先介绍一款软件——Tiled Map Editor,这是一个地图编辑器工具,它可以辅助我们更快更准确地编辑web游戏地图。具体的操作我就不讲了,可以自行百度教程。

  下载地址:http://www.mapeditor.org/

  打开Tiled—>创建新图—>划分块大小与数量—>添加图块—>利用图块拼图—>导出JS文件

   

  打开导出的js文件,我们可以看到很代码和参数,我这里就只需要layouts里面的data数组。它是地图小块的标注,0表示没图,其他数字表示相对应的图。

  2、编写界面

    (1)首先创建一个外部包裹容器wrap,宽高100%等于可视区域大小。设置超出隐藏相对定位于body,根据情况设置背景;

    (2)接着创建地图容器map,设置绝对定位,宽高等于地图大小,如3200X640px;

    (3)然后创建地图小块,绝对定位固定大小,如32X32px;

    (4)最后编写其他样式,如移动块、按钮与加载等。

  HTML&CSS代码如下:

  1 <!DOCTYPE html>
  2 <html>
  3     <head>
  4         <meta charset="utf-8" />
  5         <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
  6         <title>迷宫游戏</title>
  7         <style type="text/css">
  8             body,h1,h2,h3,h4,p,dl,dd,ul,ol,form,input,textarea,th,td,select{margin: 0;padding: 0;}
  9             em{font-style: normal;}
 10             li{list-style: none;}
 11             a{text-decoration: none;}
 12             img{border: none;vertical-align: top;margin: 0;}
 13             table{border-collapse: collapse;}
 14             input,textarea{outline: none;}
 15             textarea{resize:none;overflow: auto;}
 16             body{font-size:12px;font-family: arial;}
 17
 18             html,body,#wrap{
 19                 height: 100%;
 20                 width: 100%;
 21             }
 22             #loading{
 23                 position: absolute;
 24                 width: 32px;
 25                 height: 32px;
 26                 top: 50%;
 27                 left: 50%;
 28                 margin-left: -16px;
 29                 margin-top: -16px;
 30                 background: url(img/loading.gif) no-repeat;
 31                 z-index: 100;
 32             }
 33             #wrap{
 34                 overflow: hidden;
 35                 position: relative;
 36                 background: url(img/bg.jpg) no-repeat;
 37                 z-index: 1;
 38             }
 39             #map{
 40                 position: absolute;
 41                 left: 0;
 42                 top: 0;
 43                 width: 3200px;
 44                 height: 640px;
 45             }
 46             .wall{
 47                 position: absolute;
 48                 width: 32px;
 49                 height: 32px;
 50                 background: url(img/stick.png) no-repeat;
 51             }
 52             #move{
 53                 width: 96px;
 54                 height: 96px;
 55                 position: absolute;
 56                 background: url(img/dog.png) no-repeat;
 57                 top: 96px;
 58                 left: 64px;
 59             }
 60             #timer{
 61                 height: 32px;
 62                 width: 30%;
 63                 position: absolute;
 64                 top: 0;
 65                 right: 0;
 66                 color: #bdb632;
 67                 font-size: 1em;
 68                 line-height: 32px;
 69             }
 70             .treasure{
 71                 width: 96px;
 72                 height: 96px;
 73                 background: url(img/treasure.png) no-repeat;
 74                 position: absolute;
 75             }
 76             #start{
 77                 display: none;
 78                 position: absolute;
 79                 width: 30%;
 80                 height: 32px;
 81                 color: #BDB632;
 82                 font-size: 1.5em;
 83                 text-align: center;
 84                 line-height: 32px;
 85                 left: 35%;
 86                 top: 50%;
 87                 margin-top: -17px;
 88                 border: #BDB632 1px solid;
 89                 z-index: 80;
 90             }
 91             #end{
 92                 display: none;
 93                 position: absolute;
 94                 width: 40%;
 95                 height: 10%;
 96                 font-size: 2em;
 97                 left: 30%;
 98                 top: 40%;
 99                 text-align: center;
100                 line-height: 2;
101                 color: #BDB632;
102                 font-weight: bold;
103                 z-index: 50;
104             }
105             #cover{
106                 /*display: none;*/
107                 position: fixed;
108                 left: 0;
109                 width: 100%;
110                 height: 100%;
111                 background: #000;
112                 -webkit-opacity: 0.6;
113                 opacity: 0.6;
114                 z-index: 10;
115             }
116         </style>
117         <script src="js/touch.js" type="text/javascript" charset="utf-8"></script>
118     </head>
119     <body>
120         <div id="wrap">
121             <!--地图-->
122             <div id="map">
123                 <div id="move"></div>
124             </div>
125             <!--计时器-->
126             <div id="timer">
127                 <span>剩余时间:</span>
128                 <span id="seconds">90</span>
129                 <span>S</span>
130             </div>
131             <!--加载中-->
132             <div id="loading"></div>
133             <!--开始-->
134             <div id="start">开始游戏</div>
135             <!--结束-->
136             <div id="end">游戏结束!</div>
137             <!--覆盖层-->
138             <div id="cover"></div>
139         </div>
140     </body>
141 </html>

展开代码

  3、功能实现

    Javascript代码模块:    

    (1)获取页面元素、设置地图和移动块的位置变量、地图与移动块的高;   

 1      var Map = document.getElementById("map");
 2         var wrap = document.getElementById("wrap");
 3         var seconds = document.getElementById("seconds");//秒计时
 4         var start = document.getElementById("start");//开始
 5         var loading = document.getElementById("loading");//加载
 6         var end = document.getElementById("end");//结束
 7         var cover = document.getElementById("cover");//覆盖层
 8         var move = document.getElementById("move");//滑块
 9         var t  = move.offsetTop;//滑块位置
10         var l = move.offsetLeft;
11         var mapL = Map.offsetLeft;//地图位置
12         var mapT = Map.offsetTop;
13         var mapH = Map.offsetHeight;//地图高

    (2)根据tiled生成的数组创建地图元素,如本例是迷宫的墙体;

 1 //Tiled生成的墙体数组
 2         var sticks =[0, 0, 0, 0, 0, 0, ………………1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0];//数组太长,中间省略
 3         var r = -1;//行
 4         var c = 0;//列
 5         //生成墙
 6         for (var i = 0; i < sticks.length; i++) {
 7             if(i%100==0){
 8                 r++;
 9             }
10             c = i%100;
11             //0为空,1为有
12             if(sticks[i]==1){
13                 var div = document.createElement("div");
14                 div.className = "wall";
15                 Map.appendChild(div);
16                 div.style.left = c*32 + "px";//小块宽高为32
17                 div.style.top = r*32 + "px";
18             }
19         }

    (3)预加载图片,将本例中用到的图片进行预加载;

 1 //预加载图片
 2         var imgArr = ["bg.jpg","dog.png","treasure.png"];//图片数组
 3         (function loadImg (){
 4             var index = 0;
 5             for(var i=0;i<imgArr.length ;i++){
 6                 var img = new Image();
 7                 img.src = "img/" + imgArr[i];
 8                 img.onload = function (){
 9                     index++;
10                     if(index == imgArr.length){
11                         loading.style.display = "none";
12                         start.style.display = "block";
13                     }
14                 };
15             }
16         })();

    (4)绑定触屏事件,检测碰撞与移动,引入touch.js;

 1 //触屏事件
 2         touch.on(‘#Map‘, ‘touchstart‘, function(ev){
 3                 ev.preventDefault();
 4         });
 5         touch.on(Map,"touchstart",function(ev){
 6                 var halfW = wrap.clientWidth;//可视区宽高
 7                 var halfH = wrap.clientHeight;
 8                 var x = ev.touches[0].pageX;//1手指坐标
 9                 var y = ev.touches[0].pageY;
10                 //右
11                 if( x > halfW/2 && (y > halfH/3) && y < 2*halfH/3 && sticks[100*t/32+(l/32+3)]==0 && sticks[100*t/32+(l/32+3)+100]==0 && sticks[100*t/32+(l/32+3)+200]==0){
12                     l+=32;
13                     move.style.left = l +"px";
14                     //假如物块到达边沿,右移地图
15                     if(l+mapL>=halfW-96){
16                         Map.style.left = mapL - 192 + "px";
17                         mapL-=192;
18                     }
19                 }
20                 //左
21                 else if (x < halfW/2 && (y > halfH/3) && y < 2*halfH/3 && sticks[100*t/32+(l/32-1)]==0 && sticks[100*t/32+(l/32-1)+100]==0 && sticks[100*t/32+(l/32-1)+200]==0){
22                     l-=32;
23                     move.style.left = l +"px";
24                     //物块到达屏幕左边沿,左移地图
25                     if(l<=96-mapL){
26                         if(mapL<=-192){
27                             Map.style.left = mapL + 192 + "px";
28                             mapL+=192;
29                         }else{
30                             Map.style.left = 0 + "px";
31                             mapL=0;
32                         }
33                     }
34                 }
35                 //上
36                 else if (y < halfH/3 && sticks[(t/32-1)*100+l/32]==0 && sticks[(t/32-1)*100+l/32+1]==0 && sticks[(t/32-1)*100+l/32+2]==0){
37                     t-=32;
38                     move.style.top = t + "px";
39                     //接近上边,上移大图
40                     if( t<= -Map.offsetTop + 32){
41                         Map.style.top = 0 + "px";
42                     }
43                 }
44                 //下
45                 else if (y > 2*halfH/3 && sticks[(t/32+3)*100+l/32]==0 && sticks[(t/32+3)*100+l/32+1]==0 && sticks[(t/32+3)*100+l/32+2]==0){
46                     t+=32;
47                     move.style.top = t + "px";
48                     //到达下方,移动大图
49                     if(t>=halfH-96){
50                         Map.style.top = halfH - mapH + "px";
51                     }
52                 }
53         });    

    (5)给其他按钮绑定事件和设定定时器等。

 1 // 开始
 2         start.onclick = function (){
 3             cover.style.display = "none";
 4             this.style.display = "none";
 5             timerFn();
 6         }
 7 //计时器
 8         var timer = null;
 9         var i = 90;// 时长
10         function timerFn(){
11             timer = setInterval(function(){
12                 seconds.innerHTML = i;
13                 i--;
14                 if(i<0){
15                     cover.style.display = "block";
16                     end.style.display = "block";
17                     clearInterval(timer);
18                 }
19             },1000);
20         }

    代码块4碰撞与移动判断条件如( x > halfW/2 && (y > halfH/3) && y < 2*halfH/3 && sticks[100*t/32+(l/32+3)]==0 && sticks[100*t/32+(l/32+3)+100]==0 && sticks[100*t/32+(l/32+3)+200]==0)

    解析:由于我把屏幕触摸区域分成了以下四个区域,上下左右。

    x>halfW/2 && y>halfH/3 即表示在屏幕水平小于1/2处,垂直1/3到2/3处,其余类同;

    sticks[100*t/32+(l/32+3)]==0表示地图被划分为许多行,每行100个单位,根据sticks数组判断移动块的右侧是否为空。如果移动块的left除以单位长度32,再加上本身宽度为3个单位,即得移动块右侧的数组对应的值。如果为0说明为空1说明有div块(即有墙)。由于移动块相当于3个长度单位,所以要检测右侧上中下三块是否为空(行数加1和2)。

  结束语:当地图比较大,需要创建数以千计的div时,为了游戏更加流畅,应采用大图做地图,然后同样用数组记录位置。

  游戏地址:www.chengguanhui.com/demos/maze

  请使用手机或谷歌浏览器Device Mode下访问。

时间: 2024-10-05 05:04:51

地图游戏初尝的相关文章

初尝Mcafee之在ePO中进行策略和客户端任务设置【06】

一.策略和客户端任务概述 在ePO中点击"菜单",可以看到一个策略的大分类:ePO就是通过分配策略和客户端任务给客户端代理,然后代理将这些策略和客户端任务分配给本地相应的Mcafee杀毒防护软件进行执行: 策略是针对软件的内在参数和计划任务的配置,例如VirusScan是否扫描压缩文件,VirusScan的扫描计划的设置: 客户端任务是针对软件的外在交互,例如安装,部署,更新,信息统计等: 二.策略和客户端任务的分配结构: 策略和客户端任务的分配结构有点跟Windows Server的

《iOS应用逆向工程》学习笔记(五)初尝越狱插件OpenSSH

首先在越狱机子上装上OpenSSH插件,然后查看设备的IP地址,这里假设为192.168.xxx.xxx. 然后用Mac上的Terminal通过Open SSH连接到设备上(初次登录密码是alpine,必须立即修改,否则任何人都可以连接到你的机子上搞破坏). 连接命令为:ssh [email protected]设备IP地址 修改密码命令为:passwd 例如: $ ssh [email protected] The authenticity of host '192.168.xxx.xxx (

初尝backbone

backbone的基础知识在此将不再进行介绍.自己后续应该会整理出来,不过今天先把这几天学的成果用一个demo进行展示. 后续可运行demo将会在sinaapp上分享,不过近期在整理sinaapp上demo分享版块的重构,恕不能及时更新上去. 手把手教你搭建Hello World 虽然这次的开篇程序叫做helloworld有点牵强,但是我还是喜欢叫它为hello world~^_^ 以下程序改编自著名的todos程序,todos是什么?其实如果学过backbone的,肯定看到过todos的实例,

Challenge Checkio(python)—初尝python练习网站

最近在找点python语言练习的网站,发现这个网站不错 http://www.checkio.org/ 页面设计的也比较漂亮,比较适合学习python的语法知识.不过注册这个网站 开始就得解决一个python问题,不过很简单. 1 #python3.3 is inside 2 def checkio(els): 3 return els 4 5 if checkio([1, 2, 3, 4, 5, 6]) == 6: 6 print('Done!') 对上面的代码 修改checkio中的函数 函

初尝Mcafee之CEE企业版概述【01】

Mcafee CEE企业版英文全称Mcafee Complete Endpoint Protection –Enterprise,是多种Mcafee的防护软件的套件: Mcafee CEE是C/S模式管理的,服务端控制端名为ePO,全称ePolicy Orchestrator;客户端是由Mcafee Agent和各类Mcafee防护软件组成. ePO通过Mcafee Agent来部署,安装,执行,管理,监控在客户端的Mcafee防护软件,其架构如下: (1)Mcafee EASI是ePO的安装套

seajs初尝 加载jquery返回null解决学习日志

原文地址:http://www.tuicool.com/articles/bmuaEb 今天早上初尝seajs,发现一个非常蛋疼的事情,使用官方demo中的jquery是没有问题, 下载官方最新版jquery 2.1.1发现console.log($)返回null,百思不得其解!只能求助度娘! 在GitHub发现了玉伯的说明 < 直接调用 jQuery 插件等非标准模块的方法 > 不过这方法在2.3版本貌似已经不行,seajs.modify方法已在这版本移除! https://github.c

AWS--EC2初尝

环境是Mac OSX. 尝试了一下amazon的EC2服务,注册基本比较简单,需要一张信用卡. 进入控制台后选择EC2,点击launch instance,选择free tier的Amazon linux,一路点下去.比较重要的是保存好key pair,之后连接主机需要.网上看是以.pem为后缀的,但我下下来是以.cer为后缀的,不过基本不影响. 等待主机启动好了之后可以连接了,在命令行切换到之前key所在路径,用chmod修改权限为400(只有所有者可读). 接着输入“ssh -i <key文

初尝 Perl

本文将阐述以下几方面内容: 1.什么是Perl 2.Perl有什么用 3.Windows 下的Perl环境搭建 4.Perl 版Hello World 5.Perl 语法梗概 6.一些参考资料 什么是Perl Perl 是一门由 Larry Wall(拉里·沃尔)设计并实现的一门脚本语言,Larry Wall设计这门语言的最初的目的为了让UNIX 上得报表处理工作变得更方便.Perl 第一版的发行时间为 1987年(Python第一版的发行时间为 1991年.Ruby第一版的发行时间为 1995

分布式设计《初尝memcached》

之前听说过高性能的分布式缓存开源工具,但一直没有真正接触过,现在接触的产品中有用到过分布式缓存,所以决定一探究竟.memcached是一个优秀的开源的分布式缓存工具,也是目前比较火热的分布式缓存的解决方案雏形.memcached的服务端产品本身功能简洁,简单易用,但是玩法多种多样.但是事实上它是一个"伪分布式"解决方案,它本身并没有实现服务端分布式(服务端的memcached server之间是不能通信的),所谓的分布式都是依靠客户端来实现,而目前市面上提供了客户端分布式实现的开源工具