/// <summary> /// Spawns the specified actor to the game (with undo). /// </summary> /// <param name="actor">The actor.</param> /// <param name="parent">The parent actor. Set null as default.</param> /// <param name="autoSelect">True if automatically select the spawned actor, otherwise false.</param> public void Spawn(Actor actor, Actor parent = null, bool autoSelect = true) { bool isPlayMode = Editor.StateMachine.IsPlayMode; if (Level.IsAnySceneLoaded == false) { throw new InvalidOperationException("Cannot spawn actor when no scene is loaded."); } SpawnBegin?.Invoke(); // Add it Level.SpawnActor(actor, parent); // Peek spawned node var actorNode = Editor.Instance.Scene.GetActorNode(actor); if (actorNode == null) { throw new InvalidOperationException("Failed to create scene node for the spawned actor."); } // During play in editor mode spawned actors should be dynamic (user can move them) if (isPlayMode) { actor.StaticFlags = StaticFlags.None; } // Call post spawn action (can possibly setup custom default values) actorNode.PostSpawn(); // Create undo action IUndoAction action = new DeleteActorsAction(new List <SceneGraphNode>(1) { actorNode }, true); if (autoSelect) { var before = Selection.ToArray(); Selection.Clear(); Selection.Add(actorNode); OnSelectionChanged(); action = new MultiUndoAction(action, new SelectionChangeAction(before, Selection.ToArray(), OnSelectionUndo)); } Undo.AddAction(action); // Mark scene as dirty Editor.Scene.MarkSceneEdited(actor.Scene); SpawnEnd?.Invoke(); OnDirty(actorNode); }
/// <summary> /// Converts the selected actor to another type. /// </summary> /// <param name="to">The type to convert in.</param> public void Convert(Type to) { if (!Editor.SceneEditing.HasSthSelected || !(Editor.SceneEditing.Selection[0] is ActorNode)) return; if (Level.IsAnySceneLoaded == false) throw new InvalidOperationException("Cannot spawn actor when no scene is loaded."); var actionList = new IUndoAction[4]; Actor old = ((ActorNode)Editor.SceneEditing.Selection[0]).Actor; Actor actor = (Actor)FlaxEngine.Object.New(to); var parent = old.Parent; var orderInParent = old.OrderInParent; SelectionDeleteBegin?.Invoke(); actionList[0] = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo); actionList[0].Do(); actionList[1] = new DeleteActorsAction(new List<SceneGraphNode> { Editor.Instance.Scene.GetActorNode(old) }); actionList[1].Do(); SelectionDeleteEnd?.Invoke(); SpawnBegin?.Invoke(); // Copy properties actor.Transform = old.Transform; actor.StaticFlags = old.StaticFlags; actor.HideFlags = old.HideFlags; actor.Layer = old.Layer; actor.Tag = old.Tag; actor.Name = old.Name; actor.IsActive = old.IsActive; // Spawn actor Level.SpawnActor(actor, parent); if (parent != null) actor.OrderInParent = orderInParent; if (Editor.StateMachine.IsPlayMode) actor.StaticFlags = StaticFlags.None; // Move children for (var i = old.ScriptsCount - 1; i >= 0; i--) { var script = old.Scripts[i]; script.Actor = actor; Guid newid = Guid.NewGuid(); FlaxEngine.Object.Internal_ChangeID(FlaxEngine.Object.GetUnmanagedPtr(script), ref newid); } for (var i = old.Children.Length - 1; i >= 0; i--) { old.Children[i].Parent = actor; } var actorNode = Editor.Instance.Scene.GetActorNode(actor); if (actorNode == null) throw new InvalidOperationException("Failed to create scene node for the spawned actor."); actorNode.PostSpawn(); Editor.Scene.MarkSceneEdited(actor.Scene); actionList[2] = new DeleteActorsAction(new List<SceneGraphNode> { actorNode }, true); actionList[3] = new SelectionChangeAction(new SceneGraphNode[0], new SceneGraphNode[] { actorNode }, OnSelectionUndo); actionList[3].Do(); var actions = new MultiUndoAction(actionList); Undo.AddAction(actions); SpawnEnd?.Invoke(); OnDirty(actorNode); }
/// <summary> /// Converts the selected actor to another type. /// </summary> /// <param name="to">The type to convert in.</param> public void Convert(Type to) { if (!Editor.SceneEditing.HasSthSelected || !(Editor.SceneEditing.Selection[0] is ActorNode)) { return; } if (Level.IsAnySceneLoaded == false) { throw new InvalidOperationException("Cannot spawn actor when no scene is loaded."); } var actionList = new IUndoAction[4]; var oldNode = (ActorNode)Editor.SceneEditing.Selection[0]; var old = oldNode.Actor; var actor = (Actor)FlaxEngine.Object.New(to); var parent = old.Parent; var orderInParent = old.OrderInParent; // Steps: // - deselect old actor // - destroy old actor // - spawn new actor // - select new actor SelectionDeleteBegin?.Invoke(); actionList[0] = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo); actionList[0].Do(); actionList[1] = new DeleteActorsAction(oldNode.BuildAllNodes().Where(x => x.CanDelete).ToList()); SelectionDeleteEnd?.Invoke(); SpawnBegin?.Invoke(); // Copy properties actor.Transform = old.Transform; actor.StaticFlags = old.StaticFlags; actor.HideFlags = old.HideFlags; actor.Layer = old.Layer; actor.Tag = old.Tag; actor.Name = old.Name; actor.IsActive = old.IsActive; // Spawn actor Level.SpawnActor(actor, parent); if (parent != null) { actor.OrderInParent = orderInParent; } if (Editor.StateMachine.IsPlayMode) { actor.StaticFlags = StaticFlags.None; } // Move children var scripts = old.Scripts; for (var i = scripts.Length - 1; i >= 0; i--) { scripts[i].Actor = actor; } var children = old.Children; for (var i = children.Length - 1; i >= 0; i--) { children[i].Parent = actor; } var actorNode = Editor.Instance.Scene.GetActorNode(actor); if (actorNode == null) { throw new InvalidOperationException("Failed to create scene node for the spawned actor."); } actorNode.PostConvert(oldNode); actorNode.PostSpawn(); Editor.Scene.MarkSceneEdited(actor.Scene); actionList[1].Do(); actionList[2] = new DeleteActorsAction(actorNode.BuildAllNodes().Where(x => x.CanDelete).ToList(), true); actionList[3] = new SelectionChangeAction(new SceneGraphNode[0], new SceneGraphNode[] { actorNode }, OnSelectionUndo); actionList[3].Do(); Undo.AddAction(new MultiUndoAction(actionList, "Convert actor")); SpawnEnd?.Invoke(); OnDirty(actorNode); }
/// <summary> /// Spawns the specified actor to the game (with undo). /// </summary> /// <param name="actor">The actor.</param> /// <param name="parent">The parent actor. Set null as default.</param> public void Spawn(Actor actor, Actor parent = null) { bool isPlayMode = Editor.StateMachine.IsPlayMode; if (SceneManager.IsAnySceneLoaded == false) { throw new InvalidOperationException("Cannot spawn actor when no scene is loaded."); } SpawnBegin?.Invoke(); // Add it SceneManager.SpawnActor(actor, parent); // Peek spawned node var actorNode = Editor.Instance.Scene.GetActorNode(actor); if (actorNode == null) { throw new InvalidOperationException("Failed to create scene node for the spawned actor."); } // During play in editor mode spawned actors should be dynamic (user can move them) if (isPlayMode) { actor.StaticFlags = StaticFlags.None; } // Call post spawn action (can possibly setup custom default values) actorNode.PostSpawn(); // Create undo action var action = new DeleteActorsAction(new List <SceneGraphNode>(1) { actorNode }, true); Undo.AddAction(action); // Mark scene as dirty Editor.Scene.MarkSceneEdited(actor.Scene); SpawnEnd?.Invoke(); var options = Editor.Options.Options; // Auto CSG mesh rebuild if (!isPlayMode && options.General.AutoRebuildCSG) { if (actor is BoxBrush && actor.Scene) { actor.Scene.BuildCSG(options.General.AutoRebuildCSGTimeoutMs); } } // Auto NavMesh rebuild if (!isPlayMode && options.General.AutoRebuildNavMesh && actor.Scene && (actor.StaticFlags & StaticFlags.Navigation) == StaticFlags.Navigation) { var bounds = actor.BoxWithChildren; actor.Scene.BuildNavMesh(bounds, options.General.AutoRebuildNavMeshTimeoutMs); } }