1
0
This commit is contained in:
2026-03-07 03:35:29 +09:00
commit efc513be15
18 changed files with 1103 additions and 0 deletions

149
src/SkillEffects.jsx Normal file
View File

@@ -0,0 +1,149 @@
import React, { useRef, useMemo } from 'react';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
const SPHERE_PRESETS = {
sun: {
layers: [
{ radius: 0.3, segments: 64, size: 0.015, opacity: 0.8 },
{ radius: 0.22, segments: 48, size: 0.02, opacity: 0.5 },
{ radius: 0.38, segments: 40, size: 0.008, opacity: 0.3 },
],
lightColor: '#ffaa22',
lightIntensity: 3,
rotateSpeed: 1.5,
pulseSpeed: 2.0,
pulseRange: 0.25,
colorFn: (normDist, layerIdx) => {
if (layerIdx === 0) return [1.0, 0.7 + normDist * 0.3, 0.1];
if (layerIdx === 1) return [1.0, 0.4, 0.05];
return [1.0, 0.9, 0.5];
},
},
moon: {
layers: [
{ radius: 0.2, segments: 48, size: 0.01, opacity: 0.6 },
{ radius: 0.26, segments: 32, size: 0.006, opacity: 0.25 },
],
lightColor: '#aaccff',
lightIntensity: 2,
rotateSpeed: 0.8,
pulseSpeed: 1.0,
pulseRange: 0.12,
colorFn: (normDist, layerIdx) => {
if (layerIdx === 0) return [0.7, 0.8, 1.0];
return [0.5, 0.6, 1.0];
},
},
earth: {
layers: [
{ radius: 0.25, segments: 56, size: 0.012, opacity: 0.7 },
{ radius: 0.32, segments: 36, size: 0.007, opacity: 0.25 },
],
lightColor: '#44aaff',
lightIntensity: 2.5,
rotateSpeed: 1.0,
pulseSpeed: 1.5,
pulseRange: 0.18,
colorFn: (normDist, layerIdx) => {
if (layerIdx === 0) return [0.2, 0.6 + normDist * 0.4, 1.0];
return [0.1, 0.8, 0.6];
},
},
neutron: {
layers: [
{ radius: 0.15, segments: 72, size: 0.008, opacity: 0.9 },
{ radius: 0.1, segments: 48, size: 0.015, opacity: 0.6 },
{ radius: 0.22, segments: 32, size: 0.005, opacity: 0.3 },
],
lightColor: '#8844ff',
lightIntensity: 4,
rotateSpeed: 3.0,
pulseSpeed: 3.0,
pulseRange: 0.35,
colorFn: (normDist, layerIdx) => {
if (layerIdx === 0) return [0.9, 0.3, 1.0];
if (layerIdx === 1) return [1.0, 1.0, 1.0];
return [0.5, 0.1, 1.0];
},
},
};
function ParticleLayer({ radius, segments, size, opacity, colorFn, layerIdx }) {
const data = useMemo(() => {
const geo = new THREE.SphereGeometry(radius, segments, segments);
const posArr = new Float32Array(geo.attributes.position.array);
const colArr = new Float32Array(posArr.length);
for (let i = 0; i < posArr.length; i += 3) {
const x = posArr[i], y = posArr[i + 1], z = posArr[i + 2];
const dist = Math.sqrt(x * x + y * y + z * z);
const normDist = dist / (radius || 1);
const [r, g, b] = colorFn(normDist, layerIdx);
colArr[i] = r;
colArr[i + 1] = g;
colArr[i + 2] = b;
}
geo.dispose();
return { positions: posArr, colors: colArr };
}, [radius, segments, colorFn, layerIdx]);
return (
<points>
<bufferGeometry>
<bufferAttribute attach="attributes-position" array={data.positions} count={data.positions.length / 3} itemSize={3} />
<bufferAttribute attach="attributes-color" array={data.colors} count={data.colors.length / 3} itemSize={3} />
</bufferGeometry>
<pointsMaterial
transparent
depthWrite={false}
vertexColors
opacity={opacity}
size={size}
blending={THREE.AdditiveBlending}
/>
</points>
);
}
function EnergySphere({ type = 'sun', position = [0, 1.5, 0], scale = 1 }) {
const groupRef = useRef();
const layerRefs = useRef([]);
const preset = SPHERE_PRESETS[type] || SPHERE_PRESETS.sun;
useFrame(({ clock }) => {
if (!groupRef.current) return;
const t = clock.getElapsedTime();
const pulse = 1 + Math.sin(t * preset.pulseSpeed) * preset.pulseRange;
groupRef.current.scale.setScalar(scale * pulse);
layerRefs.current.forEach((ref, i) => {
if (!ref) return;
const speed = preset.rotateSpeed * (1 + i * 0.4);
const dir = i % 2 === 0 ? 1 : -1;
ref.rotation.y = t * speed * dir;
ref.rotation.x = Math.sin(t * speed * 0.3 + i) * 0.4;
ref.rotation.z = Math.cos(t * speed * 0.2 + i * 2) * 0.3;
});
});
return (
<group position={position} ref={groupRef}>
{preset.layers.map((layer, i) => (
<group key={i} ref={el => layerRefs.current[i] = el}>
<ParticleLayer
radius={layer.radius}
segments={layer.segments}
size={layer.size}
opacity={layer.opacity}
colorFn={preset.colorFn}
layerIdx={i}
/>
</group>
))}
<pointLight position={[0, 0, 0]} intensity={preset.lightIntensity} color={preset.lightColor} distance={5} />
</group>
);
}
export { EnergySphere, SPHERE_PRESETS };
export default EnergySphere;