phaser3学习笔记
文档内容太多了,也不好找资料,现在个人学习API途径有几种:
1.百度翻译,靠着个人使用理解来学习
2.官网API,找有几个网站
3.官方demo文件夹的使用样例(最好用的)。
4.补充一个:Notes of Phaser 3(也挺好用的) 【有些标签有特别好用的live demo,可能live为空,但是代码可以自己粘贴下来只用一样有效】
核心更新,发现了官方Git账号,里面的插件真香啊,以前不用真吃亏-》here
主要是结合here(也就是上面的4)的Usage部分的代码一起参考学习,效率嘎嘎好。
所以,为了长久发展和便利,最好还是记录一下(是散装但是可能会整理一下)。
补充一下16进制颜色表:here,便于使用。
1.this.textures.get('xxx').getFrameNames()
this.指向scene,是获取preload加载的名为'xxx'的json资源中的所有frame名(返回数组)
用于在player.setFrame或创建动作的时候使用。
player创建动作,参考:here
2.this.anims.create(7也是创建动作)
this.指向sprite(注意image类型没有anims动作,只能对其创建tweens补间动画),为其创建动作
1.从json文件,连续

示例: 如果你加载了一个名为gems它包含6个称为ruby_0001, ruby_0002,依此类推,然后您可以使用以下方式调用此方法:this.anims.generateFrameNames('gems', { prefix: 'ruby_', end: 6, zeroPad: 4 }). 这end值告诉它寻找6帧,递增编号,都从前缀开始ruby_。这zeroPad值告诉它有多少个零填充数字。要使用此方法创建动画,您可以: this.anims.create({ key: 'ruby', repeat: -1, frames: this.anims.generateFrameNames('gems', { prefix: 'ruby_', end: 6, zeroPad: 4 }) });
简写形式:

如果加载了一个名为explosion并且它包含12帧,那么您可以使用:this.anims.generateFrameNumbers('explosion', { start: 0, end: 12 }). 这end值告诉它在12帧后停止。要使用此方法创建动画,您可以: this.anims.create({ key: 'boom', frames: this.anims.generateFrameNames('explosion', { start: 0, end: 12 }) });
2.从json文件,非连续

注意到start是可选的,如果动画从第0帧开始,则不需要包含它。 若要反向指定动画,请交换start和end价值观。 如果帧不是连续的,您可以传递一个帧编号数组,例如: this.anims.generateFrameNumbers('explosion', { frames: [ 0, 1, 2, 1, 2, 3, 4, 0, 1, 2 ] })
3.this.setFrame
this.指向sprite,为其直接指定绘制的动画帧,用于创建sprite时候的指定站立动作。
其参数必须是getFrameNames中的name,不能是number序号,在官方文档中有这样解释:

你可能习惯于用一个数字来定位一个sprite表中的一个帧。 this.char.setFrame(1); 然而,对于用JSON加载的sprite工作表,帧是由图像名决定的。 this.char.setFrame("Run__006.png");
4.设定图层层级关系,建立阻挡,防止穿模
关键词是depth,对scene的元素直接指定添加,这一点是phaser3不同于phaser2的很重要的一点(我就是用着phaser2发觉有穿模没啥好的解决办法才推倒重写学习phaser3的。。。)
参考个人demo:

//创建对象 var map = this.add.tilemap('map'); console.log(map); //文件名字不能随意定义,否则找不到对象 var tileset1 = map.addTilesetImage('iso-64x64-outside', 'tiles1'); var tileset2 = map.addTilesetImage('iso-64x64-building', 'tiles2'); //布置对象,为了后续操作而赋值 var layer1 = map.createLayer('Tile Layer 1', [tileset1, tileset2]); layer1.depth = 0; console.log(layer1.depth); var layer2 = map.createLayer('Tile Layer 2', [tileset1, tileset2]); layer2.depth = 1; console.log(layer2.depth); var layer3 = map.createLayer('Tile Layer 3', [tileset1, tileset2]); layer3.depth = 2; console.log(layer3.depth); var layer4 = map.createLayer('Tile Layer 4', [tileset1, tileset2]); layer4.depth = 3; console.log(layer3.depth); var layer5 = map.createLayer('Tile Layer 5', [tileset1, tileset2]); layer5.depth = 4; console.log(layer4.depth);
5.map.getTileAt
map.指Tilemap对象,参数为(tileX, tileY, nonNull, layer),返回Tile

tileX 数字 从 X 位置获取图块(以图块单位给出,而不是像素)。 tileY 数字 从中获取图块的 Y 位置(以图块单位给出,而不是像素)。 nonNull 布尔值 如果为 true,getTile 将不会为空切片返回 null,而是返回索引为 -1 的 Tile 对象。 layer Phaser . Tilemaps . LayerData 要操作的 Tilemap 图层。
6.如果使用new Phaser.GameObjects.Sprite来在指定scene中创建sprite的话,需要使用scene.add.existing(sprite)添加
如果不使用,也可以通过 scene.add.sprite(x,y,texture) ->返回Sprite对象,来创建。
7.创建动作anims方式:
config配置创建:

