Phaser是一个简单易用且功能强大的html5游戏框架,利用它可以很轻松的开发出一个html5游戏。在这篇文章中我就教大家如何用Phaser来制作一个前段时间很火爆的游戏:Fla
Phaser是一个简单易用且功能强大的html5游戏框架,利用它可以很轻松的开发出一个html5游戏。在这篇文章中我就教大家如何用Phaser来制作一个前段时间很火爆的游戏:Flappy Bird,希望大家看后也能做出自己的html5游戏。大家可以先点击这里来试玩一下我已经做好的这个游戏,感受一下Phaser的游戏效果,游戏的完整代码我已经放到github上了。支持的浏览器:IE9+、Firefox、Chrome、Opera、Safari以及移动端的能支持html5的浏览器,推荐使用谷歌浏览器,因为它性能最好。 phaser.js的源码可以到它在github上的托管里去下载,游戏要用到的图片声音等素材资源请点击这里下载。Phaser的使用非常简单,只需要引入它的主文件,然后在页面中指定一个用来放置canvas的元素,然后实例化一个 Game 对象就可以了。
实例化Game对象后,接下来要做的就是创建游戏会用到的各种场景了,也就是上面说的state,那么怎么才能创建一个state呢?state可以是一个js自定义对象,也可以是一个函数,只要它们存在preload、create、update这三个方法中的任意一个,就是一个合法的state。
//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.aaa = function(){ }; //其他方法
this.bbb = 'hello'; //其他属性
}
在这个游戏中,我们会用到4个state,我们可以通过game.state.add()方法来给游戏添加state,然后用game.state.start()方法来调用state,详细信息请看state的文档
var game = new Phaser.Game(288,505,Phaser.AUTO,'game');
game.States = {}; //创建一个对象来存放要用到的state
game.State.boot = function(){ ... } //boot场景,用来做一些游戏启动前的准备
game.State.prelaod = function(){ ... } //prelaod场景,用来显示资源加载进度
game.State.menu = function(){ ... } //menu场景,游戏菜单
game.State.play = function(){ ... } //play场景,正式的游戏部分
//把定义好的场景添加到游戏中
game.state.add('boot',game.States.boot);
game.state.add('preload',game.States.preload);
game.state.add('menu',game.States.menu);
game.state.add('play',game.States.play);
//调用boot场景来启动游戏
game.state.start('boot');
制作资源加载进度条
游戏要用到的一些图片、声音等资源都需要提前加载,有时候如果资源很多,就有必要做一个资源加载进度的页面,提高用户等待的耐心。这里我们用一个state来实现它,命名为preload。
因为资源加载进度条需要一个进度条的背景图片,所以在制作这个state前,我们还需要另一个最基础的state,用来加载那张进度条图片,我们命名为boot。
game.States.boot = function(){
this.preload = function(){
game.load.image('loading','assets/preloader.gif'); //加载进度条图片资源
};
this.create = function(){
game.state.start('preload'); //加载完成后,调用preload场景
};
}
在preload这个场景中,我们需要把游戏后面会用到的所有资源都进行加载,然后还要展示一个加载进度条给用户看。Loader对象提供了一个 setPreloadSprite 方法,只要把一个sprite对象指定给这个方法,那么这个sprite对象的宽度或高度就会根据当前加载的百分比自动调整,达到一个动态的进度条的效果。
game.States.preload = function(){
this.preload = function(){
var preloadSprite = game.add.sprite(50,game.height/2,'loading'); //创建显示loading进度的sprite
game.load.setPreloadSprite(preloadSprite); //用setPreloadSprite方法来实现动态进度条的效果
//以下为要加载的资源
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'); //get ready图片
game.load.image('play_tip','assets/instructions.png'); //玩法提示图片
game.load.image('game_over','assets/gameover.png'); //gameover图片
game.load.image('score_board','assets/scoreboard.png'); //得分板
}
this.create = function(){
game.state.start('menu'); //当以上所有资源都加载完成后就可以进入menu游戏菜单场景了
}
}
首先是背景图与地面,我们看到这两个东西是会动的,地面移动动的速度快一些,背景图慢一些,在Phaser中有专门的东西来处理这种效果,叫做TileSprite,什么是TileSprite呢?TileSprite本质上还是一个sprite对象,不过这个sprite的贴图是可以移动的,并且会自动平铺来弥补移动后的空缺,所以我们的素材图片要是平铺后看不出有缝隙,就可以拿来当做TileSprite的移动贴图了。TileSprite的贴图既可以水平移动也可以垂直移动,或者两者同时移动,我们只需要调用TileSprite对象的autoScroll(x,y)方法就可以使它的贴图动起来了,其中x是水平方向的速度,y是垂直方向的速度。
game.States.menu = function(){
this.create = function(){
var bg = game.add.tileSprite(0,0,game.width,game.height,'background'); //当作背景的tileSprite
var ground = game.add.tileSprite(0,game.height-112,game.width,112,'ground').autoScroll(-100,0); //当作地面的tileSprite
bg.autoScroll(-10,0); //让背景动起来
ground.autoScroll(-100,0); //让地面动起来
}
}
下面再说一个非常重要的对象:Phaser.Group,也就是组。组相当于一个父容器,我们可以把许多对象放进一个组里,然后就可以使用组提供的方法对这些对象进行一个批量或是整体的操作。比如要使组里的对象同意进行一个位移,只需要对组进行位移就可以了,又比如要对组里的所有对象都进行碰撞检测,那么就只需要对这个组对象进行碰撞检测就行了。下面我们要制作的这个游戏标题是由一张文字图片和一支鸟组成的,我们就是把这两个东西放在一个组中,然后来进行整体的操作。
game.States.menu = function(){
this.create = function(){
......
var titleGroup = game.add.group(); //创建存放标题的组
titleGroup.create(0,0,'title'); //通过组的create方法创建标题图片并添加到组里
var bird = titleGroup.create(190, 10, 'bird'); //创建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); //对这个组添加一个tween动画,让它不停的上下移动
}
}
game.States.menu = function(){ this.create = function(){
...... var btn = game.add.button(game.width/2,game.height/2,'btn',function(){//添加一个按钮
game.state.start('play'); //点击按钮时跳转到play场景 });
btn.anchor.setTo(0.5,0.5); //设置按钮的中心点 }
}
game.States.menu = 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(); //创建存放标题的组
titleGroup.create(0,0,'title'); //标题
var bird = titleGroup.create(190, 10, 'bird'); //添加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.start('play');
});
btn.anchor.setTo(0.5,0.5);
}
}