phaser是一个优秀的前端canvas库,封装了不少底层的实现,能够用来制做游戏,h5场景等。今年1月新发布了phaser3,到今天为止已经更新到了3.30。html
本游戏来自于phaser小站的官方教程,加入了一些我的的注释,本文旨在帮助各位观众老爷快速上手。
各位看官也能够直接移步phaser官网查看教程前端
每个步骤后面都贴了代码,若是由于个人写做方式让您难以接受,能够直接到每一个步骤后面复制代码git
你须要一份phaser3.js
也可能须要一份文档
若是有一份随时查阅的范例固然更好
一个本地服务器
一份包含素材的空[项目]()github
这里是为观众老爷们准备的github仓库,有咱们须要的素材和脚本文件canvas
git clone https://github.com/YexChen/canvas_game.git
打开咱们的项目文件夹,修改index.html浏览器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="js/phaser.min.js"></script> <style> body{ } </style> </head> <body> <script> //生成配置文件 const config = { //初始化游戏类型 type : Phaser.AUTO, width : 800, height : 600, //物理引擎 physics : { default : 'arcade', arcade : { //重力设置 gravity : {y : 300}, debug : false } }, //场景设置 scene : { preload, create, update } } //初始化游戏 let game = new Phaser.Game(config) //游戏主要函数 function preload(){ } function create(){ } function update(){ } </script> </body> </html>
而后在命令行运行http-server,打开浏览器,效果是否是出来了呢?服务器
在上面的脚本中,咱们定义了三个函数,preload,create,update,分别表明游戏中的预加载,初始化函数,更新函数。
在preload函数中加入如下代码段:ide
this.load.image("sky","./img/sky.png") this.load.image("star","./img/star.png") this.load.image("ground","./img/platform.png") this.load.image("bomb","./img/bomb.png") this.load.spritesheet("dude","./img/dude.png",{frameWidth:32,frameHeight:48})
spritesheet是精灵图的加载方式,frameWidth是每帧的宽度,frameHeight是帧的高度,有兴趣的朋友们能够量一量函数
摸了这么久的鱼,也该看点成果了吧,咱们来制做主场景:
在create函数中加入:动画
this.add.image(400,300,"sky")
保存,刷新,咱们的界面上是否是出现了一片蓝天呢?
this.add.image(offsetX,offSetY,imagename) 有兴趣的朋友们能够调下参数,试一下(0,0,'sky')是在哪一个地方的
让咱们来继续添加场景吧,紧跟着上一句输入如下代码:
platforms = this.physics.add.staticGroup() platforms.create(400,568,"ground").setScale(2,2).refreshBody() platforms.create(600,400,"ground") platforms.create(0,300,"ground") platforms.create(600,200,"ground") platforms.create(0,100,"ground")
create(x,y,imagename) selScale(x,y):把图片缩放x,y倍,若是不设置y的话就按x的倍数缩放 这个refreshbody你们能够去掉,后面会有惊喜的
这样场景就绘制出来了,各位看官也能够本身设置参数,制做属于本身的游戏场景
尽可能不要作出这种反人类设计就行。。emmm,你的游戏你作主咯
可能内容多,你们可能会打错地方,发一下完整的代码段:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="js/phaser.min.js"></script> <style> body{ } </style> </head> <body> <script> //生成配置文件 const config = { //初始化游戏类型 type : Phaser.AUTO, width : 800, height : 600, //物理引擎 physics : { default : 'arcade', arcade : { //重力设置 gravity : {y : 300}, debug : false } }, //场景设置 scene : { preload, create, update } } //初始化游戏 let game = new Phaser.Game(config) //游戏主要函数 function preload() { this.load.image("sky","./img/sky.png") this.load.image("star","./img/star.png") this.load.image("ground","./img/platform.png") this.load.image("bomb","./img/bomb.png") this.load.spritesheet("dude","./img/dude.png",{frameWidth:32,frameHeight:48}) } function create() { this.add.image(400,300,"sky") platforms = this.physics.add.staticGroup() platforms.create(400,568,"ground").setScale(2,2).refreshBody() platforms.create(600,400,"ground") platforms.create(0,300,"ground") platforms.create(600,200,"ground") platforms.create(0,100,"ground") } function update() { } </script> </body> </html>
什么都有了,主角怎么能少呢? 紧接着上一行,写下代码:
player = this.physics.add.sprite(100,450,'dude')
刷新一下,是否是看到咱们的男主角生成出来。。而后又入土为安了呢?
聪明的你应该会想到:是缺乏了碰撞函数,那么,让咱们来添加碰撞函数吧,紧接着添加:
player.setBounce(0.2) player.setCollideWorldBounds(true)
刷新页面,哇塞
咱们的男主真入土为安了!
嗯,这不是咱们想要的结果,至少不是个人。。咱们好像忘记给障碍物添加碰撞了,咱们来加一下吧:
this.physics.add.collider(player,platforms)
你们还记得哪一个refreshbody吗?若是你当时删掉了它,那么碰撞就仍是不会成立(话说这种东西做者去内置一个方法不就行了么)
这里贴出目前完整的代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="js/phaser.min.js"></script> <style> body{ } </style> </head> <body> <script> //生成配置文件 const config = { //初始化游戏类型 type : Phaser.AUTO, width : 800, height : 600, //物理引擎 physics : { default : 'arcade', arcade : { //重力设置 gravity : {y : 300}, debug : false } }, //场景设置 scene : { preload, create, update } } //初始化游戏 let game = new Phaser.Game(config) //游戏主要函数 function preload() { this.load.image("sky","./img/sky.png") this.load.image("star","./img/star.png") this.load.image("ground","./img/platform.png") this.load.image("bomb","./img/bomb.png") this.load.spritesheet("dude","./img/dude.png",{frameWidth:32,frameHeight:48}) } function create() { this.add.image(400,300,"sky") platforms = this.physics.add.staticGroup() platforms.create(400,568,"ground").setScale(2,2).refreshBody() platforms.create(600,400,"ground") platforms.create(0,300,"ground") platforms.create(600,200,"ground") platforms.create(0,100,"ground") player = this.physics.add.sprite(100,450,'dude') player.setBounce(0.2) player.setCollideWorldBounds(true) this.physics.add.collider(player,platforms) } function update() { } </script> </body> </html>
要是不能操控的话,那这游戏也太佛系了,咱们来添加一动画效果吧
Phaser类有个anims成员,用来管理全部的动画效果(说白了就是改变图片嘛),接下来咱们经过代码感觉一下,添加到上述代码后面:
this.anims.create({ key : 'left', frames : this.anims.generateFrameNumbers('dude',{start : 0,end : 3}), frameRate : 10, repeat : -1 }) this.anims.create({ key : 'turn', frames : [{key : 'dude',frame : 4}], frameRate : 20 }) this.anims.create({ key : 'right', frames : this.anims.generateFrameNumbers('dude',{ start : 5,end : 8 }), frameRate : 10, repeat : -1 })
而后咱们初始化遥控器吧:
cursors = this.input.keyboard.createCursorKeys()
按下键盘方向键上下左右,诶?为何没反应?
咱们好像忘记在update函数中监听键盘了,难怪没反应,
在update函数中添加如下代码:
if(cursors.left.isDown) { player.setVelocityX(-50) player.anims.play("left",true) } else if(cursors.right.isDown) { player.setVelocityX(50) player.anims.play("right",true) } else{ player.setVelocityX(0) player.anims.play('turn') } if(cursors.up.isDown && player.body.touching.down){ player.setVelocityY(-300) }
好,如今移动咱们人物,哇,走的怎么这么慢!各位本身改下参数吧,每一个人都有不一样的游戏爱好,你必定能够找到最适合本身的配置的,固然啦,也能够玩出滑冰模式,月球模式,鬼畜模式,神仙模式,鬼人正邪模式等等。。开发游戏主要靠想象力对吧
贴一下咱们的代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="js/phaser.min.js"></script> <style> body{ } </style> </head> <body> <script> //生成配置文件 const config = { //初始化游戏类型 type : Phaser.AUTO, width : 800, height : 600, //物理引擎 physics : { default : 'arcade', arcade : { //重力设置 gravity : {y : 300}, debug : false } }, //场景设置 scene : { preload, create, update } } //初始化游戏 let game = new Phaser.Game(config) //游戏主要函数 function preload() { this.load.image("sky","./img/sky.png") this.load.image("star","./img/star.png") this.load.image("ground","./img/platform.png") this.load.image("bomb","./img/bomb.png") this.load.spritesheet("dude","./img/dude.png",{frameWidth:32,frameHeight:48}) } function create() { this.add.image(400,300,"sky") platforms = this.physics.add.staticGroup() platforms.create(400,568,"ground").setScale(2,2).refreshBody() platforms.create(600,400,"ground") platforms.create(0,300,"ground") platforms.create(600,200,"ground") platforms.create(0,100,"ground") player = this.physics.add.sprite(100,450,'dude') player.setBounce(0.2) player.setCollideWorldBounds(true) this.physics.add.collider(player,platforms) this.anims.create({ key : 'left', frames : this.anims.generateFrameNumbers('dude',{start : 0,end : 3}), frameRate : 10, repeat : -1 }) this.anims.create({ key : 'turn', frames : [{key : 'dude',frame : 4}], frameRate : 20 }) this.anims.create({ key : 'right', frames : this.anims.generateFrameNumbers('dude',{ start : 5,end : 8 }), frameRate : 10, repeat : -1 }) cursors = this.input.keyboard.createCursorKeys() } function update() { if(cursors.left.isDown) { player.setVelocityX(-50) player.anims.play("left",true) } else if(cursors.right.isDown) { player.setVelocityX(50) player.anims.play("right",true) } else{ player.setVelocityX(0) player.anims.play('turn') } if(cursors.up.isDown && player.body.touching.down){ player.setVelocityY(-300) } } </script> </body> </html>
好了,人物有了,接下来应该作点道具了吧,咱们来画点星星,在create函数中添加代码:
stars = this.physics.add.group({ key : 'star', repeat : 11, setXY : {x: 20,y: 0,stepX:70} }) stars.children.iterate(function(child){ //设置一下碰撞效果 child.setBounceY(Phaser.Math.FloatBetween(0.4,0.8)) }) this.physics.add.collider(stars,platforms)
咱们初始化了一些星星,添加了小小的碰撞效果,然而。。。
并不能吃到星星!就像一大盘香喷喷羊蝎子在你面前你却不能吃(我这篇博客定到晚12点发就行了)
由于没有写星星和男主的碰撞函数,咱们来在后面写一行
this.physics.add.overlap(player,stars,collectStar,null,this)
overlap(obj1,obj2,overcallback,processcallback,回掉中的上下文(this))
而后在文件底部加一个函数:
function collectStar(player,star) { //让star实体消失 star.disableBody(true,true) }
好了,如今能够正常的吃星星了
贴上目前的代码段:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="js/phaser.min.js"></script> <style> body{ } </style> </head> <body> <script> //生成配置文件 const config = { //初始化游戏类型 type : Phaser.AUTO, width : 800, height : 600, //物理引擎 physics : { default : 'arcade', arcade : { //重力设置 gravity : {y : 300}, debug : false } }, //场景设置 scene : { preload, create, update } } //初始化游戏 let game = new Phaser.Game(config) //游戏主要函数 function preload() { this.load.image("sky","./img/sky.png") this.load.image("star","./img/star.png") this.load.image("ground","./img/platform.png") this.load.image("bomb","./img/bomb.png") this.load.spritesheet("dude","./img/dude.png",{frameWidth:32,frameHeight:48}) } function create() { this.add.image(400,300,"sky") platforms = this.physics.add.staticGroup() platforms.create(400,568,"ground").setScale(2,2).refreshBody() platforms.create(600,400,"ground") platforms.create(0,300,"ground") platforms.create(600,200,"ground") player = this.physics.add.sprite(100,450,'dude') player.setBounce(0.2) player.setCollideWorldBounds(true) this.physics.add.collider(player,platforms) this.anims.create({ key : 'left', frames : this.anims.generateFrameNumbers('dude',{start : 0,end : 3}), frameRate : 10, repeat : -1 }) this.anims.create({ key : 'turn', frames : [{key : 'dude',frame : 4}], frameRate : 20 }) this.anims.create({ key : 'right', frames : this.anims.generateFrameNumbers('dude',{ start : 5,end : 8 }), frameRate : 10, repeat : -1 }) cursors = this.input.keyboard.createCursorKeys() stars = this.physics.add.group({ key : 'star', repeat : 11, setXY : {x: 20,y: 0,stepX:70} }) stars.children.iterate(function(child){ //设置一下碰撞效果 child.setBounceY(Phaser.Math.FloatBetween(0.4,0.8)) }) this.physics.add.collider(stars,platforms) this.physics.add.overlap(player,stars,collectStar,null,this) } function update() { if(cursors.left.isDown) { player.setVelocityX(-200) player.anims.play("left",true) } else if(cursors.right.isDown) { player.setVelocityX(200) player.anims.play("right",true) } else{ player.setVelocityX(0) player.anims.play('turn') } if(cursors.up.isDown && player.body.touching.down){ player.setVelocityY(-400) } } function collectStar(player,star) { //让star实体消失 star.disableBody(true,true) } </script> </body> </html>
若是这个游戏没有计分系统和炸弹的话,那么这个游戏也太过于佛系了
在preload前面加上一行:
let score = 0 let scoreText let gameover = false
而后在create函数中尾部添加:
bombs = this.physics.add.group() scoreText = this.add.text(16,16,"score : 0",{fontSize: '32px',fill: "#000"})
这是一个炸弹群组,咱们在全部星星被吃光之后使用这个群组添加炸弹
修改collectstar函数为:
function collectStar(player,star) { //让star实体消失 star.disableBody(true,true) score += 1000 scoreText.setText("score :"+ score) if(stars.countActive(true) === 0) { stars.children.iterate(function(child) { child.enableBody(true,child.x,0,true,true) }) var x = (player.x<400)?Phaser.Math.Between(400,800):Phaser.Math.Between(0,400) var bomb = bombs.create(x,16,'bomb') bomb.setBounce(true) bomb.setCollideWorldBounds(true) bomb.setVelocity(Phaser.Math.Between(-200,200),20) bomb.allowGravity = false } }
而后在create函数中加上碰撞:
this.physics.add.collider(bombs,platforms) this.physics.add.collider(player,bombs,bombbbb,null,this)
在文件尾部加上撞击函数:
function bombbbb() { this.physics.pause() //涂色,我以为绿绿的比较好看 player.setTint(0x00ff00) player.anims.play("turn") gameover = true }
至此,咱们的游戏就大功告成啦。。诶,好像个人人物还能动?这个问题就留给你们本身解决了哈哈
完整代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="js/phaser.min.js"></script> <style> body{ } </style> </head> <body> <script> //生成配置文件 const config = { //初始化游戏类型 type : Phaser.AUTO, width : 800, height : 600, //物理引擎 physics : { default : 'arcade', arcade : { //重力设置 gravity : {y : 300}, debug : false } }, //场景设置 scene : { preload, create, update } } //初始化游戏 let game = new Phaser.Game(config) let score = 0 let scoreText let gameover = false //游戏主要函数 function preload() { this.load.image("sky","./img/sky.png") this.load.image("star","./img/star.png") this.load.image("ground","./img/platform.png") this.load.image("bomb","./img/bomb.png") this.load.spritesheet("dude","./img/dude.png",{frameWidth:32,frameHeight:48}) } function create() { this.add.image(400,300,"sky") platforms = this.physics.add.staticGroup() platforms.create(400,568,"ground").setScale(2,2).refreshBody() platforms.create(600,400,"ground") platforms.create(0,300,"ground") platforms.create(600,200,"ground") player = this.physics.add.sprite(100,450,'dude') player.setBounce(0.2) player.setCollideWorldBounds(true) this.physics.add.collider(player,platforms) this.anims.create({ key : 'left', frames : this.anims.generateFrameNumbers('dude',{start : 0,end : 3}), frameRate : 10, repeat : -1 }) this.anims.create({ key : 'turn', frames : [{key : 'dude',frame : 4}], frameRate : 20 }) this.anims.create({ key : 'right', frames : this.anims.generateFrameNumbers('dude',{ start : 5,end : 8 }), frameRate : 10, repeat : -1 }) cursors = this.input.keyboard.createCursorKeys() stars = this.physics.add.group({ key : 'star', repeat : 11, setXY : {x: 20,y: 0,stepX:70} }) stars.children.iterate(function(child){ //设置一下碰撞效果 child.setBounceY(Phaser.Math.FloatBetween(0.4,0.8)) }) this.physics.add.collider(stars,platforms) this.physics.add.overlap(player,stars,collectStar,null,this) bombs = this.physics.add.group() scoreText = this.add.text(16,16,"score : 0",{fontSize: '32px',fill: "#000"}) this.physics.add.collider(bombs,platforms) this.physics.add.collider(player,bombs,bombbbb,null,this) } function update() { if(cursors.left.isDown) { player.setVelocityX(-200) player.anims.play("left",true) } else if(cursors.right.isDown) { player.setVelocityX(200) player.anims.play("right",true) } else{ player.setVelocityX(0) player.anims.play('turn') } if(cursors.up.isDown && player.body.touching.down){ player.setVelocityY(-400) } } function collectStar(player,star) { //让star实体消失 star.disableBody(true,true) score += 1000 scoreText.setText("score :"+ score) if(stars.countActive(true) === 0) { stars.children.iterate(function(child) { child.enableBody(true,child.x,0,true,true) }) var x = (player.x<400)?Phaser.Math.Between(400,800):Phaser.Math.Between(0,400) var bomb = bombs.create(x,16,'bomb') bomb.setBounce(true) bomb.setCollideWorldBounds(true) bomb.setVelocity(Phaser.Math.Between(-200,200),20) bomb.allowGravity = false } } function bombbbb() { this.physics.pause() //涂色,我以为绿绿的比较好看 player.setTint(0x00ff00) player.anims.play("turn") gameover = true } </script> </body> </html>