Contents
  1. 1. 无意义的碎碎念
  2. 2. 头疼的安全问题
  3. 3. 伪·正片

基础能吃人

无意义的碎碎念

之前花了一周左右的时间细读了《Pro HTML5 Games》这本书的前5章,发现一个很重要的道理,变量的对象(函数)化封装非常的重要,一个能够防止歧义,避免环境污染,还有一个是是代码显得简洁美观。

没有任何基础的情况下(纯原生canvas),当初做一个类东方游戏的时候,我是这样写的;总共近1k行,放个前一百行,你们体验一下:

捂眼(瞎)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// game.js
var canvas,
ctx,
w,
h,
bgPIC = new Image(),
picLoc,
picSpeed = 0.2;
//load the background
bgPIC.src = "./img/bg.png";
//console.log(bgPIC.src)
EventUtil.addHandler(window, "load", start);
EventUtil.addHandler(window, "keydown", key_down)
EventUtil.addHandler(window, "keyup", key_up)
//the game
var gameover = false,
score = 0,
Fscore = 0,
scoreL = true,
edgeScore = 5,
sScore = 200,
mScore = 500,
backgroundColor = "rgb(235,0,0)",
menuColor = "rgb(30, 30 ,100)";
//your role
var ballinit = {
x : 150,
y : 300,
r : 4,
vx : 0,
vy : 0,
v : 5, //temp speed
sv : 2, //slow speed
nv : 5, //normal speed
rate : 2.5, // nv/sv
color : "rgba(255,0,0,1)",
isSlow : false,
isProtected : false,
};
//to get the copyright
var ball = new Object();
for(var pro in ballinit){ball[pro] = ballinit[pro];}
//myThings
var lifeLeft = 2,
bombsinit = 3,
bombsLeft = 3,
bullets = [],
bombs = [],
bombAvai = true,
bombCD = 5000,
protectTime = 2000;
//enemyThings
var enemyBullet = [],
enemis = [],
levelupCD = 30000,
levelNum = 0,
level = {
dayuT : 3000,
zhongyuT : 2000,
EST : 1000,
EMT : 2000,
},
ts1,ts2,ts3,ts4,ts5,ts6,levelup;
//check the key
var isDowninit = {
up : false,
down : false,
left : false,
right : false,
item : false,
};
//getthe copyof isDown
var isDown = new Object();
for(var pro in isDowninit){isDown[pro] = isDowninit[pro]};
isDown.shoot = false;
function start(){
canvas = document.getElementById('canvas')
ctx = canvas.getContext('2d')
canvas.width = 500
canvas.height = 400
w = canvas.width - 200
h = canvas.height
picLoc=bgPIC.height-bgPIC.width*h/w
//isProtected() //init protect
var ts1 = setInterval(function(){
update(ball)
render(ball, ctx)
}, 20)
var ts2 = setInterval(function(){
//quadra shot
if(isDown.shoot){
if(ball.isSlow){
bullets.push(
bullet({swing:0.3,dx:4,dy:-3}),
bullet({swing:-0.3,dx:-4,dy:-3}),
bullet({swing:1,dx:10,dy:5}),
bullet({swing:-1,dx:-10,dy:5})
);
}else {
bullets.push(
bullet({swing:2,dx:7,dy:-3}),
bullet({swing:-2,dx:-7,dy:-3}),
bullet({swing:6,dx:15,dy:20}),
bullet({swing:-6,dx:-15,dy:20})
);
}
}
}, 50)
IntervalStart()
levelup = setInterval(levelUP, levelupCD)
}

举个例子。
一个场景对象state,我们要创建它,初始化它,更新它,渲染它,我们就不应该凌乱的陈列函数,应该用对象或是方法去封装它们比如这样:

1
2
3
4
5
6
var state = {
create: function() {},
init: function() {},
update: function() {},
render: function() {},
}

不过我更推荐下面这个构造函数(慎用)

1
2
3
4
5
6
function state () {
this.create = function() {};
this.init = function() {};
this.update = function() {};
this.render = function() {};
}

一些零碎而重要的全局变量和参数,也应该封装:

1
2
3
4
5
6
7
8
9
10
11
12
var game = {
ctx: Document.getElementById("canvas").getContext('2d'),
init: function(){},
// sth else
}
var box2d = {
scale: 30,
// else...
}

这样说可能让人更凌乱了。但是不管一个HTML游戏怎么变,都可以归于几个模块(以angry bird为例):

  • 最开头的自执行函数
    用于某些无法解释的黑科技。

  • game对象
    包含其他对象的初始化,DOM的操作判断,背景音乐的判断控制,游戏的进程管理控制,动画的数据更新与渲染器管理,以及其他不会分类的变量与方法

  • levels对象
    用于存放每一关的数据,包括音乐图片敌人数据以及它们的初始化方法和加载的方法。

  • entities对象
    存放每一种敌人或互动物体的详细信息,和创建它们时“数形结合”的方法。

  • box2d对象
    具体的物理引擎的内部方法的简化与具体实现。

  • loader对象
    加载器,所有的音乐图片加载统一用这个对象里的的方法,包括浏览器的支持,加载与渲染的顺序问题等。

  • mouse对象
    初始化鼠标操作的事件,监听移动,按下,放开等状态。

封装好以后,游戏就变成这样辣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// game.js
(function(){...
})();
$(window).load(function(){
game.init();
});
// 基本的游戏对象
var game = {...
};
// 关卡对象
var levels = {...
};
// 所有物体
var entities = {...
};
// Box2D世界对象
var box2d = {
};
// 图像声音资源加载器
var loader = {...
};
// 鼠标
var mouse = {...
};

是不是看的很爽!

头疼的安全问题

在涉及到webGL的时候,学习瓶颈的出现往往是代码OK的情况下,只要一出现drawImage,Safari抛出个”SecurityError”,Chrome抛出个”canvas tainted by cross-origin data”,解决无果,心灰意冷,放弃。

今天要学习的Phaser也是一样,就好像好不容易看上挺好一妹子,谈不上话,心塞塞。英文文档看的很吃力,前辈们表示不会,心灰意冷。一个简单的图片移动的例子,十几行代码,就是跑不动。幸好把源码放到FF里时,它跑动了,在解决跨域资源问题之前,我先把火狐当祖宗一样供着吧!(拥抱ES6)

伪·正片

我们来谈谈Phaser

Phaser.js是一个游戏引擎,目前将要出Phaser3版本。它帮开发者造好了轮子,直接通过Phaser对象方法来完成游戏的开发。

这个引擎说大不大,说小不小,近10w行代码,压缩后也还有700多kb。用这个引擎做的游戏很多,在js游戏引擎里它现在的排名是第一。我始终保持这个一个观点,框架、引擎这种东西,永远是让你程序写得更舒服而存在的,如果它让你不舒服了,那就没有学的必要。

Contents
  1. 1. 无意义的碎碎念
  2. 2. 头疼的安全问题
  3. 3. 伪·正片