136 lines
3.2 KiB
TypeScript
136 lines
3.2 KiB
TypeScript
import { TLGeoShape, TLShape, Vec, VecLike } from "tldraw";
|
|
|
|
export const GRAVITY = { x: 0.0, y: 98 };
|
|
export const DEFAULT_RESTITUTION = 0;
|
|
export const DEFAULT_FRICTION = 0.5;
|
|
|
|
export function isRigidbody(color: string) {
|
|
return !color || color === "black" ? false : true;
|
|
}
|
|
export function getGravityFromColor(color: string) {
|
|
return color === 'grey' ? 0 : 1
|
|
}
|
|
export function getRestitutionFromColor(color: string) {
|
|
return color === "orange" ? 0.9 : 0;
|
|
}
|
|
export function getFrictionFromColor(color: string) {
|
|
return color === "blue" ? 0.1 : 0.8;
|
|
}
|
|
export const MATERIAL = {
|
|
defaultRestitution: 0,
|
|
defaultFriction: 0.1,
|
|
};
|
|
export const CHARACTER = {
|
|
up: { x: 0.0, y: -1.0 },
|
|
additionalMass: 20,
|
|
maxSlopeClimbAngle: 1,
|
|
slideEnabled: true,
|
|
minSlopeSlideAngle: 0.9,
|
|
applyImpulsesToDynamicBodies: true,
|
|
autostepHeight: 5,
|
|
autostepMaxClimbAngle: 1,
|
|
snapToGroundDistance: 3,
|
|
maxMoveSpeedX: 100,
|
|
moveAcceleration: 600,
|
|
moveDeceleration: 500,
|
|
jumpVelocity: 300,
|
|
gravityMultiplier: 10,
|
|
};
|
|
|
|
|
|
type ShapeTransform = {
|
|
x: number;
|
|
y: number;
|
|
width: number;
|
|
height: number;
|
|
rotation: number;
|
|
parentGroupShape?: TLShape | undefined
|
|
}
|
|
|
|
// Define rotatePoint as a standalone function
|
|
const rotatePoint = (cx: number, cy: number, x: number, y: number, angle: number) => {
|
|
const cos = Math.cos(angle);
|
|
const sin = Math.sin(angle);
|
|
return {
|
|
x: cos * (x - cx) - sin * (y - cy) + cx,
|
|
y: sin * (x - cx) + cos * (y - cy) + cy,
|
|
};
|
|
}
|
|
|
|
export const cornerToCenter = ({
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
rotation,
|
|
parentGroupShape
|
|
}: ShapeTransform): { x: number; y: number } => {
|
|
const centerX = x + width / 2;
|
|
const centerY = y + height / 2;
|
|
if (parentGroupShape) {
|
|
return rotatePoint(parentGroupShape.x, parentGroupShape.y, centerX, centerY, rotation);
|
|
}
|
|
return rotatePoint(x, y, centerX, centerY, rotation);
|
|
|
|
}
|
|
|
|
export const centerToCorner = ({
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
rotation,
|
|
}: ShapeTransform): { x: number; y: number } => {
|
|
|
|
const cornerX = x - width / 2;
|
|
const cornerY = y - height / 2;
|
|
|
|
return rotatePoint(x, y, cornerX, cornerY, rotation);
|
|
}
|
|
|
|
export const getDisplacement = (
|
|
velocity: VecLike,
|
|
acceleration: VecLike,
|
|
timeStep: number,
|
|
speedLimitX: number,
|
|
decelerationX: number,
|
|
): VecLike => {
|
|
let newVelocityX =
|
|
acceleration.x === 0 && velocity.x !== 0
|
|
? Math.max(Math.abs(velocity.x) - decelerationX * timeStep, 0) *
|
|
Math.sign(velocity.x)
|
|
: velocity.x + acceleration.x * timeStep;
|
|
|
|
newVelocityX =
|
|
Math.min(Math.abs(newVelocityX), speedLimitX) * Math.sign(newVelocityX);
|
|
|
|
const averageVelocityX = (velocity.x + newVelocityX) / 2;
|
|
const x = averageVelocityX * timeStep;
|
|
const y =
|
|
velocity.y * timeStep + 0.5 * acceleration.y * timeStep ** 2;
|
|
|
|
return { x, y }
|
|
}
|
|
|
|
export const convertVerticesToFloat32Array = (
|
|
vertices: Vec[],
|
|
width: number,
|
|
height: number,
|
|
) => {
|
|
const vec2Array = new Float32Array(vertices.length * 2);
|
|
const hX = width / 2;
|
|
const hY = height / 2;
|
|
|
|
for (let i = 0; i < vertices.length; i++) {
|
|
vec2Array[i * 2] = vertices[i].x - hX;
|
|
vec2Array[i * 2 + 1] = vertices[i].y - hY;
|
|
}
|
|
|
|
return vec2Array;
|
|
}
|
|
|
|
export const shouldConvexify = (shape: TLShape): boolean => {
|
|
return !(
|
|
shape.type === "geo" && (shape as TLGeoShape).props.geo === "rectangle"
|
|
);
|
|
} |