初めに
最近毎日ここであさかつしてます。
https://stacklive.jp/
朝に勉強するの結構はかどります。
このコードですが、あとでスマホ対応とゲームパッド対応する予定です。
実行結果
ソースコード
import { useFrame, useThree } from "@react-three/fiber"
import { useEffect, useRef } from "react";
import { Mesh, Vector2, Vector3 } from "three";
/**
* ActionキーのリストEnum
*/
export const EActionKey = {
KeyW : "forward",
KeyS : "backward",
KeyA : "left",
KeyD : "right",
Space : "jump",
ShiftLeft : "dash",
ShiftRight : "dash",
Shift : "dash"
}
/**
* 入力イベント / 入力の型
*/
interface HTMLElementEvent<T extends HTMLElement> extends Event {
target : T;
code : string;
}
export interface IInputMovement {
forward : boolean;
backward : boolean;
left : boolean;
right : boolean;
jump : boolean;
dash : boolean;
prevDrag? : Vector2; // カメラ向きに利用(あとで実装)
currDrag? : Vector2; // カメラ向きに利用(あとで実装)
}
export const useInputControl = () => {
const moveKeyFromCode = (key: string) => EActionKey[key];
const movement = useRef<IInputMovement>({
forward : false,
backward : false,
left : false,
right : false,
jump : false,
dash : false,
prevDrag : null,
currDrag : null
});
useEffect(() => {
/**
* キーボード対応
*/
const handleKeyDown = (e: HTMLElementEvent<HTMLInputElement>) => {
movement.current[moveKeyFromCode(e.code)] = true;
}
const handleKeyUp = (e: HTMLElementEvent<HTMLInputElement>) => {
movement.current[moveKeyFromCode(e.code)] = false;
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
/**
* スマホ対応 (あとで実装)
*/
// handleTouch
/**
* ゲームパッド対応 (あとで実装)
*/
// handleGamePad
return () => {
document.removeEventListener("keydown", handleKeyDown);
document.removeEventListener("keyup", handleKeyUp);
}
}, []);
return movement.current;
}
/**
* キーボード操作Component
*/
export const TestInputControlComponent = () => {
const ref = useRef<Mesh>();
const input = useInputControl();// キーボード入力を取得
const { camera } = useThree();
useEffect(() => {
// 初期カメラの位置を物体の後ろに移動
camera.position.copy(new Vector3(0, 1, -3));
camera.lookAt(new Vector3(0, 0, 0));
}, [])
useFrame((_, delta) => {
const { forward, backward, left, right, dash, jump } = input;
if ( forward || backward || right || left || jump ){
const velocity = new Vector3(0, 0, 0);
// それぞれの方向に入力がある分だけ、ベクトルを加算していく
if (forward && !backward) velocity.add(new Vector3(0, 0, 1))
else if (!forward && backward) velocity.add(new Vector3(0, 0, -1))
if (right && !left) velocity.add(new Vector3(-1, 0, 0))
else if (!right && left) velocity.add(new Vector3(1, 0, 0))
if (jump) velocity.add(new Vector3(0, 1, 0))
// フレーム時間でかけた値を位置ベクトルに加算する
if (ref.current){
const mag = 1.5; // 速度倍率を1.5倍に早くする
ref.current.position.add(velocity.multiplyScalar(delta).multiplyScalar(mag));
}
}
});
return (
<mesh ref={ref}>
<sphereBufferGeometry/>
<meshStandardMaterial color={0xff5500}/>
</mesh>
)
}