前言

phaser是一个优秀的前端canvas库,封装了很多底层的实现,可以用来制作游戏,h5场景等。今年1月新发布了phaser3,到今天为止已经更新到了3.30。

声明

本游戏来自于phaser小站的官方教程,加入了一些个人的注释,本文旨在帮助各位观众老爷快速上手。

各位看官也可以直接移步phaser官网查看教程

小贴士

每一个步骤后面都贴了代码,如果因为我的写作方式让您难以接受,可以直接到每个步骤后面复制代码

准备工作

你需要一份phaser3.js
也可能需要一份文档
如果有一份随时查阅的范例当然更好
一个本地服务器
一份包含素材的空[项目]()

开始制作

这里是为观众老爷们准备的github仓库,有我们需要的素材和脚本文件

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函数中加入以下代码段:

      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 += 1000scoreText.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 = 0let scoreTextlet 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 += 1000scoreText.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>

[phaser3入门探坑]使用phaser3制作山寨马里奥相关推荐

  1. 机器学习原来这么有趣!第二章:用机器学习制作超级马里奥的关卡

    第一章:全世界最简单的机器学习入门指南 https://blog.csdn.net/wskzgz/article/details/89917343 第二章:用机器学习制作超级马里奥的关卡 https: ...

  2. java页面要素_Web前端入门技术之网页制作三要素

    原标题:Web前端入门技术之网页制作三要素 Web前端技术开发是由网页制作演变而来的,主要由HTML.CSS.Java三大要素组成.专业的Web前端开发入门常识也必定会包含这些内容,今日千锋教师就给我 ...

  3. LittleVGL (LVGL)干货入门教程四之制作和使用中文汉字字库

    LittleVGL (LVGL)干货入门教程四之制作和使用中文汉字字库 前言: 阅读前,请确保你至少拥有以下条件: 已实现显示API(教程一已实现, 链接:LittleVGL (LVGL)入门教程一之 ...

  4. 视频教程-【吴刚】AE(After Effects)初级入门标准教程-动画制作

    [吴刚]AE(After Effects)初级入门标准教程 业内知名UID.UED.用户体验.品牌策略与创意设计师,十三年行业职业教育培训经验,业内"UI视频第一人",教学总监.视 ...

  5. java入门-五子棋游戏的制作

    java入门-五子棋游戏的制作 想要开发一个简单的五子棋游戏,需要实现五子棋的棋盘.棋子.输赢判定.重新开始游戏.悔棋.认输.人机大战以及退出游戏等功能. 1.实现五子棋的棋盘功能 想要实现这个功能, ...

  6. python爬虫入门——13行代码制作英语翻译器教程,小白入门一点通

    有些同学一想到爬虫,就觉得很厉害,然后也认为是一个很难学,确实,会爬虫的确是个狠人,爬虫这个东西可以抓取很多东西,但是也并不是那么的难学,入门其实也很简单,爬虫都是一些套路步骤,那么接下来让我们用13 ...

  7. 3D游戏建模入门初级教学:制作纹理逼真的法线贴图

    下图是一只恐龙的低模布线,细心的朋友估计会看到恐龙头部的布线密度是要远远高于身体和四肢的,这种布线的好处就是可以在你需要着重刻画的部位经过细分后生成的模型面数会远远高于那些次要部分,会使你的细节刻画更 ...

  8. 3Dmax人物建模入门教程教学- 头部制作

    一般头部建模有两种方法 1.用box调整出头部轮廓然后细调整: 2.用面片挤压,逐步挤压出整个面部,这里用第一种方法,直观感觉较快 形体初始准备阶段 1. 创建一个长方体 2. 将长方体改为长.宽.高 ...

  9. 零基础新手入门游戏建模,制作3D建模有哪些步骤流程!必备知识

    次世代游戏的诞生掀起了技术与艺术的新浪潮.精致高清的贴图模型,实时仿真的碰撞解算,极致华丽的视觉特效,独特新颖的体感操作成为了次世代游戏的标志性特色. 目前正在学次时代游戏建模,简单分享下流程. [3 ...

  10. Div+CSS布局入门教程(五) 页面制作-用好border和clear 附加:1.DIV+CSS设计原则 2.DIV+CSS中标签ul ol li dl dt dd用法

    这一节里面,主要就是想告诉大家如何使用好border和clear这两个属性. 首先,如果你曾用过table制作网页,你就应该知道,如果要在表格中绘制一条虚线该如何做,那需要制作一个很小的图片来填充,其 ...

最新文章

  1. [LeetCode]Perfect Squares
  2. 湖南科技大学计算机控制技术,湖南科技大学控制理论与控制工程专业
  3. mysql adminer 导入csv_mysql导入csv的4种报错的解决方法
  4. 基于.NET下的人工智能|利用ICSharpCore搭建基于.NET Core的机器学习和深度学习的本地开发环境...
  5. 用计算机弹可惜不是你,可惜不是你 还是幸亏不是你
  6. centos初始配置
  7. 详解CNN五大经典模型:Lenet,Alexnet,Googlenet,VGG,DRL
  8. SpringBlade 2.0-RC3 发布,全新的微服务开发平台
  9. 管理感悟:软件第一法则
  10. Microsoft Office Visio 2007 免费下载
  11. 贵州大学计算机学院院长,贵州大学计算机科学与信息学院第七届研究生会干部选举大会...
  12. 艾永亮:酒瓶中的战争,谁是下一瓶被拿起的葡萄酒
  13. ONF发布安全部署SDN控制器指南
  14. CORBA 架构体系指南(通用对象请求代理体系架构)​
  15. 微信电脑版无法获取二维码
  16. python中fill函数_在figu中旋转matplotlib的fill函数
  17. 蚂蚁高管被约谈,IPO如何引燃了蚂蚁的监管风波?
  18. Containers feature is disabled. Enable it using the PowerShell script (in an administrative PowerShe
  19. str[]与*str的区别
  20. Mifare Classic漏洞原理之一

热门文章

  1. 计算机系统大作业-程序人生
  2. Java API(JDBC)连接操作数据库MySQL
  3. 大数据采集技术和预处理技术
  4. Linux中查看bz2压缩文件大小,Linux bz2文件解压与压缩之bzip2命令
  5. 西南科技大学OJ系统 #941: 有序顺序表的合并操作的实现
  6. 最新更新-最全泰尔指数合集:分省、地级市、产业结构泰尔指数计算模板(部分更新2020年)
  7. KL散度、JS散度以及交叉熵对比
  8. linux vim删除单个字符串,LINUX vim替换字符串指令
  9. 基于基于jsp+mysql+Spring+mybatis的SSM汽车保险理赔管理系统设计和实现
  10. EL表达式和JSTL标签库学习总结