跳转至

Phaser3学习笔记

说明#

最近Phaser的中文社区突然活跃起来。(也可能是我最近关注多一点造成的错觉。)很多初学者问一些过于基础的问题,比如怎么旋转一个精灵,有时引起社区成员的反感甚至奚落;这些问题本应该在自学入门中了解。我把自己自学Phaser的一些经验、资料累积在这里,对初学者可能有用。

  • 文中材料主要是针对Phaser3的。Phaser3变化很大,与Phaser2不同的地方做了重点标记。Phaser3官网实例学习笔记已经单列一文。
  • 摘录的代码都是片段。我用的是TypeScript语言,但摘录的代码可能是JavaScript,或在此基础上添加了TypeScript类型标记。JavaScript代码在TypeScript中是有效的,但可能使编辑器、编译工具等报错——这跟设置有关。
  • 本文是随时更新的,最终会累积成一个便览手册;可通过搜索或底端的目录快速查找。

入门三部曲#

对于初学者来说,合适的入门程序可以大大地提高成效。我的经验是:

  1. 学习官网入门教程,知道做出Phaser游戏的最必要的技术,了解一个Phaser游戏的概观;
  2. 浏览官网实例,了解Phaser能做什么,大体是怎么做的;做好注记,以便日后快速查询;
  3. 从零开始做一个Phaser游戏,遇到问题随时搜索官网实例、API文档、开发日志等;

怎么看明白phaser文档?#

Phaser文档是通过脚本工具整理成数据库,然后再生成的,所以很整齐,很有规律。但首先要找到规律。可以先看官方实例,照着写一遍,一边对照文档,这样来找规律。

最让人迷惑的地方可能是,很多对象中都有不少成员(member)是用来引用其他对象的,相当于快捷方式。所以,看文档时,你看到的往往不是实际使用的情形,而需要通过连接不断跳转。

比如类似A_Class.B_Class.c_member:D_Class.e_method()这样的形式,每个.都是一个文档跳转,可能链条更长。其中c_member:D_Class就表示一个引用关系,也就是说,实际关系是A_Class.B_Class.c_member.e_method()

而使用的时候还要实例化,可能是a_Class_instance.b_Class_instance.c_member.e_method(),也可能直接是b_Class_instance.c_member.e_method()

举一个实际的文档(旧版)例子。层级和跳转如下:

Phaser.Scene.add实际上引用的是工厂类Phaser.GameObjects.GameObjectFactory,其下有很多方法可生成游戏对象,比如Phaser.Scene.add.sprite()就是生成精灵,并把精灵加到场景的显示列表中。实际上通常是在场景实例this中使用,那就写作this.add.sprite()

this.make.sprite()引用的是游戏对象生成器Phaser.GameObjects.GameObjectCreator中的方法sprite()。这个方法能生成Sprite实例,但需要通过参数addToScene指明是否添加到场景的显示列表中,或在生成后通过this.add.existing(child)加到场景的显示列表中。

建议参看官方对模块结构的解释

如果是因为英语的问题,可以使用

  • 电子词典,配置好快捷键,比如GoldenDict可以使用ctrl+c+c把选中的文字放到词典浮窗中。
  • DeepL,方便翻译大段文字,精确度很高,能识别程序代码。

学习资源#

资源检索#

搜索引擎自然不用说了。

更新:Phaser Explorer phaser编辑器帮助中心,同时支持2、3版!!!可用空格代表通配符。 这是编辑器Phaser Editor 2D的项目。更多用法请看项目说明有一个我经常用的Phaser Chains项目,可惜目前仅基于Phaser2.4.7。期待早日支持Phaser3。 它可以对API文档和官网实例进行联合检索,支持通配符,支持对象属性的关系链条, 所以要比翻看文档方便、直观得多。比如搜"state.*sprite",就能查到很多相关条目(条目又关联着文档和官网实例):

1
2
3
4
5
Phaser.State.make.sprite(x, y, key, frame) : Phaser.Sprite;
Phaser.State.make.audioSprite(key) : Phaser.AudioSprite;
Phaser.State.add.sprite(x, y, key, frame, group) : Phaser.Sprite;
Phaser.State.add.audioSprite(key) : Phaser.AudioSprite;
//等等...
一些大规模的资源,比如实例库、文档、官方电子期刊等,也可以先下载到本地。再用PowerGrep、VSCode、FileLocator、PDF-XChange之类的全文检索工具检索。当然,你要比较熟悉Phaser的术语习惯,才能有效地检索。

