javascript 如何让第三人称相机从后面跟随物体?(React三/纤维)

wyyhbhjk  于 2023-05-16  发布在  Java
关注(0)|答案(1)|浏览(121)

我正在尝试构建一个“3D坦克游戏”,我使用了这个Original Project的大部分代码。我找不到任何有好例子的资源来演示“useRaycastVehicle”与“第三人称相机”。我的解决方案很简单,它检查z维度是否为负,如果是,在下一帧它会翻转POV,因此车辆不会面向相机。我认为,有更好的解决方案来解决这个问题。因为我在Youtube上看到解决了这个问题,但是重新实现他的代码导致相机被粘在地上,不跟随等等。

import { useFrame, useThree } from "@react-three/fiber";
import { useRaycastVehicle } from "@react-three/cannon";
import { useEffect, useRef } from "react";

import { useKeyboardControls } from "@react-three/drei";
import Beetle from "./Beetle";
import Wheel from "./Wheel";
import { Vector3 } from "three";

export default function Tank({
    radius = 0.7,
    width = 1.2,
    height = -0.04,
    front = 1.3,
    back = -1.15,
    steer = 0.75,
    force = 2000,
    maxBrake = 1e5,
    ...props
}) {
    const {
        forward,
        backward,
        leftward,
        rightward,
        // shoot: jump,
    } = useKeyboardControls((state) => state);

    const chassis = useRef();
    const wheel1 = useRef();
    const wheel2 = useRef();
    const wheel3 = useRef();
    const wheel4 = useRef();

    const wheelInfo = {
        radius,
        directionLocal: [0, -1, 0],
        suspensionStiffness: 30,
        suspensionRestLength: 0.3,
        maxSuspensionForce: 1e4,
        maxSuspensionTravel: 0.3,
        dampingRelaxation: 10,
        dampingCompression: 4.4,
        axleLocal: [-1, 0, 0],
        chassisConnectionPointLocal: [1, 0, 1],
        useCustomSlidingRotationalSpeed: true,
        customSlidingRotationalSpeed: -30,
        frictionSlip: 2,
    };

    const wheelInfo1 = {
        ...wheelInfo,
        isFrontWheel: true,
        chassisConnectionPointLocal: [-width / 2, height, front],
    };
    const wheelInfo2 = {
        ...wheelInfo,
        isFrontWheel: true,
        chassisConnectionPointLocal: [width / 2, height, front],
    };
    const wheelInfo3 = {
        ...wheelInfo,
        isFrontWheel: false,
        chassisConnectionPointLocal: [-width / 2, height, back],
    };
    const wheelInfo4 = {
        ...wheelInfo,
        isFrontWheel: false,
        chassisConnectionPointLocal: [width / 2, height, back],
    };

    const [myTank, api] = useRaycastVehicle(() => ({
        // @ts-ignore
        chassisBody: chassis,
        // @ts-ignore
        wheels: [wheel1, wheel2, wheel3, wheel4],
        //@ts-ignore
        wheelInfos: [wheelInfo1, wheelInfo2, wheelInfo3, wheelInfo4],
        indexForwardAxis: 2,
        indexRightAxis: 0,
        indexUpAxis: 1,
    }));

    const { camera, scene } = useThree();

    const pos = useRef([0, 0, 0]);
    const rot = useRef([0, 0, 0]);
    useEffect(() => {
        if (chassis.current) {
            //@ts-ignore
            chassis.current.api.rotation.subscribe((r) => (rot.current = r));
            //@ts-ignore
            chassis.current.api.position.subscribe((p) => (pos.current = p));
        }
    }, [chassis.current]);

    useFrame(() => {
        for (let e = 2; e < 4; e++)
            api.applyEngineForce(
                forward || backward
                    ? force * (forward && !backward ? -1 : 1)
                    : 0,
                2
            );
        for (let s = 0; s < 2; s++)
            api.setSteeringValue(
                leftward || rightward
                    ? steer * (leftward && !rightward ? 1 : -1)
                    : 0,
                s
            );

        const cameraOffset = new Vector3(0, 4, -5);

        var zDimensionNegative = pos.current[2] > -5 ? 0 : 10;

        camera.position
            .copy(
                new Vector3(
                    pos.current[0],
                    pos.current[1],
                    pos.current[2] + zDimensionNegative
                )
            )
            .add(cameraOffset);
    });

    return (
        // @ts-ignore
        <group ref={myTank} position={[0, -0.4, 0]}>
            <Beetle
                ref={chassis}
                //@ts-ignore
                rotation={props.rotation}
                position={props.position}
                angularVelocity={props.angularVelocity}
            />
            <Wheel
                ref={wheel1}
                //@ts-ignore
                radius={radius}
                leftSide
            />
            <Wheel
                ref={wheel2}
                //@ts-ignore
                radius={radius}
            />
            <Wheel
                ref={wheel3}
                //@ts-ignore
                radius={radius}
                leftSide
            />
            <Wheel
                ref={wheel4}
                //@ts-ignore
                radius={radius}
            />
        </group>
    );
}

o2rvlv0m

o2rvlv0m1#

老实说,很难使用React和ThreeJS。没有关于使用的文档,没有好的例子,感觉就像react fiber是用于小型3D动画的。
但如果真的有人需要解决这个问题。下面是我如何做到的:

const MyCamera = () => (
    <PerspectiveCamera
        fov={75}
        rotation={[0, Math.PI, 0]}
        makeDefault={true}
        position={[0, 6, -11]}
    >
        <PointerLockControls
            addEventListener={undefined}
            hasEventListener={undefined}
            removeEventListener={undefined}
            dispatchEvent={undefined}
        />
    </PerspectiveCamera>
);

const Beetle = ({ children }) => {
    return (
        <mesh>
            {children}
            <group dispose={null} scale={0.225}>
                {/**
                 * Car's original meshes and stuff!
                 */}
            </group>
        </mesh>
    );
};

export default function Tank() {
    return (
        // @ts-ignore
        <group ref={myTank} position={[0, -0.4, 0]}>
            <Beetle
                ref={chassis}
                //@ts-ignore
                rotation={props.rotation}
                position={props.position}
                angularVelocity={props.angularVelocity}
            >
                <MyCamera />
            </Beetle>
            <Wheel
                ref={wheel1}
                //@ts-ignore
                radius={radius}
                leftSide
            />
            <Wheel
                ref={wheel2}
                //@ts-ignore
                radius={radius}
            />
            <Wheel
                ref={wheel3}
                //@ts-ignore
                radius={radius}
                leftSide
            />
            <Wheel
                ref={wheel4}
                //@ts-ignore
                radius={radius}
            />
        </group>
    );
}

基本上,它所做的只是使相机成为Beetle网格的子对象,因此,相机继承其父对象的位置和向量。我不知道如何得到物体的世界方向向量或位置。因此,使相机成为对象的子对象是继承其位置和方向的最简单方法!

相关问题