feat: 晴天天气

This commit is contained in:
unanmed 2025-09-16 17:50:44 +08:00
parent 0fc77f5007
commit 1b8624041b
8 changed files with 81 additions and 36 deletions

View File

@ -56,5 +56,6 @@ export * from './ui';
export * from './utils'; export * from './utils';
export * from './weather'; export * from './weather';
export * from './renderer'; export * from './renderer';
export * from './scene';
export * from './shared'; export * from './shared';
export * from './use'; export * from './use';

View File

@ -1,11 +1,11 @@
import { WeatherController } from './controller'; import { WeatherController } from './controller';
import { CloudWeather, RainWeather } from './presets'; import { CloudWeather, RainWeather, SunWeather } from './presets';
export function createWeather() { export function createWeather() {
WeatherController.register('cloud', CloudWeather); WeatherController.register('cloud', CloudWeather);
WeatherController.register('rain', RainWeather); WeatherController.register('rain', RainWeather);
WeatherController.register('sun', SunWeather);
// WeatherController.register('snow', SnowWeather); // WeatherController.register('snow', SnowWeather);
// WeatherController.register('sun', SunWeather);
} }
export * from './presets'; export * from './presets';

View File

@ -17,7 +17,7 @@ export class CloudWeather extends Weather<Sprite> {
/** 云层图像 */ /** 云层图像 */
private image: HTMLImageElement | null = null; private image: HTMLImageElement | null = null;
/** 上一次执行速度变换的时刻 */ /** 上一次执行速度变换的时刻 */
private lastDvTime = 0; private lastTick = 0;
private drawCloud(canvas: MotaOffscreenCanvas2D) { private drawCloud(canvas: MotaOffscreenCanvas2D) {
const ctx = canvas.ctx; const ctx = canvas.ctx;
@ -38,31 +38,33 @@ export class CloudWeather extends Weather<Sprite> {
tick(time: number): void { tick(time: number): void {
if (!this.element || !this.image) return; if (!this.element || !this.image) return;
this.element.update(); this.element.update();
if (time - this.lastDvTime > 50) { const dt = time - this.lastTick;
this.lastDvTime = time; this.lastTick = time;
const dvx = ((Math.random() - 0.5) * this.level) / 20; if (dt > 100) return;
const dvy = ((Math.random() - 0.5) * this.level) / 20; const dvx = (Math.random() - 0.5) * this.level * 10;
if (Math.sign(dvx) === Math.sign(this.vx)) { const dvy = (Math.random() - 0.5) * this.level * 10;
const ratio = Math.sqrt( const addx = (dvx * dt) / 1000;
(this.maxSpeed - Math.abs(this.vx)) / this.maxSpeed const addy = (dvy * dt) / 1000;
); if (Math.sign(addx) === Math.sign(this.vx)) {
const value = Math.abs(dvx) * ratio; const ratio = Math.sqrt(
this.vx += value * Math.sign(dvx); (this.maxSpeed - Math.abs(this.vx)) / this.maxSpeed
} else { );
this.vx += dvx; const value = Math.abs(addx) * ratio;
} this.vx += value * Math.sign(addx);
if (Math.sign(dvy) === Math.sign(this.vy)) { } else {
const ratio = Math.sqrt( this.vx += addx;
(this.maxSpeed - Math.abs(this.vy)) / this.maxSpeed
);
const value = Math.abs(dvy) * ratio;
this.vy += value * Math.sign(dvy);
} else {
this.vy += dvy;
}
} }
this.cx += this.vx; if (Math.sign(addy) === Math.sign(this.vy)) {
this.cy += this.vy; const ratio = Math.sqrt(
(this.maxSpeed - Math.abs(this.vy)) / this.maxSpeed
);
const value = Math.abs(addy) * ratio;
this.vy += value * Math.sign(addy);
} else {
this.vy += addy;
}
this.cx += (this.vx * dt) / 1000;
this.cy += (this.vy * dt) / 1000;
this.cx %= this.image.width; this.cx %= this.image.width;
this.cy %= this.image.height; this.cy %= this.image.height;
} }
@ -70,7 +72,7 @@ export class CloudWeather extends Weather<Sprite> {
createElement(level: number): Sprite { createElement(level: number): Sprite {
const element = new Sprite('static', true); const element = new Sprite('static', true);
element.setRenderFn(canvas => this.drawCloud(canvas)); element.setRenderFn(canvas => this.drawCloud(canvas));
this.maxSpeed = Math.sqrt(level) * 5; this.maxSpeed = Math.sqrt(level) * 100;
this.vx = ((Math.random() - 0.5) * this.maxSpeed) / 2; this.vx = ((Math.random() - 0.5) * this.maxSpeed) / 2;
this.vy = ((Math.random() - 0.5) * this.maxSpeed) / 2; this.vy = ((Math.random() - 0.5) * this.maxSpeed) / 2;
this.alpha = Math.sqrt(level) / 10; this.alpha = Math.sqrt(level) / 10;

View File

@ -1,16 +1,55 @@
import { Sprite } from '@motajs/render-core'; import { MotaOffscreenCanvas2D, Sprite } from '@motajs/render-core';
import { Weather } from '../weather'; import { Weather } from '../weather';
import { clamp } from 'lodash-es';
export class SunWeather extends Weather<Sprite> { export class SunWeather extends Weather<Sprite> {
/** 阳光图片 */
private image: HTMLImageElement | null = null;
/** 阳光图片的不透明度 */
private alpha: number = 0;
/** 阳光的最大不透明度 */
private maxAlpha: number = 0;
/** 阳光的最小不透明度 */
private minAlpha: number = 0;
/** 不透明度变化率 */
private va: number = 0;
/** 上一帧的时刻 */
private lastTick: number = 0;
drawSun(canvas: MotaOffscreenCanvas2D) {
if (!this.image) return;
const ctx = canvas.ctx;
ctx.globalAlpha = this.alpha;
ctx.drawImage(this.image, 0, 0, canvas.width, canvas.height);
}
tick(timestamp: number): void { tick(timestamp: number): void {
throw new Error('Method not implemented.'); this.element?.update();
const dt = timestamp - this.lastTick;
this.lastTick = timestamp;
if (dt > 100) return;
const aa = (Math.random() - 0.5) * this.level;
this.va += (aa * dt) / 1000;
this.va = clamp(this.va, 0.1);
this.alpha += (this.va * dt) / 1000;
if (this.alpha < this.minAlpha) {
this.va = Math.abs(this.va);
this.alpha = this.minAlpha;
} else if (this.alpha > this.maxAlpha) {
this.va = -Math.abs(this.va);
this.alpha = this.maxAlpha;
}
} }
createElement(level: number): Sprite { createElement(level: number): Sprite {
throw new Error('Method not implemented.'); const element = new Sprite('static', true);
element.setRenderFn(canvas => this.drawSun(canvas));
this.maxAlpha = level / 10;
this.minAlpha = level / 20;
this.alpha = (this.maxAlpha + this.minAlpha) / 2;
this.image = core.material.images.images['sun.png'];
return element;
} }
onDestroy(): void { onDestroy(): void {}
throw new Error('Method not implemented.');
}
} }

View File

@ -108,6 +108,7 @@ export class ImageResource extends Resource<HTMLImageElement> {
img.src = this.resolveURI(); img.src = this.resolveURI();
this.resource = img; this.resource = img;
return new Promise<HTMLImageElement>(res => { return new Promise<HTMLImageElement>(res => {
img.loading = 'eager';
img.addEventListener('load', () => { img.addEventListener('load', () => {
this.loaded = true; this.loaded = true;
img.setAttribute('_width', img.width.toString()); img.setAttribute('_width', img.width.toString());
@ -575,7 +576,7 @@ export function loadDefaultResource() {
] = res.resource; ] = res.resource;
}); });
}); });
const weathers: (keyof Weather)[] = ['fog', 'sun']; const weathers: (keyof Weather)[] = ['fog'];
weathers.forEach(v => { weathers.forEach(v => {
const res = LoadTask.add('material', `material/${v}.png`); const res = LoadTask.add('material', `material/${v}.png`);
res.once('load', res => { res.once('load', res => {
@ -618,7 +619,7 @@ export async function loadCompressedResource() {
HTMLImageElement HTMLImageElement
>[]; >[];
materialImages.push('keyboard'); materialImages.push('keyboard');
const weathers: (keyof Weather)[] = ['fog', 'sun']; const weathers: (keyof Weather)[] = ['fog'];
Object.entries(list).forEach(v => { Object.entries(list).forEach(v => {
const [uri, list] = v; const [uri, list] = v;

View File

@ -150,6 +150,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"skill7.png", "skill7.png",
"skill8.png", "skill8.png",
"skill9.png", "skill9.png",
"sun.png",
"tower7.webp", "tower7.webp",
"winskin.png", "winskin.png",
"winskin2.png", "winskin2.png",

View File

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

@ -138,6 +138,7 @@ type ImageIds =
| 'skill7.png' | 'skill7.png'
| 'skill8.png' | 'skill8.png'
| 'skill9.png' | 'skill9.png'
| 'sun.png'
| 'tower7.webp' | 'tower7.webp'
| 'winskin.png' | 'winskin.png'
| 'winskin2.png' | 'winskin2.png'