mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-10-09 20:41:47 +08:00
Compare commits
1 Commits
a1dae80f71
...
e2c06258ad
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e2c06258ad |
@ -17,3 +17,4 @@ export * from './audio';
|
|||||||
export * from './fallback';
|
export * from './fallback';
|
||||||
export * from './loader';
|
export * from './loader';
|
||||||
export * from './render';
|
export * from './render';
|
||||||
|
export * from './weather';
|
||||||
|
@ -638,10 +638,10 @@ export function getChoice<T extends ChoiceKey = ChoiceKey>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChoiceRoute(defaults: number) {
|
function getChoiceRoute() {
|
||||||
const route = core.status.replay.toReplay[0];
|
const route = core.status.replay.toReplay[0];
|
||||||
if (!route.startsWith('choices:')) {
|
if (!route.startsWith('choices:')) {
|
||||||
return defaults;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return Number(route.slice(8));
|
return Number(route.slice(8));
|
||||||
}
|
}
|
||||||
@ -680,9 +680,9 @@ export async function routedConfirm(
|
|||||||
props?: Partial<ConfirmBoxProps>
|
props?: Partial<ConfirmBoxProps>
|
||||||
) {
|
) {
|
||||||
if (core.isReplaying()) {
|
if (core.isReplaying()) {
|
||||||
const confirm = getChoiceRoute(1) === 0;
|
const confirm = getChoiceRoute() === 1;
|
||||||
const timeout = core.control.__replay_getTimeout();
|
const timeout = core.control.__replay_getTimeout();
|
||||||
core.status.route.push(`choices:${confirm ? 0 : 1}`);
|
core.status.route.push(`choices:${confirm ? 1 : 0}`);
|
||||||
if (timeout === 0) return confirm;
|
if (timeout === 0) return confirm;
|
||||||
const instance = controller.open(ConfirmBoxUI, {
|
const instance = controller.open(ConfirmBoxUI, {
|
||||||
...(props ?? {}),
|
...(props ?? {}),
|
||||||
@ -696,7 +696,7 @@ export async function routedConfirm(
|
|||||||
return confirm;
|
return confirm;
|
||||||
} else {
|
} else {
|
||||||
const confirm = await getConfirm(controller, text, loc, width, props);
|
const confirm = await getConfirm(controller, text, loc, width, props);
|
||||||
core.status.route.push(`choices:${confirm ? 0 : 1}`);
|
core.status.route.push(`choices:${confirm ? 1 : 0}`);
|
||||||
return confirm;
|
return confirm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -734,7 +734,7 @@ export async function routedChoices<T extends ChoiceKey>(
|
|||||||
props?: Partial<ChoicesProps>
|
props?: Partial<ChoicesProps>
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
if (core.isReplaying()) {
|
if (core.isReplaying()) {
|
||||||
const selected = getChoiceRoute(0);
|
const selected = getChoiceRoute();
|
||||||
const timeout = core.control.__replay_getTimeout();
|
const timeout = core.control.__replay_getTimeout();
|
||||||
core.status.route.push(`choices:${selected}`);
|
core.status.route.push(`choices:${selected}`);
|
||||||
if (timeout === 0) return choices[selected][0];
|
if (timeout === 0) return choices[selected][0];
|
||||||
|
@ -10,7 +10,6 @@ import { createAction } from './action';
|
|||||||
import { createLegacy } from './legacy';
|
import { createLegacy } from './legacy';
|
||||||
import { sceneController } from './scene';
|
import { sceneController } from './scene';
|
||||||
import { GameTitleUI } from './ui/title';
|
import { GameTitleUI } from './ui/title';
|
||||||
import { createWeather } from './weather';
|
|
||||||
|
|
||||||
export function createGameRenderer() {
|
export function createGameRenderer() {
|
||||||
const App = defineComponent(_props => {
|
const App = defineComponent(_props => {
|
||||||
@ -33,7 +32,6 @@ export function createRender() {
|
|||||||
createUI();
|
createUI();
|
||||||
createAction();
|
createAction();
|
||||||
createLoopMap();
|
createLoopMap();
|
||||||
createWeather();
|
|
||||||
|
|
||||||
loading.on('loaded', () => {
|
loading.on('loaded', () => {
|
||||||
sceneController.open(GameTitleUI, {});
|
sceneController.open(GameTitleUI, {});
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
Sprite,
|
Sprite,
|
||||||
onTick
|
onTick
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { WeatherController } from '../weather';
|
import { WeatherController } from '../../weather';
|
||||||
import { defineComponent, onMounted, onUnmounted, reactive, ref } from 'vue';
|
import { defineComponent, onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||||
import { Textbox, Tip } from '../components';
|
import { Textbox, Tip } from '../components';
|
||||||
import { GameUI } from '@motajs/system-ui';
|
import { GameUI } from '@motajs/system-ui';
|
||||||
@ -23,6 +23,7 @@ import {
|
|||||||
LeftStatusBar,
|
LeftStatusBar,
|
||||||
RightStatusBar
|
RightStatusBar
|
||||||
} from './statusBar';
|
} from './statusBar';
|
||||||
|
import { onLoaded } from '../use';
|
||||||
import { ReplayingStatus } from './toolbar';
|
import { ReplayingStatus } from './toolbar';
|
||||||
import { getHeroStatusOn, HeroSkill, NightSpecial } from '@user/data-state';
|
import { getHeroStatusOn, HeroSkill, NightSpecial } from '@user/data-state';
|
||||||
import { jumpIgnoreFloor } from '@user/legacy-plugin-data';
|
import { jumpIgnoreFloor } from '@user/legacy-plugin-data';
|
||||||
@ -79,12 +80,15 @@ const MainScene = defineComponent(() => {
|
|||||||
const map = ref<LayerGroup>();
|
const map = ref<LayerGroup>();
|
||||||
const hideStatus = ref(false);
|
const hideStatus = ref(false);
|
||||||
const locked = ref(false);
|
const locked = ref(false);
|
||||||
const weather = new WeatherController();
|
const weather = new WeatherController('main');
|
||||||
|
|
||||||
|
const loaded = ref(true);
|
||||||
|
onLoaded(() => {
|
||||||
|
loaded.value = true;
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (map.value) {
|
weather.bind(map.value);
|
||||||
weather.bind(map.value);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const leftStatus: ILeftHeroStatus = reactive({
|
const leftStatus: ILeftHeroStatus = reactive({
|
||||||
@ -256,11 +260,13 @@ const MainScene = defineComponent(() => {
|
|||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<container id="main-scene" width={MAIN_WIDTH} height={MAIN_HEIGHT}>
|
<container id="main-scene" width={MAIN_WIDTH} height={MAIN_HEIGHT}>
|
||||||
<LeftStatusBar
|
{loaded.value && (
|
||||||
loc={[0, 0, STATUS_BAR_WIDTH, STATUS_BAR_HEIGHT]}
|
<LeftStatusBar
|
||||||
status={leftStatus}
|
loc={[0, 0, STATUS_BAR_WIDTH, STATUS_BAR_HEIGHT]}
|
||||||
hidden={hideStatus.value}
|
status={leftStatus}
|
||||||
></LeftStatusBar>
|
hidden={hideStatus.value}
|
||||||
|
></LeftStatusBar>
|
||||||
|
)}
|
||||||
<g-line line={[180, 0, 180, 480]} lineWidth={1} />
|
<g-line line={[180, 0, 180, 480]} lineWidth={1} />
|
||||||
<container
|
<container
|
||||||
id="map-draw"
|
id="map-draw"
|
||||||
@ -296,11 +302,13 @@ const MainScene = defineComponent(() => {
|
|||||||
/>
|
/>
|
||||||
</container>
|
</container>
|
||||||
<g-line line={[180 + 480, 0, 180 + 480, 480]} lineWidth={1} />
|
<g-line line={[180 + 480, 0, 180 + 480, 480]} lineWidth={1} />
|
||||||
<RightStatusBar
|
{loaded.value && (
|
||||||
loc={[480 + 180, 0, STATUS_BAR_WIDTH, STATUS_BAR_HEIGHT]}
|
<RightStatusBar
|
||||||
status={rightStatus}
|
loc={[480 + 180, 0, STATUS_BAR_WIDTH, STATUS_BAR_HEIGHT]}
|
||||||
hidden={hideStatus.value}
|
status={rightStatus}
|
||||||
></RightStatusBar>
|
hidden={hideStatus.value}
|
||||||
|
></RightStatusBar>
|
||||||
|
)}
|
||||||
<container
|
<container
|
||||||
loc={[0, 0, MAIN_WIDTH, MAIN_HEIGHT]}
|
loc={[0, 0, MAIN_WIDTH, MAIN_HEIGHT]}
|
||||||
hidden={!mainUIController.active.value}
|
hidden={!mainUIController.active.value}
|
||||||
|
@ -1,146 +0,0 @@
|
|||||||
import { RenderItem } from '@motajs/render-core';
|
|
||||||
import { IWeather, IWeatherController, IWeatherInstance } from './types';
|
|
||||||
import { logger } from '@motajs/common';
|
|
||||||
import { isNil } from 'lodash-es';
|
|
||||||
import { Ticker } from 'mutate-animate';
|
|
||||||
|
|
||||||
type WeatherConstructor = new () => IWeather;
|
|
||||||
|
|
||||||
export class WeatherController implements IWeatherController {
|
|
||||||
/** 暴露到全局的控制器 */
|
|
||||||
static extern: Map<string, IWeatherController> = new Map();
|
|
||||||
/** 注册的天气 */
|
|
||||||
static weathers: Map<string, WeatherConstructor> = new Map();
|
|
||||||
|
|
||||||
private static ticker: Ticker = new Ticker();
|
|
||||||
|
|
||||||
/** 暴露至全局的 id */
|
|
||||||
private externId?: string;
|
|
||||||
/** 天气元素纵深 */
|
|
||||||
private zIndex: number = 100;
|
|
||||||
|
|
||||||
readonly active: Set<IWeatherInstance> = new Set();
|
|
||||||
|
|
||||||
container: RenderItem | null = null;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
WeatherController.ticker.add(this.tick);
|
|
||||||
}
|
|
||||||
|
|
||||||
private tick = (time: number) => {
|
|
||||||
this.active.forEach(v => v.weather.tick(time));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置天气元素纵深,第一个天气会被设置为 `zIndex`,之后依次是 `zIndex+1` `zIndex+2` ...
|
|
||||||
* @param zIndex 第一个天气的纵深
|
|
||||||
*/
|
|
||||||
setZIndex(zIndex: number) {
|
|
||||||
this.zIndex = zIndex;
|
|
||||||
let n = zIndex;
|
|
||||||
this.active.forEach(v => {
|
|
||||||
v.setZIndex(n);
|
|
||||||
n++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bind(container: RenderItem): void {
|
|
||||||
if (this.container) {
|
|
||||||
logger.warn(65);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.container = container;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getWeatherObject<R extends RenderItem, T extends IWeather<R>>(
|
|
||||||
weather: string | T
|
|
||||||
): T | null {
|
|
||||||
if (typeof weather === 'string') {
|
|
||||||
const Weather = WeatherController.weathers.get(weather);
|
|
||||||
if (!Weather) {
|
|
||||||
logger.warn(25, weather);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Weather() as T;
|
|
||||||
} else {
|
|
||||||
return weather;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
activate(weather: string, level?: number): IWeatherInstance | null;
|
|
||||||
activate<R extends RenderItem, T extends IWeather<R>>(
|
|
||||||
weather: T,
|
|
||||||
level?: number
|
|
||||||
): IWeatherInstance<R, T> | null;
|
|
||||||
activate<R extends RenderItem, T extends IWeather<R>>(
|
|
||||||
weather: string | T,
|
|
||||||
level: number = 5
|
|
||||||
): IWeatherInstance<R, T> | null {
|
|
||||||
const obj = this.getWeatherObject<R, T>(weather);
|
|
||||||
if (!obj) return null;
|
|
||||||
const element = obj.create(level);
|
|
||||||
const instance = new WeatherInstance(obj, element);
|
|
||||||
instance.setZIndex(this.zIndex + this.active.size);
|
|
||||||
this.active.add(instance);
|
|
||||||
this.container?.appendChild(element);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
deactivate(instance: IWeatherInstance): void {
|
|
||||||
this.container?.removeChild(instance.element);
|
|
||||||
instance.weather.destroy();
|
|
||||||
this.active.delete(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将此控制器暴露至全局,允许使用 {@link WeatherController.get} 获取到实例
|
|
||||||
* @param id 暴露给全局的 id
|
|
||||||
*/
|
|
||||||
extern(id: string) {
|
|
||||||
WeatherController.extern.set(id, this);
|
|
||||||
this.externId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.active.forEach(v => {
|
|
||||||
v.weather.destroy();
|
|
||||||
});
|
|
||||||
this.active.clear();
|
|
||||||
WeatherController.ticker.remove(this.tick);
|
|
||||||
if (!isNil(this.externId)) {
|
|
||||||
WeatherController.extern.delete(this.externId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取暴露至全局的控制器
|
|
||||||
* @param id 控制器暴露至全局的 id
|
|
||||||
*/
|
|
||||||
static get(id: string): IWeatherController | null {
|
|
||||||
return this.extern.get(id) ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册一个天气
|
|
||||||
* @param id 天气的名称
|
|
||||||
* @param weather 天气的构造器
|
|
||||||
*/
|
|
||||||
static register(id: string, weather: WeatherConstructor) {
|
|
||||||
this.weathers.set(id, weather);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WeatherInstance<
|
|
||||||
R extends RenderItem = RenderItem,
|
|
||||||
T extends IWeather<R> = IWeather<R>
|
|
||||||
> implements IWeatherInstance<R, T>
|
|
||||||
{
|
|
||||||
constructor(
|
|
||||||
readonly weather: T,
|
|
||||||
readonly element: R
|
|
||||||
) {}
|
|
||||||
|
|
||||||
setZIndex(zIndex: number): void {
|
|
||||||
this.element.setZIndex(zIndex);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import { WeatherController } from './controller';
|
|
||||||
import { CloudWeather, RainWeather, SnowWeather, SunWeather } from './presets';
|
|
||||||
|
|
||||||
export function createWeather() {
|
|
||||||
WeatherController.register('cloud', CloudWeather);
|
|
||||||
WeatherController.register('rain', RainWeather);
|
|
||||||
WeatherController.register('snow', SnowWeather);
|
|
||||||
WeatherController.register('sun', SunWeather);
|
|
||||||
}
|
|
||||||
|
|
||||||
export * from './presets';
|
|
||||||
export * from './controller';
|
|
||||||
export * from './types';
|
|
||||||
export * from './weather';
|
|
@ -1,16 +0,0 @@
|
|||||||
import { Sprite } from '@motajs/render-core';
|
|
||||||
import { Weather } from '../weather';
|
|
||||||
|
|
||||||
export class CloudWeather extends Weather<Sprite> {
|
|
||||||
tick(timestamp: number): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
createElement(level: number): Sprite {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy(): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
export * from './cloud';
|
|
||||||
export * from './rain';
|
|
||||||
export * from './snow';
|
|
||||||
export * from './sun';
|
|
@ -1,16 +0,0 @@
|
|||||||
import { EShaderEvent, Shader } from '@motajs/render-core';
|
|
||||||
import { Weather } from '../weather';
|
|
||||||
|
|
||||||
export class SnowWeather extends Weather<Shader> {
|
|
||||||
tick(timestamp: number): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
createElement(level: number): Shader<EShaderEvent> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy(): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { Sprite } from '@motajs/render-core';
|
|
||||||
import { Weather } from '../weather';
|
|
||||||
|
|
||||||
export class SunWeather extends Weather<Sprite> {
|
|
||||||
tick(timestamp: number): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
createElement(level: number): Sprite {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy(): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
import { RenderItem } from '@motajs/render-core';
|
|
||||||
|
|
||||||
export interface IWeather<T extends RenderItem = RenderItem> {
|
|
||||||
/** 天气的等级,-1 表示未创建 */
|
|
||||||
readonly level: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建天气
|
|
||||||
* @param level 天气等级
|
|
||||||
* @returns 天气的渲染元素
|
|
||||||
*/
|
|
||||||
create(level: number): T;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 摧毁这个天气
|
|
||||||
*/
|
|
||||||
destroy(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 每帧执行一次的函数
|
|
||||||
* @param timestamp 当前时间戳
|
|
||||||
*/
|
|
||||||
tick(timestamp: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IWeatherInstance<
|
|
||||||
R extends RenderItem = RenderItem,
|
|
||||||
T extends IWeather<R> = IWeather<R>
|
|
||||||
> {
|
|
||||||
/** 天气对象 */
|
|
||||||
readonly weather: T;
|
|
||||||
/** 天气的渲染元素 */
|
|
||||||
readonly element: R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置这个天气的纵深
|
|
||||||
* @param zIndex 纵深
|
|
||||||
*/
|
|
||||||
setZIndex(zIndex: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IWeatherController {
|
|
||||||
/** 天气控制器绑定到的渲染元素 */
|
|
||||||
readonly container: RenderItem | null;
|
|
||||||
/** 所有已激活的天气 */
|
|
||||||
readonly active: Set<IWeatherInstance>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 绑定控制器到渲染元素
|
|
||||||
* @param container 绑定的渲染元素,需要能够添加子元素,一般绑定到 `container`
|
|
||||||
*/
|
|
||||||
bind(container: RenderItem): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用天气名称添加天气
|
|
||||||
* @param weather 天气的名称
|
|
||||||
* @param level 天气的等级
|
|
||||||
* @returns 天气实例
|
|
||||||
*/
|
|
||||||
activate(weather: string, level?: number): IWeatherInstance | null;
|
|
||||||
/**
|
|
||||||
* 使用天气对象添加天气
|
|
||||||
* @param weather 天气对象
|
|
||||||
* @param level 天气的等级
|
|
||||||
* @returns 天气实例
|
|
||||||
*/
|
|
||||||
activate<R extends RenderItem, T extends IWeather<R>>(
|
|
||||||
weather: T,
|
|
||||||
level?: number
|
|
||||||
): IWeatherInstance<R, T> | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消天气
|
|
||||||
* @param instance 天气实例
|
|
||||||
*/
|
|
||||||
deactivate(instance: IWeatherInstance): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 摧毁这个控制器
|
|
||||||
*/
|
|
||||||
destroy(): void;
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
import { RenderItem } from '@motajs/render-core';
|
|
||||||
import { IWeather } from './types';
|
|
||||||
|
|
||||||
export abstract class Weather<T extends RenderItem> implements IWeather<T> {
|
|
||||||
level: number = -1;
|
|
||||||
|
|
||||||
protected element: T | null = null;
|
|
||||||
|
|
||||||
create(level: number): T {
|
|
||||||
const element = this.createElement(level);
|
|
||||||
this.element = element;
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy(): void {
|
|
||||||
this.element?.destroy();
|
|
||||||
this.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract tick(timestamp: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建天气的渲染元素,并进行初始化
|
|
||||||
* @param level 天气的等级
|
|
||||||
*/
|
|
||||||
abstract createElement(level: number): T;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当天气被摧毁时调用,进行清理工作,会自动摧毁渲染元素,不需要手动处理
|
|
||||||
*/
|
|
||||||
abstract onDestroy(): void;
|
|
||||||
}
|
|
0
packages-user/client-modules/src/weather/cloud.ts
Normal file
0
packages-user/client-modules/src/weather/cloud.ts
Normal file
11
packages-user/client-modules/src/weather/index.ts
Normal file
11
packages-user/client-modules/src/weather/index.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { RainWeather } from './rain';
|
||||||
|
import { SnowWeather } from './snow';
|
||||||
|
import { SunWeather } from './sun';
|
||||||
|
import { WeatherController } from './weather';
|
||||||
|
|
||||||
|
WeatherController.register('rain', RainWeather);
|
||||||
|
WeatherController.register('sun', SunWeather);
|
||||||
|
WeatherController.register('snow', SnowWeather);
|
||||||
|
|
||||||
|
export * from './weather';
|
||||||
|
export * from './rain';
|
@ -1,10 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
Shader,
|
Shader,
|
||||||
ShaderProgram,
|
ShaderProgram,
|
||||||
|
MotaRenderer,
|
||||||
|
Container,
|
||||||
IShaderUniform,
|
IShaderUniform,
|
||||||
UniformType
|
UniformType
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { Weather } from '../weather';
|
import { IWeather } from './weather';
|
||||||
|
|
||||||
const rainVs = /* glsl */ `
|
const rainVs = /* glsl */ `
|
||||||
in vec2 a_rainVertex;
|
in vec2 a_rainVertex;
|
||||||
@ -80,25 +82,95 @@ 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]);
|
||||||
|
|
||||||
export class RainWeather extends Weather<Shader> {
|
export class RainWeather implements IWeather {
|
||||||
/** 下雨流程的 uniform 变量 */
|
readonly shader: RainShader;
|
||||||
private progress: IShaderUniform<UniformType.Uniform1f> | null = null;
|
readonly program: ShaderProgram;
|
||||||
/** 使用的着色器程序 */
|
|
||||||
private program: ShaderProgram | null = null;
|
|
||||||
|
|
||||||
|
private progress: IShaderUniform<UniformType.Uniform1f> | null = null;
|
||||||
|
|
||||||
|
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 = this.shader;
|
||||||
|
shader.appendTo(draw);
|
||||||
|
|
||||||
|
const gl = shader.gl;
|
||||||
|
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),
|
||||||
|
program
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame(): void {
|
||||||
|
this.shader.update(this.shader);
|
||||||
|
const time = 5000 - 400 * this.level;
|
||||||
|
const progress = (Date.now() % time) / time;
|
||||||
|
|
||||||
|
this.shader.useProgram(this.program);
|
||||||
|
this.progress?.set(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
deactivate(): void {
|
||||||
|
const render = MotaRenderer.get('render-main');
|
||||||
|
const draw = render?.getElementById('map-draw') as Container;
|
||||||
|
const layer = draw.children;
|
||||||
|
if (!layer || !draw) return;
|
||||||
|
const shader = this.shader;
|
||||||
|
draw.appendChild(...layer);
|
||||||
|
shader.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RainShader extends Shader {
|
||||||
/**
|
/**
|
||||||
* 生成雨滴
|
* 生成雨滴
|
||||||
* @param num 雨滴数量
|
* @param num 雨滴数量
|
||||||
*/
|
*/
|
||||||
generateRainPath(level: number, program: ShaderProgram, shader: Shader) {
|
generateRainPath(
|
||||||
const num = level * 100;
|
num: number,
|
||||||
const angle = (((Math.random() - 0.5) * Math.PI) / 30) * level;
|
angle: number,
|
||||||
const deviation = (Math.PI / 180) * (12 - level);
|
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');
|
||||||
const gl = shader.gl;
|
const gl = this.gl;
|
||||||
if (!aOffset || !aData) return;
|
if (!aOffset || !aData) return;
|
||||||
|
|
||||||
const tan = Math.tan(angle);
|
const tan = Math.tan(angle);
|
||||||
@ -137,50 +209,4 @@ export class RainWeather extends Weather<Shader> {
|
|||||||
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, num);
|
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, num);
|
||||||
color?.set(1, 1, 1, 0.1);
|
color?.set(1, 1, 1, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
createElement(level: number): Shader {
|
|
||||||
const shader = new Shader();
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, 100 * this.level);
|
|
||||||
|
|
||||||
this.progress = program.getUniform<UniformType.Uniform1f>('u_progress');
|
|
||||||
this.generateRainPath(level, program, shader);
|
|
||||||
|
|
||||||
this.program = program;
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
tick(timestamp: number): void {
|
|
||||||
if (!this.element) return;
|
|
||||||
this.element.update();
|
|
||||||
const time = 5000 - 400 * this.level;
|
|
||||||
const progress = (timestamp % time) / time;
|
|
||||||
this.progress?.set(progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy(): void {
|
|
||||||
if (!this.element || !this.program) return;
|
|
||||||
this.element.deleteProgram(this.program);
|
|
||||||
}
|
|
||||||
}
|
}
|
251
packages-user/client-modules/src/weather/snow.ts
Normal file
251
packages-user/client-modules/src/weather/snow.ts
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
import {
|
||||||
|
Shader,
|
||||||
|
ShaderProgram,
|
||||||
|
MotaRenderer,
|
||||||
|
Container,
|
||||||
|
GL2Program,
|
||||||
|
IShaderUniform,
|
||||||
|
UniformType,
|
||||||
|
Transform,
|
||||||
|
MotaOffscreenCanvas2D
|
||||||
|
} from '@motajs/render';
|
||||||
|
import { IWeather } from './weather';
|
||||||
|
import { loading } from '@user/data-base';
|
||||||
|
|
||||||
|
const snowVs = /* glsl */ `
|
||||||
|
in vec2 a_snowVertex;
|
||||||
|
in vec2 a_offset; // 雨滴的中心位置
|
||||||
|
in vec4 a_data; // x: 雨滴宽度; y: 雨滴长度; z: 雨滴旋转角度,0表示向下,逆时针为正;
|
||||||
|
// w: 属于哪一种雨,需要两种雨反复循环,一种无法实现循环,0表示第一种,1表示第二种
|
||||||
|
|
||||||
|
uniform float u_progress; // 下雨进度,从最上落到最下是0.5个进度,以保证不会出现奇怪的问题
|
||||||
|
|
||||||
|
out vec2 v_center;
|
||||||
|
out vec2 v_data; // 雨滴宽度与高度
|
||||||
|
out vec2 v_pos;
|
||||||
|
|
||||||
|
mat2 createScaleMatrix(float x, float y) {
|
||||||
|
return mat2(
|
||||||
|
x, 0,
|
||||||
|
0, y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getOffsetByProgress(vec2 offset) {
|
||||||
|
if (a_data.w == 0.0) {
|
||||||
|
if (u_progress < 0.5) {
|
||||||
|
return offset * u_progress * 2.0;
|
||||||
|
} else {
|
||||||
|
return offset * (u_progress - 1.0) * 2.0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return offset * u_progress * 2.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float cosTheta = cos(a_data.z);
|
||||||
|
float sinTheta = sin(a_data.z);
|
||||||
|
mat2 rotate = mat2(
|
||||||
|
cosTheta, -sinTheta,
|
||||||
|
sinTheta, cosTheta
|
||||||
|
);
|
||||||
|
vec2 offset = getOffsetByProgress(vec2(-sinTheta * 2.0, -cosTheta * 2.0));
|
||||||
|
mat2 scale = createScaleMatrix(a_data.x, a_data.y);
|
||||||
|
vec2 off = a_offset + offset;
|
||||||
|
|
||||||
|
// const int segments = 32; // 圆的分段数
|
||||||
|
// float angleIncrement = 2.0 * 3.14159265359 / float(segments);
|
||||||
|
// vec2 a_roundVertex[segments];
|
||||||
|
// for (int i = 0; i < segments; i++) {
|
||||||
|
// float angle = float(i) * angleIncrement;
|
||||||
|
// a_roundVertex[i] = vec2(cos(angle), sin(angle)); // 生成单位圆的顶点
|
||||||
|
// }
|
||||||
|
|
||||||
|
// vec2 pos = rotate * scale * a_roundVertex + off;
|
||||||
|
vec2 pos = rotate * scale * a_snowVertex + off;
|
||||||
|
v_center = off;
|
||||||
|
v_pos = pos;
|
||||||
|
gl_Position = vec4(pos, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const snowFs = /* glsl */ `
|
||||||
|
in vec2 v_center;
|
||||||
|
in vec2 v_data; // 雨滴的宽度与长度
|
||||||
|
in vec2 v_pos;
|
||||||
|
|
||||||
|
uniform vec4 u_color; // 雨滴的颜色
|
||||||
|
|
||||||
|
out vec4 outColor;
|
||||||
|
|
||||||
|
float random(vec2 uv) {
|
||||||
|
return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
float distanceFromCenter = length(v_pos - v_center);
|
||||||
|
if (distanceFromCenter < 0.05) {
|
||||||
|
outColor = u_color; // 雪花颜色
|
||||||
|
} else {
|
||||||
|
// outColor = vec4(0.0, 0.0, 0.0, 0.2);
|
||||||
|
discard; // 不绘制超出圆的部分
|
||||||
|
}
|
||||||
|
|
||||||
|
// float ran = random(v_pos);
|
||||||
|
// vec2 pos = vec2(v_pos.x + ran * 0.01, v_pos.y);
|
||||||
|
// vec2 texPos = (pos + 1.0) / 2.0;
|
||||||
|
// texPos.y = 1.0 - texPos.y;
|
||||||
|
// vec4 tex = texture(u_sampler, texPos);
|
||||||
|
// // outColor = mix(u_color, tex, 0.9);
|
||||||
|
// outColor = u_color;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/** 雨滴顶点坐标 */
|
||||||
|
const vertex = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
|
||||||
|
|
||||||
|
loading.once('coreInit', () => {
|
||||||
|
const shader = new SnowShader();
|
||||||
|
const gl = shader.gl;
|
||||||
|
shader.size(480, 480);
|
||||||
|
shader.setHD(true);
|
||||||
|
SnowWeather.shader = shader;
|
||||||
|
const program = shader.createProgram(ShaderProgram);
|
||||||
|
program.fs(snowFs);
|
||||||
|
program.vs(snowVs);
|
||||||
|
program.requestCompile();
|
||||||
|
const pos = program.defineAttribArray('a_snowVertex');
|
||||||
|
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);
|
||||||
|
SnowShader.snowProgram = program;
|
||||||
|
shader.useProgram(program);
|
||||||
|
|
||||||
|
if (pos) {
|
||||||
|
pos.buffer(vertex, gl.STATIC_DRAW);
|
||||||
|
pos.pointer(2, gl.FLOAT, false, 0, 0);
|
||||||
|
pos.enable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export class SnowWeather implements IWeather {
|
||||||
|
static id: string = 'snow';
|
||||||
|
|
||||||
|
static shader: SnowShader;
|
||||||
|
|
||||||
|
private progress: IShaderUniform<UniformType.Uniform1f> | null = null;
|
||||||
|
|
||||||
|
constructor(readonly level: number = 5) {}
|
||||||
|
|
||||||
|
activate(): void {
|
||||||
|
const render = MotaRenderer.get('render-main');
|
||||||
|
const draw = render?.getElementById('map-draw') as Container;
|
||||||
|
if (!draw) return;
|
||||||
|
const shader = SnowWeather.shader;
|
||||||
|
shader.appendTo(draw);
|
||||||
|
|
||||||
|
const gl = shader.gl;
|
||||||
|
const program = SnowShader.snowProgram;
|
||||||
|
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, 100 * this.level);
|
||||||
|
|
||||||
|
this.progress = program.getUniform<UniformType.Uniform1f>('u_progress');
|
||||||
|
shader.generateSnowPath(
|
||||||
|
this.level * 100,
|
||||||
|
(((Math.random() - 0.5) * Math.PI) / 30) * this.level,
|
||||||
|
(Math.PI / 180) * (12 - this.level)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame(): void {
|
||||||
|
SnowWeather.shader.update(SnowWeather.shader);
|
||||||
|
const time = 5000 - 400 * this.level;
|
||||||
|
const progress = (Date.now() % time) / time;
|
||||||
|
|
||||||
|
SnowWeather.shader.useProgram(SnowShader.snowProgram);
|
||||||
|
this.progress?.set(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
deactivate(): void {
|
||||||
|
const render = MotaRenderer.get('render-main');
|
||||||
|
const layer = render?.getElementById('layer-main');
|
||||||
|
const draw = render?.getElementById('map-draw') as Container;
|
||||||
|
if (!layer || !draw) return;
|
||||||
|
const shader = SnowWeather.shader;
|
||||||
|
layer.appendTo(draw);
|
||||||
|
shader.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SnowShader extends Shader {
|
||||||
|
static snowProgram: ShaderProgram;
|
||||||
|
static backProgram: ShaderProgram;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成雨滴
|
||||||
|
* @param num 雨滴数量
|
||||||
|
*/
|
||||||
|
generateSnowPath(num: number, angle: number, deviation: number) {
|
||||||
|
const program = SnowShader.snowProgram;
|
||||||
|
SnowWeather.shader.useProgram(program);
|
||||||
|
const aOffset = program.getAttribArray('a_offset');
|
||||||
|
const aData = program.getAttribArray('a_data');
|
||||||
|
const color = program.getUniform<UniformType.Uniform4f>('u_color');
|
||||||
|
const gl = this.gl;
|
||||||
|
if (!aOffset || !aData) return;
|
||||||
|
|
||||||
|
const tan = Math.tan(angle);
|
||||||
|
|
||||||
|
const offset = new Float32Array(num * 2);
|
||||||
|
const data = new Float32Array(num * 4);
|
||||||
|
const half = num / 2;
|
||||||
|
for (let i = 0; i < half; i++) {
|
||||||
|
const ox = Math.random() * 3 - 1.5;
|
||||||
|
const oy = Math.random() * 2 - 1;
|
||||||
|
const rad = angle + (Math.random() - 0.5) * Math.PI * deviation;
|
||||||
|
const length = Math.random() * 0.05 + 0.03;
|
||||||
|
const width = Math.random() * 0.05 + 0.03;
|
||||||
|
offset.set([ox, oy], i * 2);
|
||||||
|
data.set([width, length, rad, 0], i * 4);
|
||||||
|
}
|
||||||
|
for (let i = half; i < num; i++) {
|
||||||
|
const ox = Math.random() * 3 - 1.5 + tan * 2;
|
||||||
|
const oy = Math.random() * 2 + 1;
|
||||||
|
const rad = angle + (Math.random() - 0.5) * Math.PI * deviation;
|
||||||
|
const length = Math.random() * 0.1 + 0.05;
|
||||||
|
const width = Math.random() * 0.1 + 0.05;
|
||||||
|
offset.set([ox, oy], i * 2);
|
||||||
|
data.set([width, length, rad, 1], i * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
aOffset.buffer(offset, gl.STATIC_DRAW);
|
||||||
|
aData.buffer(data, gl.STATIC_DRAW);
|
||||||
|
aOffset.pointer(2, gl.FLOAT, false, 0, 0);
|
||||||
|
aOffset.divisor(1);
|
||||||
|
aOffset.enable();
|
||||||
|
aData.pointer(4, gl.FLOAT, false, 0, 0);
|
||||||
|
aData.divisor(1);
|
||||||
|
aData.enable();
|
||||||
|
|
||||||
|
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, num);
|
||||||
|
color?.set(1, 1, 1, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected preDraw(
|
||||||
|
canvas: MotaOffscreenCanvas2D,
|
||||||
|
transform: Transform,
|
||||||
|
gl: WebGL2RenderingContext,
|
||||||
|
program: GL2Program
|
||||||
|
): boolean {
|
||||||
|
const snow = SnowShader.snowProgram;
|
||||||
|
const snowParam = snow.getDrawParams(this.DRAW_ARRAYS_INSTANCED);
|
||||||
|
if (!snowParam) return false;
|
||||||
|
this.useProgram(snow);
|
||||||
|
if (!snow.ready()) return false;
|
||||||
|
this.draw(gl, snow);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
11
packages-user/client-modules/src/weather/sun.ts
Normal file
11
packages-user/client-modules/src/weather/sun.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { IWeather } from './weather';
|
||||||
|
|
||||||
|
export class SunWeather implements IWeather {
|
||||||
|
static id: string = 'sun';
|
||||||
|
|
||||||
|
activate(): void {}
|
||||||
|
|
||||||
|
frame(): void {}
|
||||||
|
|
||||||
|
deactivate(): void {}
|
||||||
|
}
|
130
packages-user/client-modules/src/weather/weather.ts
Normal file
130
packages-user/client-modules/src/weather/weather.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import { logger } from '@motajs/common';
|
||||||
|
import { RenderItem } from '@motajs/render';
|
||||||
|
import { Ticker } from 'mutate-animate';
|
||||||
|
|
||||||
|
export interface IWeather {
|
||||||
|
/**
|
||||||
|
* 初始化天气,当天气被添加时会被立刻调用
|
||||||
|
*/
|
||||||
|
activate(item: RenderItem): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每帧执行的函数
|
||||||
|
*/
|
||||||
|
frame(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 摧毁这个天气,当天气被删除时会执行
|
||||||
|
*/
|
||||||
|
deactivate(item: RenderItem): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空所有天气
|
||||||
|
*/
|
||||||
|
clearWeather() {
|
||||||
|
if (this.binded) {
|
||||||
|
this.active.forEach(v => {
|
||||||
|
v.deactivate(this.binded!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.active.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取一个天气
|
||||||
|
* @param weather 要获取的天气
|
||||||
|
*/
|
||||||
|
getWeather<T extends IWeather = IWeather>(weather: Weather): T | null {
|
||||||
|
return ([...this.active].find(v => v instanceof weather) as T) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个天气,如果天气不存在则抛出警告。注意虽然原则上不允许天气重复。
|
||||||
|
* @param id 天气的id
|
||||||
|
* @param level 天气的等级
|
||||||
|
* @returns 天气实例,可以操作天气的效果,也可以用来删除
|
||||||
|
*/
|
||||||
|
activate(id: string, level?: number) {
|
||||||
|
const Weather = WeatherController.list.get(id);
|
||||||
|
if (!Weather) {
|
||||||
|
logger.warn(25, id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const weather = new Weather(level);
|
||||||
|
this.active.add(weather);
|
||||||
|
if (this.binded) {
|
||||||
|
weather.activate(this.binded);
|
||||||
|
}
|
||||||
|
if (!this.ticker.funcs.has(this.tick)) {
|
||||||
|
this.ticker.add(this.tick);
|
||||||
|
}
|
||||||
|
return weather;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除一个天气
|
||||||
|
* @param weather 要删除的天气
|
||||||
|
*/
|
||||||
|
deactivate(weather: IWeather) {
|
||||||
|
this.active.delete(weather);
|
||||||
|
if (this.active.size === 0) {
|
||||||
|
this.ticker.remove(this.tick);
|
||||||
|
}
|
||||||
|
if (this.binded) {
|
||||||
|
weather.deactivate(this.binded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将这个天气控制器绑定至一个渲染元素上
|
||||||
|
* @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);
|
||||||
|
this.clearWeather();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get(id: string) {
|
||||||
|
return this.map.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static register(id: string, weather: Weather) {
|
||||||
|
this.list.set(id, weather);
|
||||||
|
}
|
||||||
|
}
|
@ -56,7 +56,7 @@
|
|||||||
"22": "There is already an active camera for delivered render item. Consider using 'Camera.for' or disable the active camera to avoid some exceptions.",
|
"22": "There is already an active camera for delivered render item. Consider using 'Camera.for' or disable the active camera to avoid some exceptions.",
|
||||||
"23": "Render item with id of '$1' has already exists. Please avoid repeat id since it may cause issues when use 'getElementById'.",
|
"23": "Render item with id of '$1' has already exists. Please avoid repeat id since it may cause issues when use 'getElementById'.",
|
||||||
"24": "Uniform block can only be used in glsl version es 300.",
|
"24": "Uniform block can only be used in glsl version es 300.",
|
||||||
"25": "Cannot activate weather since there's no weather named '$1'.",
|
"25": "Cannot activate weather since there's no weather with id of '$1'.",
|
||||||
"26": "Cannot set attribute when only element number specified. Use 'pointer' or 'pointerI' instead.",
|
"26": "Cannot set attribute when only element number specified. Use 'pointer' or 'pointerI' instead.",
|
||||||
"27": "Cannot vertex attribute integer point when specified as float. Use 'set' or 'pointer' instead.",
|
"27": "Cannot vertex attribute integer point when specified as float. Use 'set' or 'pointer' instead.",
|
||||||
"28": "Redefinition of shader $1: '$2'",
|
"28": "Redefinition of shader $1: '$2'",
|
||||||
@ -96,7 +96,6 @@
|
|||||||
"62": "Recursive fallback fonts in '$1'.",
|
"62": "Recursive fallback fonts in '$1'.",
|
||||||
"63": "Uncaught promise error in waiting box component. Error reason: $1",
|
"63": "Uncaught promise error in waiting box component. Error reason: $1",
|
||||||
"64": "Text node type and block type mismatch: '$1' vs '$2'",
|
"64": "Text node type and block type mismatch: '$1' vs '$2'",
|
||||||
"65": "Cannot bind a weather controller twice.",
|
|
||||||
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency.",
|
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency.",
|
||||||
"1101": "Cannot add new effect to point effect instance, for there's no more reserve space for it. Please increase the max count of the instance."
|
"1101": "Cannot add new effect to point effect instance, for there's no more reserve space for it. Please increase the max count of the instance."
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ main.floors.MT16=
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": "function(){\ncore.status.maps.MT14.canFlyFrom = false;\nMota.require('@user/legacy-plugin-data').chaseInit1();\n}"
|
"function": "function(){\ncore.status.maps.MT14.canFlyFrom = false;\nMota.require('chase_g').chaseInit1();\n}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "show",
|
"type": "show",
|
||||||
|
Loading…
Reference in New Issue
Block a user