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 [camSpeed, setCamSpeed] = useState(0.05);
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 teleportIndexRef = useRef(0);
const countRef = useRef(0);
@@ -28,11 +32,25 @@ export default function App() {
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) => {
countRef.current += 1;
setAnimState({ name, count: countRef.current });
}, []);
const doSkillRef = useRef(null);
const handleKey = useCallback((e) => {
if (e.code === 'Escape') {
setView(view === 'nasa' ? 'avatar' : 'nasa');
@@ -53,8 +71,7 @@ export default function App() {
teleportIndexRef.current = idx + 1;
} else if (e.code === 'KeyS') {
e.preventDefault();
playAnim('skill');
setVrmModel(prev => prev === 'ai.vrm' ? 'ai_mode.vrm' : 'ai.vrm');
doSkillRef.current?.();
}
}, [playAnim, view]);
@@ -93,10 +110,16 @@ export default function App() {
teleportIndexRef.current = idx + 1;
}, [playAnim]);
const skillCoolRef = useRef(0);
const doSkill = useCallback(() => {
const now = Date.now();
if (now - skillCoolRef.current < 3000) return;
skillCoolRef.current = now;
playAnim('skill');
playSkillVoice();
setVrmModel(prev => prev === 'ai.vrm' ? 'ai_mode.vrm' : 'ai.vrm');
}, [playAnim]);
}, [playAnim, playSkillVoice]);
doSkillRef.current = doSkill;
const appStartRef = useRef(Date.now());
const lastSwitchRef = useRef(0);
@@ -179,6 +202,8 @@ export default function App() {
camSpeed={camSpeed}
onCamSpeedChange={setCamSpeed}
onSkill={doSkill}
lang={lang}
onLangChange={handleLangChange}
/>
)}

View File

@@ -73,6 +73,14 @@ export default function VrmCharacter({ selectedAnimation: animState, vrmModel =
const vrm = gltf.userData.vrm;
vrmRef.current = vrm;
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.scene.rotation.y = Math.PI;

View File

@@ -44,7 +44,7 @@ const btnStyle = {
width: '100%',
};
export default function ControlPanel({ timeScale, onTimeScaleChange, camSpeed, onCamSpeedChange, onSkill }) {
export default function ControlPanel({ timeScale, onTimeScaleChange, camSpeed, onCamSpeedChange, onSkill, lang, onLangChange }) {
return (
<div style={containerStyle}>
<div>
@@ -77,8 +77,19 @@ export default function ControlPanel({ timeScale, onTimeScaleChange, camSpeed, o
style={sliderStyle}
/>
</div>
<button style={btnStyle} onClick={() => onSkill?.()}>
Skill
<button
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>
</div>
);