【javascript面向对象之路】让我们一起来坦克大战吧01
提问
不知道大家发现没有,运行时候浏览器或者电脑会变得很卡哦。根据我们之前的学习,你知道是什么原因导致的吗?
若是各位有兴趣,请你回答卡的原因,并提出优化方案。
前言
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("//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("//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('//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('//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
结语
好了,今天到此为止,后面点我们来一步步修改代码,让代码变得“面向对象”,有机会便加上砖块和其它东东。
今天的代码不用说,千疮百孔,无论是性能方面,或者代码优雅度,还是神马都一团糟糕,但是经过几个小时的奋战,我现在脑子已经不好使了,只好暂时停一下。
我们后面点优化吧。