update: require replacement placement before repair completion
This commit is contained in:
@@ -1,7 +1,16 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import * as THREE from "three";
|
||||
import { RepairObjectModel } from "@/components/three/gameplay/RepairObjectModel";
|
||||
import { RepairPromptVideo } from "@/components/three/gameplay/RepairPromptVideo";
|
||||
import { GrabbableObject } from "@/components/three/interaction/GrabbableObject";
|
||||
import { TriggerObject } from "@/components/three/interaction/TriggerObject";
|
||||
import type { RepairMissionConfig } from "@/data/gameplay/repairMissions";
|
||||
import type { Vector3Tuple } from "@/types/three/three";
|
||||
|
||||
const INSTALL_TARGET_POSITION: Vector3Tuple = [0, 0.8, 0];
|
||||
const INSTALL_TARGET_VECTOR = new THREE.Vector3(...INSTALL_TARGET_POSITION);
|
||||
const REPLACEMENT_START_POSITION: Vector3Tuple = [0, 1.35, 1.8];
|
||||
const REPAIR_INSTALL_RADIUS = 1.1;
|
||||
|
||||
interface RepairRepairingStepProps {
|
||||
config: RepairMissionConfig;
|
||||
@@ -12,41 +21,68 @@ export function RepairRepairingStep({
|
||||
config,
|
||||
onRepair,
|
||||
}: RepairRepairingStepProps): React.JSX.Element {
|
||||
const [isReplacementPlaced, setIsReplacementPlaced] = useState(false);
|
||||
const replacementPart = config.replacementParts[0];
|
||||
const replacementModelPath = replacementPart?.modelPath ?? config.modelPath;
|
||||
const replacementLabel = replacementPart?.label ?? config.label;
|
||||
const installColor = isReplacementPlaced ? "#22c55e" : "#f97316";
|
||||
const installFillColor = isReplacementPlaced ? "#86efac" : "#fed7aa";
|
||||
|
||||
const handleReplacementPosition = useCallback((position: THREE.Vector3) => {
|
||||
const isPlaced =
|
||||
position.distanceTo(INSTALL_TARGET_VECTOR) <= REPAIR_INSTALL_RADIUS;
|
||||
setIsReplacementPlaced((current) =>
|
||||
current === isPlaced ? current : isPlaced,
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<group>
|
||||
<TriggerObject
|
||||
position={[0, 0.8, 0]}
|
||||
position={INSTALL_TARGET_POSITION}
|
||||
colliders="ball"
|
||||
label={`Installer ${replacementLabel}`}
|
||||
onTrigger={onRepair}
|
||||
label={
|
||||
isReplacementPlaced
|
||||
? `Installer ${replacementLabel}`
|
||||
: `Approcher ${replacementLabel}`
|
||||
}
|
||||
onTrigger={() => {
|
||||
if (!isReplacementPlaced) return;
|
||||
|
||||
onRepair();
|
||||
}}
|
||||
>
|
||||
<mesh>
|
||||
<torusGeometry args={[0.95, 0.045, 12, 96]} />
|
||||
<meshBasicMaterial color="#22c55e" transparent opacity={0.85} />
|
||||
<meshBasicMaterial color={installColor} transparent opacity={0.85} />
|
||||
</mesh>
|
||||
<mesh position={[0, 0.02, 0]} rotation={[Math.PI / 2, 0, 0]}>
|
||||
<ringGeometry args={[0.15, 0.9, 96]} />
|
||||
<meshBasicMaterial color="#86efac" transparent opacity={0.35} />
|
||||
<meshBasicMaterial
|
||||
color={installFillColor}
|
||||
transparent
|
||||
opacity={0.35}
|
||||
/>
|
||||
</mesh>
|
||||
</TriggerObject>
|
||||
|
||||
<group
|
||||
<GrabbableObject
|
||||
position={[
|
||||
config.case.position[0],
|
||||
config.case.position[1] + 1.2,
|
||||
config.case.position[2],
|
||||
config.case.position[0] + REPLACEMENT_START_POSITION[0],
|
||||
config.case.position[1] + REPLACEMENT_START_POSITION[1],
|
||||
config.case.position[2] + REPLACEMENT_START_POSITION[2],
|
||||
]}
|
||||
colliders="ball"
|
||||
handControlled
|
||||
label={`Prendre ${replacementLabel}`}
|
||||
onPositionChange={handleReplacementPosition}
|
||||
>
|
||||
<RepairObjectModel
|
||||
label={replacementLabel}
|
||||
modelPath={replacementModelPath}
|
||||
scale={0.35}
|
||||
/>
|
||||
</group>
|
||||
</GrabbableObject>
|
||||
|
||||
<RepairPromptVideo src={config.interactUiPath} position={[0, 2.3, 0]} />
|
||||
</group>
|
||||
|
||||
@@ -36,6 +36,7 @@ interface GrabbableObjectProps {
|
||||
colliders?: ColliderShape;
|
||||
label?: string;
|
||||
handControlled?: boolean;
|
||||
onPositionChange?: (position: THREE.Vector3) => void;
|
||||
}
|
||||
|
||||
const grabDebugParams = {
|
||||
@@ -123,6 +124,7 @@ export function GrabbableObject({
|
||||
colliders = GRAB_DEFAULT_COLLIDERS,
|
||||
label = GRAB_DEFAULT_LABEL,
|
||||
handControlled = false,
|
||||
onPositionChange,
|
||||
}: GrabbableObjectProps): React.JSX.Element {
|
||||
const camera = useThree((state) => state.camera);
|
||||
const { hands } = useHandTrackingSnapshot();
|
||||
@@ -172,6 +174,7 @@ export function GrabbableObject({
|
||||
|
||||
const t = rbRef.current.translation();
|
||||
_currentPos.set(t.x, t.y, t.z);
|
||||
onPositionChange?.(_currentPos);
|
||||
|
||||
if (fistHand) {
|
||||
const handCenter = getHandCenterPoint(fistHand);
|
||||
|
||||
@@ -406,7 +406,7 @@ Overlays actuels :
|
||||
|
||||
## Prochaines étapes
|
||||
|
||||
La prochaine étape naturelle est de remplacer le trigger simple d'installation par des interactions de réparation plus profondes, comme choisir des pièces dans la mallette, les saisir et valider le bon remplacement sur un module cassé.
|
||||
La prochaine étape naturelle est d'étendre l'interaction de réparation avec une sélection de pièces depuis la mallette et une validation plus stricte du bon remplacement pour chaque module cassé.
|
||||
`;
|
||||
|
||||
export const featuresFr = `# Fonctionnalités implémentées
|
||||
@@ -442,7 +442,7 @@ Ce document liste les fonctionnalités présentes dans le code actuel.
|
||||
|
||||
- \`RepairGame\` de production réutilisable monté pour les états de mission \`bike\`, \`pylone\` et \`ferme\`
|
||||
- Configuration de mission partagée via \`src/data/gameplay/repairMissions.ts\`
|
||||
- Flow repair-game avec \`waiting -> inspected -> fragmented -> scanning -> repairing -> done\`, prompts \`.webm\`, apparition/ouverture de la mallette, touche \`E\`, hold deux poings, transition de modèle explosé, visuels de scan, pièce de remplacement et trigger d'installation
|
||||
- Flow repair-game avec \`waiting -> inspected -> fragmented -> scanning -> repairing -> done\`, prompts \`.webm\`, apparition/ouverture de la mallette, touche \`E\`, hold deux poings, transition de modèle explosé, visuels de scan, placement d'une pièce de remplacement grabbable et validation d'installation
|
||||
|
||||
## Audio
|
||||
|
||||
|
||||
Reference in New Issue
Block a user