地圖遊戲初嘗

《迷宮遊戲》

  今天第一次作移動端地圖遊戲,遊戲雖簡,獲益匪淺。javascript

  之前沒作過地圖遊戲,一直不懂怎麼構造地圖和檢測路徑,我想這就是作web地圖遊戲的關鍵吧。慢慢地有了思路,有了經常使用方案,那麼就算換了一個很複雜的圖也不怕實現不了了。不過web app一直離不開性能問題,尤爲在移動端。假如使用標籤元素來構圖的話(像本例),當操做的數量達到必定後,流暢度就好大打折扣。由於web app通常是沒法獲得硬件加速的,因此性能遠不如native app。除非開啓3D加速(GPU),如移動大圖時使用translate3D,不然就會有明顯的卡頓感。css

  還好,因爲本例只用了幾百個塊,操做簡單,因此暫時不會有卡頓感。下面我就分部講講如何實現一個web地圖小遊戲吧,有了這個基礎,就算換上覆雜的圖也知道怎麼實現了。html

  一、建圖拿數據java

  首先介紹一款軟件——Tiled Map Editor,這是一個地圖編輯器工具,它能夠輔助咱們更快更準確地編輯web遊戲地圖。具體的操做我就不講了,能夠自行百度教程。web

  下載地址:http://www.mapeditor.org/數組

  打開Tiled—>建立新圖—>劃分塊大小與數量—>添加圖塊—>利用圖塊拼圖—>導出JS文件瀏覽器

   

  打開導出的js文件,咱們能夠看到很代碼和參數,我這裏就只須要layouts裏面的data數組。它是地圖小塊的標註,0表示沒圖,其餘數字表示相對應的圖。app

  二、編寫界面編輯器

    (1)首先建立一個外部包裹容器wrap,寬高100%等於可視區域大小。設置超出隱藏相對定位於body,根據狀況設置背景;ide

    (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>
展開代碼

  三、功能實現

    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下訪問。

相關文章
相關標籤/搜索