refactor: 天气系统结构

This commit is contained in:
unanmed 2025-01-31 12:35:31 +08:00
parent 6f10ac3d81
commit ed229e1601
5 changed files with 104 additions and 67 deletions

View File

@ -1,3 +1,11 @@
import { RainWeather } from './rain';
import { SnowWeather } from './snow';
import { SunWeather } from './sun';
import { WeatherController } from './weather'; import { WeatherController } from './weather';
export const controller = new WeatherController(); WeatherController.register('rain', RainWeather);
WeatherController.register('sun', SunWeather);
WeatherController.register('snow', SnowWeather);
export * from './weather';
export * from './rain';

View File

@ -1,5 +1,5 @@
import { Shader, ShaderProgram } from '@/core/render/shader'; import { Shader, ShaderProgram } from '@/core/render/shader';
import { IWeather, WeatherController } from './weather'; import { IWeather } from './weather';
import { MotaRenderer } from '@/core/render/render'; import { MotaRenderer } from '@/core/render/render';
import { Container } from '@/core/render/container'; import { Container } from '@/core/render/container';
import { IShaderUniform, UniformType } from '@/core/render/gl2'; import { IShaderUniform, UniformType } from '@/core/render/gl2';
@ -78,13 +78,18 @@ void main() {
/** 雨滴顶点坐标 */ /** 雨滴顶点坐标 */
const vertex = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]); const vertex = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
Mota.require('var', 'loading').once('coreInit', () => { export class RainWeather implements IWeather {
readonly shader: RainShader;
readonly program: ShaderProgram;
private progress: IShaderUniform<UniformType.Uniform1f> | null = null;
constructor(readonly level: number = 5) {
const shader = new RainShader(); const shader = new RainShader();
const gl = shader.gl; const gl = shader.gl;
shader.size(480, 480); shader.size(480, 480);
shader.setHD(true); shader.setHD(true);
shader.setZIndex(100); shader.setZIndex(100);
RainWeather.shader = shader;
const program = shader.createProgram(ShaderProgram); const program = shader.createProgram(ShaderProgram);
program.fs(rainFs); program.fs(rainFs);
program.vs(rainVs); program.vs(rainVs);
@ -95,7 +100,6 @@ Mota.require('var', 'loading').once('coreInit', () => {
program.defineUniform('u_progress', shader.UNIFORM_1f); program.defineUniform('u_progress', shader.UNIFORM_1f);
program.defineUniform('u_color', shader.UNIFORM_4f); program.defineUniform('u_color', shader.UNIFORM_4f);
program.mode(shader.DRAW_ARRAYS_INSTANCED); program.mode(shader.DRAW_ARRAYS_INSTANCED);
RainShader.rainProgram = program;
shader.useProgram(program); shader.useProgram(program);
if (pos) { if (pos) {
@ -103,42 +107,37 @@ Mota.require('var', 'loading').once('coreInit', () => {
pos.pointer(2, gl.FLOAT, false, 0, 0); pos.pointer(2, gl.FLOAT, false, 0, 0);
pos.enable(); pos.enable();
} }
}); this.shader = shader;
this.program = program;
export class RainWeather implements IWeather { }
static id: string = 'rain';
static shader: RainShader;
private progress: IShaderUniform<UniformType.Uniform1f> | null = null;
constructor(readonly level: number = 5) {}
activate(): void { activate(): void {
const render = MotaRenderer.get('render-main'); const render = MotaRenderer.get('render-main');
const draw = render?.getElementById('map-draw') as Container; const draw = render?.getElementById('map-draw') as Container;
if (!draw) return; if (!draw) return;
const shader = RainWeather.shader; const shader = this.shader;
shader.append(draw); shader.append(draw);
const gl = shader.gl; const gl = shader.gl;
const program = RainShader.rainProgram; const program = this.program;
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, 100 * this.level); program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, 100 * this.level);
this.progress = program.getUniform<UniformType.Uniform1f>('u_progress'); this.progress = program.getUniform<UniformType.Uniform1f>('u_progress');
shader.useProgram(program);
shader.generateRainPath( shader.generateRainPath(
this.level * 100, this.level * 100,
(((Math.random() - 0.5) * Math.PI) / 30) * this.level, (((Math.random() - 0.5) * Math.PI) / 30) * this.level,
(Math.PI / 180) * (12 - this.level) (Math.PI / 180) * (12 - this.level),
program
); );
} }
frame(): void { frame(): void {
RainWeather.shader.update(RainWeather.shader); this.shader.update(this.shader);
const time = 5000 - 400 * this.level; const time = 5000 - 400 * this.level;
const progress = (Date.now() % time) / time; const progress = (Date.now() % time) / time;
RainWeather.shader.useProgram(RainShader.rainProgram); this.shader.useProgram(this.program);
this.progress?.set(progress); this.progress?.set(progress);
} }
@ -147,25 +146,23 @@ export class RainWeather implements IWeather {
const draw = render?.getElementById('map-draw') as Container; const draw = render?.getElementById('map-draw') as Container;
const layer = draw.children; const layer = draw.children;
if (!layer || !draw) return; if (!layer || !draw) return;
const shader = RainWeather.shader; const shader = this.shader;
draw.appendChild(...layer); draw.appendChild(...layer);
shader.remove(); shader.remove();
} }
} }
WeatherController.register(RainWeather);
class RainShader extends Shader { class RainShader extends Shader {
static rainProgram: ShaderProgram;
static backProgram: ShaderProgram;
/** /**
* *
* @param num * @param num
*/ */
generateRainPath(num: number, angle: number, deviation: number) { generateRainPath(
const program = RainShader.rainProgram; num: number,
RainWeather.shader.useProgram(program); angle: number,
deviation: number,
program: ShaderProgram
) {
const aOffset = program.getAttribArray('a_offset'); const aOffset = program.getAttribArray('a_offset');
const aData = program.getAttribArray('a_data'); const aData = program.getAttribArray('a_data');
const color = program.getUniform<UniformType.Uniform4f>('u_color'); const color = program.getUniform<UniformType.Uniform4f>('u_color');

View File

@ -1,5 +1,5 @@
import { Shader, ShaderProgram } from '@/core/render/shader'; import { Shader, ShaderProgram } from '@/core/render/shader';
import { IWeather, WeatherController } from './weather'; import { IWeather } from './weather';
import { MotaRenderer } from '@/core/render/render'; import { MotaRenderer } from '@/core/render/render';
import { Container } from '@/core/render/container'; import { Container } from '@/core/render/container';
import { GL2Program, IShaderUniform, UniformType } from '@/core/render/gl2'; import { GL2Program, IShaderUniform, UniformType } from '@/core/render/gl2';
@ -174,8 +174,6 @@ export class SnowWeather implements IWeather {
} }
} }
WeatherController.register(SnowWeather);
class SnowShader extends Shader { class SnowShader extends Shader {
static snowProgram: ShaderProgram; static snowProgram: ShaderProgram;
static backProgram: ShaderProgram; static backProgram: ShaderProgram;

View File

@ -1,4 +1,4 @@
import { IWeather, WeatherController } from './weather'; import { IWeather } from './weather';
export class SunWeather implements IWeather { export class SunWeather implements IWeather {
static id: string = 'sun'; static id: string = 'sun';
@ -9,5 +9,3 @@ export class SunWeather implements IWeather {
deactivate(): void {} deactivate(): void {}
} }
WeatherController.register(SunWeather);

View File

@ -1,11 +1,12 @@
import { logger } from '@/core/common/logger'; import { logger } from '@/core/common/logger';
import { RenderItem } from '@/core/render';
import { Ticker } from 'mutate-animate'; import { Ticker } from 'mutate-animate';
export interface IWeather { export interface IWeather {
/** /**
* *
*/ */
activate(): void; activate(item: RenderItem): void;
/** /**
* *
@ -15,21 +16,25 @@ export interface IWeather {
/** /**
* *
*/ */
deactivate(): void; deactivate(item: RenderItem): void;
} }
interface Weather<T extends IWeather = IWeather> { type Weather = new (level?: number) => IWeather;
id: string;
new (level?: number): T;
}
export class WeatherController { export class WeatherController {
static list: Map<string, Weather> = new Map(); static list: Map<string, Weather> = new Map();
static map: Map<string, WeatherController> = new Map();
/** 当前的所有天气 */ /** 当前的所有天气 */
active: Set<IWeather> = new Set(); active: Set<IWeather> = new Set();
ticker: Ticker = new Ticker(); ticker: Ticker = new Ticker();
private binded?: RenderItem;
constructor(public readonly id: string) {
WeatherController.map.set(id, this);
}
private tick = () => { private tick = () => {
this.active.forEach(v => { this.active.forEach(v => {
v.frame(); v.frame();
@ -40,9 +45,11 @@ export class WeatherController {
* *
*/ */
clearWeather() { clearWeather() {
if (this.binded) {
this.active.forEach(v => { this.active.forEach(v => {
v.deactivate(); v.deactivate(this.binded!);
}); });
}
this.active.clear(); this.active.clear();
} }
@ -50,7 +57,7 @@ export class WeatherController {
* *
* @param weather * @param weather
*/ */
getWeather<T extends IWeather>(weather: Weather<T>): T | null { getWeather<T extends IWeather = IWeather>(weather: Weather): T | null {
return ([...this.active].find(v => v instanceof weather) as T) ?? null; return ([...this.active].find(v => v instanceof weather) as T) ?? null;
} }
@ -68,7 +75,9 @@ export class WeatherController {
} }
const weather = new Weather(level); const weather = new Weather(level);
this.active.add(weather); this.active.add(weather);
weather.activate(); if (this.binded) {
weather.activate(this.binded);
}
if (!this.ticker.funcs.has(this.tick)) { if (!this.ticker.funcs.has(this.tick)) {
this.ticker.add(this.tick); this.ticker.add(this.tick);
} }
@ -84,10 +93,37 @@ export class WeatherController {
if (this.active.size === 0) { if (this.active.size === 0) {
this.ticker.remove(this.tick); this.ticker.remove(this.tick);
} }
weather.deactivate(); if (this.binded) {
weather.deactivate(this.binded);
}
} }
static register(weather: Weather) { /**
this.list.set(weather.id, weather); *
* @param item
*/
bind(item?: RenderItem) {
if (this.binded) {
this.active.forEach(v => v.deactivate(this.binded!));
}
this.binded = item;
if (item) {
this.active.forEach(v => v.activate(item));
}
}
/**
*
*/
destroy() {
WeatherController.map.delete(this.id);
}
static get(id: string) {
return this.map.get(id);
}
static register(id: string, weather: Weather) {
this.list.set(id, weather);
} }
} }