另外,官方文档有SQLite和json版,值得深入挖掘。

Game配置对象GameConfig#

Phaser3的配置对象包含很多项目,详见配置对象GameConfig文档,也参考Phaser.Game配置文件详例,还有小抄

Phaser3广泛使用配置对象,又比如在生成Sprites、Tweens实例时。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 300 },
            debug: false
        }
    },
    scene: { // 第一个场景自动运行,其余场景除非标有{ active: true },否则不会自动运行
        preload: preload, // 资源加载场景
        create: create,  // 内容生成场景
        update: update  // 逐帧更新/循环处理的内容,如键盘、鼠标监控
    }
};
// **Phaser2的Game实例是通往内部系统的入口,Phaser3不再是这样,因此保存在全局变量中保存实例没有实际意义。**
var game = new Phaser.Game(config);

function preload (){}
function create (){}
function update (){}

Scene 场景#

引用其他的资源#

1
(this.scene.get(sceneA) as SceneA).myFunction();

场景间的通信#

https://blog.ourcade.co/posts/2020/phaser3-how-to-communicate-between-scenes/

GameObjects游戏对象#

简明关系请参看Phaser3游戏对象一览

  • Phaser3游戏对象的一个重要变化,是把Phaser2中Sprite、Text、Group等游戏对象的容器功能分离出来,归到Container中。这样一来,Sprite、Text等不能添加子项;Group有子项,但实际是逻辑分组,非独占,通常也不能整体地控制显示状态(可以通过Actions批处理)。Phaser2的渲染核心是PIXI,虽然PIXI有Container,但在Phaser2中一般不直接使用。

  • Phaser3游戏对象的原点(origin,对应于Phaser2的锚点/anchor属性)默认为中心点,而不是左上角。原点通过属性originX, originY获取,通过方法setOrigin(x, y)设置。origin以比分比计算(0到1),另有以像素计算的displayOrigin。

  • Phaser.GameObjects.GameObjectFactory/游戏对象工厂类。实际上通过Scene.add属性引用,比如this.add.sprite(config)

  • Phaser.GameObjects.GameObjectCreator/游戏对象生成器。实际上通过Scene.make属性引用,比如this.make.sprite(config)。与工厂类不同,生成器生成的游戏对象不会自动加载到场景上。

Sprite精灵#

精灵是Phaser游戏中最主要的游戏对象,在游戏对象中有代表性。要便览精灵的属性和方法,请参考《Phaser3 API文档大纲-Sprite》

1
let newSprite = this.add.sprite(20, 30, "spriteTexture", 2);

参考小抄Phaser.GameObject.Sprite

Size内部尺寸#

Size内部尺寸、原本(native)尺寸,包括:

  • Sprite.width
  • Sprite.height

改变内部尺寸,供帧或物理体生成之用,不会影响已经渲染的游戏对象的尺寸:

  • Sprite.setSize(width, height)

DisplaySize显示尺寸#

  • Sprite.displayWidth
  • Sprite.displayHeight

有两个方法改变显示尺寸:

  • Sprite.setScale(x [, y])
  • Sprite.setDisplaySize(width, height)

直接生成有物理属性的精灵#

1
2
3
4
5
player = this.physics.add.sprite(100, 450, 'dude');
player.setBounce(0.2); // 设置反弹
player.setCollideWorldBounds(true);  // 设置与世界边缘碰撞
player.body.setGravityY(300) // 物理精灵的body包含了物理属性
player.setTint(0xff0000); // 着色

Image/图像#

图像与精灵的不同主要在于,Image没有动画(Animation)组件,消耗更小。 但图像也有输入事件、物理体,可以应用补间动画,可以滚动,所以只要你不使用动画,那么就应该用Image代替精灵。图像常用于显示静态图像,比如logo,背景,布景等没有动画(Animation)的元素。(在Phaser2中,Image的操控项更少,尤其是没有物理属性。) 注意:Tween(补间运动/补间动画)不同于动画(Animation)。

1
2
3
this.add.image(400, 300, 'sky');  // 指定原点/中心点位置位置
this.add.image(this.sys.canvas.width / 2, this.sys.canvas.height / 2, "background"); // 居中放置
this.add.image(0, 0, 'sky').setOrigin(0, 0) // 设左上角为原点/锚点

