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>