From df3e6033a708cbd12a7700764a448fa0662def4a Mon Sep 17 00:00:00 2001 From: LucaHaverty Date: Tue, 9 Jul 2024 11:46:56 -0700 Subject: [PATCH 1/9] Modify saved scoring zones with zone config panels --- fission/src/Synthesis.tsx | 8 +- .../systems/preferences/PreferenceTypes.ts | 25 +- .../synthesis_brain/SynthesisBrain.ts | 11 +- fission/src/ui/components/MainHUD.tsx | 24 +- .../modals/configuring/ChangeInputsModal.tsx | 4 +- .../configuring/scoring/ScoringZonesPanel.tsx | 266 ++++++------------ .../configuring/scoring/ZoneConfigPanel.tsx | 69 +++-- 7 files changed, 159 insertions(+), 248 deletions(-) diff --git a/fission/src/Synthesis.tsx b/fission/src/Synthesis.tsx index 65fa57c87d..73710ecb37 100644 --- a/fission/src/Synthesis.tsx +++ b/fission/src/Synthesis.tsx @@ -55,7 +55,7 @@ import { AddRobotsModal, AddFieldsModal, SpawningModal } from "@/modals/spawning import ImportMirabufModal from "@/modals/mirabuf/ImportMirabufModal.tsx" import ImportLocalMirabufModal from "@/modals/mirabuf/ImportLocalMirabufModal.tsx" import ResetAllInputsModal from "./ui/modals/configuring/ResetAllInputsModal.tsx" -import Skybox from './ui/components/Skybox.tsx'; +import Skybox from './ui/components/Skybox.tsx' const DEFAULT_MIRA_PATH = "/api/mira/Robots/Team 2471 (2018)_v7.mira" @@ -201,7 +201,7 @@ const initialModals = [ , , , -] +] const initialPanels: ReactElement[] = [ , @@ -210,8 +210,8 @@ const initialPanels: ReactElement[] = [ , , , - , - , + , + , ] export default Synthesis diff --git a/fission/src/systems/preferences/PreferenceTypes.ts b/fission/src/systems/preferences/PreferenceTypes.ts index eff4cf6cbe..77f04844bb 100644 --- a/fission/src/systems/preferences/PreferenceTypes.ts +++ b/fission/src/systems/preferences/PreferenceTypes.ts @@ -1,4 +1,4 @@ -import { Vector3Tuple, Vector4Tuple } from "three" +import { Vector3Tuple } from "three" import { InputScheme } from "../input/DefaultInputs" export type GlobalPreference = @@ -26,12 +26,12 @@ export const DefaultGlobalPreferences: { [key: string]: Object } = { } export type IntakePreferences = { - location: Vector3Tuple, + location: [number, number, number], diameter: number } export type EjectorPreferences = { - location: Vector3Tuple, + location: [number, number, number], ejectorVelocity: number } @@ -41,18 +41,17 @@ export type RobotPreferences = { ejector: EjectorPreferences } -export type Alliance = "Blue" | "Red" export type ScoringZonePreferences = { - name: string, - alliance: Alliance, - parent: string, - points: number, - destroyGamepiece: boolean, - persistentPoints: boolean, - localPosition: Vector3Tuple, - localRotation: Vector4Tuple, - localScale: Vector3Tuple + name: string + alliance: "red" | "blue" + parent: string + points: number + destroyGamepiece: boolean + persistentPoints: boolean + position: [number, number, number] + rotation: [number, number, number, number] + scale: [number, number, number] } export type FieldPreferences = { diff --git a/fission/src/systems/simulation/synthesis_brain/SynthesisBrain.ts b/fission/src/systems/simulation/synthesis_brain/SynthesisBrain.ts index 0e84bce617..17bafa7493 100644 --- a/fission/src/systems/simulation/synthesis_brain/SynthesisBrain.ts +++ b/fission/src/systems/simulation/synthesis_brain/SynthesisBrain.ts @@ -37,6 +37,9 @@ class SynthesisBrain extends Brain { // The total number of robots spawned private static _currentRobotIndex: number = 0 + // A list of all the fields spawned + public static fieldsSpawned: string[] = [] + public constructor(mechanism: Mechanism, assemblyName: string) { super(mechanism) @@ -65,6 +68,7 @@ class SynthesisBrain extends Brain { } else { this.configureField() + SynthesisBrain.fieldsSpawned.push(assemblyName) } SynthesisBrain._currentRobotIndex++ @@ -82,7 +86,7 @@ class SynthesisBrain extends Brain { public clearControls(): void { let index = SynthesisBrain.robotsSpawned.indexOf(`[${this._assemblyIndex}] ${this._assemblyName}`); - SynthesisBrain.robotsSpawned.splice(index, 1); + SynthesisBrain.robotsSpawned.splice(index, 1) } // Creates an instance of ArcadeDriveBehavior and automatically configures it @@ -208,10 +212,9 @@ class SynthesisBrain extends Brain { } private configureField() { - const fieldPrefs = PreferencesSystem.getFieldPreferences(this._assemblyName) - console.log("Loaded field prefs " + fieldPrefs) + //const fieldPrefs = PreferencesSystem.getFieldPreferences(this._assemblyName) - /** Put any scoring zone or other field configuration here */ + /** Put any field configuration here */ } private static parseInputs(rawInputs: InputScheme) { diff --git a/fission/src/ui/components/MainHUD.tsx b/fission/src/ui/components/MainHUD.tsx index f634d80173..0b0cf0ca83 100644 --- a/fission/src/ui/components/MainHUD.tsx +++ b/fission/src/ui/components/MainHUD.tsx @@ -5,7 +5,7 @@ import { BiMenuAltLeft } from "react-icons/bi" import { GrFormClose } from "react-icons/gr" import { GiSteeringWheel } from "react-icons/gi" import { HiDownload } from "react-icons/hi" -import { IoBug, IoGameControllerOutline, IoPeople } from "react-icons/io5" +import { IoBasket, IoBug, IoGameControllerOutline, IoPeople } from "react-icons/io5" import { useModalControlContext } from "@/ui/ModalContext" import { usePanelControlContext } from "@/ui/PanelContext" import { motion } from "framer-motion" @@ -129,20 +129,6 @@ const MainHUD: React.FC = () => { onClick={() => openModal("import-local-mirabuf")} /> } onClick={TestGodMode} /> - 5"} - icon={} - onClick={() => - (PreferencesSystem.getRobotPreferences("Team 2471 (2018) v7").intake.diameter = 5) - } - /> - 2"} - icon={} - onClick={() => - (PreferencesSystem.getRobotPreferences("Team 2471 (2018) v7").intake.diameter = 2) - } - /> } @@ -193,7 +179,13 @@ const MainHUD: React.FC = () => { new TransformGizmo("translate").setMode = "rotate" }} /> - + } + onClick={() => { + openPanel("scoring-zones") + }} + /> {userInfo ? ( void + closePanel: (paneId: string) => void deleteZone: () => void + saveZones: () => void } -const ScoringZoneRow: React.FC = ({ zone, openPanel, deleteZone }) => { +export class SelectedZone { + public static zone: ScoringZonePreferences; +} + +const ScoringZoneRow: React.FC = ({ zone, openPanel, closePanel, deleteZone, saveZones }) => { return ( @@ -26,179 +34,43 @@ const ScoringZoneRow: React.FC = ({ zone, openPanel, delete - @@ -116,9 +121,7 @@ const ConfigureShotTrajectoryPanel: React.FC = ({ panelId, openL defaultValue={selectedEjector.ejectorVelocity} label="Velocity" format={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} - onChange={(vel: number) => - setEjectorVelocity(vel) - } + onChange={(vel: number) => setEjectorVelocity(vel)} step={0.01} /> diff --git a/fission/src/ui/panels/configuring/scoring/ScoringZonesPanel.tsx b/fission/src/ui/panels/configuring/scoring/ScoringZonesPanel.tsx index 4a2bc46a6f..a277d51c08 100644 --- a/fission/src/ui/panels/configuring/scoring/ScoringZonesPanel.tsx +++ b/fission/src/ui/panels/configuring/scoring/ScoringZonesPanel.tsx @@ -1,4 +1,4 @@ -import { useState } from "react" +import { useEffect, useState } from "react" import { usePanelControlContext } from "@/ui/PanelContext" import Button from "@/components/Button" import Label, { LabelSize } from "@/components/Label" @@ -12,7 +12,6 @@ import SynthesisBrain from "@/systems/simulation/synthesis_brain/SynthesisBrain" type ScoringZoneRowProps = { zone: ScoringZonePreferences openPanel: (id: string) => void - closePanel: (paneId: string) => void deleteZone: () => void saveZones: () => void } @@ -21,7 +20,7 @@ export class SelectedZone { public static zone: ScoringZonePreferences; } -const ScoringZoneRow: React.FC = ({ zone, openPanel, closePanel, deleteZone, saveZones }) => { +const ScoringZoneRow: React.FC = ({ zone, openPanel, deleteZone, saveZones }) => { return ( @@ -39,7 +38,6 @@ const ScoringZoneRow: React.FC = ({ zone, openPanel, closeP onClick={() => { SelectedZone.zone = zone saveZones() - closePanel("scoring-zones") openPanel("zone-config") }} /> @@ -72,6 +70,10 @@ const ScoringZonesPanel: React.FC = ({ panelId, openLocation, si } } + useEffect(() => { + closePanel("zone-config") + },[]) + return ( = ({ panelId, openLocation, si key={i} zone={z} openPanel={openPanel} - closePanel={closePanel} deleteZone={() => { setZones(zones.filter((_, idx) => idx !== i)) }} @@ -119,7 +120,6 @@ const ScoringZonesPanel: React.FC = ({ panelId, openLocation, si zones.push(newZone) SelectedZone.zone = newZone saveZones() - closePanel(panelId) openPanel("zone-config") }} className="px-36 w-full" diff --git a/fission/src/ui/panels/configuring/scoring/ZoneConfigPanel.tsx b/fission/src/ui/panels/configuring/scoring/ZoneConfigPanel.tsx index b84424fa93..1fa41b3f87 100644 --- a/fission/src/ui/panels/configuring/scoring/ZoneConfigPanel.tsx +++ b/fission/src/ui/panels/configuring/scoring/ZoneConfigPanel.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react" +import { useEffect, useRef, useState } from "react" import Input from "@/components/Input" import Panel, { PanelPropsImpl } from "@/components/Panel" import Button from "@/components/Button" @@ -10,9 +10,13 @@ import { usePanelControlContext } from "@/ui/PanelContext" import Stack, { StackDirection } from "@/ui/components/Stack" import SelectButton from "@/ui/components/SelectButton" import Jolt from "@barclah/jolt-physics" +import TransformGizmos from "@/ui/components/TransformGizmos" +import * as THREE from "three" const ZoneConfigPanel: React.FC = ({ panelId, openLocation, sidePadding }) => { - const { openPanel } = usePanelControlContext() + const { openPanel, closePanel } = usePanelControlContext() + + const transformGizmoRef = useRef() const [name, setName] = useState(SelectedZone.zone.name) const [alliance, setAlliance] = useState<"red" | "blue">(SelectedZone.zone.alliance) @@ -24,8 +28,53 @@ const ZoneConfigPanel: React.FC = ({ panelId, openLocation, side const [transformMode, setTransformMode] = useState<"translate" | "rotate" | "scale">("translate") useEffect(() => { - // TODO: create transform gizmo - }) + closePanel("scoring-zones") + + configureGizmo("translate") + },[]) + + const configureGizmo = (mode: "translate" | "rotate" | "scale") => { + // Remove the old transform gizmo + if (transformGizmoRef.current) transformGizmoRef.current.RemoveGizmos() + + transformGizmoRef.current = new TransformGizmos( + new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0xffffff })) + ) + transformGizmoRef.current.AddMeshToScene() + + transformGizmoRef.current.CreateGizmo(mode, 1.5) + + const position = SelectedZone.zone.position + const rotation = SelectedZone.zone.rotation + const scale = SelectedZone.zone.scale + + transformGizmoRef.current.mesh.position.set(position[0], position[1], position[2]) + transformGizmoRef.current.mesh.rotation.setFromQuaternion( + new THREE.Quaternion(rotation[0], rotation[1], rotation[2], rotation[3]) + ) + transformGizmoRef.current.mesh.scale.set(scale[0], scale[1], scale[2]) + } + + const saveSettings = () => { + SelectedZone.zone.name = name + SelectedZone.zone.alliance = alliance + SelectedZone.zone.parent = parent + SelectedZone.zone.points = points + SelectedZone.zone.destroyGamepiece = destroy + SelectedZone.zone.persistentPoints = persistent + + if (transformGizmoRef.current != undefined) { + const position = transformGizmoRef.current.mesh.position + const rotation = transformGizmoRef.current.mesh.quaternion + const scale = transformGizmoRef.current.mesh.scale + + SelectedZone.zone.position = [position.x, position.y, position.z] + SelectedZone.zone.rotation = [rotation.x, rotation.y, rotation.z, rotation.w] + SelectedZone.zone.scale = [scale.x, scale.y, scale.z] + } + + PreferencesSystem.savePreferences() + } return ( = ({ panelId, openLocation, side openLocation={openLocation} sidePadding={sidePadding} onAccept={() => { - SelectedZone.zone.name = name - SelectedZone.zone.alliance = alliance - SelectedZone.zone.parent = parent - SelectedZone.zone.points = points - SelectedZone.zone.destroyGamepiece = destroy - SelectedZone.zone.persistentPoints = persistent - - // TODO: Yoink transform info from the transform gizmo - - PreferencesSystem.savePreferences() + saveSettings() + if (transformGizmoRef.current) transformGizmoRef.current.RemoveGizmos() + openPanel("scoring-zones") + }} + onCancel={() => { openPanel("scoring-zones") + if (transformGizmoRef.current) transformGizmoRef.current.RemoveGizmos() }} > @@ -53,7 +98,10 @@ const ZoneConfigPanel: React.FC = ({ panelId, openLocation, side onClick={() => setAlliance(alliance == "blue" ? "red" : "blue")} colorOverrideClass={`bg-match-${alliance}-alliance`} /> - setParent(p)} /> + (setParent(body))} + /> = ({ panelId, openLocation, side onClick={setPersistent} /> - <> - + ) + })} + + ) : ( <> - {zones.map((z: ScoringZonePreferences, i: number) => ( + {zones.map((zonePrefs: ScoringZonePreferences, i: number) => ( { + return zonePrefs + })()} + field={selectedField} openPanel={openPanel} + save={() => saveZones(zones, selectedField)} deleteZone={() => { setZones(zones.filter((_, idx) => idx !== i)) }} - saveZones={saveZones} /> ))}