Files
OpenFrontIO/src/client/graphics/fx/NukeFx.ts
T
evanpelle e246289876 Revert "New Year's Eve FX (#2745)"
This reverts commit ec694593a6.
2026-01-12 20:56:17 -08:00

111 lines
2.8 KiB
TypeScript

import { GameView } from "../../../core/game/GameView";
import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader";
import { Fx, FxType } from "./Fx";
import { FadeFx, SpriteFx } from "./SpriteFx";
/**
* Shockwave effect: draw a growing 1px white circle
*/
export class ShockwaveFx implements Fx {
private lifeTime: number = 0;
constructor(
private x: number,
private y: number,
private duration: number,
private maxRadius: number,
) {}
renderTick(frameTime: number, ctx: CanvasRenderingContext2D): boolean {
this.lifeTime += frameTime;
if (this.lifeTime >= this.duration) {
return false;
}
const t = this.lifeTime / this.duration;
const radius = t * this.maxRadius;
ctx.beginPath();
ctx.arc(this.x, this.y, radius, 0, Math.PI * 2);
ctx.strokeStyle = "rgba(255, 255, 255, " + (1 - t) + ")";
ctx.lineWidth = 0.5;
ctx.stroke();
return true;
}
}
/**
* Spawn @p number of @p type animation within a perimeter
*/
function addSpriteInCircle(
animatedSpriteLoader: AnimatedSpriteLoader,
x: number,
y: number,
radius: number,
num: number,
type: FxType,
result: Fx[],
game: GameView,
) {
const count = Math.max(0, Math.floor(num));
for (let i = 0; i < count; i++) {
const angle = Math.random() * 2 * Math.PI;
const distance = Math.random() * (radius / 2);
const spawnX = Math.floor(x + Math.cos(angle) * distance);
const spawnY = Math.floor(y + Math.sin(angle) * distance);
if (
game.isValidCoord(spawnX, spawnY) &&
game.isLand(game.ref(spawnX, spawnY))
) {
const sprite = new FadeFx(
new SpriteFx(animatedSpriteLoader, spawnX, spawnY, type, 6000),
0.1,
0.8,
);
result.push(sprite as Fx);
}
}
}
/**
* Explosion effect:
* - explosion animation
* - shockwave
* - ruins and desolation fx
*/
export function nukeFxFactory(
animatedSpriteLoader: AnimatedSpriteLoader,
x: number,
y: number,
radius: number,
game: GameView,
): Fx[] {
const nukeFx: Fx[] = [];
// Explosion animation
nukeFx.push(new SpriteFx(animatedSpriteLoader, x, y, FxType.Nuke));
// Shockwave animation
nukeFx.push(new ShockwaveFx(x, y, 1500, radius * 1.5));
// Ruins and desolation sprites
const debrisPlan: Array<{
type: FxType;
radiusFactor: number;
density: number;
}> = [
{ type: FxType.MiniFire, radiusFactor: 1.0, density: 1 / 25 },
{ type: FxType.MiniSmoke, radiusFactor: 1.0, density: 1 / 28 },
{ type: FxType.MiniBigSmoke, radiusFactor: 0.9, density: 1 / 70 },
{ type: FxType.MiniSmokeAndFire, radiusFactor: 0.9, density: 1 / 70 },
];
for (const { type, radiusFactor, density } of debrisPlan) {
addSpriteInCircle(
animatedSpriteLoader,
x,
y,
radius * radiusFactor,
radius * density,
type,
nukeFx,
game,
);
}
return nukeFx;
}