blockly3d/src/components/ObjectViewInternal.tsx

66 lines
2.7 KiB
TypeScript

import { observer } from "mobx-react-lite";
import type { ObjectType, RuntimeObjectInstance } from "../types";
import { forwardRef, useMemo } from "react";
import type { Group } from "three";
import { Instance, Instances } from "@react-three/drei";
import type { ThreeEvent } from "@react-three/fiber";
import { state } from "../state";
import { TrimeshCollider } from "@react-three/rapier";
import { SyncRigidBody } from "./SyncRigidBody";
import { runInAction } from "mobx";
import { buildObjectTrimesh } from "../utils/graphics/mesh";
type ObjectViewInternalProps = {
object: Omit<RuntimeObjectInstance, 'typeId'>;
objectType: ObjectType;
onClick?: (e: ThreeEvent<MouseEvent>) => void;
}
export const ObjectViewInternal = observer(forwardRef<Group | null, ObjectViewInternalProps>(
function ({ object, objectType, onClick }, ref) {
const trimeshArgs = useMemo(
() => buildObjectTrimesh(objectType, state.world.data.voxelTypes),
// eslint-disable-next-line react-hooks/exhaustive-deps
[objectType.id]
);
return (
<SyncRigidBody
colliders={false}
gravityScale={object.physics ? 1 : 0.1}
onSync={(data) => {
runInAction(() => {
const obj = state.game?.scene.objects[object.id];
if (obj) {
obj.position = data.position;
obj.rotation = data.rotation;
obj.linearVelocity = data.linearVelocity;
obj.radialVelocity = data.radialVelocity;
}
});
}}
>
<group
ref={ref}
name={`${object.id} (${objectType.id} instance)`}
position={object.position}
rotation={object.rotation}
scale={object.scale}
onClick={onClick}
>
{
object.cache.voxelGroups.map((vg) =>
<Instances key={vg.id} limit={vg.positions.length}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={vg.color} opacity={vg.opacity} transparent={vg.opacity < 1} />
{vg.positions.map((pos, i) => <Instance key={i} position={pos} />)}
</Instances>
)
}
{trimeshArgs && <TrimeshCollider args={trimeshArgs} />}
</group>
</SyncRigidBody>
);
}
));