关于 graphics-and-shapes
面向 Phaser 4 开发者的图形与形状技能,说明如何用 Graphics 绘制图元,以及使用独立 Shape 游戏对象。内容对比两种方式,并涵盖样式、路径、变换和纹理生成。
主要功能
- 01Graphics 填充、描边与路径绘制
- 02圆角矩形、渐变及画布变换
- 03从 Graphics 生成纹理
- 04使用多种 Shape 几何对象
- 05Shape 样式与游戏对象组件
适用场景
- 01绘制动态路径或组合图形
- 02创建可交互或可加入物理系统的形状
- 03将绘图结果烘焙为纹理
- 04为界面制作简单几何元素
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ phaserjs/ phaser --skill graphics-and-shapes安装后在 Claude Code 中输入/graphics-and-shapes确认已加载。
详细介绍
Phaser 4 — 图形与形状
使用 Graphics 游戏对象绘制图元,并使用 Shape 游戏对象(Arc、Curve、Ellipse、Grid、IsoBox、IsoTriangle、Line、Polygon、Rectangle、Star、Triangle)。
相关技能:sprites-and-images.md、game-object-components.md
快速开始
// Draw a filled rectangle and stroked circle with Graphics
const gfx = this.add.graphics();
gfx.fillStyle(0x00aa00, 1);
gfx.fillRect(50, 50, 200, 100);
gfx.lineStyle(3, 0xff0000, 1);
gfx.strokeCircle(400, 150, 60);
// Same shapes as standalone Shape game objects
const rect = this.add.rectangle(150, 100, 200, 100, 0x00aa00);
const circle = this.add.circle(400, 150, 60);
circle.setStrokeStyle(3, 0xff0000);
核心概念 — Graphics 与 Shape 对象
Phaser 提供两种无需纹理即可渲染图元的方法。
Graphics 游戏对象
通过 this.add.graphics() 创建。它是一种命令式绘图表面 —— 你调用 fillRect、strokeCircle、beginPath/lineTo/strokePath 等方法,构建一个每帧都会重放的命令缓冲区。
- 工厂方法:
this.add.graphics(config?),其中 config 为{ x?, y?, lineStyle?, fillStyle? }。 - 支持路径、弧线、渐变、圆角矩形、画布变换(
translateCanvas、scaleCanvas、rotateCanvas)以及save/restore。 - 可以通过
generateTexture(key, width, height)从绘制内容生成纹理。 - 渲染开销较大,尤其是绘制复杂形状时。它使用自己的 WebGL 着色器。将多个 Graphics 对象归组,以尽量减少批次刷新。
- 组件:AlphaSingle、BlendMode、Depth、Lighting、Mask、RenderNodes、Transform、Visible、ScrollFactor。
- 不包含 Origin 或 GetBounds(位置通过选项或
setPosition设置)。
Shape 游戏对象
各个独立的游戏对象(Arc、Rectangle、Star 等),继承自基础 Shape 类。每个对象使用预先计算好的路径数据渲染一个预定义的几何形状。
- 通过专用工厂方法创建:
this.add.rectangle(...)、this.add.circle(...)等。 - 功能完整的游戏对象:可以进行补间、缩放、添加到组/容器,以及启用输入/物理。
- 通过
setFillStyle(color, alpha)和setStrokeStyle(lineWidth, color, alpha)设置样式。 - 与 Graphics 共享同一个 WebGL 批次,以实现高效渲染。
- 不支持渐变、路径细节阈值或画布变换。
- 组件:AlphaSingle、BlendMode、Depth、GetBounds、Lighting、Mask、Origin、RenderNodes、ScrollFactor、Transform、Visible。
- 包含 Origin 和 GetBounds(与 Graphics 不同)。
何时使用哪一种:
- 使用 Graphics 进行动态绘制、复杂路径、在一个对象上绘制多个形状、渐变或生成纹理。
- 使用 Shape 对象 制作单个 UI 元素、简单指示器、启用物理的形状,或任何受益于游戏对象特性(origin、bounds、input)的场景。
常见模式
填充与描边样式(Graphics)
const gfx = this.add.graphics();
// Solid fill — call before any fill* method
gfx.fillStyle(0xff0000, 1); // (color, alpha)
// Line style — call before any stroke* method
gfx.lineStyle(4, 0x00ff00, 1); // (width, color, alpha)
// Gradient fill (WebGL only) — 4 corner colors
gfx.fillGradientStyle(
0xff0000, 0x00ff00, 0x0000ff, 0xffff00, // tl, tr, bl, br colors
1, 1, 1, 1 // tl, tr, bl, br alphas
);
gfx.fillRect(0, 0, 300, 200);
// Gradient line style (WebGL only)
gfx.lineGradientStyle(2, 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 1);
绘制图元(Graphics)
const gfx = this.add.graphics();
// Rectangles
gfx.fillStyle(0x0000ff);
gfx.fillRect(x, y, width, height);
gfx.lineStyle(2, 0xffffff);
gfx.strokeRect(x, y, width, height);
// Circles
gfx.fillCircle(x, y, radius);
gfx.strokeCircle(x, y, radius);
// Ellipses
gfx.fillEllipse(x, y, width, height, smoothness);
gfx.strokeEllipse(x, y, width, height, smoothness); // smoothness defaults to 32
// Triangles
gfx.fillTriangle(x0, y0, x1, y1, x2, y2);
gfx.strokeTriangle(x0, y0, x1, y1, x2, y2);
// Points (draws a small square)
gfx.fillPoint(x, y, size); // size defaults to 1
// Lines
gfx.lineBetween(x1, y1, x2, y2);
圆角矩形
const gfx = this.add.graphics();
// Uniform radius (default 20)
gfx.fillStyle(0x333333);
gfx.fillRoundedRect(50, 50, 300, 200, 16);
gfx.lineStyle(2, 0xffffff);
gfx.strokeRoundedRect(50, 50, 300, 200, 16);
// Per-corner radius
gfx.fillRoundedRect(50, 50, 300, 200, {
tl: 20, tr: 20, bl: 0, br: 0
});
// Concave corners (negative values)
gfx.fillRoundedRect(50, 50, 300, 200, { tl: -10, tr: -10, bl: -10, br: -10 });
路径绘制
const gfx = this.add.graphics();
// Manual path
gfx.lineStyle(3, 0xffff00);
gfx.beginPath();
gfx.moveTo(100, 100);
gfx.lineTo(200, 50);
gfx.lineTo(300, 100);
gfx.lineTo(250, 200);
gfx.closePath();
gfx.strokePath(); // or gfx.stroke() — alias for strokePath
// Fill a path
gfx.fillStyle(0x00aaff);
gfx.beginPath();
gfx.moveTo(100, 100);
gfx.lineTo(200, 50);
gfx.lineTo(300, 100);
gfx.closePath();
gfx.fillPath(); // or gfx.fill() — alias for fillPath
// Arc within a path (angles in radians)
gfx.beginPath();
gfx.arc(200, 200, 80, 0, Math.PI / 2, false, 0); // (x, y, radius, startAngle, endAngle, anticlockwise, overshoot)
gfx.strokePath();
// Pie slice
gfx.slice(200, 200, 80, 0, Math.PI / 3, false); // auto begins/closes path
gfx.fillPath();
// Stroke/fill from point arrays
gfx.strokePoints(points, closeShape, closePath, endIndex);
gfx.fillPoints(points, closeShape, closePath, endIndex);
Geom 形状辅助方法
Graphics 提供了便捷方法,可直接接受 Phaser.Geom 对象:
const circle = new Phaser.Geom.Circle(200, 200, 50);
const rect = new Phaser.Geom.Rectangle(50, 50, 100, 80);
gfx.fillCircleShape(circle);
gfx.strokeCircleShape(circle);
gfx.fillRectShape(rect);
gfx.strokeRectShape(rect);
gfx.fillTriangleShape(triangle);
gfx.strokeTriangleShape(triangle);
gfx.strokeLineShape(line);
gfx.fillEllipseShape(ellipse, smoothness);
gfx.strokeEllipseShape(ellipse, smoothness);
画布变换(Graphics)
const gfx = this.add.graphics();
gfx.save();
gfx.translateCanvas(100, 100);
gfx.rotateCanvas(0.5); // radians
gfx.scaleCanvas(2, 2);
gfx.fillStyle(0xff0000);
gfx.fillRect(0, 0, 50, 50); // draws at translated/rotated/scaled position
gfx.restore();
从 Graphics 生成纹理
const gfx = this.add.graphics();
gfx.fillStyle(0xff0000);
gfx.fillCircle(32, 32, 32);
gfx.generateTexture('redCircle', 64, 64);
gfx.destroy();
// Now use as a regular texture
this.add.image(400, 300, 'redCircle');
注意:fillGradientStyle 不会出现在生成的纹理中(Canvas API 的限制)。
Shape 对象 — 填充与描边
// Shapes set fill via constructor or setFillStyle
const rect = this.add.rectangle(200, 150, 100, 80, 0xff0000, 1);
// Change fill later
rect.setFillStyle(0x00ff00, 0.8);
// Add stroke (not set by default)
rect.setStrokeStyle(3, 0xffffff, 1); // (lineWidth, color, alpha)
// Remove fill or stroke
rect.setFillStyle(); // no args = isFilled becomes false
rect.setStrokeStyle(); // no args = isStroked becomes false
// Direct property access
rect.fillColor = 0x0000ff;
rect.fillAlpha = 0.5;
rect.strokeColor = 0xffffff;
rect.strokeAlpha = 1;
rect.lineWidth = 2;
rect.isFilled = true;
rect.isStroked = true;
rect.closePath = true; // close stroke path (default true)
所有形状类型
| 工厂方法 | 类 | 参数(在 x、y 之后) | 填充 | 描边 | 说明 |
|---|---|---|---|---|---|
this.add.arc(x, y, radius, startAngle, endAngle, anticlockwise, fillColor, fillAlpha) | Arc | radius=128, startAngle=0, endAngle=360(度), anticlockwise=false | 是 | 是 | 角度以度为单位。默认绘制完整圆形。 |
this.add.circle(x, y, radius, fillColor, fillAlpha) | Arc | radius=128 | 是 | 是 | 使用 0-360 角度的 Arc 别名。 |
this.add.curve(x, y, curve, fillColor, fillAlpha) | Curve | Phaser.Curves.Curve 对象 | 是 | 是 | 具有 smoothness 属性 / setSmoothness()。 |
this.add.ellipse(x, y, width, height, fillColor, fillAlpha) | Ellipse | width=128, height=128 | 是 | 是 | 宽高相等时渲染为圆形。具有 smoothness。 |
this.add.grid(x, y, width, height, cellWidth, cellHeight, fillColor, fillAlpha, outlineFillColor, outlineFillAlpha) | Grid | width=128, height=128, cellWidth=32, cellHeight=32 | 是 | 否 | 具有用于棋盘格的 altFillColor/altFillAlpha。通过 outlineFillColor 绘制轮廓。 |
this.add.isobox(x, y, size, height, fillTop, fillLeft, fillRight) | IsoBox | size=48, height=32, fillTop=0xeeeeee, fillLeft=0x999999, fillRight=0xcccccc | 是 | 否 | 等距盒。showTop、showLeft、showRight、projection。 |
this.add.isotriangle(x, y, size, height, reversed, fillTop, fillLeft, fillRight) | IsoTriangle | size=48, height=32, reversed=false | 是 | 否 | 等距棱锥。showTop、showLeft、showRight、projection、reversed。 |
this.add.line(x, y, x1, y1, x2, y2, strokeColor, strokeAlpha) | Line | x1=0, y1=0, x2=128, y2=0 | 否 | 是 | 仅描边。构造函数接受描边颜色(而非填充)。 |
this.add.polygon(x, y, points, fillColor, fillAlpha) | Polygon | points(多种格式) | 是 | 是 | 点:Vec2 数组、[x,y,...] 对,或 [[x,y],...]。 |
this.add.rectangle(x, y, width, height, fillColor, fillAlpha) | Rectangle | width=128, height=128 | 是 | 是 | 通过 width/height 属性更改尺寸。 |
this.add.star(x, y, points, innerRadius, outerRadius, fillColor, fillAlpha) | Star | points=5, innerRadius=32, outerRadius=64 | 是 | 是 | 4 个角 = 菱形。角越多越尖锐。 |
this.add.triangle(x, y, x1, y1, x2, y2, x3, y3, fillColor, fillAlpha) | Triangle | x1=0,y1=128, x2=64,y2=0, x3=128,y3=128 | 是 | 是 | 始终闭合。开放形状请使用 Polygon。 |
API 快速参考 — Graphics 方法
样式方法
| 方法 | 签名 | 说明 |
|---|---|---|
fillStyle | (color, alpha=1) | 为后续填充调用设置填充样式 |
lineStyle | (lineWidth, color, alpha=1) | 为后续描边调用设置描边样式 |
fillGradientStyle | (tl, tr, bl, br, aTL=1, aTR, aBL, aBR) | 仅 WebGL。4 个角颜色。 |
lineGradientStyle | (lineWidth, tl, tr, bl, br, alpha=1) | 仅 WebGL。 |
setDefaultStyles | (options) | 通过 { lineStyle: {width,color,alpha}, fillStyle: {color,alpha} } 设置 |
路径方法
| 方法 | 签名 | 说明 |
|---|---|---|
beginPath | () | 开始新路径 |
moveTo | (x, y) | 移动绘制位置 |
lineTo | (x, y) | 绘制直线到指定位置 |
arc | (x, y, radius, startAngle, endAngle, anticlockwise=false, overshoot=0) | 角度以弧度为单位 |
closePath | () | 闭合当前路径 |
fillPath / fill | () | 填充当前路径 |
strokePath / stroke | () | 描边当前路径 |
slice | (x, y, radius, startAngle, endAngle, anticlockwise=false, overshoot=0) | 饼图切片。自动开始/闭合路径。角度以弧度为单位。 |
形状绘制方法
| 方法 | 签名 |
|---|---|
fillRect | (x, y, width, height) |
strokeRect | (x, y, width, height) |
fillRoundedRect | (x, y, width, height, radius=20) |
strokeRoundedRect | (x, y, width, height, radius=20) |
fillCircle | (x, y, radius) |
strokeCircle | (x, y, radius) |
fillEllipse | (x, y, width, height, smoothness=32) |
strokeEllipse | (x, y, width, height, smoothness=32) |
fillTriangle | (x0, y0, x1, y1, x2, y2) |
strokeTriangle | (x0, y0, x1, y1, x2, y2) |
fillPoint | (x, y, size=1) |
lineBetween | (x1, y1, x2, y2) |
strokePoints | (points, closeShape=false, closePath=false, endIndex) |
fillPoints | (points, closeShape=false, closePath=false, endIndex) |
Geom 形状方法
| 方法 | 签名 |
|---|---|
fillRectShape | (rect) |
strokeRectShape | (rect) |
fillCircleShape | (circle) |
strokeCircleShape | (circle) |
fillTriangleShape | (triangle) |
strokeTriangleShape | (triangle) |
strokeLineShape | (line) |
fillEllipseShape | (ellipse, smoothness=32) |
strokeEllipseShape | (ellipse, smoothness=32) |
变换与状态方法
| 方法 | 签名 | 说明 |
|---|---|---|
translateCanvas | (x, y) | 平移后续绘制 |
scaleCanvas | (x, y) | 缩放后续绘制 |
rotateCanvas | (radians) | 旋转后续绘制 |
save | () | 将状态压入栈 |
restore | () | 从栈中弹出状态 |
clear | () | 清空命令缓冲区,重置为默认样式 |
generateTexture | (key, width, height) | 烘焙为 Texture(Canvas API) |
形状基类方法
| 方法 | 签名 | 说明 |
|---|---|---|
setFillStyle | (color?, alpha=1) | 无参数 = 禁用填充 |
setStrokeStyle | (lineWidth?, color?, alpha=1) | 无参数 = 禁用描边 |
注意事项
-
Graphics 的 arc() 使用弧度;Shape 的 arc 工厂方法使用角度。 Graphics 的
arc方法以弧度接收起始/结束角度。this.add.arc()工厂方法则以角度(0-360)接收。混淆这两者是最常见的 bug。 -
在绘制之前设置样式。
fillStyle和lineStyle必须在对应的填充/描边方法之前调用。它们不是追溯生效的。 -
Graphics 没有 Origin 或 GetBounds。 与 Shape 对象不同,Graphics 不包含 Origin 或 GetBounds 组件。请改用
setPosition(x, y)和displayOriginX/displayOriginY。 -
Shape 的 isFilled/isStroked 默认值。 使用
fillColor参数创建的 Shape 其isFilled = true。但isStroked默认为false—— 你必须显式调用setStrokeStyle()。 -
Line shape 仅支持描边。 Line shape 不支持填充。其构造函数接收
strokeColor/strokeAlpha(而非 fillColor)。 -
IsoBox/IsoTriangle 仅支持填充。 这些形状无法描边。Grid 通过其构造函数参数(
outlineFillColor、outlineFillAlpha)支持轮廓描边。 -
generateTexture 使用 Canvas API。 渐变填充(
fillGradientStyle)不会出现在用generateTexture生成的纹理中。只有 Canvas 兼容的特性会被捕获。 -
性能:Graphics 开销较大。 每一帧都会重放命令缓冲区并重建几何体(WebGL 会将其分解为多边形)。对于静态形状,请调用
generateTexture并将生成的纹理用作 Sprite。将 Graphics 对象分组在一起以尽量减少批处理中断。 -
pathDetailThreshold(v4 新增)。 Graphics 有一个
pathDetailThreshold属性(默认 -1,使用配置项render.pathDetailThreshold)。低于此像素阈值的路径段会被合并,从而提升复杂形状在 WebGL 下的性能。该值以屏幕像素为单位进行评估,因此放大时细节会显现出来。 -
圆角矩形的半径可以是对象或数字。 传入
{ tl, tr, bl, br }可分别控制每个角。负值会创建凹角。省略时默认为 20。 -
Shape 的 closePath 属性。 Shape 对象上的
closePath属性(默认true)控制描边路径是否自动闭合。对于开放的描边形状,请设置为false。 -
Shape 对象不支持 tint 方法。 与 Sprite 和 Image 不同,Shape 游戏对象没有
setTint()或tint属性。请改用setFillStyle(color, alpha)和setStrokeStyle(lineWidth, color, alpha)。 -
多边形在负坐标点下 getBounds() 不正确。 如果任何多边形点具有负坐标,
getBounds()会返回错误的值。请改用Phaser.Geom.Polygon.GetAABB(polygon.geom)并调整返回的 Rectangle 位置。
形状专属方法
Star
const star = this.add.star(400, 300, 5, 32, 64, 0xffff00);
star.setPoints(8); // change number of points
star.setInnerRadius(20); // change inner radius
star.setOuterRadius(80); // change outer radius
Line(渐细)
const line = this.add.line(400, 300, 0, 0, 200, 100, 0xffffff);
// setLineWidth(startWidth, endWidth) — endWidth is WebGL only (tapering effect)
line.setLineWidth(4, 1); // tapers from 4px to 1px (Canvas uses startWidth only)
Grid(交替颜色、描边、内边距)
const grid = this.add.grid(400, 300, 320, 240, 32, 32, 0x222222);
// Alternating cell color (checkerboard)
grid.setAltFillStyle(0x444444, 1); // no args = disable alternating cells
// Grid uses setStrokeStyle for cell outlines (inherited from Shape)
grid.setStrokeStyle(1, 0x666666, 1);
// v4: control outside edge stroke
grid.strokeOutside = true; // stroke the outer border
grid.strokeOutsideIncomplete = false; // skip partial cells on right/bottom edges
// Cell padding (default 0.5) — gutter between cells is 2x this value
grid.cellPadding = 1;
IsoBox / IsoTriangle
const box = this.add.isobox(200, 200, 48, 32, 0xeeeeee, 0x999999, 0xcccccc);
box.setFaces(true, true, false); // showTop, showLeft, showRight
box.setProjection(4); // isometric projection value
const tri = this.add.isotriangle(400, 200, 48, 32, false, 0xeeeeee, 0x999999, 0xcccccc);
tri.setReversed(true); // flip upside down
tri.setFaces(true, true, true);
tri.setProjection(4);
源文件映射
| 文件 | 用途 |
|---|---|
src/gameobjects/graphics/Graphics.js | Graphics 类 — 所有绘制方法 |
src/gameobjects/graphics/GraphicsFactory.js | this.add.graphics() 工厂 |
src/gameobjects/graphics/Commands.js | 命令缓冲区的内部命令常量 |
src/gameobjects/graphics/GraphicsRender.js | 渲染调度 |
src/gameobjects/shape/Shape.js | 基础 Shape 类(填充/描边/路径数据、setFillStyle、setStrokeStyle) |
src/gameobjects/shape/arc/Arc.js | Arc 形状(也用于圆) |
src/gameobjects/shape/arc/ArcFactory.js | this.add.arc() 和 this.add.circle() 工厂 |
src/gameobjects/shape/curve/Curve.js | Curve 形状 |
src/gameobjects/shape/curve/CurveFactory.js | this.add.curve() 工厂 |
src/gameobjects/shape/ellipse/Ellipse.js | Ellipse 形状 |
src/gameobjects/shape/ellipse/EllipseFactory.js | this.add.ellipse() 工厂 |
src/gameobjects/shape/grid/Grid.js | Grid 形状 |
src/gameobjects/shape/grid/GridFactory.js | this.add.grid() 工厂 |
src/gameobjects/shape/isobox/IsoBox.js | IsoBox 形状 |
src/gameobjects/shape/isobox/IsoBoxFactory.js | this.add.isobox() 工厂 |
src/gameobjects/shape/isotriangle/IsoTriangle.js | IsoTriangle 形状 |
src/gameobjects/shape/isotriangle/IsoTriangleFactory.js | this.add.isotriangle() 工厂 |
src/gameobjects/shape/line/Line.js | Line 形状 |
src/gameobjects/shape/line/LineFactory.js | this.add.line() 工厂 |
src/gameobjects/shape/polygon/Polygon.js | Polygon 形状 |
src/gameobjects/shape/polygon/PolygonFactory.js | this.add.polygon() 工厂 |
src/gameobjects/shape/rectangle/Rectangle.js | Rectangle 形状 |
src/gameobjects/shape/rectangle/RectangleFactory.js | this.add.rectangle() 工厂 |
src/gameobjects/shape/star/Star.js | Star 形状 |
src/gameobjects/shape/star/StarFactory.js | this.add.star() 工厂 |
src/gameobjects/shape/triangle/Triangle.js | Triangle 形状 |
src/gameobjects/shape/triangle/TriangleFactory.js | this.add.triangle() 工厂 |