feat: Enhance asset and human event handling with animation and loop capabilities
This commit is contained in:
@@ -6,145 +6,128 @@ import PositionInput from "../customInput/PositionInputs";
|
||||
import RotationInput from "../customInput/RotationInput";
|
||||
import { useSelectedFloorItem, useObjectPosition, useObjectRotation } from "../../../../store/builder/store";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
|
||||
interface UserData {
|
||||
id: number; // Unique identifier for the user data
|
||||
label: string; // Label of the user data field
|
||||
value: string; // Value of the user data field
|
||||
id: number;
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const AssetProperties: React.FC = () => {
|
||||
const [userData, setUserData] = useState<UserData[]>([]); // State to track user data
|
||||
const [nextId, setNextId] = useState(1); // Unique ID for new entries
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { objectPosition } = useObjectPosition();
|
||||
const { objectRotation } = useObjectRotation();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets, setCurrentAnimation } = assetStore()
|
||||
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
|
||||
const [isPlaying, setIsplaying] = useState(false);
|
||||
// Function to handle adding new user data
|
||||
const handleAddUserData = () => {
|
||||
const newUserData: UserData = {
|
||||
id: nextId,
|
||||
label: `Property ${nextId}`,
|
||||
value: "",
|
||||
const [userData, setUserData] = useState<UserData[]>([]);
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { objectPosition } = useObjectPosition();
|
||||
const { objectRotation } = useObjectRotation();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets, setCurrentAnimation } = assetStore();
|
||||
const { loopAnimation } = useBuilderStore();
|
||||
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
|
||||
|
||||
const handleAddUserData = () => {
|
||||
};
|
||||
setUserData([...userData, newUserData]);
|
||||
setNextId(nextId + 1); // Increment the ID for the next entry
|
||||
};
|
||||
|
||||
// Function to update the value of a user data entry
|
||||
const handleUserDataChange = (id: number, newValue: string) => {
|
||||
setUserData((prevUserData) =>
|
||||
prevUserData.map((data) =>
|
||||
data.id === id ? { ...data, value: newValue } : data
|
||||
)
|
||||
);
|
||||
};
|
||||
const handleUserDataChange = (id: number, newValue: string) => {
|
||||
};
|
||||
|
||||
// Remove user data
|
||||
const handleRemoveUserData = (id: number) => {
|
||||
setUserData((prevUserData) =>
|
||||
prevUserData.filter((data) => data.id !== id)
|
||||
);
|
||||
};
|
||||
const handleRemoveUserData = (id: number) => {
|
||||
};
|
||||
|
||||
const handleAnimationClick = (animation: string) => {
|
||||
if (selectedFloorItem) {
|
||||
setCurrentAnimation(selectedFloorItem.uuid, animation, true);
|
||||
const handleAnimationClick = (animation: string) => {
|
||||
if (selectedFloorItem) {
|
||||
setCurrentAnimation(selectedFloorItem.uuid, animation, true, loopAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedFloorItem) return null;
|
||||
if (!selectedFloorItem) return null;
|
||||
|
||||
return (
|
||||
<div className="asset-properties-container">
|
||||
{/* Name */}
|
||||
<div className="header">{selectedFloorItem.userData.modelName}</div>
|
||||
<section>
|
||||
{objectPosition.x && objectPosition.z &&
|
||||
<PositionInput
|
||||
onChange={() => { }}
|
||||
value1={parseFloat(objectPosition.x.toFixed(5))}
|
||||
value2={parseFloat(objectPosition.z.toFixed(5))}
|
||||
/>
|
||||
}
|
||||
{objectRotation.y &&
|
||||
<RotationInput
|
||||
onChange={() => { }}
|
||||
value={parseFloat(objectRotation.y.toFixed(5))}
|
||||
/>
|
||||
}
|
||||
</section>
|
||||
return (
|
||||
<div className="asset-properties-container">
|
||||
{/* Name */}
|
||||
<div className="header">{selectedFloorItem.userData.modelName}</div>
|
||||
<section>
|
||||
{objectPosition &&
|
||||
<PositionInput
|
||||
onChange={() => { }}
|
||||
value1={parseFloat(objectPosition.x.toFixed(5))}
|
||||
value2={parseFloat(objectPosition.z.toFixed(5))}
|
||||
/>
|
||||
}
|
||||
{objectRotation &&
|
||||
<RotationInput
|
||||
onChange={() => { }}
|
||||
value={parseFloat(objectRotation.y.toFixed(5))}
|
||||
/>
|
||||
}
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className="header">Render settings</div>
|
||||
<InputToggle inputKey="visible" label="Visible" />
|
||||
<InputToggle inputKey="frustumCull" label="Frustum cull" />
|
||||
</section>
|
||||
<section>
|
||||
<div className="header">Render settings</div>
|
||||
<InputToggle inputKey="visible" label="Visible" />
|
||||
<InputToggle inputKey="frustumCull" label="Frustum cull" />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className="header">User Data</div>
|
||||
{userData.map((data) => (
|
||||
<div className="input-container">
|
||||
<InputWithDropDown
|
||||
key={data.id}
|
||||
label={data.label}
|
||||
value={data.value}
|
||||
editableLabel
|
||||
onChange={(newValue) => handleUserDataChange(data.id, newValue)} // Pass the change handler
|
||||
/>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleRemoveUserData(data.id)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<section>
|
||||
<div className="header">User Data</div>
|
||||
{userData.map((data) => (
|
||||
<div className="input-container">
|
||||
<InputWithDropDown
|
||||
key={data.id}
|
||||
label={data.label}
|
||||
value={data.value}
|
||||
editableLabel
|
||||
onChange={(newValue) => handleUserDataChange(data.id, newValue)}
|
||||
/>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleRemoveUserData(data.id)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Add new user data */}
|
||||
<div className="optimize-button" onClick={handleAddUserData}>
|
||||
+ Add
|
||||
</div>
|
||||
</section>
|
||||
<div style={{ display: "flex", flexDirection: "column", outline: "1px solid var(--border-color)" }}>
|
||||
{selectedFloorItem.uuid && <div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>Animations</div>}
|
||||
{assets.map((asset) => (
|
||||
<div key={asset.modelUuid} className="asset-item">
|
||||
{asset.modelUuid === selectedFloorItem.uuid &&
|
||||
asset.animations &&
|
||||
asset.animations.length > 0 &&
|
||||
asset.animations.map((animation, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{ gap: "15px", cursor: "pointer", padding: "5px" }}
|
||||
>
|
||||
<div
|
||||
onClick={() => handleAnimationClick(animation)}
|
||||
onMouseEnter={() => setHoveredIndex(index)}
|
||||
onMouseLeave={() => setHoveredIndex(null)}
|
||||
style={{
|
||||
height: "20px",
|
||||
width: "100%",
|
||||
borderRadius: "5px",
|
||||
background:
|
||||
hoveredIndex === index
|
||||
? "#7b4cd3"
|
||||
: "transparent",
|
||||
}}
|
||||
>
|
||||
{animation.charAt(0).toUpperCase() +
|
||||
animation.slice(1).toLowerCase()}
|
||||
</div>
|
||||
{/* Add new user data */}
|
||||
<div className="optimize-button" onClick={handleAddUserData}>
|
||||
+ Add
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
</section>
|
||||
<div style={{ display: "flex", flexDirection: "column", outline: "1px solid var(--border-color)" }}>
|
||||
{selectedFloorItem.uuid && <div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>Animations</div>}
|
||||
{assets.map((asset) => (
|
||||
<div key={asset.modelUuid} className="asset-item">
|
||||
{asset.modelUuid === selectedFloorItem.uuid &&
|
||||
asset.animations &&
|
||||
asset.animations.length > 0 &&
|
||||
asset.animations.map((animation, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{ gap: "15px", cursor: "pointer", padding: "5px" }}
|
||||
>
|
||||
<div
|
||||
onClick={() => handleAnimationClick(animation)}
|
||||
onMouseEnter={() => setHoveredIndex(index)}
|
||||
onMouseLeave={() => setHoveredIndex(null)}
|
||||
style={{
|
||||
height: "20px",
|
||||
width: "100%",
|
||||
borderRadius: "5px",
|
||||
background:
|
||||
hoveredIndex === index
|
||||
? "#7b4cd3"
|
||||
: "transparent",
|
||||
}}
|
||||
>
|
||||
{animation.charAt(0).toUpperCase() +
|
||||
animation.slice(1).toLowerCase()}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AssetProperties;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as THREE from "three"
|
||||
import * as THREE from "three"
|
||||
import { useEffect } from 'react'
|
||||
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
|
||||
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
||||
@@ -226,7 +226,8 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle",
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
@@ -242,6 +243,36 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
}
|
||||
};
|
||||
addEvent(storageEvent);
|
||||
} else if (item.eventData.type === 'Human') {
|
||||
const humanEvent: HumanEventSchema = {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "human",
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "animation",
|
||||
animation: null,
|
||||
loopAnimation: true,
|
||||
loadCapacity: 1,
|
||||
travelPoints: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
addEvent(humanEvent);
|
||||
}
|
||||
} else {
|
||||
assets.push({
|
||||
|
||||
@@ -162,6 +162,7 @@ async function handleModelLoad(
|
||||
// SOCKET
|
||||
|
||||
if (selectedItem.type) {
|
||||
console.log('selectedItem: ', selectedItem);
|
||||
const data = PointsCalculator(
|
||||
selectedItem.type,
|
||||
gltf.scene.clone(),
|
||||
@@ -170,7 +171,7 @@ async function handleModelLoad(
|
||||
|
||||
if (!data || !data.points) return;
|
||||
|
||||
const eventData: any = { type: selectedItem.type, };
|
||||
const eventData: any = { type: selectedItem.type };
|
||||
|
||||
if (selectedItem.type === "Conveyor") {
|
||||
const ConveyorEvent: ConveyorEventSchema = {
|
||||
@@ -378,6 +379,7 @@ async function handleModelLoad(
|
||||
actionName: "Action 1",
|
||||
actionType: "animation",
|
||||
animation: null,
|
||||
loopAnimation: true,
|
||||
loadCapacity: 1,
|
||||
travelPoints: {
|
||||
startPoint: null,
|
||||
@@ -416,6 +418,7 @@ async function handleModelLoad(
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
console.log('completeData: ', completeData);
|
||||
socket.emit("v1:model-asset:add", completeData);
|
||||
|
||||
const asset: Asset = {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||
import { CameraControls, Html } from '@react-three/drei';
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||
import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore';
|
||||
import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore';
|
||||
@@ -15,6 +15,7 @@ import { useParams } from 'react-router-dom';
|
||||
import { getUserData } from '../../../../../functions/getUserData';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { useVersionContext } from '../../../version/versionContext';
|
||||
import { SkeletonUtils } from 'three-stdlib';
|
||||
|
||||
function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { camera, controls, gl } = useThree();
|
||||
@@ -23,7 +24,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { subModule } = useSubModuleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||
const { assets, removeAsset, setAnimations } = assetStore();
|
||||
const { removeAsset, setAnimations, resetAnimation } = assetStore();
|
||||
const { setTop } = useTopData();
|
||||
const { setLeft } = useLeftData();
|
||||
const { getIsEventInProduct } = productStore();
|
||||
@@ -33,7 +34,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
const { socket } = useSocketStore();
|
||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { limitDistance } = useLimitDistance();
|
||||
const { renderDistance } = useRenderDistance();
|
||||
const [isRendered, setIsRendered] = useState(false);
|
||||
@@ -46,13 +47,15 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization } = getUserData();
|
||||
const [animationNames, setAnimationNames] = useState<string[]>([]);
|
||||
const mixerRef = useRef<THREE.AnimationMixer>();
|
||||
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
||||
|
||||
useEffect(() => {
|
||||
setDeletableFloorItem(null);
|
||||
}, [activeModule, toolMode])
|
||||
if (selectedFloorItem === null) {
|
||||
resetAnimation(asset.modelUuid);
|
||||
}
|
||||
}, [activeModule, toolMode, selectedFloorItem])
|
||||
|
||||
useEffect(() => {
|
||||
const loader = new GLTFLoader();
|
||||
@@ -62,40 +65,21 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
const loadModel = async () => {
|
||||
try {
|
||||
// Check Cache
|
||||
// const assetId = asset.assetId;
|
||||
// const cachedModel = THREE.Cache.get(assetId);
|
||||
// if (cachedModel) {
|
||||
// setGltfScene(cachedModel.scene.clone());
|
||||
// calculateBoundingBox(cachedModel.scene);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Check Cache
|
||||
// const assetId = asset.assetId;
|
||||
// console.log('assetId: ', assetId);
|
||||
// const cachedModel = THREE.Cache.get(assetId);
|
||||
// console.log('cachedModel: ', cachedModel);
|
||||
// if (cachedModel) {
|
||||
// setGltfScene(cachedModel.scene.clone());
|
||||
// calculateBoundingBox(cachedModel.scene);
|
||||
// return;
|
||||
// }
|
||||
|
||||
const assetId = asset.assetId;
|
||||
const cachedModel = THREE.Cache.get(assetId);
|
||||
if (cachedModel) {
|
||||
const clonedScene = cachedModel.scene.clone();
|
||||
clonedScene.animations = cachedModel.animations || [];
|
||||
setGltfScene(clonedScene);
|
||||
calculateBoundingBox(clonedScene);
|
||||
if (cachedModel.animations && clonedScene.animations.length > 0) {
|
||||
const animationName = clonedScene.animations.map((clip: any) => clip.name);
|
||||
setAnimationNames(animationName)
|
||||
const clone: any = SkeletonUtils.clone(cachedModel.scene);
|
||||
clone.animations = cachedModel.animations || [];
|
||||
setGltfScene(clone);
|
||||
calculateBoundingBox(clone);
|
||||
if (cachedModel.animations && clone.animations.length > 0) {
|
||||
const animationName = clone.animations.map((clip: any) => clip.name);
|
||||
setAnimations(asset.modelUuid, animationName)
|
||||
mixerRef.current = new THREE.AnimationMixer(clonedScene);
|
||||
mixerRef.current = new THREE.AnimationMixer(clone);
|
||||
|
||||
clonedScene.animations.forEach((animation: any) => {
|
||||
clone.animations.forEach((animation: any) => {
|
||||
const action = mixerRef.current!.clipAction(animation);
|
||||
actions.current[animation.name] = action;
|
||||
});
|
||||
@@ -293,28 +277,27 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
clearSelectedAsset()
|
||||
}
|
||||
}
|
||||
|
||||
useFrame((_, delta) => {
|
||||
if (mixerRef.current) {
|
||||
mixerRef.current.update(delta);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (asset.animationState && asset.animationState.playing) {
|
||||
if (asset.animationState && asset.animationState.isPlaying) {
|
||||
if (!mixerRef.current) return;
|
||||
|
||||
Object.values(actions.current).forEach((action) => action.stop());
|
||||
|
||||
const action = actions.current[asset.animationState.current];
|
||||
if (action && asset.animationState?.playing) {
|
||||
action.reset().setLoop(THREE.LoopOnce, 1).play();
|
||||
if (action && asset.animationState?.isPlaying) {
|
||||
const loopMode = asset.animationState.loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce;
|
||||
action.reset().setLoop(loopMode, loopMode === THREE.LoopRepeat ? Infinity : 1).play();
|
||||
}
|
||||
} else {
|
||||
Object.values(actions.current).forEach((action) => action.stop());
|
||||
}
|
||||
|
||||
}, [asset.animationState])
|
||||
|
||||
return (
|
||||
|
||||
@@ -22,7 +22,8 @@ interface AssetsStore {
|
||||
|
||||
// Animation controls
|
||||
setAnimations: (modelUuid: string, animations: string[]) => void;
|
||||
setCurrentAnimation: (modelUuid: string, current: string, isPlaying: boolean) => void;
|
||||
setCurrentAnimation: (modelUuid: string, current: string, isisPlaying: boolean, loopAnimation: boolean) => void;
|
||||
resetAnimation: (modelUuid: string) => void;
|
||||
addAnimation: (modelUuid: string, animation: string) => void;
|
||||
removeAnimation: (modelUuid: string, animation: string) => void;
|
||||
|
||||
@@ -149,18 +150,28 @@ export const createAssetStore = () => {
|
||||
if (asset) {
|
||||
asset.animations = animations;
|
||||
if (!asset.animationState) {
|
||||
asset.animationState = { current: '', playing: false };
|
||||
asset.animationState = { current: '', isPlaying: false, loopAnimation: true };
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setCurrentAnimation: (modelUuid, current, isPlaying) => {
|
||||
setCurrentAnimation: (modelUuid, current, isisPlaying, loopAnimation) => {
|
||||
set((state) => {
|
||||
const asset = state.assets.find(a => a.modelUuid === modelUuid);
|
||||
if (asset?.animationState) {
|
||||
asset.animationState.current = current;
|
||||
asset.animationState.playing = isPlaying;
|
||||
asset.animationState.isPlaying = isisPlaying;
|
||||
asset.animationState.loopAnimation = loopAnimation;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
resetAnimation: (modelUuid) => {
|
||||
set((state) => {
|
||||
const asset = state.assets.find(a => a.modelUuid === modelUuid);
|
||||
if (asset?.animationState) {
|
||||
asset.animationState = { current: '', isPlaying: false, loopAnimation: true };
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -184,7 +195,7 @@ export const createAssetStore = () => {
|
||||
if (asset?.animations) {
|
||||
asset.animations = asset.animations.filter(a => a !== animation);
|
||||
if (asset.animationState?.current === animation) {
|
||||
asset.animationState.playing = false;
|
||||
asset.animationState.isPlaying = false;
|
||||
asset.animationState.current = '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ interface BuilderState {
|
||||
|
||||
// Floor Asset
|
||||
selectedFloorAsset: Object3D | null;
|
||||
loopAnimation: boolean;
|
||||
|
||||
// Wall Settings
|
||||
selectedWall: Object3D | null;
|
||||
@@ -64,6 +65,7 @@ interface BuilderState {
|
||||
|
||||
// Setters - Floor Asset
|
||||
setSelectedFloorAsset: (asset: Object3D | null) => void;
|
||||
setLoopAnimation: (loop: boolean) => void;
|
||||
|
||||
// Setters - Wall
|
||||
setSelectedWall: (wall: Object3D | null) => void;
|
||||
@@ -118,6 +120,7 @@ export const useBuilderStore = create<BuilderState>()(
|
||||
deletableWallAsset: null,
|
||||
|
||||
selectedFloorAsset: null,
|
||||
loopAnimation: true,
|
||||
|
||||
selectedWall: null,
|
||||
wallThickness: 0.5,
|
||||
@@ -197,6 +200,12 @@ export const useBuilderStore = create<BuilderState>()(
|
||||
});
|
||||
},
|
||||
|
||||
setLoopAnimation(loopAnimation: boolean) {
|
||||
set((state) => {
|
||||
state.loopAnimation = loopAnimation;
|
||||
});
|
||||
},
|
||||
|
||||
// === Setters: Wall ===
|
||||
|
||||
setSelectedWall: (wall: Object3D | null) => {
|
||||
|
||||
3
app/src/types/builderTypes.d.ts
vendored
3
app/src/types/builderTypes.d.ts
vendored
@@ -26,7 +26,8 @@ interface Asset {
|
||||
animations?: string[];
|
||||
animationState?: {
|
||||
current: string;
|
||||
playing: boolean;
|
||||
isPlaying: boolean;
|
||||
loopAnimation: boolean;
|
||||
};
|
||||
eventData?: {
|
||||
type: string;
|
||||
|
||||
1
app/src/types/simulationTypes.d.ts
vendored
1
app/src/types/simulationTypes.d.ts
vendored
@@ -74,6 +74,7 @@ interface HumanAction {
|
||||
actionName: string;
|
||||
actionType: "animation" | "animatedTravel";
|
||||
animation: string | null;
|
||||
loopAnimation: boolean;
|
||||
loadCapacity: number;
|
||||
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; }
|
||||
triggers: TriggerSchema[];
|
||||
|
||||
Reference in New Issue
Block a user