object instance creation and deletion
This commit is contained in:
parent
93e127b2f7
commit
dee28ba5b2
|
|
@ -1,6 +1,6 @@
|
||||||
.menu {
|
.menu {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
font-size: 13px;
|
font-size: 16px;
|
||||||
|
|
||||||
& details {
|
& details {
|
||||||
&>summary {
|
&>summary {
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 8px 8px;
|
padding: 8px 8px;
|
||||||
|
gap: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
@ -28,15 +29,22 @@
|
||||||
background: rgba(255, 255, 255, 0.15);
|
background: rgba(255, 255, 255, 0.15);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
&>.title {
|
&>.title {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>.actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
& svg {
|
& svg {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import { useMemo, useRef, type RefObject } from "react";
|
||||||
import type { Group } from "three";
|
import type { Group } from "three";
|
||||||
import { TransformControls, useHelper } from "@react-three/drei";
|
import { TransformControls, useHelper } from "@react-three/drei";
|
||||||
import { BoxHelper } from "three";
|
import { BoxHelper } from "three";
|
||||||
import type { ThreeEvent } from "@react-three/fiber";
|
|
||||||
import { state } from "../state";
|
import { state } from "../state";
|
||||||
import { nextObjectEditMode } from "../state/worldEditorState";
|
import { nextObjectEditMode } from "../state/worldEditorState";
|
||||||
import { ObjectViewInternal, type ObjectViewInternalHandle } from "./ObjectViewInternal";
|
import { ObjectViewInternal, type ObjectViewInternalHandle } from "./ObjectViewInternal";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { makeAutoObservable } from "mobx";
|
import { makeAutoObservable } from "mobx";
|
||||||
import { state } from "./rootState";
|
import { state } from "./rootState";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { IconRun } from '@tabler/icons-react';
|
import { IconRun, IconTrash, IconCubePlus, IconPlus } from '@tabler/icons-react';
|
||||||
|
|
||||||
export type MenuNodeAction = {
|
export type MenuNodeAction = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -26,27 +26,43 @@ export class MenuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
private get editorObjectTypesMenu(): MenuNode[] {
|
private get editorObjectTypesMenu(): MenuNode[] {
|
||||||
const scene = state.worldEditor.scene;
|
const editor = state.worldEditor;
|
||||||
|
const scene = editor.scene;
|
||||||
|
|
||||||
return Object.values(state.world.data.objectTypes)
|
return Object.values(state.world.data.objectTypes)
|
||||||
.map((ot) => ({
|
.map((ot) => ({
|
||||||
id: `ot-${ot.id}`,
|
id: `ot-${ot.id}`,
|
||||||
title: ot.name,
|
title: ot.name,
|
||||||
onClick: () => { state.worldEditor.setSelectedObjectType({ id: ot.id, editMode: 'scripts' }) },
|
actions: [
|
||||||
selected: () => state.worldEditor.selection?.type === 'objectType' && state.worldEditor.selection?.id === ot.id,
|
{
|
||||||
|
id: 'create-instance',
|
||||||
|
content: <IconPlus size="1em" />,
|
||||||
|
tooltip: 'Create new object instance',
|
||||||
|
onClick: () => { editor.addObjectInstanceAtRandomPosition(ot.id); },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onClick: () => { editor.setSelectedObjectType({ id: ot.id, editMode: 'scripts' }) },
|
||||||
|
selected: () => editor.selection?.type === 'objectType' && editor.selection?.id === ot.id,
|
||||||
children: Object.values(scene.objects)
|
children: Object.values(scene.objects)
|
||||||
.filter((o) => o.typeId === ot.id)
|
.filter((o) => o.typeId === ot.id)
|
||||||
.map((o) => {
|
.map((o) => {
|
||||||
const isPlayer = scene.playerObjectId === o.id;
|
const isPlayer = scene.playerObjectId === o.id;
|
||||||
|
|
||||||
const actions: MenuNodeAction[] = [];
|
const actions: MenuNodeAction[] = [];
|
||||||
if (!isPlayer)
|
if (!isPlayer) {
|
||||||
|
actions.push({
|
||||||
|
id: 'delete',
|
||||||
|
content: <IconTrash size="1em" />,
|
||||||
|
tooltip: 'Delete the object',
|
||||||
|
onClick: () => { editor.deleteObject(o.id); },
|
||||||
|
});
|
||||||
actions.push({
|
actions.push({
|
||||||
id: 'control-by-player',
|
id: 'control-by-player',
|
||||||
content: <IconRun size="1em" />,
|
content: <IconRun size="1em" />,
|
||||||
tooltip: 'Mark as player',
|
tooltip: 'Mark as player',
|
||||||
onClick: () => { state.markObjectAsPlayer(o); },
|
onClick: () => { scene.playerObjectId = o.id; },
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: `o-${o.id}`,
|
id: `o-${o.id}`,
|
||||||
|
|
|
||||||
|
|
@ -116,14 +116,14 @@ export class WorldEditorState {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public addObjectCloneAtRandomPosition(typeId: string): ObjectInstance {
|
public addObjectInstanceAtRandomPosition(typeId: string): ObjectInstance {
|
||||||
return this.addObjectClone(
|
return this.addObjectInstance(
|
||||||
typeId,
|
typeId,
|
||||||
{ x: Math.random() * 3, y: Math.random() * 3, z: Math.random() * 1 },
|
{ x: Math.random() * 3, y: Math.random() * 3, z: Math.random() * 1 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addObjectClone(
|
public addObjectInstance(
|
||||||
typeId: string,
|
typeId: string,
|
||||||
pos: { x: number; y: number; z: number; },
|
pos: { x: number; y: number; z: number; },
|
||||||
): ObjectInstance {
|
): ObjectInstance {
|
||||||
|
|
@ -133,7 +133,15 @@ export class WorldEditorState {
|
||||||
|
|
||||||
this.scene.objects[obj.id] = obj;
|
this.scene.objects[obj.id] = obj;
|
||||||
|
|
||||||
|
this.setSelectedObject({ id: obj.id, editMode: 'translate' });
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public deleteObject(objectId: string) {
|
||||||
|
if (this.selection?.type ==='object' && this.selection.id === objectId)
|
||||||
|
this.resetSelection();
|
||||||
|
delete (this.scene.objects[objectId]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue