event systems

This commit is contained in:
wass08
2026-01-15 11:24:41 +09:00
parent 0c07c482a5
commit c0626662a8
9 changed files with 382 additions and 15 deletions
@@ -1,7 +1,8 @@
import { ItemNode, useRegistry } from "@pascal-app/core";
import { emitter, ItemNode, useRegistry } from "@pascal-app/core";
import { Clone } from "@react-three/drei/core/Clone";
import { useGLTF } from "@react-three/drei/core/Gltf";
import { useRef } from "react";
import { ThreeEvent } from "@react-three/fiber/dist/declarations/src/core/events";
import { useCallback, useRef } from "react";
import { Group } from "three";
export const ItemRenderer = ({ node }: { node: ItemNode }) => {
@@ -14,12 +15,127 @@ export const ItemRenderer = ({ node }: { node: ItemNode }) => {
nodes.cutout.visible = false;
}
// Event handlers
const onPointerDown = useCallback(
(e: ThreeEvent<PointerEvent>) => {
// Only emit events for left-click (button 0)
if (e.button !== 0) return;
const eventData = {
node,
position: [e.point.x, e.point.y, e.point.z] as [number, number, number],
normal: e.face
? ([e.face.normal.x, e.face.normal.y, e.face.normal.z] as [
number,
number,
number
])
: undefined,
stopPropagation: () => e.stopPropagation(),
};
emitter.emit("item:pointerdown", eventData);
},
[node]
);
const onClick = useCallback(
(e: ThreeEvent<PointerEvent>) => {
// Only emit events for left-click (button 0)
if (e.button !== 0) return;
const eventData = {
node,
position: [e.point.x, e.point.y, e.point.z] as [number, number, number],
normal: e.face
? ([e.face.normal.x, e.face.normal.y, e.face.normal.z] as [
number,
number,
number
])
: undefined,
stopPropagation: () => e.stopPropagation(),
};
emitter.emit("item:click", eventData);
},
[node]
);
const onPointerUp = useCallback(
(e: ThreeEvent<PointerEvent>) => {
// Only emit events for left-click (button 0)
if (e.button !== 0) return;
emitter.emit("item:pointerup", {
node,
position: [e.point.x, e.point.y, e.point.z],
normal: e.face
? ([e.face.normal.x, e.face.normal.y, e.face.normal.z] as [
number,
number,
number
])
: undefined,
stopPropagation: () => e.stopPropagation(),
});
},
[node]
);
const onPointerEnter = useCallback(
(e: ThreeEvent<PointerEvent>) => {
emitter.emit("item:enter", {
node,
position: [e.point.x, e.point.y, e.point.z],
normal: e.face
? [e.face.normal.x, e.face.normal.y, e.face.normal.z]
: undefined,
stopPropagation: () => e.stopPropagation(),
});
},
[node]
);
const onPointerLeave = useCallback(
(e: ThreeEvent<PointerEvent>) => {
emitter.emit("item:leave", {
node,
position: [e.point.x, e.point.y, e.point.z],
normal: e.face
? [e.face.normal.x, e.face.normal.y, e.face.normal.z]
: undefined,
stopPropagation: () => e.stopPropagation(),
});
},
[node]
);
const onPointerMove = useCallback(
(e: ThreeEvent<PointerEvent>) => {
emitter.emit("item:move", {
node,
position: [e.point.x, e.point.y, e.point.z],
normal: e.face
? [e.face.normal.x, e.face.normal.y, e.face.normal.z]
: undefined,
stopPropagation: () => e.stopPropagation(),
});
},
[node]
);
return (
<Clone
ref={ref}
object={scene}
position={node.position}
rotation={node.rotation}
onPointerDown={onPointerDown}
onClick={onClick}
onPointerUp={onPointerUp}
onPointerEnter={onPointerEnter}
onPointerLeave={onPointerLeave}
onPointerMove={onPointerMove}
/>
);
};
@@ -1,5 +1,6 @@
import { useRegistry, WallNode } from "@pascal-app/core";
import { useRef } from "react";
import { emitter, useRegistry, WallNode } from "@pascal-app/core";
import { ThreeEvent } from "@react-three/fiber";
import { useCallback, useRef } from "react";
import { Mesh } from "three";
import { NodeRenderer } from "../node-renderer";
@@ -8,8 +9,127 @@ export const WallRenderer = ({ node }: { node: WallNode }) => {
useRegistry(node.id, "wall", ref);
// Event handlers
const onPointerDown = useCallback(
(e: ThreeEvent<PointerEvent>) => {
// Only emit events for left-click (button 0)
if (e.button !== 0) return;
const eventData = {
node,
position: [e.point.x, e.point.y, e.point.z] as [number, number, number],
normal: e.face
? ([e.face.normal.x, e.face.normal.y, e.face.normal.z] as [
number,
number,
number
])
: undefined,
stopPropagation: () => e.stopPropagation(),
};
emitter.emit("wall:pointerdown", eventData);
},
[node]
);
const onClick = useCallback(
(e: ThreeEvent<PointerEvent>) => {
// Only emit events for left-click (button 0)
if (e.button !== 0) return;
const eventData = {
node,
position: [e.point.x, e.point.y, e.point.z] as [number, number, number],
normal: e.face
? ([e.face.normal.x, e.face.normal.y, e.face.normal.z] as [
number,
number,
number
])
: undefined,
stopPropagation: () => e.stopPropagation(),
};
emitter.emit("wall:click", eventData);
},
[node]
);
const onPointerUp = useCallback(
(e: ThreeEvent<PointerEvent>) => {
// Only emit events for left-click (button 0)
if (e.button !== 0) return;
emitter.emit("wall:pointerup", {
node,
position: [e.point.x, e.point.y, e.point.z],
normal: e.face
? ([e.face.normal.x, e.face.normal.y, e.face.normal.z] as [
number,
number,
number
])
: undefined,
stopPropagation: () => e.stopPropagation(),
});
},
[node]
);
const onPointerEnter = useCallback(
(e: ThreeEvent<PointerEvent>) => {
emitter.emit("wall:enter", {
node,
position: [e.point.x, e.point.y, e.point.z],
normal: e.face
? [e.face.normal.x, e.face.normal.y, e.face.normal.z]
: undefined,
stopPropagation: () => e.stopPropagation(),
});
},
[node]
);
const onPointerLeave = useCallback(
(e: ThreeEvent<PointerEvent>) => {
emitter.emit("wall:leave", {
node,
position: [e.point.x, e.point.y, e.point.z],
normal: e.face
? [e.face.normal.x, e.face.normal.y, e.face.normal.z]
: undefined,
stopPropagation: () => e.stopPropagation(),
});
},
[node]
);
const onPointerMove = useCallback(
(e: ThreeEvent<PointerEvent>) => {
emitter.emit("wall:move", {
node,
position: [e.point.x, e.point.y, e.point.z],
normal: e.face
? [e.face.normal.x, e.face.normal.y, e.face.normal.z]
: undefined,
stopPropagation: () => e.stopPropagation(),
});
},
[node]
);
return (
<mesh ref={ref} castShadow receiveShadow>
<mesh
ref={ref}
castShadow
receiveShadow
onPointerDown={onPointerDown}
onPointerUp={onPointerUp}
onPointerEnter={onPointerEnter}
onPointerLeave={onPointerLeave}
onPointerMove={onPointerMove}
onClick={onClick}
>
{/* WallSystem will replace this geometry in the next frame */}
<boxGeometry args={[0, 0, 0]} />
<meshStandardMaterial color="lightgray" />
@@ -1,6 +1,6 @@
"use client";
import { Environment, OrbitControls } from "@react-three/drei";
import { Bvh, Environment, OrbitControls } from "@react-three/drei";
import { Canvas, ThreeToJSXElements } from "@react-three/fiber";
import { LevelSystem, WallSystem } from "@pascal-app/core";
@@ -14,9 +14,11 @@ declare module "@react-three/fiber" {
extend(THREE as any);
interface ViewerProps {}
interface ViewerProps {
children?: React.ReactNode;
}
const Viewer: React.FC<ViewerProps> = () => {
const Viewer: React.FC<ViewerProps> = ({ children }) => {
return (
<Canvas
className={"bg-[#303035]"}
@@ -30,11 +32,15 @@ const Viewer: React.FC<ViewerProps> = () => {
>
<OrbitControls />
<Environment preset="sunset" />
<SceneRenderer />
<Bvh>
<SceneRenderer />
</Bvh>
{/* Default Systems */}
<LevelSystem />
<WallSystem />
{children}
</Canvas>
);
};