Release v0.1.12 2026-07-13
This commit is contained in:
+288
-47
@@ -25,6 +25,8 @@ import {
|
||||
type ActorAnimationState,
|
||||
} from "../game/actorAnimation";
|
||||
import { PERFORMANCE_PROBE_ENABLED, recordSimulationTick, simulationTickSnapshot } from "../game/performance";
|
||||
import type { PartyAbilityId } from "../game/partyCombat";
|
||||
import { partyAttackVfxProfile } from "../game/partyAttackVisuals";
|
||||
import { useGameStore } from "../game/store";
|
||||
import type { BossId, MemberId, PulseKind } from "../game/types";
|
||||
import { BossRoom } from "./BossRoom";
|
||||
@@ -999,7 +1001,15 @@ function TankAuraField() {
|
||||
}
|
||||
|
||||
function RangedProjectile({ memberId }: { memberId: "nia" | "orin" }) {
|
||||
const group = useRef<THREE.Group>(null);
|
||||
const projectile = useRef<THREE.Group>(null);
|
||||
const impact = useRef<THREE.Group>(null);
|
||||
const coreMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const accentMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const trailMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const trail = useRef<THREE.Mesh>(null);
|
||||
const impactMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const impactCoreMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const lastAbilityId = useRef<PartyAbilityId | null>(null);
|
||||
const start = useMemo(() => new THREE.Vector3(), []);
|
||||
const end = useMemo(() => new THREE.Vector3(), []);
|
||||
const current = useMemo(() => new THREE.Vector3(), []);
|
||||
@@ -1007,7 +1017,7 @@ function RangedProjectile({ memberId }: { memberId: "nia" | "orin" }) {
|
||||
const up = useMemo(() => new THREE.Vector3(0, 1, 0), []);
|
||||
|
||||
useFrame(({ clock }) => {
|
||||
if (!group.current) return;
|
||||
if (!projectile.current || !impact.current) return;
|
||||
const state = useGameStore.getState();
|
||||
const action = state.partyCombat.combatants[memberId].visualAction;
|
||||
const member = state.party.find((entry) => entry.id === memberId)!;
|
||||
@@ -1018,8 +1028,19 @@ function RangedProjectile({ memberId }: { memberId: "nia" | "orin" }) {
|
||||
&& action.abilityId !== "overcharge"
|
||||
&& state.time >= action.startedAt
|
||||
&& (rapid ? state.time <= action.endsAt : state.time <= action.impactAt);
|
||||
group.current.visible = active;
|
||||
if (!active || !action) return;
|
||||
projectile.current.visible = active;
|
||||
impact.current.visible = false;
|
||||
if (!action || state.phase !== "combat" || member.hp <= 0 || action.abilityId === "overcharge") return;
|
||||
|
||||
const profile = partyAttackVfxProfile(action.abilityId);
|
||||
if (lastAbilityId.current !== action.abilityId) {
|
||||
lastAbilityId.current = action.abilityId;
|
||||
coreMaterial.current?.color.set(profile.primary);
|
||||
accentMaterial.current?.color.set(profile.accent);
|
||||
trailMaterial.current?.color.set(profile.primary);
|
||||
impactMaterial.current?.color.set(profile.accent);
|
||||
impactCoreMaterial.current?.color.set(profile.primary);
|
||||
}
|
||||
|
||||
const targetMotion = targetBossMotionByInstance(state, action.targetInstanceId);
|
||||
const projectileDuration = Math.max(0.12, action.impactAt - action.startedAt);
|
||||
@@ -1030,44 +1051,81 @@ function RangedProjectile({ memberId }: { memberId: "nia" | "orin" }) {
|
||||
const target = targetMotion.position;
|
||||
start.set(source[0], 1.18, source[1]);
|
||||
end.set(target[0], 1.12, target[1]);
|
||||
current.copy(start).lerp(end, progress);
|
||||
current.y += Math.sin(progress * Math.PI) * (memberId === "orin" ? 0.95 : 0.34);
|
||||
group.current.position.copy(current);
|
||||
direction.subVectors(end, start).normalize();
|
||||
group.current.quaternion.setFromUnitVectors(up, direction);
|
||||
if (memberId === "orin") group.current.scale.setScalar(0.9 + Math.sin(clock.elapsedTime * 14) * 0.12);
|
||||
if (active) {
|
||||
current.copy(start).lerp(end, progress);
|
||||
current.y += Math.sin(progress * Math.PI) * (memberId === "orin" ? 0.95 : 0.34);
|
||||
projectile.current.position.copy(current);
|
||||
direction.subVectors(end, start).normalize();
|
||||
projectile.current.quaternion.setFromUnitVectors(up, direction);
|
||||
const pulseScale = memberId === "orin" ? 1 + Math.sin(clock.elapsedTime * 14) * 0.12 : 1;
|
||||
projectile.current.scale.setScalar(profile.scale * pulseScale);
|
||||
trail.current?.scale.set(1, profile.trail, 1);
|
||||
if (trailMaterial.current) trailMaterial.current.opacity = 0.34 + Math.sin(clock.elapsedTime * 10) * 0.08;
|
||||
}
|
||||
|
||||
const impactProgress = rapid
|
||||
? progress > 0.72 ? (progress - 0.72) / 0.28 : -1
|
||||
: (state.time - action.impactAt) / 0.3;
|
||||
const impactVisible = impactProgress >= 0 && impactProgress <= 1 && state.time <= action.endsAt + 0.3;
|
||||
impact.current.visible = impactVisible;
|
||||
if (impactVisible) {
|
||||
impact.current.position.copy(end);
|
||||
impact.current.scale.setScalar(profile.scale * (0.45 + impactProgress * 2.15));
|
||||
if (impactMaterial.current) impactMaterial.current.opacity = (1 - impactProgress) * 0.9;
|
||||
if (impactCoreMaterial.current) impactCoreMaterial.current.opacity = (1 - impactProgress) * 0.72;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<group ref={group} visible={false}>
|
||||
{memberId === "nia" ? (
|
||||
<>
|
||||
<mesh>
|
||||
<cylinderGeometry args={[0.026, 0.026, 0.82, 6]} />
|
||||
<meshBasicMaterial color="#d7b477" />
|
||||
</mesh>
|
||||
<mesh position={[0, 0.5, 0]}>
|
||||
<coneGeometry args={[0.085, 0.2, 6]} />
|
||||
<meshBasicMaterial color="#f1ddaa" />
|
||||
</mesh>
|
||||
<mesh position={[0, -0.4, 0]}>
|
||||
<coneGeometry args={[0.1, 0.18, 4]} />
|
||||
<meshBasicMaterial color="#70cf8e" />
|
||||
</mesh>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<mesh>
|
||||
<sphereGeometry args={[0.19, 12, 10]} />
|
||||
<meshBasicMaterial color="#bc8cff" />
|
||||
</mesh>
|
||||
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
||||
<torusGeometry args={[0.25, 0.025, 6, 20]} />
|
||||
<meshBasicMaterial color="#ead8ff" transparent opacity={0.8} />
|
||||
</mesh>
|
||||
</>
|
||||
)}
|
||||
</group>
|
||||
<>
|
||||
<group ref={projectile} visible={false}>
|
||||
{memberId === "nia" ? (
|
||||
<>
|
||||
<mesh>
|
||||
<cylinderGeometry args={[0.026, 0.026, 0.82, 6]} />
|
||||
<meshBasicMaterial ref={coreMaterial} color="#77d596" />
|
||||
</mesh>
|
||||
<mesh position={[0, 0.5, 0]}>
|
||||
<coneGeometry args={[0.085, 0.2, 6]} />
|
||||
<meshBasicMaterial ref={accentMaterial} color="#e5ffb8" />
|
||||
</mesh>
|
||||
<mesh position={[0, -0.4, 0]}>
|
||||
<coneGeometry args={[0.1, 0.18, 4]} />
|
||||
<meshBasicMaterial color="#d7b477" />
|
||||
</mesh>
|
||||
<mesh ref={trail} position={[0, -0.62, 0]}>
|
||||
<coneGeometry args={[0.12, 0.72, 6, 1, true]} />
|
||||
<meshBasicMaterial ref={trailMaterial} color="#77d596" transparent opacity={0.34} depthWrite={false} blending={THREE.AdditiveBlending} />
|
||||
</mesh>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<mesh>
|
||||
<sphereGeometry args={[0.19, 12, 10]} />
|
||||
<meshBasicMaterial ref={coreMaterial} color="#a87cff" toneMapped={false} />
|
||||
</mesh>
|
||||
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
||||
<torusGeometry args={[0.25, 0.025, 6, 20]} />
|
||||
<meshBasicMaterial ref={accentMaterial} color="#ead9ff" transparent opacity={0.8} depthWrite={false} />
|
||||
</mesh>
|
||||
<mesh ref={trail} position={[0, -0.48, 0]}>
|
||||
<coneGeometry args={[0.18, 0.95, 8, 1, true]} />
|
||||
<meshBasicMaterial ref={trailMaterial} color="#a87cff" transparent opacity={0.34} depthWrite={false} blending={THREE.AdditiveBlending} />
|
||||
</mesh>
|
||||
</>
|
||||
)}
|
||||
</group>
|
||||
<group ref={impact} visible={false}>
|
||||
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<ringGeometry args={[0.28, 0.45, 24]} />
|
||||
<meshBasicMaterial ref={impactMaterial} color="#ffffff" transparent opacity={0} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
<mesh>
|
||||
<octahedronGeometry args={[0.24, 0]} />
|
||||
<meshBasicMaterial ref={impactCoreMaterial} color="#ffffff" transparent opacity={0} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
</group>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1080,6 +1138,144 @@ function RangedProjectiles() {
|
||||
);
|
||||
}
|
||||
|
||||
function CloseAttackVfx({ memberId }: { memberId: "brann" | "orin" | "vale" }) {
|
||||
const group = useRef<THREE.Group>(null);
|
||||
const firstArc = useRef<THREE.Mesh>(null);
|
||||
const secondArc = useRef<THREE.Mesh>(null);
|
||||
const groundRing = useRef<THREE.Mesh>(null);
|
||||
const core = useRef<THREE.Mesh>(null);
|
||||
const primaryMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const secondaryMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const ringMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const coreMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const lastAbilityId = useRef<PartyAbilityId | null>(null);
|
||||
|
||||
useFrame(({ clock }) => {
|
||||
if (!group.current || !firstArc.current || !secondArc.current || !groundRing.current || !core.current) return;
|
||||
const state = useGameStore.getState();
|
||||
const actor = state.partyCombat.combatants[memberId];
|
||||
const action = actor.visualAction;
|
||||
const member = state.party.find((entry) => entry.id === memberId)!;
|
||||
const visible = action !== null
|
||||
&& state.phase === "combat"
|
||||
&& member.hp > 0
|
||||
&& state.time >= action.startedAt
|
||||
&& state.time <= action.endsAt + 0.18
|
||||
&& partyAttackVfxProfile(action.abilityId).style !== "projectile";
|
||||
group.current.visible = visible;
|
||||
if (!visible || !action) return;
|
||||
|
||||
const profile = partyAttackVfxProfile(action.abilityId);
|
||||
if (lastAbilityId.current !== action.abilityId) {
|
||||
lastAbilityId.current = action.abilityId;
|
||||
primaryMaterial.current?.color.set(profile.primary);
|
||||
secondaryMaterial.current?.color.set(profile.accent);
|
||||
ringMaterial.current?.color.set(profile.primary);
|
||||
coreMaterial.current?.color.set(profile.accent);
|
||||
}
|
||||
|
||||
const duration = Math.max(0.2, action.endsAt - action.startedAt);
|
||||
const progress = THREE.MathUtils.clamp((state.time - action.startedAt) / duration, 0, 1);
|
||||
const impactProgress = THREE.MathUtils.clamp((state.time - action.impactAt + 0.08) / 0.3, 0, 1);
|
||||
const source = state.partyPositions[memberId];
|
||||
const targetMotion = targetBossMotionByInstance(state, action.targetInstanceId);
|
||||
const target = targetMotion.position;
|
||||
const sourceStyle = profile.style === "buff" || profile.style === "spin";
|
||||
const effectHeight = sourceStyle ? 0.22 : profile.style === "slam" ? 0.18 : 1.05;
|
||||
group.current.position.set(sourceStyle ? source[0] : target[0], effectHeight, sourceStyle ? source[1] : target[1]);
|
||||
group.current.rotation.y = sourceStyle
|
||||
? clock.elapsedTime * 0.8
|
||||
: Math.atan2(target[0] - source[0], target[1] - source[1]);
|
||||
|
||||
const slashStyle = profile.style === "slash" || profile.style === "double-slash";
|
||||
firstArc.current.visible = slashStyle;
|
||||
secondArc.current.visible = profile.style === "double-slash";
|
||||
groundRing.current.visible = profile.style === "slam" || profile.style === "spin" || profile.style === "buff";
|
||||
core.current.visible = profile.style === "slam" || profile.style === "buff";
|
||||
const actionScale = profile.scale * (0.65 + Math.sin(progress * Math.PI) * 0.75);
|
||||
firstArc.current.scale.setScalar(actionScale);
|
||||
firstArc.current.rotation.z = -Math.PI * (0.82 - progress * 0.34);
|
||||
secondArc.current.scale.setScalar(actionScale * 0.92);
|
||||
secondArc.current.rotation.z = -Math.PI * (0.15 + progress * 0.36);
|
||||
const burstScale = profile.scale * (0.5 + impactProgress * 2.2);
|
||||
groundRing.current.scale.setScalar(burstScale);
|
||||
groundRing.current.rotation.z = clock.elapsedTime * (memberId === "vale" ? -1.6 : 0.85);
|
||||
core.current.scale.setScalar(profile.scale * (0.6 + Math.sin(progress * Math.PI) * 1.1));
|
||||
core.current.rotation.set(clock.elapsedTime, clock.elapsedTime * 1.4, 0);
|
||||
if (primaryMaterial.current) primaryMaterial.current.opacity = Math.sin(progress * Math.PI) * 0.9;
|
||||
if (secondaryMaterial.current) secondaryMaterial.current.opacity = Math.sin(progress * Math.PI) * 0.84;
|
||||
if (ringMaterial.current) ringMaterial.current.opacity = (1 - impactProgress * 0.7) * 0.76;
|
||||
if (coreMaterial.current) coreMaterial.current.opacity = Math.sin(progress * Math.PI) * 0.72;
|
||||
});
|
||||
|
||||
return (
|
||||
<group ref={group} visible={false}>
|
||||
<mesh ref={firstArc} rotation={[0, 0, -Math.PI * 0.72]}>
|
||||
<torusGeometry args={[0.72, 0.055, 6, 28, Math.PI * 1.28]} />
|
||||
<meshBasicMaterial ref={primaryMaterial} color="#ffffff" transparent opacity={0} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
<mesh ref={secondArc} position={[0.16, 0.02, 0.05]} rotation={[0, 0, -Math.PI * 0.2]}>
|
||||
<torusGeometry args={[0.64, 0.045, 6, 26, Math.PI * 1.18]} />
|
||||
<meshBasicMaterial ref={secondaryMaterial} color="#ffffff" transparent opacity={0} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
<mesh ref={groundRing} rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<ringGeometry args={[0.38, 0.54, 28]} />
|
||||
<meshBasicMaterial ref={ringMaterial} color="#ffffff" transparent opacity={0} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
<mesh ref={core} position={[0, 0.3, 0]}>
|
||||
<octahedronGeometry args={[0.26, 0]} />
|
||||
<meshBasicMaterial ref={coreMaterial} color="#ffffff" transparent opacity={0} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
function PartyPowerAuraVfx({ memberId }: { memberId: "orin" | "vale" }) {
|
||||
const group = useRef<THREE.Group>(null);
|
||||
const material = useRef<THREE.MeshBasicMaterial>(null);
|
||||
useFrame(({ clock }) => {
|
||||
if (!group.current) return;
|
||||
const state = useGameStore.getState();
|
||||
const actor = state.partyCombat.combatants[memberId];
|
||||
const member = state.party.find((entry) => entry.id === memberId)!;
|
||||
const active = state.phase === "combat" && member.hp > 0 && (memberId === "orin" ? actor.overchargeStacks > 0 : actor.bladeFlurryUntil > state.time);
|
||||
group.current.visible = active;
|
||||
if (!active) return;
|
||||
const position = state.partyPositions[memberId];
|
||||
group.current.position.set(position[0], 0.16, position[1]);
|
||||
group.current.rotation.y = clock.elapsedTime * (memberId === "orin" ? 1.4 : -1.8);
|
||||
const pulse = 0.92 + Math.sin(clock.elapsedTime * 5.5) * 0.12;
|
||||
group.current.scale.setScalar(pulse);
|
||||
if (material.current) material.current.opacity = 0.38 + Math.sin(clock.elapsedTime * 4.2) * 0.1;
|
||||
});
|
||||
const color = memberId === "orin" ? "#bc72ff" : "#9a86ff";
|
||||
return (
|
||||
<group ref={group} visible={false}>
|
||||
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<torusGeometry args={[0.7, 0.035, 6, 28]} />
|
||||
<meshBasicMaterial ref={material} color={color} transparent opacity={0.4} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
<mesh position={[0, 0.72, 0]} rotation={[Math.PI / 2, 0, 0]}>
|
||||
<torusGeometry args={[0.46, 0.025, 6, 24]} />
|
||||
<meshBasicMaterial color={color} transparent opacity={0.5} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
function PartyCombatVfx() {
|
||||
return (
|
||||
<>
|
||||
<RangedProjectiles />
|
||||
<CloseAttackVfx memberId="brann" />
|
||||
<CloseAttackVfx memberId="orin" />
|
||||
<CloseAttackVfx memberId="vale" />
|
||||
<PartyPowerAuraVfx memberId="orin" />
|
||||
<PartyPowerAuraVfx memberId="vale" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function BossActor() {
|
||||
const phase = useGameStore((state) => state.phase);
|
||||
const primaryBossId = useGameStore((state) => state.boss.id);
|
||||
@@ -1185,27 +1381,72 @@ function PerformanceProbe() {
|
||||
return null;
|
||||
}
|
||||
|
||||
const FX_BURST_PARTICLE_COUNT = 8;
|
||||
|
||||
function scenePulseColor(kind: PulseKind) {
|
||||
if (kind === "shield") return "#62bdff";
|
||||
if (kind === "purify") return "#c39bff";
|
||||
if (kind === "renew") return "#72e0a1";
|
||||
if (kind === "breath") return "#66dcff";
|
||||
if (kind === "venom") return "#8fdb4f";
|
||||
if (kind === "tether") return "#d482ff";
|
||||
if (kind === "skyfall") return "#ffd36b";
|
||||
if (kind === "boss" || kind === "debuff" || kind === "charge" || kind === "pounce" || kind === "slash") return "#ff643c";
|
||||
return "#ffe087";
|
||||
}
|
||||
|
||||
function FxBurst({ kind, targetId }: { kind: PulseKind; targetId?: MemberId }) {
|
||||
const group = useRef<THREE.Group>(null);
|
||||
const ring = useRef<THREE.Mesh>(null);
|
||||
const material = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const particles = useRef<THREE.InstancedMesh>(null);
|
||||
const particleMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const core = useRef<THREE.Mesh>(null);
|
||||
const coreMaterial = useRef<THREE.MeshBasicMaterial>(null);
|
||||
const transform = useMemo(() => new THREE.Object3D(), []);
|
||||
const age = useRef(0);
|
||||
const isBossFx = kind === "boss";
|
||||
const state = useGameStore.getState();
|
||||
const worldPosition = isBossFx ? targetBossMotion(state).position : targetId ? state.partyPositions[targetId] : [0, 0];
|
||||
const position: [number, number, number] = [worldPosition[0], 0.15, worldPosition[1]];
|
||||
const color = kind === "boss" || kind === "debuff" || kind === "charge" || kind === "pounce" || kind === "slash" ? "#ff643c" : kind === "shield" ? "#62bdff" : kind === "purify" ? "#c39bff" : "#ffe087";
|
||||
useFrame((_, delta) => {
|
||||
const color = scenePulseColor(kind);
|
||||
useFrame(({ clock }, delta) => {
|
||||
age.current += delta;
|
||||
if (!ring.current || !material.current) return;
|
||||
if (!group.current || !ring.current || !material.current || !particles.current || !core.current) return;
|
||||
const progress = Math.min(1, age.current / 0.7);
|
||||
ring.current.scale.setScalar(0.5 + progress * 3.6);
|
||||
material.current.opacity = (1 - progress) * 0.85;
|
||||
core.current.scale.setScalar(0.45 + Math.sin(progress * Math.PI) * 1.8);
|
||||
core.current.rotation.set(clock.elapsedTime * 1.5, clock.elapsedTime * 2, 0);
|
||||
if (coreMaterial.current) coreMaterial.current.opacity = (1 - progress) * 0.72;
|
||||
for (let index = 0; index < FX_BURST_PARTICLE_COUNT; index += 1) {
|
||||
const angle = index / FX_BURST_PARTICLE_COUNT * Math.PI * 2 + clock.elapsedTime * 0.6;
|
||||
const radial = progress * (kind === "boss" ? 3.2 : 1.65);
|
||||
const scale = (1 - progress) * (kind === "boss" ? 1.4 : 0.9);
|
||||
transform.position.set(Math.sin(angle) * radial, 0.18 + Math.sin(progress * Math.PI) * (0.7 + (index % 2) * 0.45), Math.cos(angle) * radial);
|
||||
transform.rotation.set(angle, progress * Math.PI * 2 + index, clock.elapsedTime);
|
||||
transform.scale.setScalar(scale);
|
||||
transform.updateMatrix();
|
||||
particles.current.setMatrixAt(index, transform.matrix);
|
||||
}
|
||||
particles.current.instanceMatrix.needsUpdate = true;
|
||||
if (particleMaterial.current) particleMaterial.current.opacity = (1 - progress) * 0.82;
|
||||
});
|
||||
return (
|
||||
<mesh ref={ring} position={position} rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<ringGeometry args={[0.38, 0.5, 32]} />
|
||||
<meshBasicMaterial ref={material} color={color} transparent depthWrite={false} />
|
||||
</mesh>
|
||||
<group ref={group} position={position}>
|
||||
<mesh ref={ring} rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<ringGeometry args={[0.38, 0.5, 32]} />
|
||||
<meshBasicMaterial ref={material} color={color} transparent depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
<mesh ref={core} position={[0, 0.42, 0]}>
|
||||
<octahedronGeometry args={[0.24, 0]} />
|
||||
<meshBasicMaterial ref={coreMaterial} color={color} transparent opacity={0.72} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</mesh>
|
||||
<instancedMesh ref={particles} args={[undefined, undefined, FX_BURST_PARTICLE_COUNT]} frustumCulled={false}>
|
||||
<tetrahedronGeometry args={[0.18, 0]} />
|
||||
<meshBasicMaterial ref={particleMaterial} color={color} transparent opacity={0.82} depthWrite={false} blending={THREE.AdditiveBlending} toneMapped={false} />
|
||||
</instancedMesh>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1237,7 +1478,7 @@ export function GameScene() {
|
||||
<TankAuraField />
|
||||
<Party />
|
||||
<BossActor />
|
||||
<RangedProjectiles />
|
||||
<PartyCombatVfx />
|
||||
<CombatFx />
|
||||
{PERFORMANCE_PROBE_ENABLED && <PerformanceProbe />}
|
||||
</GameAssetProvider>
|
||||
|
||||
Reference in New Issue
Block a user