参考小抄Phaser.GameObject.Image

Shape/几何图形及其子类#

Shape是Phaser3新增的游戏对象。Shape本身不能加到场景上,而是用作下列几何图形游戏对象的基类:

  • Arc弧形
  • Curve曲线形
  • Ellipse椭圆(包括正圆)
  • Grid栅格
  • IsoBox等距(isometric)方体
  • IsoTriangle等距三角体(四面体)
  • Line线条(包括三角形、梯形)
  • Polygon多边形
  • Rectangle方形
  • Start星形
  • Triangle三角形

这些Shape子类,可以加入场景、组和容器中。你可以像处理其他常见游戏对象一样处理它们,比如应用补间动画、缩放、打开输入和物理属性。Shape通常支持填充色和笔触色。

Shape拥有常规游戏对象的所有特性,不同之处在于它有高效的渲染方式。Shape不需要使用纹理,但又可以利用WebGL中的批处理的好处,所以能很方便地在游戏中快速渲染形状。它不仅没有Graphics的高消耗问题,甚至有些Shape子类比Sprite还要快。

Graphics/图形#

Graphics主要用于绘制一些基本几何图形(比如方形、圆形、多边形、直线、弧线、曲线)。 Graphics初始的时候是空的,需要制定笔触色、填充色,然后用路径绘制,最后笔触着色、填充。有些常见形状,比如方形,可以方便地绘制。

在Canvas和WebGL两种模式中,Graphics的渲染是不同的。在Canvas下是绘制路径,在WebGL下是绘制多边形。这两种方式都很消耗资源,尤其是图画复杂的时候。所以,如果你的几何图画不会变化,或者变化少,你应该用Phaser.GameObjects.Graphics.generateTexture把几何图画“备份”成一个纹理,并把它返回用于生成精灵Sprite或者其他游戏对象。请注意你的几何图画的复杂程度和数量。

??不适合做缩放操作,而要重绘。因为,相对于Image而言,Graphics缺少一些控制尺寸、位置、纹理的属性和方法,缺少的父类有Phaser.GameObjects.Components.之下的

  • Alpha(但有AlphaSingle)
  • Flip
  • GetBounds
  • Origin
  • Size
  • TextureCrop
  • Tint
1
2
3
4
// 绘制圆角方形
var graphics = this.add.graphics();
graphics.fillStyle(0xffff00, 1);
graphics.fillRoundedRect(0, 0, 200, 100, 32);
1
2
3
4
5
var graphics = this.make.graphics().fillStyle(0x00ff00).fillRect(0, 0, 800, 100);
// 由几何图画生成纹理,由纹理生成Image,销毁几何图画
graphics.generateTexture('hudbar', 800, 100);
graphics.destroy();
this.add.image(400, 300, 'hudbar');

TileSprite瓦片精灵#

用小块Tile铺设背景。【有待补充】

Sprite3D/3D精灵#

标准精灵的封装,可以被3D相机渲染,可以放在3D空间内。

PathFollower/循路器#

PathFollower是一种特殊的Sprite,拥有精灵的所有属性,同时可以自动循着一条Path运动。

Blitter/显存块移动单元/位块传送器#

Blitter是一种特殊容器,用于更新、管理Bob对象。Bob主要目标是快速渲染,而不是追求弹性;它包括一个纹理或者纹理中的帧、位置、透明度,还有翻转、是否可见的开关,但不能旋转、缩放;它们批量绘制方法以加速渲染。

一个Blitter绑定一个纹理。由这个Blitter生成的Bob可以使用这个纹理中的任何帧(可以动态改变),但不能使用别的纹理。就是因为绑定唯一的纹理,使得它们速度很快。

可以从游戏代码直接操控Bob对象,但Bob的生成和销毁需要通过父级Blitter来操作。

如果你需要在屏幕上渲染大量的帧,那么可以考虑Blitter;尤其是用作自己的特效系统的基础,它是特别有用的。

Bob/显存块移动对象/位块传送对象#

参见Blitter。

Text文本#

Text对象使用标准的Canvas fillText API(效果比较多),在内部隐层画布上预先渲染,然后生成纹理,再渲染到游戏上。 文本所用字体必须是浏览器已经可以取用的,或通过第三方加载器预先已载入(Phaser没有字体加载功能),或已经嵌入CSS中。注意:如果字体名称中有空格或者数字,需要加上引号。

