Skip to content

Commit 9a56f45

Browse files
committed
修复雷击和热气流的alpha渐变问题
1 parent 25dd0ac commit 9a56f45

17 files changed

+335
-57
lines changed

src/config/AssetKeys.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export const VFXTextureKeys = {
9191
VfxAlertIcon: 'vfx_alert_icon',
9292
VfxAlertBg: 'vfx_alert_bg',
9393
VfxShield: 'vfx_shield',
94+
VfxTrail: 'vfx_sx_trail',
9495
} as const;
9596
export type VFXTextureKey = typeof VFXTextureKeys[keyof typeof VFXTextureKeys];
9697

src/config/AssetManifest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export const AssetManifest: IAssetDefinition[] = [
126126
// 3x3 网格,256 / 3 = 85.33,向下取整为 85
127127
createSpriteSheet(VFXTextureKeys.VfxAlertBg, 'assets/vfx/FX_TEX_Lightning_04.png', 85, 85, 9),
128128
{key: VFXTextureKeys.VfxShield, path: 'assets/vfx/tactics_effect.png', type: 'image'},
129-
129+
{key: VFXTextureKeys.VfxTrail, path: 'assets/vfx/FX_TEX_Speed_Line_02.png', type: 'image'},
130130

131131
// ✅ 新增:音频资源
132132
// BGM

src/config/EntityConfig.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export const EntityConfig = {
7979
texture: TextureKeys.TacticsShild,
8080
scale: EntityTextureScale,
8181
type: EntityType.Buff, // ✅ 有益
82-
comment: "八卦盾",
82+
comment: "太极盾",
8383
// color: 0x00ff00,
8484
onHit: [
8585
new BoostAction(-900),
@@ -93,7 +93,7 @@ export const EntityConfig = {
9393
texture: TextureKeys.Bamboo,
9494
scale: EntityTextureScale * 0.45,
9595
type: EntityType.Coin,
96-
comment: "金币",
96+
comment: "竹筏",
9797
// color: 0xffd700,
9898
onHit: [
9999
new AddCoinAction(1),

src/config/SummonConfig.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { WindVane } from "../entities/summons/WindVane";
55
import { FrostVortex } from "../entities/summons/FrostVortex";
66
import { LightningColumn } from "../entities/summons/LightningColumn";
77
import { Shield } from "../entities/summons/Shield";
8+
import { SubaruTrail } from "../entities/summons/SubaruTrail";
89

910
// ✅ 1. 定义召唤物 ID 常量 (替代硬编码字符串)
1011
export const SummonId = {
@@ -14,6 +15,7 @@ export const SummonId = {
1415
FrostVortex: 'frost_vortex',
1516
LightningColumn: 'lightning_column',
1617
Shield: 'shield',
18+
SubaruTrail: 'subaru_trail',
1719
} as const;
1820

1921
export type SummonId = typeof SummonId[keyof typeof SummonId];
@@ -56,5 +58,11 @@ export const SummonConfig: Record<SummonId, ISummonDef> = {
5658
classType: Shield,
5759
space: SpaceType.World,
5860
poolSize: 1
61+
},
62+
[SummonId.SubaruTrail]: {
63+
classType: SubaruTrail,
64+
space: SpaceType.World,
65+
poolSize: 3
5966
}
60-
};
67+
};
68+

src/entities/summons/LightningColumn.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export class LightningColumn extends BaseSummon {
2626
}
2727

2828
protected onStart(_data: ISummonInitData): void {
29+
this.setVisible(false); // 本体仅仅是逻辑锚点
30+
this.setAlpha(0);
2931
const minZoom = GameConfig.camera.zoom.sprinting;
3032
const screenHeight = this.scene.scale.height;
3133
// const screenWidth = this.scene.scale.width;
@@ -116,6 +118,7 @@ export class LightningColumn extends BaseSummon {
116118
let pipeline: LightningFadePipeline | undefined;
117119
if (this.scene.game.renderer instanceof Phaser.Renderer.WebGL.WebGLRenderer) {
118120
this.strikeSprite.setPipeline(PipelineID.LightningFade);
121+
this.strikeSprite.setBlendMode(Phaser.BlendModes.ADD);
119122
pipeline = this.strikeSprite.pipeline as LightningFadePipeline;
120123
pipeline?.setProgress(0);
121124
// pipeline?.setColor(0x3aa0ff);
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import Phaser from 'phaser';
2+
import { BaseSummon, type ISummonInitData } from './BaseSummon';
3+
import { VFXTextureKeys } from '../../config/AssetKeys';
4+
import { PipelineID } from '../../managers/RenderManager';
5+
6+
export class SubaruTrail extends BaseSummon {
7+
private trailPlane?: Phaser.GameObjects.Plane;
8+
private baseVertices?: { x: number; y: number; z: number }[];
9+
10+
private readonly gridWidth = 8;
11+
private readonly gridHeight = 12;
12+
private readonly trailDisplayWidth = 100;
13+
private readonly trailDisplayHeight = 400;
14+
private readonly expandStrength = 0.6;
15+
16+
constructor(scene: Phaser.Scene, x: number, y: number) {
17+
super(scene, x, y, VFXTextureKeys.VfxTrail);
18+
}
19+
20+
protected onStart(_data: ISummonInitData): void {
21+
this.setVisible(false);
22+
this.setAlpha(0);
23+
24+
if (this.trailPlane) {
25+
this.trailPlane.destroy();
26+
}
27+
28+
this.trailPlane = this.scene.add.plane(
29+
this.x,
30+
this.y,
31+
VFXTextureKeys.VfxTrail,
32+
undefined,
33+
this.gridWidth,
34+
this.gridHeight,
35+
false
36+
);
37+
38+
this.trailPlane.setDisplaySize(this.trailDisplayWidth, this.trailDisplayHeight);
39+
this.trailPlane.setPipeline(PipelineID.SubaruTrail);
40+
this.trailPlane.setBlendMode(Phaser.BlendModes.ADD);
41+
this.trailPlane.setTint(0x004422);
42+
this.trailPlane.setAlpha(1);
43+
this.trailPlane.ignoreDirtyCache = true;
44+
45+
// Plane origin fixed at center; shift so top aligns to this.y
46+
this.trailPlane.setPosition(this.x, this.y + this.trailDisplayHeight / 2);
47+
48+
this.captureBaseVertices();
49+
this.applyCurveShape();
50+
}
51+
52+
private captureBaseVertices() {
53+
if (!this.trailPlane) return;
54+
this.baseVertices = this.trailPlane.vertices.map((v) => ({ x: v.x, y: v.y, z: v.z }));
55+
}
56+
57+
// 中上部分外展
58+
private applyCurveShape() {
59+
if (!this.trailPlane || !this.baseVertices) return;
60+
61+
const verts = this.trailPlane.vertices;
62+
let minY = Infinity;
63+
let maxY = -Infinity;
64+
65+
for (const v of this.baseVertices) {
66+
if (v.y < minY) minY = v.y;
67+
if (v.y > maxY) maxY = v.y;
68+
}
69+
70+
const range = Math.max(1, maxY - minY);
71+
72+
for (let i = 0; i < verts.length; i++) {
73+
const base = this.baseVertices[i];
74+
const yNorm = (base.y - minY) / range; // 0 top, 1 bottom
75+
76+
const rise = Phaser.Math.Clamp((yNorm - 0.12) / 0.22, 0, 1);
77+
const fall = Phaser.Math.Clamp((0.58 - yNorm) / 0.26, 0, 1);
78+
const bulge = rise * fall;
79+
80+
const bottomTaper = Phaser.Math.Clamp((yNorm - 0.7) / 0.3, 0, 1);
81+
const taper = 1 - bottomTaper * 0.3;
82+
83+
const expand = 1 + bulge * this.expandStrength;
84+
const factor = expand * taper;
85+
86+
verts[i].x = base.x * factor;
87+
verts[i].y = base.y;
88+
verts[i].z = base.z;
89+
}
90+
}
91+
92+
protected onUpdate(_dt: number): void {
93+
if (this.target && this.target.active) {
94+
const offsetY = this.target.height * 0.5;
95+
this.setPosition(this.target.x, this.target.y + offsetY);
96+
}
97+
98+
if (this.trailPlane) {
99+
this.trailPlane.setPosition(this.x, this.y + this.trailDisplayHeight / 2);
100+
}
101+
}
102+
103+
protected onDespawn(): void {
104+
if (this.trailPlane) {
105+
this.scene.tweens.add({
106+
targets: this.trailPlane,
107+
alpha: 0,
108+
duration: 300,
109+
onComplete: () => {
110+
this.trailPlane?.destroy();
111+
this.trailPlane = undefined;
112+
this.baseVertices = undefined;
113+
this.kill();
114+
}
115+
});
116+
} else {
117+
this.kill();
118+
}
119+
}
120+
}

src/entities/summons/ThermalVent.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export class ThermalVent extends BaseSummon {
1717

1818
protected onStart(_data: ISummonInitData): void {
1919
// 1. 设置外观 (红光柱)
20-
this.setTint(0xff0000);
20+
this.setTint(0x0000ff);
21+
this.setBlendMode(Phaser.BlendModes.ADD);
2122
this.setAlpha(0);
2223

2324
// ✅ 启用 Shader Pipeline
@@ -45,7 +46,7 @@ export class ThermalVent extends BaseSummon {
4546
// 进场动画
4647
this.scene.tweens.add({
4748
targets: this,
48-
alpha: { from: 0, to: 0.3 },
49+
alpha: { from: 0, to: 0.5 },
4950
duration: 1000
5051
});
5152
}

src/managers/RenderManager.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import DissolvePipeline from '../pipelines/DissolvePipeline';
55
import ColdnessPipeline from '../pipelines/ColdnessPipeline';
66
import LightningFadePipeline from '../pipelines/LightningFadePipeline';
77
import ThermalVentPipeline from '../pipelines/ThermalVentPipeline';
8+
import SubaruTrailPipeline from '../pipelines/SubaruTrailPipeline';
89

910
export const PipelineID = {
1011
Fog: 'FogPipeline',
@@ -13,6 +14,7 @@ export const PipelineID = {
1314
LightningFade: 'LightningFade',
1415
Coldness: 'Coldness', // ✅ Add ID
1516
ThermalVent: 'ThermalVent', // ✅ 新增 ID
17+
SubaruTrail: 'SubaruTrail', // ✅ 新增 ID
1618
} as const;
1719
export type PipelineKey = typeof PipelineID[keyof typeof PipelineID];
1820

@@ -66,6 +68,12 @@ export default class RenderManager {
6668
this.renderer.pipelines.add(PipelineID.ThermalVent, new ThermalVentPipeline(this.scene.game));
6769
console.log(`[RenderManager] Pipeline Registered: ${PipelineID.ThermalVent}`);
6870
}
71+
72+
// ✅ 注册 SubaruTrail Pipeline
73+
if (!this.renderer.pipelines.has(PipelineID.SubaruTrail)) {
74+
this.renderer.pipelines.add(PipelineID.SubaruTrail, new SubaruTrailPipeline(this.scene.game));
75+
console.log(`[RenderManager] Pipeline Registered: ${PipelineID.SubaruTrail}`);
76+
}
6977
}
7078

7179
// ✅ 3. 公开获取 Pipeline 的方法
@@ -96,6 +104,11 @@ export default class RenderManager {
96104
if (coldPipeline) {
97105
coldPipeline.updateTime(time);
98106
}
107+
108+
const trailPipeline = this.getPipeline<SubaruTrailPipeline>(PipelineID.SubaruTrail);
109+
if (trailPipeline) {
110+
trailPipeline.updateTime(time);
111+
}
99112
}
100113
}
101114

src/phases/LabPhase.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ import { TextureKeys, VFXTextureKeys } from '../config/AssetKeys';
66
import { PipelineID } from '../managers/RenderManager';
77
import { GroupSpawnPatterns } from '../managers/SpawnManager';
88
import { EntityIds } from '../config/EntityIds';
9+
import type { BaseSummon } from '../entities/summons/BaseSummon';
910

1011
export class LabPhase implements IGamePhase {
12+
private subaruTrail: BaseSummon | null = null;
13+
private thermalVent: BaseSummon | null = null;
14+
1115
onEnter(scene: GameScene): void {
1216
console.log("🧪 Entered Lab Phase: Ready for experiments.");
1317
scene.scoreManager.startTracking();
@@ -49,6 +53,8 @@ export class LabPhase implements IGamePhase {
4953
keyboard.off('keydown-FIVE');
5054
keyboard.off('keydown-SIX');
5155
keyboard.off('keydown-SEVEN');
56+
keyboard.off('keydown-EIGHT');
57+
keyboard.off('keydown-R');
5258
keyboard.off('keydown-Q');
5359
keyboard.off('keydown-W');
5460
keyboard.off('keydown-E');
@@ -98,6 +104,38 @@ export class LabPhase implements IGamePhase {
98104
scene.summonManager.summon(SummonId.FrostVortex, scene.player.x - 200, scene.player.y - 600);
99105
});
100106

107+
// 测试 8: 召唤/回收 SubaruTrail
108+
keyboard.on('keydown-EIGHT', () => {
109+
if (this.subaruTrail && this.subaruTrail.active) {
110+
console.log("🧪 Test: Despawn SubaruTrail");
111+
this.subaruTrail.despawn();
112+
this.subaruTrail = null;
113+
return;
114+
}
115+
console.log("🧪 Test: Summon SubaruTrail");
116+
this.subaruTrail = scene.summonManager.summon(
117+
SummonId.SubaruTrail,
118+
scene.player.x,
119+
scene.player.y
120+
);
121+
});
122+
123+
// 测试 R: 召唤/回收 ThermalVent
124+
keyboard.on('keydown-R', () => {
125+
if (this.thermalVent && this.thermalVent.active) {
126+
console.log("🧪 Test: Despawn ThermalVent");
127+
this.thermalVent.despawn();
128+
this.thermalVent = null;
129+
return;
130+
}
131+
console.log("🧪 Test: Summon ThermalVent");
132+
this.thermalVent = scene.summonManager.summon(
133+
SummonId.ThermalVent,
134+
scene.player.x,
135+
scene.player.y
136+
);
137+
});
138+
101139
// 测试 3: 触发雷暴
102140
keyboard.on('keydown-Q', () => {
103141
console.log("🧪 Test: Trigger Thunder");
@@ -173,4 +211,4 @@ export class LabPhase implements IGamePhase {
173211
}
174212
});
175213
}
176-
}
214+
}

src/pipelines/LightningFadePipeline.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@ import Phaser from 'phaser';
22
import LightningFadeVert from '../shaders/LightningFade.vert?raw';
33
import LightningFadeFrag from '../shaders/LightningFade.frag?raw';
44

5-
export default class LightningFadePipeline extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline {
5+
export default class LightningFadePipeline extends Phaser.Renderer.WebGL.Pipelines.SinglePipeline {
66
private _progress: number = 0;
7-
private _color = new Phaser.Display.Color(0, 0, 255);
7+
private _color = new Phaser.Display.Color(255, 255, 255);
88

99
constructor(game: Phaser.Game) {
10-
const safeFragShader = LightningFadeFrag.replace(/%count%/gi, '1');
1110
super({
1211
game,
1312
vertShader: LightningFadeVert,
14-
fragShader: safeFragShader,
13+
fragShader: LightningFadeFrag,
1514
});
1615
}
1716

0 commit comments

Comments
 (0)