Phaser 3 リボントレイルを作る④ : blendmodeを変更する
前回に引き続きリボントレイルを作ります。 gpnotes.hatenablog.jp
particleで星空のアニメーションを作る
公式のサンプルを参考にして星空のアニメーションを作ります。
ソースはほとんどそのまま拝借し、手裏剣型のスプライトparticle1とparticle2を自作しました。
tintを設定することで色を変えられるようにしてあります。
create() { this.player=this.add.image(40,this.sys.canvas.height/2,"block") this.cameras.main.setBackgroundColor(0x000000); let offscreen = new Phaser.Geom.Rectangle(-400, 0, 400, 600); let screen = new Phaser.Geom.Rectangle(-400, 0, 1200, 600); //パーティクルを作る this.add.particles('particle2', [ { emitZone: { source: offscreen }, deathZone: { source: screen, type: 'onLeave' }, frequency: 100, speedX: { min: 80, max: 120 }, lifespan: 30000, scale: { min: 0.1, max: 0.5 }, tint: 0x535678 , blendMode: 'ADD' }, ]); this.add.particles('particle2', [ { emitZone: { source: offscreen }, deathZone: { source: screen, type: 'onLeave' }, frequency: 150, speedX: { min: 180, max: 220 }, lifespan: 30000, scale: { min: 0.3, max: 0.7 }, tint: 0x332211 , blendMode: 'ADD' }, ]); this.add.particles('particle1', [ { emitZone: { source: offscreen }, deathZone: { source: screen, type: 'onLeave' }, frequency: 500, quantity: 4, speedX: { min: 280, max: 320 }, lifespan: 30000, scale: { min: 0.3, max: 0.7 }, tint: 0x118811, blendMode: 'ADD' }, ]); this.beamGroup = this.add.group(null, {runChildUpdate:true}) }
リボントレイルを使ったビームエフェクト
前回までで一応動くリボントレイルエフェクトができたので、これをビームとして撃てるようにしたいと思います。
Trailクラスを改造し、Beamクラスを作成しました。
Init関数ではメッシュの部分をビームごとに色が変わるようにし、Blendmodeで加算合成を指定しています。
加算合成は
export class Beam extends Phaser.GameObjects.Container { //グラフィックオブジェクトを用意 public graphics: Phaser.GameObjects.Graphics; public mesh: Phaser.GameObjects.Mesh; public curve: Phaser.Curves.CubicBezier; public curvePoints: Phaser.Math.Vector2[] = []; public drawDebug: boolean = false; public points: number = 100; //各ポイントの設定 public tail: Phaser.Math.Vector2; public head: Phaser.Math.Vector2; public controlPoint1: Phaser.Math.Vector2; public controlPoint2: Phaser.Math.Vector2; //ポイント用のtween public tweens: Phaser.Tweens.Tween[] = []; public t1: Phaser.Tweens.Tween public t2: Phaser.Tweens.Tween public t3: Phaser.Tweens.Tween public t4: Phaser.Tweens.Tween public startX: number; public startY: number; public targetX: number; public targetY: number; constructor(scene: Phaser.Scene, x?: number, y?: number, children?: Phaser.GameObjects.GameObject[]) { super(scene, x, y, children); } Init(sx:number,sy:number,x: number, y: number) { this.startX = sx; this.startY = sy; this.targetX = x; this.targetY = y; this.CreateCurve(); this.curvePoints = this.curve.getPoints(this.points); //頂点配列の作成 let array = this.CreateVerts(5, this.points); //uv配列の作成 let uv = this.CreateUVs(array.length / 12); //頂点色を適当に変化 let colors = [] let c = Phaser.Math.Between(0x444444, 0xeeeeee) for (let i = 0; i < array.length/2; i++) { colors.push(c); } this.mesh = this.scene.make.mesh({ key: 'block', x: 0, y: 0, vertices: array, uv: uv, colors: colors }); this.mesh.setBlendMode(Phaser.BlendModes.ADD); } public CreateVerts(width: number, points: number): number[] { let arr = []; let pointArray: Phaser.Geom.Point[][] = new Array(); for (let i = 0; i < points; i++) { let mul = width let vecA = new Phaser.Math.Vector2(this.curvePoints[i + 1].x - this.curvePoints[i].x, this.curvePoints[i + 1].y - this.curvePoints[i].y).normalize(); var point1 = new Phaser.Geom.Point(-vecA.y * mul + this.curvePoints[i + 1].x, vecA.x * mul + this.curvePoints[i + 1].y); var point2 = new Phaser.Geom.Point(vecA.y * mul + this.curvePoints[i + 1].x, -vecA.x * mul + this.curvePoints[i + 1].y); pointArray.push([point1, point2]); } for (let i = 0; i < pointArray.length - 1; i++) { //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //左下 arr.push(pointArray[i][0].x, pointArray[i][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //右上 arr.push(pointArray[i + 1][1].x, pointArray[i + 1][1].y); } return arr; } public UpdateVerts(width: number, points: number): number[] { let arr = []; let pointArray: Phaser.Geom.Point[][] = new Array(); for (let i = 0; i < points; i++) { let mul = width let vecA = new Phaser.Math.Vector2(this.curvePoints[i + 1].x - this.curvePoints[i].x, this.curvePoints[i + 1].y - this.curvePoints[i].y).normalize(); var point1 = new Phaser.Geom.Point(-vecA.y * mul + this.curvePoints[i + 1].x, vecA.x * mul + this.curvePoints[i + 1].y); var point2 = new Phaser.Geom.Point(vecA.y * mul + this.curvePoints[i + 1].x, -vecA.x * mul + this.curvePoints[i + 1].y); pointArray.push([point1, point2]); } for (let i = 0; i < pointArray.length - 1; i++) { //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //左下 arr.push(pointArray[i][0].x, pointArray[i][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //右上 arr.push(pointArray[i + 1][1].x, pointArray[i + 1][1].y); } return arr; } public CreateUVs(points: number): number[] { let arr = []; let uvincr = 1 / points; for (let i = 0; i < points; i++) { //左上 arr.push(0); arr.push(uvincr * i); //左下 arr.push(0); arr.push(uvincr * (i + 1)); //右下 arr.push(1); arr.push(uvincr * (i + 1)); //左上 arr.push(0); arr.push(uvincr * i); //右下 arr.push(1); arr.push(uvincr * (i + 1)); //右上 arr.push(1); arr.push(uvincr * i); } return arr; } public CreateCurve() { //制御点を作成 this.tail = new Phaser.Math.Vector2(this.startX, this.startY); this.head = new Phaser.Math.Vector2(Phaser.Math.Between(this.startX , this.startX+50), Phaser.Math.Between(this.startY-100, this.startY+100)); this.controlPoint1 = new Phaser.Math.Vector2(Phaser.Math.Between(this.tail.x, this.head.x), Phaser.Math.Between(this.tail.y, this.head.y)); this.controlPoint2 = new Phaser.Math.Vector2(Phaser.Math.Between(this.controlPoint1.x, this.head.x), Phaser.Math.Between(this.controlPoint1.x, this.head.y)); this.curve = new Phaser.Curves.CubicBezier(this.tail, this.controlPoint1, this.controlPoint2, this.head); this.graphics = this.scene.add.graphics(); //各制御点にtweenを作成する this.t1 = this.scene.tweens.add({ targets: this.tail, x: this.controlPoint1.x, y: this.controlPoint1.y, duration: 5000, repeat: -1 }) this.t2 = this.scene.tweens.add({ targets: this.controlPoint1, x: this.controlPoint2.x, y: this.controlPoint2.y, duration: 5000, repeat: -1 }) this.t3 = this.scene.tweens.add({ targets: this.controlPoint2, x: this.head.x, y: this.head.y, duration: 5000, repeat: -1 }) this.t4 = this.scene.tweens.add({ targets: this.head, x: this.scene.input.x, y: this.scene.input.y, duration: 5000, repeat: -1 }) } update() { //制御点のtweenをアップデートする this.t4.updateTo("x", this.targetX, true) this.t4.updateTo("y", this.targetY, true) this.t3.updateTo("x", this.head.x, true) this.t3.updateTo("y", this.head.y, true) this.t2.updateTo("x", this.controlPoint2.x, true) this.t2.updateTo("y", this.controlPoint2.y, true) this.t1.updateTo("x", this.controlPoint1.x, true) this.t1.updateTo("y", this.controlPoint1.y, true) this.curvePoints = this.curve.getPoints(100); this.mesh.vertices = Float32Array.from(this.UpdateVerts(5, this.points)); this.graphics.clear(); //ビームが目標地点に達したらゲームオブジェクトを破棄 if (this.tail.x === this.targetX && this.tail.y === this.targetY) { this.graphics.clear(); this.graphics.destroy(); this.mesh.destroy(); this.destroy(); } } }
Myscene1のupdateでクリックに応じてビームを打てるようにします。
update() { if (this.input.activePointer.isDown) { let beam = new Beam(this); beam.Init(this.player.x, this.player.y, this.input.activePointer.x, this.input.activePointer.y) this.beamGroup.add(beam) } }
実行結果がこちらです。
Trailの作りが甘く、ぎこちないビームとなってしまっていますが、ビームを連射できているのがわかります。
ビームの発射自体は軽快な挙動なのですが、破棄処理がうまくできているのか不安があります。
一応Beamクラスで尾のオブジェクトが目標地点に達したとき各種オブジェクトをdestroyするようにしているのですが、これで本当に破棄できているのかは時間をとって調べてみたいと思います。
今回のソースはこちらになります。
/// <reference path="../app.ts" /> namespace MyGame { interface XY { x: number; y: number; } export class Trail extends Phaser.GameObjects.Container { //グラフィックオブジェクトを用意 public graphics: Phaser.GameObjects.Graphics; public mesh: Phaser.GameObjects.Mesh; public curve: Phaser.Curves.CubicBezier; public curvePoints: Phaser.Math.Vector2[] = []; public drawDebug: boolean = false; public points: number = 100; //各ポイントの設定 public tail: Phaser.Math.Vector2; public head: Phaser.Math.Vector2; public controlPoint1: Phaser.Math.Vector2; public controlPoint2: Phaser.Math.Vector2; //ポイント用のtween public tweens: Phaser.Tweens.Tween[]=[]; public t1: Phaser.Tweens.Tween public t2: Phaser.Tweens.Tween public t3: Phaser.Tweens.Tween public t4: Phaser.Tweens.Tween constructor(scene: Phaser.Scene, x?: number, y?: number, children?: Phaser.GameObjects.GameObject[]) { super(scene, x, y, children); } Init() { this.CreateCurve(); this.curvePoints = this.curve.getPoints(this.points); //頂点配列の作成 let array = this.CreateVerts(5, this.points); //uv配列の作成 let uv = this.CreateUVs(array.length / 12); //頂点色を適当に変化 let colors = [] for (let i = 0; i < array.length / 12; i++) { colors.push(i); colors.push(i * 2); colors.push(i * 2); colors.push(i); colors.push(i * 2); colors.push(i); } this.mesh = this.scene.make.mesh({ key: 'block', x: 0, y: 0, vertices: array, uv: uv, colors: colors }); this.mesh.setBlendMode(Phaser.BlendModes.ADD); } public CreateVerts(width: number, points: number): number[] { let arr = []; let pointArray: Phaser.Geom.Point[][] = new Array(); for (let i = 0; i < points; i++) { let mul = width let vecA = new Phaser.Math.Vector2(this.curvePoints[i + 1].x - this.curvePoints[i].x, this.curvePoints[i + 1].y - this.curvePoints[i].y).normalize(); var point1 = new Phaser.Geom.Point(-vecA.y * mul + this.curvePoints[i + 1].x, vecA.x * mul + this.curvePoints[i + 1].y); var point2 = new Phaser.Geom.Point(vecA.y * mul + this.curvePoints[i + 1].x, -vecA.x * mul + this.curvePoints[i + 1].y); pointArray.push([point1, point2]); } for (let i = 0; i < pointArray.length - 1; i++) { //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //左下 arr.push(pointArray[i][0].x, pointArray[i][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //右上 arr.push(pointArray[i + 1][1].x, pointArray[i + 1][1].y); } return arr; } public UpdateVerts(width: number, points: number): number[] { let arr = []; let pointArray: Phaser.Geom.Point[][] = new Array(); for (let i = 0; i < points; i++) { let mul = width let vecA = new Phaser.Math.Vector2(this.curvePoints[i + 1].x - this.curvePoints[i].x, this.curvePoints[i + 1].y - this.curvePoints[i].y).normalize(); var point1 = new Phaser.Geom.Point(-vecA.y * mul + this.curvePoints[i + 1].x, vecA.x * mul + this.curvePoints[i + 1].y); var point2 = new Phaser.Geom.Point(vecA.y * mul + this.curvePoints[i + 1].x, -vecA.x * mul + this.curvePoints[i + 1].y); pointArray.push([point1, point2]); } for (let i = 0; i < pointArray.length - 1; i++) { //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //左下 arr.push(pointArray[i][0].x, pointArray[i][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //右上 arr.push(pointArray[i + 1][1].x, pointArray[i + 1][1].y); } return arr; } public CreateUVs(points: number): number[] { let arr = []; let uvincr = 1 / points; for (let i = 0; i < points; i++) { //左上 arr.push(0); arr.push(uvincr * i); //左下 arr.push(0); arr.push(uvincr * (i + 1)); //右下 arr.push(1); arr.push(uvincr * (i + 1)); //左上 arr.push(0); arr.push(uvincr * i); //右下 arr.push(1); arr.push(uvincr * (i + 1)); //右上 arr.push(1); arr.push(uvincr * i); } return arr; } public CreateCurve() { //制御点を作成 this.tail = new Phaser.Math.Vector2(100, 100); this.head = new Phaser.Math.Vector2(500, 500); this.controlPoint1 = new Phaser.Math.Vector2(Phaser.Math.Between(this.tail.x, this.head.x), Phaser.Math.Between(this.tail.y, this.head.y)); this.controlPoint2 = new Phaser.Math.Vector2(Phaser.Math.Between(this.controlPoint1.x, this.head.x), Phaser.Math.Between(this.controlPoint1.x, this.head.y)); this.curve = new Phaser.Curves.CubicBezier(this.tail, this.controlPoint1, this.controlPoint2, this.head); this.graphics = this.scene.add.graphics(); //各制御点にtweenを作成する this.t1 = this.scene.tweens.add({ targets: this.tail, x: this.controlPoint1.x, y: this.controlPoint1.y, duration: 5000, repeat: -1 }) this.t2 = this.scene.tweens.add({ targets: this.controlPoint1, x: this.controlPoint2.x, y: this.controlPoint2.y, duration: 5000, repeat: -1 }) this.t3 = this.scene.tweens.add({ targets: this.controlPoint2, x: this.head.x, y: this.head.y, duration: 5000, repeat: -1 }) this.t4 = this.scene.tweens.add({ targets: this.head, x: this.scene.input.x, y: this.scene.input.y, duration: 5000, repeat: -1 }) } update() { //制御点のtweenをアップデートする this.t1.updateTo("x", this.controlPoint1.x, true) this.t1.updateTo("y", this.controlPoint1.y, true) this.t2.updateTo("x", this.controlPoint2.x, true) this.t2.updateTo("y", this.controlPoint2.y, true) this.t3.updateTo("x", this.head.x, true) this.t3.updateTo("y", this.head.y, true) this.t4.updateTo("x", this.scene.input.x, true) this.t4.updateTo("y", this.scene.input.y, true) this.curvePoints = this.curve.getPoints(100); this.mesh.vertices = Float32Array.from(this.UpdateVerts(5, this.points)); this.graphics.clear(); } } export class Beam extends Phaser.GameObjects.Container { //グラフィックオブジェクトを用意 public graphics: Phaser.GameObjects.Graphics; public mesh: Phaser.GameObjects.Mesh; public curve: Phaser.Curves.CubicBezier; public curvePoints: Phaser.Math.Vector2[] = []; public drawDebug: boolean = false; public points: number = 100; //各ポイントの設定 public tail: Phaser.Math.Vector2; public head: Phaser.Math.Vector2; public controlPoint1: Phaser.Math.Vector2; public controlPoint2: Phaser.Math.Vector2; //ポイント用のtween public tweens: Phaser.Tweens.Tween[] = []; public t1: Phaser.Tweens.Tween public t2: Phaser.Tweens.Tween public t3: Phaser.Tweens.Tween public t4: Phaser.Tweens.Tween public startX: number; public startY: number; public targetX: number; public targetY: number; constructor(scene: Phaser.Scene, x?: number, y?: number, children?: Phaser.GameObjects.GameObject[]) { super(scene, x, y, children); } Init(sx:number,sy:number,x: number, y: number) { this.startX = sx; this.startY = sy; this.targetX = x; this.targetY = y; this.CreateCurve(); this.curvePoints = this.curve.getPoints(this.points); //頂点配列の作成 let array = this.CreateVerts(5, this.points); //uv配列の作成 let uv = this.CreateUVs(array.length / 12); //頂点色を適当に変化 let colors = [] let c = Phaser.Math.Between(0x444444, 0xeeeeee) for (let i = 0; i < array.length/2; i++) { colors.push(c); } this.mesh = this.scene.make.mesh({ key: 'block', x: 0, y: 0, vertices: array, uv: uv, colors: colors }); this.mesh.setBlendMode(Phaser.BlendModes.ADD); } public CreateVerts(width: number, points: number): number[] { let arr = []; let pointArray: Phaser.Geom.Point[][] = new Array(); for (let i = 0; i < points; i++) { let mul = width let vecA = new Phaser.Math.Vector2(this.curvePoints[i + 1].x - this.curvePoints[i].x, this.curvePoints[i + 1].y - this.curvePoints[i].y).normalize(); var point1 = new Phaser.Geom.Point(-vecA.y * mul + this.curvePoints[i + 1].x, vecA.x * mul + this.curvePoints[i + 1].y); var point2 = new Phaser.Geom.Point(vecA.y * mul + this.curvePoints[i + 1].x, -vecA.x * mul + this.curvePoints[i + 1].y); pointArray.push([point1, point2]); } for (let i = 0; i < pointArray.length - 1; i++) { //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //左下 arr.push(pointArray[i][0].x, pointArray[i][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //右上 arr.push(pointArray[i + 1][1].x, pointArray[i + 1][1].y); } return arr; } public UpdateVerts(width: number, points: number): number[] { let arr = []; let pointArray: Phaser.Geom.Point[][] = new Array(); for (let i = 0; i < points; i++) { let mul = width let vecA = new Phaser.Math.Vector2(this.curvePoints[i + 1].x - this.curvePoints[i].x, this.curvePoints[i + 1].y - this.curvePoints[i].y).normalize(); var point1 = new Phaser.Geom.Point(-vecA.y * mul + this.curvePoints[i + 1].x, vecA.x * mul + this.curvePoints[i + 1].y); var point2 = new Phaser.Geom.Point(vecA.y * mul + this.curvePoints[i + 1].x, -vecA.x * mul + this.curvePoints[i + 1].y); pointArray.push([point1, point2]); } for (let i = 0; i < pointArray.length - 1; i++) { //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //左下 arr.push(pointArray[i][0].x, pointArray[i][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //左上 arr.push(pointArray[i + 1][0].x, pointArray[i + 1][0].y); //右下 arr.push(pointArray[i][1].x, pointArray[i][1].y); //右上 arr.push(pointArray[i + 1][1].x, pointArray[i + 1][1].y); } return arr; } public CreateUVs(points: number): number[] { let arr = []; let uvincr = 1 / points; for (let i = 0; i < points; i++) { //左上 arr.push(0); arr.push(uvincr * i); //左下 arr.push(0); arr.push(uvincr * (i + 1)); //右下 arr.push(1); arr.push(uvincr * (i + 1)); //左上 arr.push(0); arr.push(uvincr * i); //右下 arr.push(1); arr.push(uvincr * (i + 1)); //右上 arr.push(1); arr.push(uvincr * i); } return arr; } public CreateCurve() { //制御点を作成 this.tail = new Phaser.Math.Vector2(this.startX, this.startY); this.head = new Phaser.Math.Vector2(Phaser.Math.Between(this.startX , this.startX+50), Phaser.Math.Between(this.startY-100, this.startY+100)); this.controlPoint1 = new Phaser.Math.Vector2(Phaser.Math.Between(this.tail.x, this.head.x), Phaser.Math.Between(this.tail.y, this.head.y)); this.controlPoint2 = new Phaser.Math.Vector2(Phaser.Math.Between(this.controlPoint1.x, this.head.x), Phaser.Math.Between(this.controlPoint1.x, this.head.y)); this.curve = new Phaser.Curves.CubicBezier(this.tail, this.controlPoint1, this.controlPoint2, this.head); this.graphics = this.scene.add.graphics(); //各制御点にtweenを作成する this.t1 = this.scene.tweens.add({ targets: this.tail, x: this.controlPoint1.x, y: this.controlPoint1.y, duration: 5000, repeat: -1 }) this.t2 = this.scene.tweens.add({ targets: this.controlPoint1, x: this.controlPoint2.x, y: this.controlPoint2.y, duration: 5000, repeat: -1 }) this.t3 = this.scene.tweens.add({ targets: this.controlPoint2, x: this.head.x, y: this.head.y, duration: 5000, repeat: -1 }) this.t4 = this.scene.tweens.add({ targets: this.head, x: this.scene.input.x, y: this.scene.input.y, duration: 5000, repeat: -1 }) } update() { //制御点のtweenをアップデートする this.t4.updateTo("x", this.targetX, true) this.t4.updateTo("y", this.targetY, true) this.t3.updateTo("x", this.head.x, true) this.t3.updateTo("y", this.head.y, true) this.t2.updateTo("x", this.controlPoint2.x, true) this.t2.updateTo("y", this.controlPoint2.y, true) this.t1.updateTo("x", this.controlPoint1.x, true) this.t1.updateTo("y", this.controlPoint1.y, true) this.curvePoints = this.curve.getPoints(100); this.mesh.vertices = Float32Array.from(this.UpdateVerts(5, this.points)); this.graphics.clear(); //ビームが目標地点に達したらゲームオブジェクトを破棄 if (this.tail.x === this.targetX && this.tail.y === this.targetY) { this.graphics.clear(); this.graphics.destroy(); this.mesh.destroy(); this.destroy(); } } } export class MyScene1 extends Phaser.Scene { //グラフィックオブジェクトを用意 public player: Phaser.GameObjects.Image; public beamGroup: Phaser.GameObjects.Group; constructor() { super({ key: 'MyScene1', active: false }); } preload() { this.load.image("block","assets/images/block1.png") this.load.image("particle1", "assets/images/particle1.png") this.load.image("particle2", "assets/images/particle2.png") } create() { this.player=this.add.image(40,this.sys.canvas.height/2,"block") this.cameras.main.setBackgroundColor(0x000000); let offscreen = new Phaser.Geom.Rectangle(-400, 0, 400, 600); let screen = new Phaser.Geom.Rectangle(-400, 0, 1200, 600); //パーティクルを作る this.add.particles('particle2', [ { emitZone: { source: offscreen }, deathZone: { source: screen, type: 'onLeave' }, frequency: 100, speedX: { min: 80, max: 120 }, lifespan: 30000, scale: { min: 0.1, max: 0.5 }, tint: 0x535678 , blendMode: 'ADD' }, ]); this.add.particles('particle2', [ { emitZone: { source: offscreen }, deathZone: { source: screen, type: 'onLeave' }, frequency: 150, speedX: { min: 180, max: 220 }, lifespan: 30000, scale: { min: 0.3, max: 0.7 }, tint: 0x332211 , blendMode: 'ADD' }, ]); this.add.particles('particle1', [ { emitZone: { source: offscreen }, deathZone: { source: screen, type: 'onLeave' }, frequency: 500, quantity: 4, speedX: { min: 280, max: 320 }, lifespan: 30000, scale: { min: 0.3, max: 0.7 }, tint: 0x118811, blendMode: 'ADD' }, ]); this.beamGroup = this.add.group(null, {runChildUpdate:true}) } update() { if (this.input.activePointer.isDown) { let beam = new Beam(this); beam.Init(this.player.x, this.player.y, this.input.activePointer.x, this.input.activePointer.y) this.beamGroup.add(beam) } } } }