0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Three.js(R3F)でWASD操作を行う

Posted at

初めに

最近毎日ここであさかつしてます。
https://stacklive.jp/
朝に勉強するの結構はかどります。

このコードですが、あとでスマホ対応とゲームパッド対応する予定です。

実行結果

layer1.gif

ソースコード

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>
    )
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?