new animation, refactor, fixes
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { UpdateController } from "@24tools/playable_template";
|
||||
import { Color, Material, Mesh, Object3D, Vector3 } from "three";
|
||||
import { ResourceScreenFly } from "../Resources/ResourceScreenFly";
|
||||
import {
|
||||
@@ -9,10 +10,19 @@ import {
|
||||
const FILL_TARGET = 10;
|
||||
const FILL_COLOR = new Color(0x2db83a);
|
||||
|
||||
/** Амплітуда «поглинаючого» імпульсу (частка від базового масштабу). 0.05 = 5%. */
|
||||
const PULSE_AMPLITUDE = 0.05;
|
||||
/** Тривалість одного імпульсу, сек: базовий розмір → пік → базовий. */
|
||||
const PULSE_DURATION = 0.18;
|
||||
/** Значення таймера, коли імпульс неактивний. */
|
||||
const PULSE_IDLE = Infinity;
|
||||
|
||||
export class InteractiveZoneC {
|
||||
private static zoneRoot: Object3D | null = null;
|
||||
private static deposited = 0;
|
||||
private static baseColors = new WeakMap<Material, Color>();
|
||||
private static baseScale = new Vector3(1, 1, 1);
|
||||
private static pulseTime = PULSE_IDLE;
|
||||
|
||||
static init(mapObject: Object3D) {
|
||||
const zone = findInteractiveZoneFromMap(mapObject);
|
||||
@@ -22,7 +32,41 @@ export class InteractiveZoneC {
|
||||
}
|
||||
|
||||
this.zoneRoot = zone;
|
||||
this.baseScale.copy(zone.scale);
|
||||
this.setupMaterials(zone);
|
||||
|
||||
UpdateController.Instance.onUpdate.addDelegate((delta: number) => {
|
||||
this.updatePulse(delta);
|
||||
});
|
||||
}
|
||||
|
||||
/** Один «поглинаючий» імпульс зони — викликати на приліт кожного ресурсу. */
|
||||
static pulse() {
|
||||
this.pulseTime = 0;
|
||||
}
|
||||
|
||||
/** Повертає зону до базового розміру і гасить імпульс (teardown/зупинка). */
|
||||
static resetPulse() {
|
||||
this.pulseTime = PULSE_IDLE;
|
||||
if (this.zoneRoot) this.zoneRoot.scale.copy(this.baseScale);
|
||||
}
|
||||
|
||||
private static updatePulse(delta: number) {
|
||||
if (!this.zoneRoot || this.pulseTime === PULSE_IDLE) return;
|
||||
|
||||
this.pulseTime += delta;
|
||||
if (this.pulseTime >= PULSE_DURATION) {
|
||||
this.resetPulse();
|
||||
return;
|
||||
}
|
||||
|
||||
const env = Math.sin(Math.PI * (this.pulseTime / PULSE_DURATION));
|
||||
const k = 1 + PULSE_AMPLITUDE * env;
|
||||
this.zoneRoot.scale.set(
|
||||
this.baseScale.x * k,
|
||||
this.baseScale.y * k,
|
||||
this.baseScale.z * k,
|
||||
);
|
||||
}
|
||||
|
||||
static getWorldCenter(out = new Vector3()) {
|
||||
@@ -39,6 +83,27 @@ export class InteractiveZoneC {
|
||||
this.refreshFillVisual();
|
||||
}
|
||||
|
||||
/** Звільняє клоновані матеріали зони (виклик на teardown playable). */
|
||||
static dispose() {
|
||||
if (!this.zoneRoot) return;
|
||||
|
||||
this.resetPulse();
|
||||
|
||||
this.zoneRoot.traverse((child) => {
|
||||
const mesh = child as Mesh;
|
||||
if (!mesh.isMesh) return;
|
||||
|
||||
const material = mesh.material;
|
||||
if (Array.isArray(material)) {
|
||||
material.forEach((entry) => entry.dispose());
|
||||
} else if (material) {
|
||||
material.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
this.baseColors = new WeakMap<Material, Color>();
|
||||
}
|
||||
|
||||
static getFillRatio() {
|
||||
return Math.min(this.deposited / FILL_TARGET, 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user