提問
不知道大家發現沒有,運行時候瀏覽器或者電腦會變得很卡哦。根據我們之前的學習,你知道是什么原因導致的嗎?
若是各位有興趣,請你回答卡的原因,並提出優化方案。
前言
PS 各位要看效果還是使用ff或者google吧,ie7以下好像有問題。
最近大家都在坦克大戰,我突然想了下我是不是也應該坦克大戰一番呢?於是,我們就有了今天的東西。
其實做坦克大戰並不是為了坦克大戰,而是為了javascript面向對象!所以我這里並不會完成這個游戲,做到哪步是哪步吧。
怎么說呢?javascript面向對象大家都聽得很多了,但能真正理解的人並不多,我事實上也是水的,知道一點皮毛是沒用的,所以想以此提升面向對象的思想。
PS:最近其實事情挺多的,HTML5+CSS3、CSS、javascript、bootstrap、響應式布局......我現在是想到哪打哪啊!
算了,扯遠了,我們開始今天的學習吧。
PS:運行的時候請使用高版本瀏覽器,這里暫時沒有做瀏覽器兼容
工欲善其事必先利其器
剛開始干我就在想,我是不是該寫個類庫神馬的,於是在這里磨磨蹭蹭的搞了一個多小時,硬是擠出了以下代碼:
1 function getById(id) { 2 return !id ? null : document.getElementById(id); 3 } 4 5 function getAttr(el, k) { 6 if (el) { 7 var v = el.getAttribute[k] ? el.getAttribute[k] : null; 8 return v; 9 } 10 } 11 12 function setAttr(el, k, v) { 13 if (el) { 14 el.setAttribute(k, v); 15 } 16 } 17 18 function getCss(el, k) { 19 if (el) { 20 21 if (el.style[k]) { 22 return el.style[k]; 23 } 24 return null; 25 } 26 } 27 28 function setCss(el, k, v) { 29 if (el) { 30 if (!el.style || el.style.length == 0) { 31 el.style = {}; 32 } 33 el.style[k] = v; 34 } 35 }
不用看,也不用說,光是想求得元素的樣式這塊我就知道有問題,但是我們不能舍本逐末,這里暫時不管他(因為我搞了個把小時了),我們還是按着邏輯往下走吧。
資料准備
我們這里需要一點點坦克的圖片,於是打開我們的PS,PS之:
這個坦克的資源,我不知道原來從哪里來的,這里先私自用了,原作者若是覺得有問題請留言。
PS:我們這里先不考慮小圖標的問題,一點點來吧
首先是我們的子彈爆炸要用到的圖片:
看到這個圖片各位就應該要想到炮彈爆炸式怎么實現的了哦!
然后我們的主角,坦克的圖片:
下面是我們的子彈:
於是我們幾個坦克也有了,子彈也有了,好了我們先不關注其它,看看我們能不能把坦克給搞出來(話說我PS不是太好,這個也必須納入必學范圍)。
移動的坦克
我們搞移動的坦克之前,在頁面上先弄一張地圖,作為坦克使用:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 <style type="text/css"> 5 .map { background: gray; border: 1px solid black; position: relative; margin: 50px auto; width: 416px; height: 416px; } 6 </style> 7 </head> 8 <body> 9 <div class="map" id="map"> 10 <div id="me" class="tank"> 11 </div> 12 </div> 13 </body> 14 </html>
好了,讓我們主角坦克登場吧,注意其中的me:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 <style type="text/css"> 5 .map { background: gray; border: 1px solid black; position: relative; margin: 50px auto; width: 416px; height: 416px; } 6 .tank { background-image: url("images/tank.gif"); overflow: hidden; position: absolute; width: 32px; height: 32px; z-index: 3; } 7 8 </style> 9 </head> 10 <body> 11 <div class="map" id="map"> 12 <div id="me" class="tank"> 13 </div> 14 </div> 15 </body> 16 </html>
我們可愛的坦克,還是2二級的坦克出現啦,現在我們為他加上移動效果,這里就要開始寫代碼啦,首先我們定義一個坦克類:
1 var Tank = function (id, dir, x, y) { 2 this.el = getById(id); 3 this.direction = dir ? dir : 'up'; 4 this.tid = null; 5 this.speed = 10; 6 //坦克活動狀態 0 未活動 1 正在活動 7 this.activeState = 0; 8 this.x = x ? x : 100; 9 this.y = y ? y : 200; 10 this.dirState = { 11 up: 1, 12 right: 1, 13 down: 1, 14 left: 1 15 }; 16 }
我現在能想到坦克具有的屬性便是:
1 坦克對應的html標簽
2 坦克的初始化方向
3 坦克的初始化位置
在修改一點點,我們就能控制坦克轉向了:

1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 <style type="text/css"> 5 .map { background: gray; border: 1px solid black; position: relative; margin: 50px auto; width: 416px; height: 416px; } 6 .tank { background-image: url("images/tank.gif"); background-repeat: no-repeat; overflow: hidden; position: absolute; width: 32px; height: 32px; z-index: 3; } 7 </style> 8 </head> 9 <body> 10 <div class="map" id="map"> 11 <div id="me" class="tank"> 12 </div> 13 </div> 14 15 <script src="../06tank/js/core.js" type="text/javascript"></script> 16 <script type="text/javascript"> 17 var Tank = function (id, dir, x, y) { 18 this.el = getById(id); 19 this.direction = dir ? dir : 'up'; 20 this.tid = null; 21 this.speed = 10; 22 //坦克活動狀態 0 未活動 1 正在活動 23 this.activeState = 0; 24 this.x = x ? x : 100; 25 this.y = y ? y : 200; 26 this.dirState = { 27 up: 1, 28 right: 1, 29 down: 1, 30 left: 1 31 }; 32 }; 33 Tank.prototype.init = function () { 34 var dir = this.direction; 35 var tank = this.el; 36 setCss(tank, 'left', this.x + 'px'); 37 setCss(tank, 'top', this.y + 'px'); 38 this.setDirection(dir); 39 }; 40 Tank.prototype.setDirection = function (dir) { 41 var tank = this.el; 42 if (dir == 'up') { 43 setCss(tank, 'backgroundPosition', '0 0'); 44 } 45 if (dir == 'right') { 46 setCss(tank, 'backgroundPosition', '-5px -36px'); 47 } 48 if (dir == 'down') { 49 setCss(tank, 'backgroundPosition', '0 -73px'); 50 } 51 if (dir == 'left') { 52 setCss(tank, 'backgroundPosition', '0 -105px'); 53 } 54 this.dirState[dir] = 1; 55 }; 56 57 var tank = new Tank('me', 'right', 100, 100); 58 tank.init(); 59 60 function getDir(code) { 61 if (code == '87' || code == '119') { 62 return 'up'; 63 } 64 if (code == '100' || code == '68') { 65 return 'right'; 66 } 67 if (code == '115' || code == '83') { 68 return 'down'; 69 } 70 if (code == '97' || code == '65') { 71 return 'left'; 72 } 73 return null; 74 } 75 76 document.onkeydown = function (evt) { 77 evt = (evt) ? evt : window.event; 78 var keyCode = evt.keyCode; 79 var charCode = evt.charCode; 80 var dir = getDir(); 81 if (keyCode) { 82 dir = getDir(keyCode.toString()); 83 } 84 if (charCode) { 85 dir = getDir(charCode.toString()); 86 } 87 tank.setDirection(dir); 88 89 evt.preventDefault(); 90 return false; 91 }; 92 document.onkeyup = function (evt) { 93 }; 94 document.onkeypress = function (evt) { 95 evt = (evt) ? evt : window.event; 96 var keyCode = evt.keyCode; 97 var charCode = evt.charCode; 98 var dir = getDir(); 99 if (keyCode) { 100 dir = getDir(keyCode.toString()); 101 } 102 if (charCode) { 103 dir = getDir(charCode.toString()); 104 } 105 evt.preventDefault(); 106 return false; 107 }; 108 </script> 109 </body> 110 </html>
運行效果(此處可運行):
然后我們來加上移動的動畫,各位注意啦,我們這里要使用js實現動畫啦!我們來看看這段代碼:

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 .map { background: gray; border: 1px solid black; position: relative; margin: 50px auto; width: 416px; height: 416px; } 7 .tank { background-image: url("https://images0.cnblogs.com/blog/294743/201306/12123133-eaa9ada8690e4216a2bee3e56442e032.gif"); background-repeat: no-repeat; overflow: hidden; position: absolute; width: 32px; height: 32px; z-index: 3; } 8 </style> 9 </head> 10 <body> 11 <div class="map" id="map"> 12 <div id="me" class="tank"> 13 </div> 14 </div> 15 <script type="text/javascript"> 16 function getById(id) { 17 return !id ? null : document.getElementById(id); 18 } 19 20 function getAttr(el, k) { 21 if (el) { 22 var v = el.getAttribute[k] ? el.getAttribute[k] : null; 23 return v; 24 } 25 } 26 27 function setAttr(el, k, v) { 28 if (el) { 29 el.setAttribute(k, v); 30 } 31 } 32 33 function getCss(el, k) { 34 if (el) { 35 36 if (el.style[k]) { 37 return el.style[k]; 38 } 39 return null; 40 } 41 } 42 43 function setCss(el, k, v) { 44 if (el) { 45 if (!el.style || el.style.length == 0) { 46 el.style = {}; 47 } 48 el.style[k] = v; 49 } 50 } 51 52 var MyGlobal = { 53 mapWidth: 416, 54 mapHeight: 416, 55 width: 448, 56 height: 512 57 }; 58 59 var Tank = function (id, dir, x, y) { 60 this.el = getById(id); 61 this.direction = dir ? dir : 'up'; 62 this.tid = null; 63 this.speed = 10; 64 //坦克活動狀態 0 未活動 1 正在活動 65 this.activeState = 0; 66 this.x = x ? x : 100; 67 this.y = y ? y : 200; 68 this.dirState = { 69 up: 1, 70 right: 1, 71 down: 1, 72 left: 1 73 }; 74 }; 75 Tank.prototype.init = function () { 76 var dir = this.direction; 77 var tank = this.el; 78 setCss(tank, 'left', this.x + 'px'); 79 setCss(tank, 'top', this.y + 'px'); 80 this.setDirection(dir); 81 }; 82 Tank.prototype.setDirection = function (dir) { 83 var tank = this.el; 84 if (dir == 'up') { 85 setCss(tank, 'backgroundPosition', '0 0'); 86 } 87 if (dir == 'right') { 88 setCss(tank, 'backgroundPosition', '-5px -36px'); 89 } 90 if (dir == 'down') { 91 setCss(tank, 'backgroundPosition', '0 -73px'); 92 } 93 if (dir == 'left') { 94 setCss(tank, 'backgroundPosition', '0 -105px'); 95 } 96 this.dirState[dir] = 1; 97 }; 98 99 Tank.prototype.move = function (dir) { 100 if (this.activeState != 0) return false; //正在運動我們便不管他 101 this.activeState = 1; //將當前狀態設置為正在運動 102 if (this.direction != dir) { 103 this.direction = dir; 104 this.setDirection(dir); 105 } 106 //處理運動中的定時器 107 if (this.tid) { 108 clearTimeout(this.tid); 109 this.tid = null; 110 } 111 var state = this.dirState[dir]; 112 var tank = this.el; 113 if (state == 1 || state == -1) { 114 var strPos = getCss(tank, 'backgroundPosition'); 115 var arrPos = strPos.split(' '); 116 var l = arrPos ? arrPos[0] : 0; 117 var t = arrPos ? arrPos[1] : 0; 118 var curPos = parseInt(l); 119 var top = parseInt(t); 120 var po = curPos - (43) * (state); 121 var curPos = po + 'px ' + t + 'px'; 122 setCss(tank, 'backgroundPosition', curPos); 123 } 124 var xpos = getCss(tank, 'left') ? getCss(tank, 'left') : 0; 125 var ypos = getCss(tank, 'top') ? getCss(tank, 'top') : 0; 126 xpos = parseInt(xpos); 127 ypos = parseInt(ypos); 128 var mx = MyGlobal.mapWidth - 32; 129 var my = MyGlobal.mapHeight - 32; 130 switch (dir) { 131 case 'up': ypos <= 0 ? 0 : ypos--; break; 132 case 'right': xpos >= mx ? mx : xpos++; break; 133 case 'down': ypos >= my ? my : ypos++; break; 134 case 'left': xpos <= 0 ? 0 : xpos--; break; 135 } 136 setCss(tank, 'left', xpos + 'px'); 137 setCss(tank, 'top', ypos + 'px'); 138 var scope = this; 139 var speed = this.speed; 140 var repeat = function () { 141 scope.move(dir); 142 }; 143 if (!this.tid) { 144 this.tid = setTimeout(repeat, speed); 145 } 146 //移動結束 147 this.activeState = 0; 148 } 149 Tank.prototype.stop = function () { 150 clearTimeout(this.tid); 151 this.tid = null; 152 }; 153 154 var tank = new Tank('me', 'up', 100, 100); 155 tank.init(); 156 157 function getDir(code) { 158 if (code == '87' || code == '119') { 159 return 'up'; 160 } 161 if (code == '100' || code == '68') { 162 return 'right'; 163 } 164 if (code == '115' || code == '83') { 165 return 'down'; 166 } 167 if (code == '97' || code == '65') { 168 return 'left'; 169 } 170 return null; 171 } 172 173 document.onkeydown = function (evt) { 174 evt = (evt) ? evt : window.event; 175 var keyCode = evt.keyCode; 176 var charCode = evt.charCode; 177 var dir = getDir(); 178 if (keyCode) { 179 dir = getDir(keyCode.toString()); 180 } 181 if (charCode) { 182 dir = getDir(charCode.toString()); 183 } 184 tank.move(dir); 185 186 evt.preventDefault(); 187 return false; 188 }; 189 document.onkeyup = function (evt) { 190 tank.stop(); 191 }; 192 document.onkeypress = function (evt) { 193 evt = (evt) ? evt : window.event; 194 var keyCode = evt.keyCode; 195 var charCode = evt.charCode; 196 var dir = getDir(); 197 if (keyCode) { 198 dir = getDir(keyCode.toString()); 199 } 200 if (charCode) { 201 dir = getDir(charCode.toString()); 202 } 203 tank.move(dir); 204 205 evt.preventDefault(); 206 return false; 207 }; 208 </script> 209 </body> 210 </html>
1 Tank.prototype.move = function (dir) { 2 if (this.activeState != 0) return false; //正在運動我們便不管他 3 this.activeState = 1; //將當前狀態設置為正在運動 4 if (this.direction != dir) { 5 this.direction = dir; 6 this.setDirection(dir); 7 } 8 //處理運動中的定時器 9 if (this.tid) { 10 clearTimeout(this.tid); 11 this.tid = null; 12 } 13 var state = this.dirState[dir]; 14 var tank = this.el; 15 if (state == 1 || state == -1) { 16 var strPos = getCss(tank, 'backgroundPosition'); 17 var arrPos = strPos.split(' '); 18 var l = arrPos ? arrPos[0] : 0; 19 var t = arrPos ? arrPos[1] : 0; 20 var curPos = parseInt(l); 21 var top = parseInt(t); 22 var po = curPos - (43) * (state); 23 var curPos = po + 'px ' + t + 'px'; 24 setCss(tank, 'backgroundPosition', curPos); 25 } 26 var xpos = getCss(tank, 'left') ? getCss(tank, 'left') : 0; 27 var ypos = getCss(tank, 'top') ? getCss(tank, 'top') : 0; 28 xpos = parseInt(xpos); 29 ypos = parseInt(ypos); 30 var mx = MyGlobal.mapWidth - 32; 31 var my = MyGlobal.mapHeight - 32; 32 switch (dir) { 33 case 'up': ypos <= 0 ? 0 : ypos--; break; 34 case 'right': xpos >= mx ? mx : xpos++; break; 35 case 'down': ypos >= my ? my : ypos++; break; 36 case 'left': xpos <= 0 ? 0 : xpos--; break; 37 } 38 setCss(tank, 'left', xpos + 'px'); 39 setCss(tank, 'top', ypos + 'px'); 40 var scope = this; 41 var speed = this.speed; 42 var repeat = function () { 43 scope.move(dir); 44 }; 45 if (!this.tid) { 46 this.tid = setTimeout(repeat, speed); 47 } 48 //移動結束 49 this.activeState = 0; 50 };
這個代碼其實沒什么好說的,只不過我們每次運動后會改變其方向的狀態值,為的就是不停的改變背景,以達到坦克前進的效果。
運行效果(此處可運行):
於是我們簡單的完成了坦克移動的功能了,現在我們來考慮炮彈的問題了。
炮彈對象
上面的是坦克對象,我們現在來看看炮彈對象,我們將坦克,炮彈,磚塊各自看做一個對象,這樣不知道面向對象沒。。。
1 //子彈對象 2 var Bullet = function (dir) { 3 this.direction = dir ? dir : 'up'; 4 this.speed = 5; 5 var factor = 0; 6 this.tid = null; 7 this.activeState = 0; 8 this.blastState = 0; //爆炸狀態 0-4 9 this.blastReason = 0; //爆炸原因 0一般爆炸,4 集中坦克 3...... 10 this.x = 0; 11 this.y = 0; 12 if (dir) { 13 switch (dir) { 14 case 'up': factor = 0; break; 15 case 'right': factor = 1; break; 16 case 'down': factor = 2; break; 17 case 'left': factor = 3; break; 18 } 19 } 20 var el = document.createElement('div'); 21 var bp = 'background-position :' + (0 - 8 * factor) + 'px 0 ;'; 22 el.setAttribute('style', bp); 23 el.setAttribute('class', 'bullet'); 24 this.el = el; 25 }; 26 27 Bullet.prototype.move = function () { 28 29 var bullet = this.el; 30 var dir = this.direction; 31 var xpos = getCss(bullet, 'left') ? getCss(bullet, 'left') : 0; 32 var ypos = getCss(bullet, 'top') ? getCss(bullet, 'top') : 0; 33 xpos = parseInt(xpos); 34 ypos = parseInt(ypos); 35 var mx = MyGlobal.mapWidth - 8; 36 var my = MyGlobal.mapHeight - 8; 37 var stop = false; 38 switch (dir) { 39 case 'up': 40 if (ypos <= 0) { 41 stop = true; 42 } else { 43 ypos--; 44 } 45 break; 46 case 'right': 47 if (xpos >= mx) { 48 stop = true; 49 } else { 50 xpos++; 51 } 52 break; 53 case 'down': 54 if (ypos >= my) { 55 stop = true; 56 } else { 57 ypos++; 58 } 59 break; 60 case 'left': 61 if (xpos <= 0) { 62 stop = true; 63 } else { 64 xpos--; 65 } 66 break; 67 } 68 69 setCss(bullet, 'left', xpos + 'px'); 70 setCss(bullet, 'top', ypos + 'px'); 71 this.x = xpos; 72 this.y = ypos; 73 74 var scope = this; 75 var speed = this.speed; 76 var repeat = function () { 77 scope.move(); 78 }; 79 if (this.tid) { 80 clearTimeout(this.tid); 81 this.tid = null; 82 } 83 if (!this.tid) { 84 this.tid = setTimeout(repeat, speed); 85 } 86 if (stop) { 87 this.blast(); 88 } 89 }; 90 91 Bullet.prototype.blast = function (reason) { 92 var el = this.el; 93 var x = this.x - 28; 94 var y = this.y - 28; 95 setCss(el, 'left', x + 'px'); 96 setCss(el, 'top', y + 'px'); 97 this.x = x; 98 this.y = y; 99 var scope = this; 100 setAttr(el, 'class', 'Boom'); 101 setCss(scope.el, 'backgroundPosition', '0 0'); 102 var action = function () { 103 if (scope.blastState < (scope.blastReason + 1)) { 104 var b = scope.blastState * 64 * (-1); 105 b = b + 'px 0'; 106 setCss(scope.el, 'backgroundPosition', b); 107 scope.blastState++; 108 setTimeout(action, 20); 109 } else { 110 getById('map').removeChild(scope.el); 111 delete scope; 112 } 113 }; 114 if (reason) { 115 this.blastReason = reason; 116 } 117 setTimeout(action, 20); 118 119 clearTimeout(this.tid); 120 this.tid = null; 121 122 // this.blastState 123 124 };
完整代碼:

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 .map { background: gray; border: 1px solid black; position: relative; margin: 50px auto; width: 416px; height: 416px; } 7 .tank { background-image: url("https://images0.cnblogs.com/blog/294743/201306/12123133-eaa9ada8690e4216a2bee3e56442e032.gif"); background-repeat: no-repeat; overflow: hidden; position: absolute; width: 32px; height: 32px; z-index: 3; } 8 .bullet { background-image: url('https://images0.cnblogs.com/blog/294743/201306/12123510-662de29d9e0c447389b42fcb47bff652.gif'); width: 8px; height: 8px; position: absolute; z-index: 4; background-repeat: no-repeat; } 9 .Boom { background-image: url('https://images0.cnblogs.com/blog/294743/201306/12121341-0e6fba003915418a909cde86d0b8aac6.png'); width: 64px; height: 64px; position: absolute; z-index: 4; } 10 </style> 11 </head> 12 <body> 13 <div class="map" id="map"> 14 <div id="me" class="tank"> 15 </div> 16 </div> 17 <script type="text/javascript"> 18 function getById(id) { 19 return !id ? null : document.getElementById(id); 20 } 21 22 function getAttr(el, k) { 23 if (el) { 24 var v = el.getAttribute[k] ? el.getAttribute[k] : null; 25 return v; 26 } 27 } 28 29 function setAttr(el, k, v) { 30 if (el) { 31 el.setAttribute(k, v); 32 } 33 } 34 35 function getCss(el, k) { 36 if (el) { 37 38 if (el.style[k]) { 39 return el.style[k]; 40 } 41 return null; 42 } 43 } 44 45 function setCss(el, k, v) { 46 if (el) { 47 if (!el.style || el.style.length == 0) { 48 el.style = {}; 49 } 50 el.style[k] = v; 51 } 52 } 53 54 var MyGlobal = { 55 mapWidth: 416, 56 mapHeight: 416, 57 width: 448, 58 height: 512 59 }; 60 61 //子彈對象 62 var Bullet = function (dir) { 63 this.direction = dir ? dir : 'up'; 64 this.speed = 5; 65 var factor = 0; 66 this.tid = null; 67 this.activeState = 0; 68 this.blastState = 0; //爆炸狀態 0-4 69 this.blastReason = 0; //爆炸原因 0一般爆炸,4 集中坦克 3...... 70 this.x = 0; 71 this.y = 0; 72 if (dir) { 73 switch (dir) { 74 case 'up': factor = 0; break; 75 case 'right': factor = 1; break; 76 case 'down': factor = 2; break; 77 case 'left': factor = 3; break; 78 } 79 } 80 var el = document.createElement('div'); 81 var bp = 'background-position :' + (0 - 8 * factor) + 'px 0 ;'; 82 el.setAttribute('style', bp); 83 el.setAttribute('class', 'bullet'); 84 this.el = el; 85 }; 86 87 Bullet.prototype.move = function () { 88 89 var bullet = this.el; 90 var dir = this.direction; 91 var xpos = getCss(bullet, 'left') ? getCss(bullet, 'left') : 0; 92 var ypos = getCss(bullet, 'top') ? getCss(bullet, 'top') : 0; 93 xpos = parseInt(xpos); 94 ypos = parseInt(ypos); 95 var mx = MyGlobal.mapWidth - 8; 96 var my = MyGlobal.mapHeight - 8; 97 var stop = false; 98 switch (dir) { 99 case 'up': 100 if (ypos <= 0) { 101 stop = true; 102 } else { 103 ypos--; 104 } 105 break; 106 case 'right': 107 if (xpos >= mx) { 108 stop = true; 109 } else { 110 xpos++; 111 } 112 break; 113 case 'down': 114 if (ypos >= my) { 115 stop = true; 116 } else { 117 ypos++; 118 } 119 break; 120 case 'left': 121 if (xpos <= 0) { 122 stop = true; 123 } else { 124 xpos--; 125 } 126 break; 127 } 128 129 setCss(bullet, 'left', xpos + 'px'); 130 setCss(bullet, 'top', ypos + 'px'); 131 this.x = xpos; 132 this.y = ypos; 133 134 var scope = this; 135 var speed = this.speed; 136 var repeat = function () { 137 scope.move(); 138 }; 139 if (this.tid) { 140 clearTimeout(this.tid); 141 this.tid = null; 142 } 143 if (!this.tid) { 144 this.tid = setTimeout(repeat, speed); 145 } 146 if (stop) { 147 this.blast(); 148 } 149 }; 150 151 Bullet.prototype.blast = function (reason) { 152 var el = this.el; 153 var x = this.x - 28; 154 var y = this.y - 28; 155 setCss(el, 'left', x + 'px'); 156 setCss(el, 'top', y + 'px'); 157 this.x = x; 158 this.y = y; 159 var scope = this; 160 setAttr(el, 'class', 'Boom'); 161 setCss(scope.el, 'backgroundPosition', '0 0'); 162 var action = function () { 163 if (scope.blastState < (scope.blastReason + 1)) { 164 var b = scope.blastState * 64 * (-1); 165 b = b + 'px 0'; 166 setCss(scope.el, 'backgroundPosition', b); 167 scope.blastState++; 168 setTimeout(action, 20); 169 } else { 170 getById('map').removeChild(scope.el); 171 delete scope; 172 } 173 }; 174 if (reason) { 175 this.blastReason = reason; 176 } 177 setTimeout(action, 20); 178 179 clearTimeout(this.tid); 180 this.tid = null; 181 182 // this.blastState 183 184 }; 185 186 //坦克對象 187 var Tank = function (id, dir, x, y) { 188 this.el = getById(id); 189 this.direction = dir ? dir : 'up'; 190 this.tid = null; 191 this.speed = 10; 192 //坦克活動狀態 0 未活動 1 正在活動 193 this.activeState = 0; 194 this.x = x ? x : 100; 195 this.y = y ? y : 200; 196 this.dirState = { 197 up: 1, 198 right: 1, 199 down: 1, 200 left: 1 201 }; 202 }; 203 Tank.prototype.init = function () { 204 var dir = this.direction; 205 var tank = this.el; 206 setCss(tank, 'left', this.x + 'px'); 207 setCss(tank, 'top', this.y + 'px'); 208 this.setDirection(dir); 209 }; 210 Tank.prototype.setDirection = function (dir) { 211 var tank = this.el; 212 if (dir == 'up') { 213 setCss(tank, 'backgroundPosition', '0 0'); 214 } 215 if (dir == 'right') { 216 setCss(tank, 'backgroundPosition', '-5px -36px'); 217 } 218 if (dir == 'down') { 219 setCss(tank, 'backgroundPosition', '0 -73px'); 220 } 221 if (dir == 'left') { 222 setCss(tank, 'backgroundPosition', '0 -105px'); 223 } 224 this.dirState[dir] = 1; 225 }; 226 227 Tank.prototype.move = function (dir) { 228 if (this.activeState != 0) return false; //正在運動我們便不管他 229 this.activeState = 1; //將當前狀態設置為正在運動 230 if (this.direction != dir) { 231 this.direction = dir; 232 this.setDirection(dir); 233 } 234 //處理運動中的定時器 235 if (this.tid) { 236 clearTimeout(this.tid); 237 this.tid = null; 238 } 239 var state = this.dirState[dir]; 240 var tank = this.el; 241 if (state == 1 || state == -1) { 242 var strPos = getCss(tank, 'backgroundPosition'); 243 var arrPos = strPos.split(' '); 244 var l = arrPos ? arrPos[0] : 0; 245 var t = arrPos ? arrPos[1] : 0; 246 var curPos = parseInt(l); 247 var top = parseInt(t); 248 var po = curPos - (40) * (state); 249 var curPos = po + 'px ' + top + 'px'; 250 setCss(tank, 'backgroundPosition', curPos); 251 this.dirState[dir] = state == 1 ? -1 : 1; 252 253 } 254 var xpos = getCss(tank, 'left') ? getCss(tank, 'left') : 0; 255 var ypos = getCss(tank, 'top') ? getCss(tank, 'top') : 0; 256 xpos = parseInt(xpos); 257 ypos = parseInt(ypos); 258 var mx = MyGlobal.mapWidth - 32; 259 var my = MyGlobal.mapHeight - 32; 260 switch (dir) { 261 case 'up': ypos <= 0 ? 0 : ypos--; break; 262 case 'right': xpos >= mx ? mx : xpos++; break; 263 case 'down': ypos >= my ? my : ypos++; break; 264 case 'left': xpos <= 0 ? 0 : xpos--; break; 265 } 266 setCss(tank, 'left', xpos + 'px'); 267 setCss(tank, 'top', ypos + 'px'); 268 this.x = xpos; 269 this.y = ypos; 270 var scope = this; 271 var speed = this.speed; 272 var repeat = function () { 273 scope.move(dir); 274 }; 275 if (!this.tid) { 276 this.tid = setTimeout(repeat, speed); 277 } 278 //移動結束 279 this.activeState = 0; 280 }; 281 282 Tank.prototype.stop = function () { 283 clearTimeout(this.tid); 284 this.tid = null; 285 }; 286 287 Tank.prototype.fire = function () { 288 var bullet = new Bullet(this.direction); 289 var l = (this.x + 12) + 'px'; 290 var t = (this.y + 12) + 'px' 291 // top:12px;left:12px; 292 var el = bullet.el; 293 setCss(el, 'top', t); 294 setCss(el, 'left', l); 295 bullet.y = this.y + 12; 296 bullet.x = this.x + 12; 297 getById('map').appendChild(el); 298 // bullet.el = this.el.getElementsByTagName('div')[0]; 299 bullet.move(); 300 }; 301 302 303 //實際應用 304 var tank = new Tank('me', 'right', 100, 100); 305 tank.init(); 306 307 function getDir(code) { 308 if (code == '87' || code == '119') { 309 return 'up'; 310 } 311 if (code == '100' || code == '68') { 312 return 'right'; 313 } 314 if (code == '115' || code == '83') { 315 return 'down'; 316 } 317 if (code == '97' || code == '65') { 318 return 'left'; 319 } 320 return null; 321 } 322 323 document.onkeydown = function (evt) { 324 evt = (evt) ? evt : window.event; 325 var keyCode = evt.keyCode; 326 var charCode = evt.charCode; 327 var dir = getDir(); 328 if (keyCode) { 329 dir = getDir(keyCode.toString()); 330 } 331 if (charCode) { 332 dir = getDir(charCode.toString()); 333 } 334 if (dir) 335 tank.move(dir); 336 if (charCode == '106' || keyCode == '74') { 337 tank.fire(); 338 } 339 evt.preventDefault(); 340 return false; 341 }; 342 document.onkeyup = function (evt) { 343 tank.stop(); 344 }; 345 document.onkeypress = function (evt) { 346 evt = (evt) ? evt : window.event; 347 var keyCode = evt.keyCode; 348 var charCode = evt.charCode; 349 var dir = getDir(); 350 if (keyCode) { 351 dir = getDir(keyCode.toString()); 352 } 353 if (charCode) { 354 dir = getDir(charCode.toString()); 355 } 356 if (dir) 357 tank.move(dir); 358 if (charCode == '106' || keyCode == '74') { 359 tank.fire(); 360 } 361 evt.preventDefault(); 362 return false; 363 }; 364 </script> 365 </body> 366 </html>
效果演示(可運行)J可以發子彈,沒有子彈就到高版本瀏覽器去試試
http://sandbox.runjs.cn/show/evpyzcku
結語
好了,今天到此為止,后面點我們來一步步修改代碼,讓代碼變得“面向對象”,有機會便加上磚塊和其它東東。
今天的代碼不用說,千瘡百孔,無論是性能方面,或者代碼優雅度,還是神馬都一團糟糕,但是經過幾個小時的奮戰,我現在腦子已經不好使了,只好暫時停一下。
我們后面點優化吧。