今天第一次作移動端地圖遊戲,遊戲雖簡,獲益匪淺。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下訪問。