prendy
Version:
Make games with prerendered backdrops using babylonjs and repond
185 lines (184 loc) • 8.29 kB
JavaScript
import { Space, Vector3 } from "@babylonjs/core";
import { getShortestAngle, getVectorFromSpeedAndAngle } from "chootils/dist/speedAngleDistance2d";
import { getRefs, getState, setState } from "repond";
import { get2DAngleBetweenDolls, get2DAngleFromDollToSpot } from "../../helpers/prendyUtils/dolls";
import { setGlobalState } from "../../helpers/prendyUtils/global";
import { meta } from "../../meta";
import { vector3ToPoint3d } from "../babylonjs/vectors";
import { getSpotPosition, getSpotRotation } from "../prendyUtils/spots";
// --------------------------------------------------------------
export function setDollPosition(dollName, newPositon) {
const dollRefs = getRefs().dolls[dollName];
if (!dollRefs.meshRef)
return console.warn("NO MESH REF", dollName);
// const prevCollisionsEnabled = dollRefs.canCollide;
dollRefs.canGoThroughWalls = true;
setState({ dolls: { [dollName]: { position: vector3ToPoint3d(newPositon) } } }, () => {
dollRefs.canGoThroughWalls = false;
setState({ dolls: { [dollName]: { position: vector3ToPoint3d(newPositon) } } });
});
}
function springDollPosition(dollName, newPositon) { }
function slideDollPosition(dollName, newPositon) { }
export function setDollRotation(dollName, newRotation) {
const dollRefs = getRefs().dolls[dollName];
if (!dollRefs.meshRef)
return console.warn("no mesh ref", dollName);
dollRefs.meshRef.rotationQuaternion = null;
dollRefs.meshRef.rotation = newRotation; // the spot rotation can be on all x,y and z
// setDollRotationY(dollName, newRotation.y); // currently this will replace the meshes xz rotations TODO have doll 3d rotation state
}
export function lookAtOtherDoll(dollA, dollB // defaults to playerChaarcter
) {
// NOTE could be async
const angle = get2DAngleBetweenDolls(dollB, dollA);
springDollRotationY(dollB, angle);
}
export function dollLooksAtSpot({ place, spot, doll, }) {
const angle = get2DAngleFromDollToSpot(doll, place, spot);
springDollRotationY(doll, angle);
}
export function setDollRotationY(dollName, newRotationY) {
setState({
dolls: {
[dollName]: {
rotationY: newRotationY,
// rotationYGoal: newRotationY, // NOTE setting both can make the goal rotate multiple times, it might not be finding the shortest angle
},
},
});
}
export function springDollRotationY(dollName, newRotation) {
setState({ dolls: { [dollName]: { rotationYGoal: newRotation } } });
}
export function springAddToDollRotationY(dollName, addedRotation, useShortestAngle = false) {
setState((state) => {
const currentAngle = state.dolls[dollName].rotationYGoal;
let newAngle = currentAngle + addedRotation;
if (useShortestAngle) {
newAngle = currentAngle + getShortestAngle(currentAngle, newAngle);
}
return {
dolls: {
[dollName]: {
rotationYGoal: newAngle,
rotationYIsMoving: true,
rotationYMoveMode: "spring",
},
},
};
});
}
export function setDollAnimation(doll, animation) {
setState({ dolls: { [doll]: { nowAnimation: animation } } });
}
export function focusOnDoll(dollName, zoom) {
const { prendyOptions } = meta.assets;
setGlobalState({
focusedDoll: dollName,
slateZoomGoal: zoom !== undefined ? Math.min(zoom, prendyOptions.zoomLevels.max) : prendyOptions.zoomLevels.default,
});
}
export function setDollToSpot({ place, spot, doll: dollName, dontSetRotationState, }) {
const newPositon = getSpotPosition(place, spot);
const newRotation = getSpotRotation(place, spot);
const dollRefs = getRefs().dolls[dollName];
if (!dollRefs.meshRef)
return console.warn("no mesh ref for", dollName);
setDollPosition(dollName, newPositon);
if (!dontSetRotationState)
setDollRotation(dollName, newRotation);
}
// NOTE this isn't really working atm, maybe because falling sortof sets positionMoveMode to "push" ?
// it was the movement speed being slow so stopping the mover from keeping going
export function springDollToSpot({ place, spot, doll: dollName, }) {
const newPositon = getSpotPosition(place, spot);
// const newRotation = getSpotRotation(place, spot);
// FIXME , adding random so the same spot can be set as goal twice
const newPositionPoint = vector3ToPoint3d(newPositon);
newPositionPoint.y += Math.random() * 0.0001;
setState({
dolls: {
[dollName]: {
positionGoal: newPositionPoint,
positionMoveMode: "spring",
// rotationYGoal: useRotation ? newRotation.y : undefined,
},
},
});
}
export function moveDollAt2DAngle(dollName, angle, speed = 3) {
const dollState = getState().dolls[dollName];
const dollRefs = getRefs().dolls[dollName];
const { positionIsMoving, positionMoveMode } = dollState;
if (!positionIsMoving || positionMoveMode !== "push") {
setState({
dolls: { [dollName]: { positionIsMoving: true, positionMoveMode: "push" } },
});
}
let newVelocity = getVectorFromSpeedAndAngle(speed, angle);
setState({ dolls: { [dollName]: { rotationYGoal: angle + 180 } } });
dollRefs.positionMoverRefs.velocity.z = newVelocity.x;
dollRefs.positionMoverRefs.velocity.x = newVelocity.y;
dollRefs.positionMoverRefs.velocity.y = -1.5;
}
export function pushDollRotationY(dollName, direction, speed = 3) {
const dollState = getState().dolls[dollName];
const dollRefs = getRefs().dolls[dollName];
const { rotationYIsMoving, rotationYMoveMode } = dollState;
if (speed === 0) {
setState({ dolls: { [dollName]: { rotationYIsMoving: false } } });
dollRefs.rotationYMoverRefs.velocity = 0;
}
if (!rotationYIsMoving || rotationYMoveMode !== "push") {
setState({
dolls: {
[dollName]: { rotationYIsMoving: true, rotationYMoveMode: "push" },
},
});
}
let newVelocity = direction === "right" ? speed : -speed;
// setState({ dolls: { [dollName]: { rotationYGoal: angle + 180 } } });
dollRefs.rotationYMoverRefs.velocity = newVelocity;
// dollRefs.rotationYMoverRefs.velocity.z = newVelocity.x;
// dollRefs.rotationYMoverRefs.velocity.x = newVelocity.y;
// dollRefs.rotationYMoverRefs.velocity.y = -1.5;
}
export function hideDoll(dollName, shouldHide = true) {
setState({ dolls: { [dollName]: { isVisible: !shouldHide } } }, () => { });
}
export function toggleDollMeshes(dollName, toggledMeshes) {
// IDEA have dollState toggledMeshes and rules to auto enable the meshes
// const { left_shoe, right_shoe, long_teeth } = otherMeshes;
// const otherMeshes = getRefs().dolls[dollName].otherMeshes;
// const modelName = getModelNameFromDoll(dollName);
// const modelInfo = modelInfoByName[modelName as unknown as ModelName];
// const typedMeshNames = modelInfo.meshNames as unknown as MeshNamesFromDoll<T_DollName>[];
// TODO move this into a rule listening to toggledMeshes state
// forEach(typedMeshNames, (meshName) => {
// const newToggle = toggledMeshes[meshName];
// const theMesh = otherMeshes[meshName];
// if (theMesh && newToggle !== undefined) theMesh.setEnabled(newToggle!);
// });
// NOTE could update to set properties in a loop to avoid spreading
setState((state) => ({
dolls: { [dollName]: { toggledMeshes: { ...state.dolls[dollName].toggledMeshes, ...toggledMeshes } } },
}));
}
// TODO move to utils
// (or maybe rename utils to getters, and the rest are in events)
export function getDollBonePosition({ doll, model, bone, }) {
// ModelNameFromDoll
const dollRefs = getRefs().dolls.dino;
const dollBone = dollRefs.assetRefs?.bones?.[bone];
if (dollRefs.meshRef) {
dollRefs.meshRef.scaling = new Vector3(1.95, 1.95, -1.95);
// dollRefs.canCollide = true;
}
if (dollBone && dollRefs.meshRef) {
let position = dollBone.getPosition(Space.WORLD, dollRefs.meshRef);
return position || Vector3.Zero();
}
return Vector3.Zero();
}
// }