diff --git a/src/components/Yatai/YataiStage.tsx b/src/components/Yatai/YataiStage.tsx
index cd25219..d7d79c6 100644
--- a/src/components/Yatai/YataiStage.tsx
+++ b/src/components/Yatai/YataiStage.tsx
@@ -1,6 +1,7 @@
import { Physics } from "@react-three/cannon";
import { Canvas } from "@react-three/fiber";
import { memo } from "react";
+import { initialTargets } from "../../const/target";
import { CameraController } from "./CameraController";
import { YataiFoundation } from "./YataiFoundation";
import styles from "./YataiStage.module.css";
@@ -28,9 +29,12 @@ export const YataiStage = memo(() => {
-
-
-
+ {initialTargets.map((target) => (
+
+ ))}
diff --git a/src/components/Yatai/YataiTarget.tsx b/src/components/Yatai/YataiTarget.tsx
index f44f56d..77a00f1 100644
--- a/src/components/Yatai/YataiTarget.tsx
+++ b/src/components/Yatai/YataiTarget.tsx
@@ -1,6 +1,6 @@
import { useBox } from "@react-three/cannon";
import type { ThreeElements } from "@react-three/fiber";
-import { useEffect, useState } from "react";
+import { useEffect, useMemo, useState } from "react";
import type {
BufferGeometry,
Material,
@@ -9,25 +9,56 @@ import type {
Object3DEventMap,
} from "three";
import { randFloat } from "three/src/math/MathUtils.js";
+import { type TargetProperty, initialTargets } from "../../const/target";
import { useSocketReceiver } from "../../hooks/useSocketReceiver";
import { useSocketSender } from "../../hooks/useSocketSender";
+import { useTargetStatusStore } from "../../store";
import { message_type } from "../../type/schema";
import {
type ActionSchema,
MessageType,
type Target,
} from "../../type/shooting";
+import { TargetStatus } from "../../type/target";
+
+const getTargetProperty = (pos: [number, number, number]): TargetProperty => {
+ const target = initialTargets.find(
+ (target) =>
+ target.pos.x === pos[0] &&
+ target.pos.y === pos[1] &&
+ target.pos.z === pos[2],
+ );
+ return (
+ target || {
+ index: -1,
+ pos: { x: 0, y: 0, z: 0 },
+ size: { x: 0, y: 0, z: 0 },
+ }
+ );
+};
export const YataiTarget = (props: ThreeElements["mesh"]) => {
const { sendData } = useSocketSender();
const { onMessage } = useSocketReceiver();
+
const position = props.position as [number, number, number];
+ const property = getTargetProperty(position);
+ const { targetStatus, updateTargetStatus } = useTargetStatusStore(
+ (state) => ({
+ targetStatus: state.targetStatus,
+ updateTargetStatus: state.updateTargetStatus,
+ }),
+ );
+
+ //
+ const size: [number, number, number] = useMemo(() => {
+ return [property.size.x, property.size.y, property.size.z];
+ }, [property.size]);
- const args: [number, number, number] = [0.7, 2, 0.7];
const [ref, api] = useBox(() => ({
mass: 1,
position: position,
- args: args,
+ args: size,
}));
useEffect(() => {
@@ -49,18 +80,30 @@ export const YataiTarget = (props: ThreeElements["mesh"]) => {
useEffect(() => {
if (!target) return;
if (
- target.x * 8 > position[0] - args[0] / 2 &&
- target.x * 8 < position[0] + args[0] / 2 &&
- target.y * 8 > position[1] - args[1] / 2 - 2 &&
- target.y * 8 < position[1] + args[1] / 2 - 2
+ targetStatus[property.index] === TargetStatus.Live &&
+ target.x * 8 > position[0] - size[0] / 2 &&
+ target.x * 8 < position[0] + size[0] / 2 &&
+ target.y * 8 > position[1] - size[1] / 2 - 2 &&
+ target.y * 8 < position[1] + size[1] / 2 - 2
) {
api.applyImpulse(
[randFloat(-2, 2), 4, 8],
[randFloat(-1, 1), randFloat(-1, 1), randFloat(-1, 1)],
);
+ updateTargetStatus(property.index, TargetStatus.Hit);
sendData(message_type.hit, uuid, { alpha: 0, beta: 0 });
}
- }, [uuid, target, position, api, sendData]);
+ }, [
+ target,
+ targetStatus,
+ property,
+ position,
+ size,
+ api,
+ sendData,
+ updateTargetStatus,
+ uuid,
+ ]);
return (
{
castShadow
receiveShadow
>
-
+
);
diff --git a/src/const/target.ts b/src/const/target.ts
new file mode 100644
index 0000000..893da0c
--- /dev/null
+++ b/src/const/target.ts
@@ -0,0 +1,18 @@
+export type TargetProperty = {
+ index: number;
+ pos: ThreeDim;
+ size: ThreeDim;
+};
+
+export type ThreeDim = {
+ x: number;
+ y: number;
+ z: number;
+};
+
+export const initialTargets: TargetProperty[] = [
+ // 本来posはy=1.8だが0.1だけ埋め込むことで反動を利用したいい感じのアニメーションを出している
+ { index: 0, pos: { x: -3, y: 1.7, z: 0 }, size: { x: 0.7, y: 1.8, z: 0.7 } },
+ { index: 1, pos: { x: 0, y: 1.7, z: 0 }, size: { x: 0.7, y: 1.8, z: 0.7 } },
+ { index: 2, pos: { x: 3, y: 1.7, z: 0 }, size: { x: 0.7, y: 1.8, z: 0.7 } },
+];
diff --git a/src/store/index.ts b/src/store/index.ts
index 725c6ae..c28cd5d 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -1,3 +1,4 @@
export { useSocketRefStore } from "./useSocketRefStore";
export { useUUIDStore } from "./useUUIDStore";
export { useRoomIdStore } from "./useRoomIdStore";
+export { useTargetStatusStore } from "./useTargetStatusStore";
diff --git a/src/store/useTargetStatusStore.ts b/src/store/useTargetStatusStore.ts
new file mode 100644
index 0000000..dcda4c1
--- /dev/null
+++ b/src/store/useTargetStatusStore.ts
@@ -0,0 +1,21 @@
+import { create } from "zustand";
+import { TargetStatus } from "../type/target";
+
+type State = {
+ targetStatus: TargetStatus[];
+};
+
+type Action = {
+ updateTargetStatus: (index: number, status: TargetStatus) => void;
+};
+
+export const useTargetStatusStore = create((set) => ({
+ // left, center, right
+ targetStatus: [TargetStatus.Live, TargetStatus.Live, TargetStatus.Live],
+ updateTargetStatus: (index: number, status: TargetStatus) =>
+ set((state) => {
+ const targetStatus = [...state.targetStatus];
+ targetStatus[index] = status;
+ return { targetStatus };
+ }),
+}));
diff --git a/src/type/target.ts b/src/type/target.ts
new file mode 100644
index 0000000..994d42e
--- /dev/null
+++ b/src/type/target.ts
@@ -0,0 +1,4 @@
+export enum TargetStatus {
+ Live = "live",
+ Hit = "hit",
+}