任何内容和格式变动都需要整体重制,因此很消耗算力。变动频繁,或者文本很多时,最好使用BitmapText。

1
2
var scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });
scoreText.setText('Score: ' + 10);

BitmapText静态位图文本#

BitmapText的灵活性不如Text,比如不能使用阴影、填充、Web字体,但速度更快。 生成工具:

推荐使用XML格式,如果使用JSON格式,必须符合X2JS库的转换标准。这里有在线工具。

DynamicBitmapText动态位图文本#

与静态位图文本不同的是,动态位图文本每渲染一个字都会引发一次回调,让你控制这个字的渲染属性,比如位置、缩放、着色;这样会更耗时,所以不需要逐字控制时应使用静态位图文本。

Zone区块#

Zone是一个矩形区块,没有纹理,不显示,但存在于与显示列表中,有游戏对象的一般属性。主要用做点击、角色变动的定位,或重叠检测,或作为非显示对象的基类。

RenderTexture渲染器纹理#

能够在运行时绘制多个游戏对象,实时生成纹理,以供他用。对webGL友好,不激发GPU加载。但不能抗锯齿(如渲染Shape时有锯齿)。

Container容器#

一个游戏对象加入容器后,即从显示列表中删除,而加入容器内部的显示列表,由容器负责它的渲染;位置也是相对于容器位置而言的。

容器可以嵌套。

容器可以添加遮罩或作为遮罩,但是子项不能添加遮罩,即遮罩不能叠加。

容器可以添加输入,但是因为它没有纹理,所以你必须提供一个shape作为点击区域。容器的子项也能添加输入,并独立于容器。

容器可以赋予物理体。不过,如果子项也有物理属性,并且容器或任何前辈对象不是位于0x0位置的话,那么你可能碰到意外的结果,比如物理体偏置。不把带物理属性的子项考虑进来,是因为需要过多的运算。

要注意容器带来的额外问题。嵌套越深,消耗越会升级,尤其是在输入事件上。尽可能避免使用。

参考Group

Group组#

Group是多维的抽象分组,类似于打标签,便于批量地生成、排布、控制、循环处理近似游戏对象。与Container不同,它自身没有没有显隐、缩放、定位、旋转属性(但可以快速控制子项的这些属性)。他对子项不是独占的,子项可以存在于多个组中。因此Container更适于把多个显示对象集合成一个复合型显示对象,以便整体地控制显示状态;Group则适合于对近似对象进行批量操作。

组的一个重要用途是对象池。

生成静态物理组#

1
2
3
4
5
6
var platforms;
platforms = this.physics.add.staticGroup(); // 物理静态组
platforms.create(400, 568, 'ground').setScale(2).refreshBody();  // 物理静态组变换尺寸后需要刷新物理Body,即通知物理系统
platforms.create(600, 400, 'ground');
platforms.create(50, 250, 'ground');
platforms.create(750, 220, 'ground');

生成动态物理组#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
stars = this.physics.add.group({
    key: 'star',
    repeat: 11,
    setXY: { x: 12, y: 0, stepX: 70 } // 生成一个行列
});

stars.children.iterate(function (child) {  // 组内遍历、随机赋值
    child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));

});

Lights (WebGL only)/光照#

Light2D的管道。

Mesh(WebGL only)网格#

Mesh/网格是Phaser3新增功能,只支持webGL渲染模式。Phaser2不支持Mesh,因此也不支持Drangonbone等动画格式中的网格蒙皮功能。

