Html5小游戏之【是男人就忍30秒】
好久没写过小游戏了,最近抽时间写了一个,看了一些高人写的游戏,无限感慨呀。。。也从中学到了不少东西。
我不会写什么大的游戏,因为需要很多时间与精力,而且自认水平有限,个人喜欢写些小游戏。
这次的游戏是【是男人就忍30秒】,游戏玩法很简单,就是用键盘控制飞机,飞来飞去,躲开子弹,看你能撑多久。
本来是打算写一个教程来一步步说明的,但后来想了想,还是算了,免得误人子弟,在源码上加些注释就可以。
没有测试过IE9,因为没有IE9。。。鄙人还是用XP的。。。所以还是请用谷歌或者FF或者Safari吧。
刚刚修复了在FF下不能使用的问题,因为没给canvas设置tabindex属性,它就不能触发keydown事件,以及设置canvas为focus,现在可以了。。。
游戏预览如下:
请使用chrome,safari,ff
此游戏用了四个js文件。
1。canvas.js,简单了封装了一些需要用到的画图方法,相信一看就懂了。。。
1
//
画布类
2
var
Canvas
=
{
3
//
画布的2d对象
4
cxt :
null
,
5
//
初始化画布
6
init :
function
(id){
7
this
.cxt
=
(
typeof
id
==
\’
string
\’
?
document.getElementById(id):id).getContext(
\’
2d
\’
);
8
},
9
//
清除画布
10
clear :
function
(x,y){
11
this
.cxt.clearRect(
0
,
0
,x,y);
12
},
13
//
画图
14
drawImg :
function
(obj){
15
this
.cxt.drawImage(obj.img,obj.x,obj.y);
16
},
17
//
画文字
18
drawText :
function
(string,x,y,color){
19
20
this
.cxt.fillStyle
=
color;
21
this
.cxt.font
=
\’
bold 14px sans-serif
\’
;
22
this
.cxt.fillText(string,x,y);
23
},
24
//
加载图片
25
//
imgs:图片对象的数组
26
//
callback:回调函数
27
//
context:上下文对象
28
loadImgs :
function
(imgs,callback,context){
29
30
var
success_count
=
0
;
31
32
var
addCount
=
function
(){
33
success_count
+=
1
;
34
35
if
(success_count
==
l)callback
&&
callback.call(context);
36
}
37
38
for
(
var
i
=
0
,l
=
imgs.length;i
<
l;i
++
){
39
imgs[i].onload
=
addCount;
40
}
41
42
}
43
}
2。fly.js,飞机类,采用在计时器中移动,而非一般的键盘按一下就移动一格,这样做,控制得更流畅,而且,可以支持打斜飞。
1
var
Fly
=
function
(img,x,y){
2
//
飞机的图片
3
this
.img
=
img;
4
//
飞机的坐标
5
this
.x
=
x;
6
this
.y
=
y;
7
//
飞机的移动方向值
8
this
.moveDir
=
{
9
left:
false
,
10
right:
false
,
11
up:
false
,
12
down:
false
13
};
14
//
移动的速度
15
this
.movesp
=
2
;
16
}
17
Fly.prototype
=
{
18
//
键盘码对应移动方向
19
keyCode2Dir : {
20
37
:
\’
left
\’
,
21
38
:
\’
up
\’
,
22
39
:
\’
right
\’
,
23
40
:
\’
down
\’
24
},
25
//
键盘按下事件
26
//
keyCode:键盘码
27
keyDown :
function
(keyCode){
28
//
修改对应的移动值
29
this
.moveDir[
this
.keyCode2Dir[keyCode]]
=
true
;
30
},
31
//
键盘释放事件
32
//
keyCode:键盘码
33
keyUp :
function
(keyCode){
34
//
修改对应的移动值
35
this
.moveDir[
this
.keyCode2Dir[keyCode]]
=
false
;
36
},
37
//
判断是否在移动中
38
checkMove :
function
(){
39
if
(
this
.moveDir.left
||
this
.moveDir.right
||
this
.moveDir.up
||
this
.moveDir.down)
return
true
;
40
return
false
;
41
},
42
//
移动
43
//
gameInfo:游戏背景信息
44
move :
function
(gameInfo){
45
46
var
This
=
this
;
47
//
根据方向来移动
48
if
(This.moveDir.left)This.x
-=
This.movesp;
49
if
(This.moveDir.right)This.x
+=
This.movesp;
50
if
(This.moveDir.up)This.y
-=
This.movesp;
51
if
(This.moveDir.down)This.y
+=
This.movesp;
52
//
边界值检测
53
if
(This.x
<
0
)This.x
=
0
;
54
else
if
(This.x
>
gameInfo.width
–
This.img.width)This.x
=
gameInfo.width
–
This.img.width;
55
if
(This.y
<
0
)This.y
=
0
;
56
else
if
(This.y
>
gameInfo.height
–
This.img.height)This.y
=
gameInfo.height
–
This.img.height;
57
}
58
59
}
3。bullet.js,子弹类,子弹的飞,我承认,确实做得很简单,希望大家自己改进这个算法。。。
1
var
Bullet
=
function
(img){
2
//
子弹的图片
3
this
.img
=
img;
4
//
X坐标
5
this
.x
=
0
;
6
//
Y坐标
7
this
.y
=
0
;
8
//
子弹要飞的x与y的速度
9
this
.arc
=
{};
10
//
移动的帧数
11
this
.moveFps
=
20
;
12
//
帧数延迟
13
this
.moveFpsLazy
=
0
;
14
//
初始化
15
this
.init();
16
}
17
Bullet.prototype
=
{
18
//
方向数组
19
arrDir : [
\’
left
\’
,
\’
right
\’
,
\’
up
\’
,
\’
down
\’
],
20
//
初始化
21
init :
function
(){
22
//
最小位置
23
var
min
=
5
,
24
//
最大位置
25
max
=
395
,
26
//
随机位置
27
rnd
=
Math.floor(Math.random()
*
370
+
10
),
28
//
移动方向
29
dir
=
this
.arrDir[Math.floor(Math.random()
*
4
)];
30
31
//
设置子弹的初始位置与将要飞的方向与速度
32
switch
(dir){
33
case
\’
left
\’
:{
34
this
.x
=
max;
35
this
.y
=
rnd;
36
if
(
this
.y
>=
max
/
2)this.arc = {x:-5,y:-2};
37
else
this
.arc
=
{x:
–
5
,y:
2
};
38
break
;
39
}
40
case
\’
right
\’
:{
41
this
.x
=
min;
42
this
.y
=
rnd;
43
if
(
this
.y
>=
max
/
2)this.arc = {x:5,y:-2};
44
else
this
.arc
=
{x:
5
,y:
2
};
45
break
;
46
}
47
case
\’
up
\’
:{
48
this
.y
=
max;
49
this
.x
=
rnd;
50
if
(
this
.x
>=
max
/
2)this.arc = {x:-3,y:-5};
51
else
this
.arc
=
{x:
3
,y:
–
5
};
52
break
;
53
}
54
case
\’
down
\’
:{
55
this
.y
=
min;
56
this
.x
=
rnd;
57
if
(
this
.x
>=
max
/
2)this.arc = {x:-3,y:5};
58
else
this
.arc
=
{x:
3
,y:
5
};
59
break
;
60
}
61
}
62
},
63
//
更新子弹数据
64
//
gameInfo:游戏背景信息
65
updata :
function
(gameInfo){
66
//
延迟+10
67
this
.moveFpsLazy
+=
10
;
68
//
判断延迟是否等于移动帧数
69
if
(
this
.moveFpsLazy
==
this
.moveFps){
70
//
移动
71
this
.x
+=
this
.arc.x;
72
this
.y
+=
this
.arc.y;
73
//
边界值检测
74
if
(
this
.x
<
0
||
this
.x
>
gameInfo.width
||
this
.y
<
0
||
this
.y
>
gameInfo.height){
75
this
.callback();
76
return
false
;
77
}
78
//
清0
79
this
.moveFpsLazy
=
0
;
80
}
81
},
82
//
检测是否撞到飞机
83
//
fly:飞机对象
84
checkCrashFly :
function
(fly){
85
//
获取子弹与飞机的圆心坐标
86
var
bx
=
this
.x
+
this
.img.width
/
2,by = this.y+this.img.height
/
2
,
87
fx
=
fly.x
+
fly.img.width
/
2,fy = fly.y+fly.img.height
/
2
;
88
//
判断圆心距
89
if
(Math.sqrt(Math.pow(bx
–
fx,
2
)
+
Math.pow(by
–
fy,
2
))
<
(fly.img.width
/
2+this.img.width
/
2
)){
90
return
true
;
91
}
92
return
false
;
93
},
94
//
回调函数
95
callback :
function
(){}
96
97
}
4。Game.js,游戏控制类,主要控制游戏的逻辑
1
var
Game
=
{
2
//
游戏背景数据,主要是宽与高
3
gameInfo :{width:
0
,height:
0
},
4
//
飞机对象
5
fly :
null
,
6
//
子弹对象数组
7
bullets : [],
8
//
子弹图片
9
bulletImg :
null
,
10
//
子弹产生的延迟
11
bulletLazyFps :
0
,
12
//
绘画处理计时器ID
13
processId :
0
,
14
//
分数
15
score :
0
,
16
//
是否开始
17
isStart :
false
,
18
//
显示开始信息
19
showStart :
function
(){
20
21
var
This
=
this
;
22
//
画开始字
23
Canvas.drawText(
“
Press Enter to Start!
“
,
120
,
200
,
\’
white
\’
);
24
//
绑定事件
25
document.body.onkeydown
=
function
(e){This.keyDown(e);};
26
document.body.onkeyup
=
function
(e){This.keyUp(e);};
27
},
28
//
游戏初始化
29
init :
function
(){
30
//
设置游戏背景信息
31
var
gameBg
=
document.getElementById(
\’
js_canvas
\’
);
32
this
.gameInfo.width
=
gameBg.offsetWidth;
33
this
.gameInfo.height
=
gameBg.offsetHeight;
34
//
初始化画布
35
gameBg.focus();Canvas.init(gameBg);
36
//
设置飞机图片与子弹图片
37
var
flyImg
=
new
Image();
38
var
bulletImg
=
new
Image();
39
flyImg.src
=
“
img/fly.gif
“
;
40
bulletImg.src
=
“
img/bullet.gif
“
;
41
//
加载图片,成功后,回调显示开始信息
42
Canvas.loadImgs([flyImg,bulletImg],
this
.showStart,
this
);
43
//
设置飞机对象
44
this
.fly
=
new
Fly(flyImg,
200
,
200
);
45
//
设置Game子弹图片
46
this
.bulletImg
=
bulletImg;
47
},
48
//
生成子弹
49
createBullets :
function
(){
50
51
var
This
=
this
;
52
//
判断延时是否200
53
if
(
this
.bulletLazyFps
==
200
){
54
//
创建子弹,添加到数组中
55
var
bullet
=
new
Bullet(
this
.bulletImg);
56
bullet.callback
=
function
(){
57
This.removeBullet(
this
);
58
}
59
60
this
.bullets.push(bullet);
61
this
.bulletLazyFps
=
0
;
62
}
63
else
{
64
this
.bulletLazyFps
+=
10
;
65
}
66
},
67
//
开始
68
start :
function
(){
69
70
var
This
=
this
;
71
//
重置数据
72
this
.reset();
73
//
设置开始
74
this
.isStart
=
true
;
75
//
开始绘画
76
this
.process();
77
78
},
79
//
重置数据
80
reset :
function
(){
81
82
this
.score
=
0
;
83
this
.bullets
=
[];
84
},
85
//
结束
86
end :
function
(){
87
88
this
.isStart
=
false
;
89
90
clearInterval(
this
.processId);
91
92
this
.showStart();
93
},
94
//
绘画函数
95
process :
function
(){
96
97
var
This
=
this
;
98
//
绘画计时器
99
this
.processId
=
setInterval(
function
(){
100
101
if
(
!
This.isStart)
return
;
102
//
清除画布
103
Canvas.clear(This.gameInfo.width,This.gameInfo.height);
104
//
判断飞机是否移动
105
if
(This.fly.checkMove())This.fly.move(This.gameInfo);
106
//
画飞机
107
Canvas.drawImg(This.fly);
108
//
生产子弹
109
This.createBullets();
110
//
画出所有子弹
111
for
(
var
i
=
0
,l
=
This.bullets.length;i
<
l;i
++
){
112
113
var
bullet
=
This.bullets[i];
114
115
if
(
!
bullet)
continue
;
116
//
更新子弹信息
117
bullet.updata(This.gameInfo);
118
//
画子弹
119
Canvas.drawImg(bullet);
120
//
检测是否撞到飞机
121
if
(bullet.checkCrashFly(This.fly)){
122
This.end();
123
}
124
}
125
//
画分数
126
Canvas.drawText(Math.floor(This.score
/
1000)+”秒”,20,20,\’white\’);
127
This.score
+=
10
;
128
},
10
);
129
},
130
//
键盘按下事件
131
keyDown :
function
(e){
132
133
var
This
=
this
;
134
//
游戏还没开始,而且按了回车
135
if
(e.keyCode
==
13
&&
!
this
.isStart){
136
e.preventDefault();
137
//
开始
138
this
.start();
139
}
140
//
游戏开始而且按了方向键
141
if
(e.keyCode
>=
37
&&
e.keyCode
<=
40
&&
this
.isStart){
142
e.preventDefault();
143
144
This.fly.keyDown(e.keyCode);
145
}
146
},
147
//
键盘释放事件
148
keyUp :
function
(e){
149
150
var
This
=
this
;
151
//
释放了方向键
152
if
(e.keyCode
>=
37
&&
e.keyCode
<=
40
){
153
e.preventDefault();
154
155
This.fly.keyUp(e.keyCode);
156
}
157
},
158
//
移除子弹
159
removeBullet :
function
(item){
160
161
for
(
var
i
=
0
,l
=
this
.bullets.length;i
<
l;i
++
){
162
163
if
(
this
.bullets[i]
==
item){
164
this
.bullets.splice(i,
1
);
165
return
true
;
166
}
167
}
168
}
169
170
}
突然发觉自己写的那些,为啥会那么卡了。。。因为,我以前都是计时器分开来写,后来才发现,要放在同一个计时器去做动画。。。
希望大家喜欢,有啥不好的,欢迎指出。。。
源码下载>>