// var animConfig = { // key: 'back_right', // frames: this.anims.generateFrameNames( // 'char', { // prefix: 'greenhood_walk_back_right_', // start: 1, // end: 8 // }), // frameRate: 20, // repeat: -1 // }; // this.anims.create(animConfig);
直接创建:

this.anims.create({ key: 'front_right', frames: this.anims.generateFrameNames('char', { prefix: 'greenhood_walk_front_right_', start: 1, end: 8, }), frameRate: 10, repeat: -1, });
记录一份官方代码——create animation from sprite sheet(从sprite sheet的序列帧图创建动作):

class Example extends Phaser.Scene { constructor () { super(); } preload () { this.load.spritesheet('brawler', 'assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 }); this.load.image('grid', 'assets/textures/grid-ps2.png'); } create () { // Text section this.add.tileSprite(400, 300, 800, 600, 'grid'); this.add.image(0, 0, 'brawler', '__BASE').setOrigin(0, 0); this.add.grid(0, 0, 192, 384, 48, 48).setOrigin(0, 0).setOutlineStyle(0x00ff00); this.add.text(200, 24, '<- walk', { color: '#00ff00' }).setOrigin(0, 0.5); this.add.text(200, 72, '<- idle', { color: '#00ff00' }).setOrigin(0, 0.5); this.add.text(200, 120, '<- kick', { color: '#00ff00' }).setOrigin(0, 0.5); this.add.text(200, 168, '<- punch', { color: '#00ff00' }).setOrigin(0, 0.5); this.add.text(200, 216, '<- jump', { color: '#00ff00' }).setOrigin(0, 0.5); this.add.text(200, 264, '<- jump kick', { color: '#00ff00' }).setOrigin(0, 0.5); this.add.text(200, 312, '<- win', { color: '#00ff00' }).setOrigin(0, 0.5); this.add.text(200, 360, '<- die', { color: '#00ff00' }).setOrigin(0, 0.5); this.add.text(48, 440, 'Click to change animation', { color: '#00ff00' }); const current = this.add.text(48, 460, 'Playing: walk', { color: '#00ff00' }); // Animation set this.anims.create({ key: 'walk', frames: this.anims.generateFrameNumbers('brawler', { frames: [ 0, 1, 2, 3 ] }), frameRate: 8, repeat: -1 }); this.anims.create({ key: 'idle', frames: this.anims.generateFrameNumbers('brawler', { frames: [ 5, 6, 7, 8 ] }), frameRate: 8, repeat: -1 }); this.anims.create({ key: 'kick', frames: this.anims.generateFrameNumbers('brawler', { frames: [ 10, 11, 12, 13, 10 ] }), frameRate: 8, repeat: -1, repeatDelay: 2000 }); this.anims.create({ key: 'punch', frames: this.anims.generateFrameNumbers('brawler', { frames: [ 15, 16, 17, 18, 17, 15 ] }), frameRate: 8, repeat: -1, repeatDelay: 2000 }); this.anims.create({ key: 'jump', frames: this.anims.generateFrameNumbers('brawler', { frames: [ 20, 21, 22, 23 ] }), frameRate: 8, repeat: -1 }); this.anims.create({ key: 'jumpkick', frames: this.anims.generateFrameNumbers('brawler', { frames: [ 20, 21, 22, 23, 25, 23, 22, 21 ] }), frameRate: 8, repeat: -1 }); this.anims.create({ key: 'win', frames: this.anims.generateFrameNumbers('brawler', { frames: [ 30, 31 ] }), frameRate: 8, repeat: -1, repeatDelay: 2000 }); this.anims.create({ key: 'die', frames: this.anims.generateFrameNumbers('brawler', { frames: [ 35, 36, 37 ] }), frameRate: 8, }); const keys = [ 'walk', 'idle', 'kick', 'punch', 'jump', 'jumpkick', 'win', 'die' ]; const cody = this.add.sprite(600, 370); cody.setScale(8); cody.play('walk'); let c = 0; this.input.on('pointerdown', function () { c++; if (c === keys.length) { c = 0; } cody.play(keys[c]); current.setText('Playing: ' + keys[c]); }); } } const config = { type: Phaser.AUTO, parent: 'phaser-example', width: 800, height: 600, pixelArt: true, scene: [ Example ] }; const game = new Phaser.Game(config);
8.对于phaser3的游戏场景暂停,启动相关API(学习记录):
调用方式为:this.scene.xxx,this指代当前scene场景
onComplete |
相位枪。types . tweens . tweenoncompletecallback | <optional> |
补间完成时要调用的函数。 |
|
onCompleteParams |
排列 | <optional> |
要传递给的附加参数 |
|
onCompleteScope |
任何的 | <optional> |
的范围 |
|
onLoop |
相位枪。types . tweens . tweenonloopcallback | <optional> |
每次补间循环时调用的函数。 |
|
onLoopParams |
排列 | <optional> |
要传递给的附加参数 |
|
onLoopScope |
任何的 | <optional> |
的范围 |
|
onRepeat |
相位枪。types . tweens . tweenonrepeatcallback | <optional> |
每次补间重复时调用的函数。每个目标的每个属性调用一次。 |
|
onRepeatParams |
排列 | <optional> |
要传递给的附加参数 |
|
onRepeatScope |
任何的 | <optional> |
的范围 |
|
onStart |
相位枪。types . tweens . tweenonstartcallback | <optional> |
补间开始时要调用的函数。 |
|
onStartParams |
排列 | <optional> |
要传递给的附加参数 |
|
onStartScope |
任何的 | <optional> |
的范围 |
|
onStop |
相位枪。types . tweens . tweenonstopcallback | <optional> |
补间停止时要调用的函数。 |
|
onStopParams |
排列 | <optional> |
要传递给的附加参数 |
|
onStopScope |
任何的 | <optional> |
的范围 |
|
onUpdate |
相位枪。types . tweens . tweenonupdatecallback | <optional> |
每次补间步进时调用的函数。每个目标的每个属性调用一次。 |
|
onUpdateParams |
排列 | <optional> |
要传递给的附加参数 |
|
onUpdateScope |
任何的 | <optional> |
的范围 |
|
onYoyo |
相位枪。types . tweens . tweenonyoyocallback | <optional> |
每次补间溜溜球时调用的函数。每个目标的每个属性调用一次。 |
|
onYoyoParams |
排列 | <optional> |
要传递给的附加参数 |
|
onYoyoScope |
任何的 | <optional> |
的范围 |
补充实际创建方式:
(将create改为add,即实现直接播放该补间动画,而create需要搭配play才能播放)

var tween=now_scene.tweens.create({ targets: sp, x: (sp.x < u) ? u - 150 : u + 150, // 距离有待修改1 y: v, alpha: { from: 0, to: 1 }, delay: 500, //后期在该延迟区间补充施法特效 ease: 'Expo.Out', duration: 500, onComplete: function () { sp.play('atk' + atk_id); check=this; this.remove();//删除当前补间动画 console.log(this); } }); console.log("当前创建的补间动画 ->",tween); tween.play();
这里是官网API的config配置:here(看TweenBuilderConfig)
10.指定FPS帧率,查了大半天资料,并没有找到我所想要的游戏内动态改动FPS达到变速的效果,只能是在GameConfig处配置fps对象的target属性(默认60),且一定需要forceSetTimeout:true,否则不生效【另外,这里的target也只是告诉phaser3理想帧率,实际并不一定能达到,实际帧率在game.loop.actualFps查看】
配置格式可以参考:here
11.加载动画
参考这里代码就行了,找帧率控制意外发现的官网样例代码。
12.反向动画,补充部分anims事件:here
对其监听事件模板(动作进行中每一帧都会调用):
sprite.on(Phaser.Animations.Events.ANIMATION_UPDATE, function (anim, frame, gameObject){}
中间的一句话即是,关键词为anims.reverse()
13.文本绘制,
API学习:here
这里有一个技巧,将文本转换为图像再进行绘制会提高绘制性能:
/** 文字精灵 * @description 把输入的文字转换成纹理后再转成精灵,以提高性能 * */ export class Character extends Phaser.GameObjects.Sprite { constructor(scene:Phaser.Scene,x:number,y:number, character:string) { const text = scene.make.text({ add: false, x: 0, y: 0, text: character, style: { fontSize: '64px', fontFamily: 'gb_kaiti', color: '#ffffff', align: 'center', backgroundColor: '#ff00ff' } }); // 用Text的画布生成纹理,加到场景的纹理管理器中 scene.textures.addCanvas(character, text.canvas); // 用字头的纹理生成精灵 super(scene,x,y,character); } }
14.graphsic图形绘制
基本添加方式为var pic=scene.add.graphsic();
需要注意的是,对于一个graphsic绘制的所有图形,对于其graphsic.clear()的作用与其绘制图形的.clear()是一样的,清除该graphsic绘制的所有图形,所以,应该把一个graphsic视为一个绘制图形的整体模块,如果有需要,一个scene最好由多个graphsic构成。
15.更改鼠标样式
1.全局修改:this.input.setDefaultCursor('url(./xxx.cur), pointer');
2.局部组件修改(按钮之类的效果):(xxx为需要添加按钮交互功能的指向变量)xxx.setInteractive({cursor: 'url(./yyy.cur), pointer'});
16.按键绑定
两个图共同展示AD按键实现相机移动,其他情况的话就去参考官网的input-keyboard看demo样例学习吧。
下面是通过左右按键绑定相机移动的特定方式:
17.
【Over】
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!