1
2
3
4
5
6
7
8
9
let newMesh = this.add.mesh(
  300,
  300,
  [-250, -250, -250, 250, 250, 250, -250, -250, 250, 250, 250, -250],
  [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
  [0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff],
  [1, 1, 1, 1, 1, 1],
  "texture"
);

Parameters

1
2
3
4
5
6
7
8
x                    : the x position of the mesh
y                    : the y position of the mesh
vertices             : array of x and y positions relative to center of mesh object
uv                   : mapping of the uv coordinates
colors               : array of colors for each uv texture coordinate
alphas               : array of alphas for each uv texture coordinate
texture              : sprite name
frame                : the sprite frame

通过newMesh.vertices[0]newMesh.uv[0]等引用、操作。

参考小抄 Phaser.GameObject.Mesh

Quad (WebGL only)/方块#

Mesh网格的一个单元。

Shader (WebGL only)/着色器#

控制quad方块的显示。【???】

DOMElement/DOM元素#

DOMElement是在游戏上操控HTML元素的方法。需要在游戏配置对象中开启:

1
2
3
dom {
  createContainer: true
}

这样会自动在游戏画布上方生成一个尺寸相同的DOM容器div。所有DOM元素都会插入同一个DOM容器,而不管是在那个场景中生成的。可以这样添加DOM元素到容器中:

1
this.add.dom(x, y, 'div', 'background-color: lime; width: 220px; height: 100px; font: 48px Arial', 'Phaser');

你可以像操控其他游戏对象一样操控DOM对象,比如设置位置、缩放、旋转、透明度等属性。但它不能开启输入;但可以直接用addListener方法添加原生事件监听器。

DOM元素是对齐原生HTML和游戏对象的好办法。比如,你可以你可以插入登录框,或文本输入框,或者从第三方服务插入条幅广告,或者用于高解析度的文本显示与UI。

Video/视频#

Video对象可以回放预先载入缓存的视频,或者播放给定链接的视频。视频可以是本地的,也可以是流式的。

1
2
3
4
5
6
preload () {
  this.load.video('pixar', 'nemo.mp4');
}
create () {
  this.add.video(400, 300, 'pixar');
}
Video是标准游戏对象,跟Sprite一样,通常的缩放、旋转、修剪、着色、交互、赋予物理体等操作都可以。 如果视频文件有透明通道,那么通过WebM文件格式,还可以实现透明;但需要浏览器支持。

loader#

从字符串加载svg#

by Milton

1
2
3
4
5
6
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
   <path d="M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z"/>
</svg>`;
const blob = new Blob([svg], {type: 'image/svg+xml'});
const url = URL.createObjectURL(blob);
this.load.svg('plus', url)

文字清晰度(crisp)问题#

文字清晰度问题

场景及其中的文本整体拉伸会导致模糊(blurry),最好指适配/拉伸主场景,其他场景不拉伸;每个Text对象都可以设置分辨率 resolution > 1,这样做有大量消耗内存的风险。

有时使用bitmap text效果比较好。

像素对齐也可能有好处:使用Math.round等计算出图像的整数位置(x,y)。

SVG在加载时渲染成纹理,默认情况下,其尺寸由SVG文件自身指定;同样有消耗内存的问题。但可以指定:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
this.load.svg('morty', 'images/Morty.svg', { width: 300, height: 600 }); // or { scale: 2.5 }

// or
this.load.svg({
    key: 'morty',
    url: 'images/Morty.svg',
    svgConfig: {
        width: 300,
        height: 600
    }
});

输入#

输入事件请参考Phaser3事件一览

游戏对象的输入控制#

  • GameObject.setInteractive( [shape] [, callback] [, dropZone])

开启交互,生成交互游戏对象,即把此对象传给输入管理器,以开启输入。 点击区域(hitArea)默认是基于游戏对象纹理帧生成的正方形。 没有绑定纹理的游戏对象(如Graphics、BitmapText)则需要传递一个shape(配置对象或geometric shape),这时候还需要传递回调函数。 回调函数要能接收三个变量,并返回表示击中与否的布尔值:callback(hitArea, x, y): boolean。比较常用的一类是几何图形的静态函数Contains,如Phaser.Geom.Rectangle.Contains(<static> Contains(rect, x, y))。

1
2
3
4
5
6
7
8
9
text.setInteractive(new Phaser.Geom.Rectangle(0, 0, text.width, text.height), Phaser.Geom.Rectangle.Contains);
//  Input Event listeners
// this: Phaser.Scene
this.input.on('gameobjectover', function (pointer, gameObject) {
    gameObject.setTint(0xff0000, 0xff0000, 0xffff00, 0xff00ff);
});
this.input.on('gameobjectout', function (pointer, gameObject) {
    gameObject.clearTint();
});
  • GameObject.removeInteractive()

移除交互游戏对象。不是即时的,是在the next game step。

  • GameObject.disableInteractive()

临时禁用。

  • GameObject.input.hitArea.setSize(width, height)

设置击中区域(默认方形)。

  • GameObject.input

此属性用以保存交互对象。

Input问题,可参考开发日志。

Scene.input生成输入管理对象#

如方向键管理对象:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cursors = this.input.keyboard.createCursorKeys();
if (cursors.left.isDown)
{
    player.setVelocityX(-160);
    player.anims.play('left', true);
}
else if (cursors.right.isDown){}
else{}

if (cursors.up.isDown && player.body.touching.down)
{
    player.setVelocityY(-330);
}

Input.Events输入事件#

DRAG#

热点拖拽输入事件(Pointer Drag Input Event)。

当一个热点拖拽着一个游戏对象移动时,本事件由当前场景所属的输入插件发送。

在场景内监听本事件的用法是:this.input.on('drag', listener)

一个热点一次只能拖拽一个游戏对象。

特定游戏对象监听此事件,则要用:GAMEOBJECT_DRAG事件。

参数:

Name Type Description
pointer Phaser.Input.Pointer 激发此事件的热点。
gameObject Phaser.GameObjects.GameObject 拖拽中的交互游戏对象。
dragX number 拖拽热点当前在世界中的x坐标。
dragY number 拖拽热点当前在世界中的y坐标。

相关事件:

  • DRAG_END
  • DRAG_ENTER
  • DRAG_LEAVE
  • DRAG_OVER
  • DRAG_START
  • DROP

POINTER_WHEEL#

热点滚轮输入事件(Pointer Wheel Input Event),比如鼠标滚轮。

当热点有滚轮事件更新时,本事件由当前场景所属的输入插件发送。

在场景内监听本事件的用法是:this.input.on('wheel', listener)

事件等级关系如下:

  • GAMEOBJECT_POINTER_WHEEL
  • GAMEOBJECT_WHEEL
  • POINTER_WHEEL

最上层事件最先被派发,同时再往下流动。请注意,上级事件处理器可以停止该事件的进一步传播。

参数:

Name Type Description
currentlyOver Array. 一个数组,包含事件生成时热点下的所有交互游戏对象。
deltaX number 鼠标滚轮或类似设备水平移动的总量。
deltaY number 鼠标滚轮或类似设备垂直移动的总量。通常,上滚为负值,下滚为正值。
deltaZ number 鼠标滚轮或类似设备z轴移动的总量。
1
2
3
4
this.input.on("wheel", function(pointer, currentlyOver, deltaX, deltaY, deltaZ){
    const delta = 30; //预计每次滚动距离
    this.cameras.main.scrollY += (deltaY * -0.01 * delta); // 鼠标滚轮上滚一次为“-100”
},this); // 不加context可能出错

生成碰撞、重叠管理对象#

1
2
3
4
5
6
7
8
this.physics.add.collider(player, platforms);
this.physics.add.collider(stars, platforms); // 组与组碰撞

this.physics.add.overlap(player, stars, collectStar, null, this);
function collectStar (player, star)
{
    star.disableBody(true, true); 
}

调整尺寸Game.resize#

根据浏览器窗口变动调整尺寸。

1
2
3
window.onresize = () => {
  game.resize(window.innerWidth, window.innerHeight);
};

销毁Game实例#

1
Game.destroy(removeCanvas [, noReturn])

src文件结构(最佳实践)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
src
|   phaser.d.ts  // Phaser类型声明文件,Typescript编译器需要
|   main.ts      // web版入口文件
|   game.ts      // 微信版入口文件
|   
+---const        // 存放配置常量
|       
+---js           // 存放js库,比如微信适配用的
|           
+---objects      // 存放游戏对象类
|       
\---scenes       // 存放场景类
        BootScene.ts       // 启动,为生成载入场景预备必要资源(尽可能少)
        PreloadScene.ts    // 载入各场景通用资源,显示载入动画
        MainMenuScene.ts   // 游戏菜单
        GameScene.ts       // 游戏场景

另外,如果不使用webpack等打包工具,index.html文件和资源文件夹assets/可以跟入口文件main.ts放在同一层级(即src/)。

微信版需要单建一个项目文件夹,存放微信小游戏必须的文件game.jsgame.ts的编译目标)、game.jsonproject.config.json,以及assets/js/等资源。微信版的问题当专文说明。

Math数学#

RND随机数#

  • 随机取选取列表中的项目
1
2
var nouns = ["ninja", "chair", "pancake"]
var str = Phaser.Math.RND.pick(nouns);

对象对齐(定位)#

常用四个类中的静态方法:

Phaser.Display.Align.In.#

  • BottomCenter(gameObject, alignIn [, offsetX] [, offsetY])
  • BottomLeft(gameObject, alignIn [, offsetX] [, offsetY])
  • BottomRight(gameObject, alignIn [, offsetX] [, offsetY])
  • Center(gameObject, alignIn [, offsetX] [, offsetY])
  • LeftCenter(gameObject, alignIn [, offsetX] [, offsetY])
  • QuickSet(child, alignIn, position [, offsetX] [, offsetY])
  • RightCenter(gameObject, alignIn [, offsetX] [, offsetY])
  • TopCenter(gameObject, alignIn [, offsetX] [, offsetY])]
  • TopLeft(gameObject, alignIn [, offsetX] [, offsetY])]
  • TopRight(gameObject, alignIn [, offsetX] [, offsetY])]

都是Phaser.Display.Align.In下的静态方法,BottomCenter(gameObject, alignIn),是使gameObject与alignIn两个游戏对象,叠置时底边中心对齐(同侧对齐)。以下各项类此。

Display.Bounds.#

Bounds(边界)类包含一些用于游戏对象定位的静态方法。

  • CenterOn(gameObject, x, y),将游戏对象的中点对齐某点。
  • GetBottom(gameObject),获取游戏对象的底部坐标。以下各Get方法类此。
  • GetCenterX(gameObject)
  • GetCenterY(gameObject)
  • GetLeft(gameObject)
  • GetOffsetX(gameObject)
  • GetOffsetY(gameObject)
  • GetRight(gameObject)
  • GetTop(gameObject)
  • SetBottom(gameObject, value),设置底边值。以下各Set方法类此。
  • SetCenterX(gameObject, x)
  • SetCenterY(gameObject, y)
  • SetLeft(gameObject, value)
  • SetRight(gameObject, value)
  • SetTop(gameObject, value)

Actions动作(批处理)#

Actions动作(批处理)

Phaser. Actions包含一组静态方法,可以对一组游戏对象进行批量处理,应用相同的动作。常常结合逻辑分组Group.getChildren()一起使用。 条目要包含要处理的属性、方法,否则无效。

@actions\place on circle.js

1
2
3
4
var circle = new Phaser.Geom.Circle(400, 300, 260);
group = this.add.group({ key: 'ball', frameQuantity: 32 });
// 把组中游戏对象放置在圆环上
Phaser.Actions.PlaceOnCircle(group.getChildren(), circle);

设置背景色、背景透明#

1
2
3
4
const config:Phaser.Types.Core.GameConfig = {
    backgroundColor: "#cccccc", //游戏背景色
    transparent: false, //背景透明;游戏是否浮动在页面上由Game实例所使用的DOM容器确定的;Phaser内部可以操控DOM
}
1
2
// 相机背景色
this.cameras.main.setBackgroundColor("#FEDFE1")

几何学方法Phaser.Geom#

几何学方法Phaser.Geom

几何学对象,包含一组静态的几何学方法,比如计算面积、周长、比例等,判断两个几何形包含与否、重叠与否等,生成、克隆、拷贝几何形等,以及集合形的移动、调整尺寸、适配等。

1
2
// 判断精灵是否在世界中
Phaser.Geom.Rectangle.Overlaps(Scene.physics.world.bounds, sprite.getBounds())

成员:

\<static> CIRCLE :number \<static> ELLIPSE :number \<static> LINE :number \<static> POINT :number \<static> POLYGON :number \<static> RECTANGLE :number \<static> TRIANGLE :numbe

逐帧控制对象/主循环控制#

参考:

通过扩展游戏对象类的preUpdate, update, postUpdate方法可以逐帧控制对象,或回调,但不是好办法。

update每帧调用一次;注意在其中调用super.update,如果父类有此方法。

preUpdate每帧调用一次,在update之前执行;注意在其中调用super.preUpdate,如果父类有此方法。

更清晰的方法是,比如,通过在场景上监听Phaser.Scenes.Events.UPDATE,来代替使用update方法:

1
2
3
scene.events.on('update', function(time, delta){
    //
}, scope);

缩放适配#

屏幕旋转后保持全屏适配phaser3-scaling-resizing-example

编译/构建后文件过大问题#

  • inline-source-map 体积大,注释掉;
  • 不直接导入Phaser,而是逐一导入其下的对象,如import { AUTO } from 'phaser/src/const';import { AUTO } from 'phaser';,或
    • 定制构建 https://github.com/photonstorm/phaser3-project-template-custom-build

支持动态tilemap#

评论