Skip to content

Instantly share code, notes, and snippets.

@shrirambalaji
Last active January 20, 2022 05:32
Show Gist options
  • Save shrirambalaji/b33f0123af0f17e64e66bbb239990cac to your computer and use it in GitHub Desktop.
Save shrirambalaji/b33f0123af0f17e64e66bbb239990cac to your computer and use it in GitHub Desktop.
exampleGltfModel.js
import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { useGLTF, useAnimations } from "@react-three/drei";
import { useFrame, useThree } from "@react-three/fiber";
import { Quaternion, Vector3 } from "three";
// import { useCompoundBody} from "@react-three/cannon";
import { useStore } from "../store";
const keys = {
KeyW: "forward",
KeyS: "backward",
KeyA: "left",
KeyD: "right",
Space: "jump",
};
const moveFieldByKey = (key) => keys[key];
// temporary data
const walkDirection = new Vector3();
const rotateAngle = new Vector3(0, 1, 0);
const rotateQuarternion = new Quaternion();
const cameraTarget = new Vector3();
// constants
// const runVelocity = 5;
const walkVelocity = 2;
const compoundStructure = [
{
position: [0, 0, 0],
args: [0.5, 0.4, 0.1],
},
{
position: [0, 0.25, 0],
args: [0.5, 0.4, 0.1],
},
{
position: [0, 0.5, 0],
args: [0.5, 0.4, 0.1],
},
];
export default function Soldier({ pose, ...props }) {
const model = useRef();
const { nodes, materials, animations } = useGLTF("/models/Soldier.glb");
const { actions, names } = useAnimations(animations, model);
const [index, setIndex] = useState(pose);
const [toggleRun, setToggleRun] = useState(false);
const runVelocity = useStore((state) => state.runVelocity);
const { camera } = useThree();
function switchRunToggle() {
setToggleRun(!toggleRun);
}
function updateCameraTarget(moveX, moveZ) {
// move camera
}
const usePlayerControls = () => {
const [movement, setMovement] = useState({
forward: false,
backward: false,
left: false,
right: false,
jump: false,
});
useEffect(() => {
const handleKeyDown = (e) => {
setIndex(1);
setMovement((m) => {
return { ...m, [moveFieldByKey(e.code)]: true };
});
};
const handleKeyUp = (e) => {
setIndex(0);
setMovement((m) => {
return { ...m, [moveFieldByKey(e.code)]: false };
});
setToggleRun(false);
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
return () => {
document.removeEventListener("keydown", handleKeyDown);
document.removeEventListener("keyup", handleKeyUp);
};
}, []);
return movement;
};
const { forward, backward, left, right, jump } = usePlayerControls();
useLayoutEffect(() => {
// Reset and fade in animation after an index has been changed
actions[names[index]].reset().fadeIn(0.5).play();
// In the clean-up phase, fade it out
return () => actions[names[index]].fadeOut(0.5);
// actions[names[index]].play()
}, [index, actions, names, pose, toggleRun]);
useFrame((state) => {
let delta = state.clock.getDelta();
if (names[index] == "Run" || names[index] == "Walk") {
// calculate towards camera direction
let angleYCameraDirection = Math.atan2(
camera.position.x - model.current.position.x,
camera.position.z - model.current.position.z
);
// diagonal movement angle offset
let directionOffset = getDirectionOffset(forward, backward, right, left);
// // rotate model
rotateQuarternion.setFromAxisAngle(
rotateAngle,
angleYCameraDirection + directionOffset
);
model.current.quaternion.rotateTowards(rotateQuarternion, 0.2);
// // calculate direction
camera.getWorldDirection(walkDirection);
walkDirection.y = 0;
walkDirection.normalize();
walkDirection.applyAxisAngle(rotateAngle, directionOffset);
// // run/walk velocity
// const velocity = names[index] == "Run" ? runVelocity : walkVelocity;
const velocity = runVelocity;
// // move model & camera
const moveX = walkDirection.x * velocity * delta * 80;
const moveZ = walkDirection.z * velocity * delta * 80;
model.current.position.x += moveX;
model.current.position.z += moveZ;
// move camera
camera.position.x += moveX;
camera.position.z += moveZ;
// update camera target
cameraTarget.x = model.current.position.x;
cameraTarget.y = model.current.position.y + 1;
cameraTarget.z = model.current.position.z;
state.controls.target = cameraTarget;
}
});
return (
<group
position={[0, -0.45, -10]}
castShadow
ref={model}
{...props}
dispose={null}
>
<group rotation={[-Math.PI / 2, 0, 0]} scale={[0.01, 0.01, 0.01]}>
<primitive object={nodes.mixamorigHips} />
<skinnedMesh
wireframe
geometry={nodes.vanguard_Mesh.geometry}
material={materials.VanguardBodyMat}
skeleton={nodes.vanguard_Mesh.skeleton}
/>
<skinnedMesh
geometry={nodes.vanguard_visor.geometry}
material={materials.Vanguard_VisorMat}
skeleton={nodes.vanguard_visor.skeleton}
/>
</group>
</group>
);
}
function getDirectionOffset(w, s, d, a) {
let directionOffset = 0; // w
if (a) {
if (a) {
directionOffset = Math.PI / 4; // w+a
} else if (d) {
directionOffset = -Math.PI / 4; // w+d
}
} else if (s) {
if (a) {
directionOffset = Math.PI / 4 + Math.PI / 2; // s+a
} else if (d) {
directionOffset = -Math.PI / 4 - Math.PI / 2; // s+d
} else {
directionOffset = Math.PI; // s
}
} else if (a) {
directionOffset = Math.PI / 2; // a
} else if (d) {
directionOffset = -Math.PI / 2; // d
}
return directionOffset;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment