1
0

fix skill

This commit is contained in:
2026-03-07 16:57:46 +09:00
parent 309d93af04
commit 2bc35563a2
3 changed files with 50 additions and 6 deletions

View File

@@ -20,6 +20,10 @@ export default function App() {
const [timeScale, setTimeScale] = useState(100); const [timeScale, setTimeScale] = useState(100);
const [camSpeed, setCamSpeed] = useState(0.05); const [camSpeed, setCamSpeed] = useState(0.05);
const [vrmModel, setVrmModel] = useState('ai.vrm'); const [vrmModel, setVrmModel] = useState('ai.vrm');
const [lang, setLang] = useState('ja');
const langRef = useRef('ja');
const voiceIndexRef = useRef(0);
const voicePattern = ['normal','normal','normal','normal','normal','normal','normal','normal','skill','skill'];
const actionIndexRef = useRef(0); const actionIndexRef = useRef(0);
const teleportIndexRef = useRef(0); const teleportIndexRef = useRef(0);
const countRef = useRef(0); const countRef = useRef(0);
@@ -28,11 +32,25 @@ export default function App() {
return onAdminChange((v) => setIsAdmin(v)); return onAdminChange((v) => setIsAdmin(v));
}, []); }, []);
const handleLangChange = useCallback((v) => { setLang(v); langRef.current = v; }, []);
const playSkillVoice = useCallback(() => {
const type = voicePattern[voiceIndexRef.current % voicePattern.length];
voiceIndexRef.current += 1;
const suffix = langRef.current === 'en' ? '_en' : '';
const file = `${import.meta.env.BASE_URL}voice/ai/${type}_1${suffix}.mp3`;
const audio = new Audio(file);
audio.volume = 0.7;
audio.play().catch(() => {});
}, []);
const playAnim = useCallback((name) => { const playAnim = useCallback((name) => {
countRef.current += 1; countRef.current += 1;
setAnimState({ name, count: countRef.current }); setAnimState({ name, count: countRef.current });
}, []); }, []);
const doSkillRef = useRef(null);
const handleKey = useCallback((e) => { const handleKey = useCallback((e) => {
if (e.code === 'Escape') { if (e.code === 'Escape') {
setView(view === 'nasa' ? 'avatar' : 'nasa'); setView(view === 'nasa' ? 'avatar' : 'nasa');
@@ -53,8 +71,7 @@ export default function App() {
teleportIndexRef.current = idx + 1; teleportIndexRef.current = idx + 1;
} else if (e.code === 'KeyS') { } else if (e.code === 'KeyS') {
e.preventDefault(); e.preventDefault();
playAnim('skill'); doSkillRef.current?.();
setVrmModel(prev => prev === 'ai.vrm' ? 'ai_mode.vrm' : 'ai.vrm');
} }
}, [playAnim, view]); }, [playAnim, view]);
@@ -93,10 +110,16 @@ export default function App() {
teleportIndexRef.current = idx + 1; teleportIndexRef.current = idx + 1;
}, [playAnim]); }, [playAnim]);
const skillCoolRef = useRef(0);
const doSkill = useCallback(() => { const doSkill = useCallback(() => {
const now = Date.now();
if (now - skillCoolRef.current < 3000) return;
skillCoolRef.current = now;
playAnim('skill'); playAnim('skill');
playSkillVoice();
setVrmModel(prev => prev === 'ai.vrm' ? 'ai_mode.vrm' : 'ai.vrm'); setVrmModel(prev => prev === 'ai.vrm' ? 'ai_mode.vrm' : 'ai.vrm');
}, [playAnim]); }, [playAnim, playSkillVoice]);
doSkillRef.current = doSkill;
const appStartRef = useRef(Date.now()); const appStartRef = useRef(Date.now());
const lastSwitchRef = useRef(0); const lastSwitchRef = useRef(0);
@@ -179,6 +202,8 @@ export default function App() {
camSpeed={camSpeed} camSpeed={camSpeed}
onCamSpeedChange={setCamSpeed} onCamSpeedChange={setCamSpeed}
onSkill={doSkill} onSkill={doSkill}
lang={lang}
onLangChange={handleLangChange}
/> />
)} )}

View File

@@ -73,6 +73,14 @@ export default function VrmCharacter({ selectedAnimation: animState, vrmModel =
const vrm = gltf.userData.vrm; const vrm = gltf.userData.vrm;
vrmRef.current = vrm; vrmRef.current = vrm;
VRMUtils.removeUnnecessaryJoints(vrm.scene); VRMUtils.removeUnnecessaryJoints(vrm.scene);
// SpringBone: centerをRotatingStage(親group)に設定し、回転に追従させる
const sbm = vrm.springBoneManager;
if (sbm) {
const stageGroup = vrm.scene.parent;
sbm.joints?.forEach(joint => {
if (stageGroup) joint.center = stageGroup;
});
}
vrm.humanoid.resetPose(); vrm.humanoid.resetPose();
vrm.scene.rotation.y = Math.PI; vrm.scene.rotation.y = Math.PI;

View File

@@ -44,7 +44,7 @@ const btnStyle = {
width: '100%', width: '100%',
}; };
export default function ControlPanel({ timeScale, onTimeScaleChange, camSpeed, onCamSpeedChange, onSkill }) { export default function ControlPanel({ timeScale, onTimeScaleChange, camSpeed, onCamSpeedChange, onSkill, lang, onLangChange }) {
return ( return (
<div style={containerStyle}> <div style={containerStyle}>
<div> <div>
@@ -77,8 +77,19 @@ export default function ControlPanel({ timeScale, onTimeScaleChange, camSpeed, o
style={sliderStyle} style={sliderStyle}
/> />
</div> </div>
<button style={btnStyle} onClick={() => onSkill?.()}> <button
Skill style={{ ...btnStyle, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}
onClick={() => onSkill?.()}
>
<img src={`${import.meta.env.BASE_URL}icon/dot.svg`} alt="" style={{ width: 14, height: 14, filter: 'brightness(0) invert(1)', opacity: 0.7 }} />
<span>Skill</span>
</button>
<button
style={{ ...btnStyle, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}
onClick={() => onLangChange?.(lang === 'ja' ? 'en' : 'ja')}
>
<img src={`${import.meta.env.BASE_URL}icon/language.svg`} alt="" style={{ width: 14, height: 14, filter: 'brightness(0) invert(1)', opacity: 0.7 }} />
<span>{lang?.toUpperCase()}</span>
</button> </button>
</div> </div>
); );