mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-04-11 15:47:06 +08:00
refactor: 天气系统结构
This commit is contained in:
parent
6f10ac3d81
commit
ed229e1601
@ -1,3 +1,11 @@
|
||||
import { RainWeather } from './rain';
|
||||
import { SnowWeather } from './snow';
|
||||
import { SunWeather } from './sun';
|
||||
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';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Shader, ShaderProgram } from '@/core/render/shader';
|
||||
import { IWeather, WeatherController } from './weather';
|
||||
import { IWeather } from './weather';
|
||||
import { MotaRenderer } from '@/core/render/render';
|
||||
import { Container } from '@/core/render/container';
|
||||
import { IShaderUniform, UniformType } from '@/core/render/gl2';
|
||||
@ -78,67 +78,66 @@ void main() {
|
||||
/** 雨滴顶点坐标 */
|
||||
const vertex = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
|
||||
|
||||
Mota.require('var', 'loading').once('coreInit', () => {
|
||||
const shader = new RainShader();
|
||||
const gl = shader.gl;
|
||||
shader.size(480, 480);
|
||||
shader.setHD(true);
|
||||
shader.setZIndex(100);
|
||||
RainWeather.shader = shader;
|
||||
const program = shader.createProgram(ShaderProgram);
|
||||
program.fs(rainFs);
|
||||
program.vs(rainVs);
|
||||
program.requestCompile();
|
||||
const pos = program.defineAttribArray('a_rainVertex');
|
||||
program.defineAttribArray('a_offset');
|
||||
program.defineAttribArray('a_data');
|
||||
program.defineUniform('u_progress', shader.UNIFORM_1f);
|
||||
program.defineUniform('u_color', shader.UNIFORM_4f);
|
||||
program.mode(shader.DRAW_ARRAYS_INSTANCED);
|
||||
RainShader.rainProgram = program;
|
||||
shader.useProgram(program);
|
||||
|
||||
if (pos) {
|
||||
pos.buffer(vertex, gl.STATIC_DRAW);
|
||||
pos.pointer(2, gl.FLOAT, false, 0, 0);
|
||||
pos.enable();
|
||||
}
|
||||
});
|
||||
|
||||
export class RainWeather implements IWeather {
|
||||
static id: string = 'rain';
|
||||
|
||||
static shader: RainShader;
|
||||
readonly shader: RainShader;
|
||||
readonly program: ShaderProgram;
|
||||
|
||||
private progress: IShaderUniform<UniformType.Uniform1f> | null = null;
|
||||
|
||||
constructor(readonly level: number = 5) {}
|
||||
constructor(readonly level: number = 5) {
|
||||
const shader = new RainShader();
|
||||
const gl = shader.gl;
|
||||
shader.size(480, 480);
|
||||
shader.setHD(true);
|
||||
shader.setZIndex(100);
|
||||
const program = shader.createProgram(ShaderProgram);
|
||||
program.fs(rainFs);
|
||||
program.vs(rainVs);
|
||||
program.requestCompile();
|
||||
const pos = program.defineAttribArray('a_rainVertex');
|
||||
program.defineAttribArray('a_offset');
|
||||
program.defineAttribArray('a_data');
|
||||
program.defineUniform('u_progress', shader.UNIFORM_1f);
|
||||
program.defineUniform('u_color', shader.UNIFORM_4f);
|
||||
program.mode(shader.DRAW_ARRAYS_INSTANCED);
|
||||
shader.useProgram(program);
|
||||
|
||||
if (pos) {
|
||||
pos.buffer(vertex, gl.STATIC_DRAW);
|
||||
pos.pointer(2, gl.FLOAT, false, 0, 0);
|
||||
pos.enable();
|
||||
}
|
||||
this.shader = shader;
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
activate(): void {
|
||||
const render = MotaRenderer.get('render-main');
|
||||
const draw = render?.getElementById('map-draw') as Container;
|
||||
if (!draw) return;
|
||||
const shader = RainWeather.shader;
|
||||
const shader = this.shader;
|
||||
shader.append(draw);
|
||||
|
||||
const gl = shader.gl;
|
||||
const program = RainShader.rainProgram;
|
||||
const program = this.program;
|
||||
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, 100 * this.level);
|
||||
|
||||
this.progress = program.getUniform<UniformType.Uniform1f>('u_progress');
|
||||
shader.useProgram(program);
|
||||
shader.generateRainPath(
|
||||
this.level * 100,
|
||||
(((Math.random() - 0.5) * Math.PI) / 30) * this.level,
|
||||
(Math.PI / 180) * (12 - this.level)
|
||||
(Math.PI / 180) * (12 - this.level),
|
||||
program
|
||||
);
|
||||
}
|
||||
|
||||
frame(): void {
|
||||
RainWeather.shader.update(RainWeather.shader);
|
||||
this.shader.update(this.shader);
|
||||
const time = 5000 - 400 * this.level;
|
||||
const progress = (Date.now() % time) / time;
|
||||
|
||||
RainWeather.shader.useProgram(RainShader.rainProgram);
|
||||
this.shader.useProgram(this.program);
|
||||
this.progress?.set(progress);
|
||||
}
|
||||
|
||||
@ -147,25 +146,23 @@ export class RainWeather implements IWeather {
|
||||
const draw = render?.getElementById('map-draw') as Container;
|
||||
const layer = draw.children;
|
||||
if (!layer || !draw) return;
|
||||
const shader = RainWeather.shader;
|
||||
const shader = this.shader;
|
||||
draw.appendChild(...layer);
|
||||
shader.remove();
|
||||
}
|
||||
}
|
||||
|
||||
WeatherController.register(RainWeather);
|
||||
|
||||
class RainShader extends Shader {
|
||||
static rainProgram: ShaderProgram;
|
||||
static backProgram: ShaderProgram;
|
||||
|
||||
/**
|
||||
* 生成雨滴
|
||||
* @param num 雨滴数量
|
||||
*/
|
||||
generateRainPath(num: number, angle: number, deviation: number) {
|
||||
const program = RainShader.rainProgram;
|
||||
RainWeather.shader.useProgram(program);
|
||||
generateRainPath(
|
||||
num: number,
|
||||
angle: number,
|
||||
deviation: number,
|
||||
program: ShaderProgram
|
||||
) {
|
||||
const aOffset = program.getAttribArray('a_offset');
|
||||
const aData = program.getAttribArray('a_data');
|
||||
const color = program.getUniform<UniformType.Uniform4f>('u_color');
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Shader, ShaderProgram } from '@/core/render/shader';
|
||||
import { IWeather, WeatherController } from './weather';
|
||||
import { IWeather } from './weather';
|
||||
import { MotaRenderer } from '@/core/render/render';
|
||||
import { Container } from '@/core/render/container';
|
||||
import { GL2Program, IShaderUniform, UniformType } from '@/core/render/gl2';
|
||||
@ -174,8 +174,6 @@ export class SnowWeather implements IWeather {
|
||||
}
|
||||
}
|
||||
|
||||
WeatherController.register(SnowWeather);
|
||||
|
||||
class SnowShader extends Shader {
|
||||
static snowProgram: ShaderProgram;
|
||||
static backProgram: ShaderProgram;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IWeather, WeatherController } from './weather';
|
||||
import { IWeather } from './weather';
|
||||
|
||||
export class SunWeather implements IWeather {
|
||||
static id: string = 'sun';
|
||||
@ -9,5 +9,3 @@ export class SunWeather implements IWeather {
|
||||
|
||||
deactivate(): void {}
|
||||
}
|
||||
|
||||
WeatherController.register(SunWeather);
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { logger } from '@/core/common/logger';
|
||||
import { RenderItem } from '@/core/render';
|
||||
import { Ticker } from 'mutate-animate';
|
||||
|
||||
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> {
|
||||
id: string;
|
||||
new (level?: number): T;
|
||||
}
|
||||
type Weather = new (level?: number) => IWeather;
|
||||
|
||||
export class WeatherController {
|
||||
static list: Map<string, Weather> = new Map();
|
||||
static map: Map<string, WeatherController> = new Map();
|
||||
|
||||
/** 当前的所有天气 */
|
||||
active: Set<IWeather> = new Set();
|
||||
ticker: Ticker = new Ticker();
|
||||
|
||||
private binded?: RenderItem;
|
||||
|
||||
constructor(public readonly id: string) {
|
||||
WeatherController.map.set(id, this);
|
||||
}
|
||||
|
||||
private tick = () => {
|
||||
this.active.forEach(v => {
|
||||
v.frame();
|
||||
@ -40,9 +45,11 @@ export class WeatherController {
|
||||
* 清空所有天气
|
||||
*/
|
||||
clearWeather() {
|
||||
this.active.forEach(v => {
|
||||
v.deactivate();
|
||||
});
|
||||
if (this.binded) {
|
||||
this.active.forEach(v => {
|
||||
v.deactivate(this.binded!);
|
||||
});
|
||||
}
|
||||
this.active.clear();
|
||||
}
|
||||
|
||||
@ -50,7 +57,7 @@ export class WeatherController {
|
||||
* 获取一个天气
|
||||
* @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;
|
||||
}
|
||||
|
||||
@ -68,7 +75,9 @@ export class WeatherController {
|
||||
}
|
||||
const weather = new Weather(level);
|
||||
this.active.add(weather);
|
||||
weather.activate();
|
||||
if (this.binded) {
|
||||
weather.activate(this.binded);
|
||||
}
|
||||
if (!this.ticker.funcs.has(this.tick)) {
|
||||
this.ticker.add(this.tick);
|
||||
}
|
||||
@ -84,10 +93,37 @@ export class WeatherController {
|
||||
if (this.active.size === 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user