phaserjs教程一之像素小鸟
Phaser是一个简单易用且功能强大的html5游戏框架,利用它可以很轻松的开发出一个html5游戏。
项目上线一周,闲来无事,捣鼓一个新的框架吧!
1.Phaser的使用非常简单,只需要引入它的主文件,然后在页面中指定一个用来放置canvas的元素,然后实例化一个 Game 对象就可以了。当然如果不指定canvas元素的存放位置会默认到body里面。
html代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<html>
<head>
<meta content="yes" name="apple-mobile-web-app-capable"/>
<meta content="yes" name="apple-touch-fullscreen"/>
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
<meta charset="utf-8" />
<title>flappy bird</title>
<style type="text/css">
*{
padding: 0px;
margin: 0px;
}
</style>
</head>
<body>
<script src="js/phaser.min.js"></script>
<script src="js/game.js"></script>
</body>
</html>
2.然后实例化一个Game对象
部分代码如下:1
2
3
4window.onload = function(){
var renderMode = Phaser.Device.isAndroidStockBrowser() ? Phaser.CANVAS: Phaser.AUTO;
game = new Phaser.Game(320, 505, renderMode, null, bootState);
}
稍微解析下Phaser.Game这个函数1
Phaser.Game(width, height, renderer, parent, state, transparent, antialias, physicsConfig)
width: 渲染游戏的canvas的宽度
height: 渲染游戏的canvas的高度
renderer: 渲染方式,Phaser.CANVAS为画布,Phaser.WEBGL为WebGL来渲染,Phaser.AUTO为自动侦测
parent: 用来放置canvas元素的父元素,可以是一个元素id,也可以是dom元素本身,phaser会自动创建一个canvas并插入到这个元素中,实测不带会追加到body
state: state可以理解为场景,在这里指定state表示让游戏首先加载这个场景,但也可以不在这里指定state,而在之后的代码中决定首先加载哪个state。
transparent: 是否使用透明的canvas背景
antialias: 是否启用抗锯齿
physicsConfig: 游戏物理系统配置参数
3.实例化Game对象后,接下来要做的就是创建游戏的各种场景(state)。state可以是一个js自定义对象,也可以是一个函数,只要它们存在preload、create、update这三个方法中的任意一个,就是一个合法的state。
ex: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//state可以是一个自定义对象
var state1 = {
preload : function(){},
create : function(){},
update : function(){}
}
//state也可以是一个构造函数
var state2 = function(){
this.preload = function(){};
this.create = function(){};
this.update = function(){};
}
//只要存在preload、create、update三个方法中的一个就可以了
var state3 = function(){
this.update = function(){};
}
//当然state里也可以存在其他属性或方法
var state4 = function(){
this.create = function(){};
this.funcA = function(){}; //其他方法
this.funcB = 'hello'; //其他属性
}
其中
- preload是预加载(最先执行)
- create是初始化以及构建场景
- update是更新函数,会在游戏的每一帧都执行,以此来创造一个动态的游戏。
在文中代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var bootState = function(){
this.preload = function(){};
this.create = function(){};
this.update = function(){};
}
var preloadState = function(){
this.preload = function(){};
this.create = function(){};
this.update = function(){};
}
var menuState = function(){
this.preload = function(){};
this.create = function(){};
this.update = function(){};
}
var playState = function(){
this.preload = function(){};
this.create = function(){};
this.update = function(){};
}
4.制作资源加载进度条
游戏要用到的一些图片、声音等资源都需要提前加载,有时候如果资源很多,就有必要做一个资源加载进度的页面,提高用户体验,这时在预加载场景用到的进度条需要在一个基础的场景来加载,命名这个场景为bootState。
具体代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21bootState = function(){
this.preload = function(){
game.load.image('loading','assets/preloader.gif');
};
this.create = function(){
game.canvas.style.backgroundColor = "#000000";
game.canvas.oncontextmenu = function(e) {
e.preventDefault()
};
game.stage.disableVisibilityChange = true;
game.device.desktop ? this.scale.scaleMode = Phaser.ScaleManager.EXACT_FIT : this.scale.scaleMode = Phaser.ScaleManager.EXACT_FIT;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
game.scale.refresh();
this.scale.forcePortrait = true;
this.input.maxPointers = 1;
game.state.add('preloadState',preloadState);
game.state.start('preloadState');
};
}
5.加载资源
Phaser中资源的加载都是通过 Phaser.Loader 这个对象的方法来完成的,游戏实例的load属性就是指向当前游戏的Loader对象,在我们这里就是game.load。
代码如下: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
27preloadState = function(){
this.preload = function(){
var preloadSprite = game.add.sprite(35,game.height/2,'loading');
game.load.setPreloadSprite(preloadSprite);
game.load.image('background','assets/background.png');
game.load.image('ground','assets/ground.png');
game.load.image('title','assets/title.png');
game.load.spritesheet('bird','assets/bird.png',34,24,3);
game.load.image('btn','assets/start-button.png');
game.load.spritesheet('pipe','assets/pipes.png',54,320,2);
game.load.bitmapFont('flappy_font', 'assets/fonts/flappyfont/flappyfont.png', 'assets/fonts/flappyfont/flappyfont.fnt');
game.load.audio('fly_sound', 'assets/flap.wav');
game.load.audio('score_sound', 'assets/score.wav');
game.load.audio('hit_pipe_sound', 'assets/pipe-hit.wav');
game.load.audio('hit_ground_sound', 'assets/ouch.wav');
game.load.image('ready_text','assets/get-ready.png');
game.load.image('play_tip','assets/instructions.png');
game.load.image('game_over','assets/gameover.png');
game.load.image('score_board','assets/scoreboard.png');
}
this.create = function(){
game.state.add('menuState',menuState);
game.state.start('menuState');
}
}
6.制作游戏菜单页面
代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19menuState = function(){
this.create = function(){
game.add.tileSprite(0,0,game.width,game.height,'background').autoScroll(-10,0);
game.add.tileSprite(0,game.height-112,game.width,112,'ground').autoScroll(-100,0);
var titleGroup = game.add.group();//Phaser.Group,也就是组。组相当于一个父容器
titleGroup.create(0,0,'title');
var bird = titleGroup.create(190, 10, 'bird');
bird.animations.add('fly');
bird.animations.play('fly',12,true);
titleGroup.x = 35;
titleGroup.y = 100;
game.add.tween(titleGroup).to({ y:120 },1000,null,true,0,Number.MAX_VALUE,true);
var btn = game.add.button(game.width/2,game.height/2,'btn',function(){
game.state.add('playState',playState);
game.state.start('playState');
});
btn.anchor.setTo(0.5,0.5);
}
}
TileSprite本质上还是一个sprite对象,TileSprite的贴图既可以水平移动也可以垂直移动,或者两者同时移动,我们只需要调用TileSprite对象的autoScroll(x,y)方法就可以使它的贴图动起来
7.游戏主场景
部分代码:
启用物理系统,默认是关闭的
1 | game.physics.enable(object, system, debug) |
object : 要开启物理系统的对象,可以是单个对象,也可以是一个包含多个对象的数组
system : 要启用的物理系统,默认为 Phaser.Physics.ARCADE,Phaser目前支持三种物理引擎,分别是Arcade ,P2 以及 Ninja。
debug : 是否开启调试
鼠标点击事件
1 | var input = game.input; //当前游戏的input对象 |
计时器
Phaser提供Timer对象来实现1
2loop(delay, callback, callbackContext, arguments); //以指定的时间间隔无限重复执行某一个函数,直到调用了Timer对象的stop()方法才停止
repeat(delay, repeatCount, callback, callbackContext, arguments); //让某个函数重复执行,可以指定重复的次数
ex:1
2game.time.events.loop(time, function(){}, this); //利用时钟对象来重复产生管道
game.time.events.stop(false); //先让他停止,因为即使没调用start方法,它也会自动启动,这应该是一个bug
重力和速度
Phaser.Physics.Arcade.Body 对象,也就是当你是用arcade物理引擎时 sprite.body 所指向的对象,拥有很多跟物理相关的属性和方法。其中的 gravity 对象代表重力,它有x和y两个属性,分别代表水平方向和垂直方向的重力。我们可以使用它的 setTo(x,y)方法来同事设置两个方向的重力。设置了重力的物体,它的运动会受到重力的影响,与真实生活中的物理现象是一致的。然后这个body它还有一个 velocity 对象,表示物体的速度,跟重力一样,都分水平和垂直两个方向,也可以用setTo(x,y)方法来设置。一旦给物体设置了合适的速度,它便能动了
碰撞检测
在Arcade物理引擎中,碰撞检测主要用到两个函数,一个是collide,还有一个是overlap。
声音的播放
ex:1
2
3game.load.audio('score_sound', 'assets/score.wav');//得分的音效
this.soundScore = game.add.sound('score_sound');
this.soundScore.play(); //播放声音