提问
不知道大家发现没有,运行时候浏览器或者电脑会变得很卡哦。根据我们之前的学习,你知道是什么原因导致的吗?
若是各位有兴趣,请你回答卡的原因,并提出优化方案。
前言
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 坦克的初始化位置
在修改一点点,我们就能控制坦克转向了:
View Code
运行效果(此处可运行):
然后我们来加上移动的动画,各位注意啦,我们这里要使用js实现动画啦!我们来看看这段代码:
完整代码
复制代码
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 };
复制代码
完整代码:
完整代码
效果演示(可运行)J可以发子弹,没有子弹就到高版本浏览器去试试
http://sandbox.runjs.cn/show/evpyzcku
结语
好了,今天到此为止,后面点我们来一步步修改代码,让代码变得“面向对象”,有机会便加上砖块和其它东东。
今天的代码不用说,千疮百孔,无论是性能方面,或者代码优雅度,还是神马都一团糟糕,但是经过几个小时的奋战,我现在脑子已经不好使了,只好暂时停一下。
我们后面点优化吧。
本文转自叶小钗博客园博客,原文链接http://www.cnblogs.com/yexiaochai/archive/2013/06/12/3132553.html,如需转载请自行联系原作者