public void AddTargetAgentActionNodeEditor(ActionNode_GS new_node) { //Set new node agent new_node.agent = _selected_agent; //Check if we need to allocate more items in the array if (_action_node_editors_num == _action_node_editors.Length) { //Double array capacity ActionNode_GS_Editor[] new_array = new ActionNode_GS_Editor[_action_node_editors_num * 2]; //Copy values for (int k = 0; k < _action_node_editors_num; k++) { new_array[k] = _action_node_editors[k]; } //Set new array _action_node_editors = new_array; } //Generate the new action node editor ActionNode_GS_Editor new_node_editor = new ActionNode_GS_Editor(new_node); //Add it to the array _action_node_editors[_action_node_editors_num] = new_node_editor; //Update editors num _action_node_editors_num += 1; }
//Constructors ================ public ActionNode_GS_Editor(ActionNode_GS new_target) { //Set targets _target_action_node = new_target; //Generate new description ui content _description_label = new GUIContent(_target_action_node.description); //Calculate new ui content size //Allocate condition editors array _condition_editors = new Property_GS_Editor[ProTools.INITIAL_ARRAY_SIZE]; //Generate conditions UI for (int k = 0; k < _target_action_node.conditions_num; k++) { AddConditionEditor(_target_action_node.conditions[k]); } //Allocate effect editors array _effect_editors = new Property_GS_Editor[ProTools.INITIAL_ARRAY_SIZE]; //Generate conditions UI for (int k = 0; k < _target_action_node.effects_num; k++) { AddEffectEditor(_target_action_node.effects[k]); } //Allocate action editor if (_target_action_node.action != null) { _action_editor = new Action_GS_Editor(this); } }
//Constructors ================ public ActionNode_GS_Debugger(ActionNode_GS new_target) { //Set targets _target_action_node = new_target; //Generate uuid _window_uuid = System.Guid.NewGuid().ToString().GetHashCode(); }
ActionNode_GS _action = null; //Node Action //Constructors ================ public PlannerNode_GS(float node_g, float node_h, int node_id, int parent_node_id, WorldState_GS resultant_ws, ActionNode_GS node_action) { _g = node_g; _h = node_h; _id = node_id; _parent_id = parent_node_id; _resultant_world_state = resultant_ws; _action = node_action; }
//Constructors ================ public ActionSelectMenu_GS(ActionNode_GS_Editor new_target_action_node_editor) { if (new_target_action_node_editor != null) { //Focus the action node _target_action_node_editor = new_target_action_node_editor; _target_action_node = _target_action_node_editor.target_action_node; } //Get dropdown slot for action select _action_dropdown_slot = ProTools.GetDropdownSlot(); }
//Loop Methods ================ public override void OnGUI(Rect rect) { //Set window size editorWindow.minSize = new Vector2(180.0f, 167.5f); editorWindow.maxSize = new Vector2(180.0f, 167.5f); //Menu title GUILayout.BeginHorizontal("Box"); GUILayout.FlexibleSpace(); GUILayout.Label("Node Editor Menu", UIConfig_GS.Instance.select_menu_title_style, GUILayout.ExpandWidth(true)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); //Separator EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); //Add action button if (GUILayout.Button(new GUIContent("Add Action Node", "Add action node to the selected agent"), GUILayout.ExpandWidth(true), GUILayout.Height(25))) { //Focus the target selected agent and add an action in the target canvas pos Vector2 mouse_pos = NodeEditor_GS.Instance.ScreenCoordsToZoomCoords(editorWindow.position.position); ActionNode_GS new_action_node = NodeEditor_GS.Instance.selected_agent.AddActionNode(mouse_pos); //Add the new node editor NodeEditor_GS.Instance.AddTargetAgentActionNodeEditor(new_action_node); //Repaint the target window NodeEditor_GS.Instance.Repaint(); //Close this window editorWindow.Close(); } //Clear planning button if (GUILayout.Button(new GUIContent("Clear Plannig", "Remove all action nodes of the selected agent"), GUILayout.ExpandWidth(true), GUILayout.Height(25))) { //Add clear agent planning SecurityAcceptMenu_GS.on_accept_delegate += () => NodeEditor_GS.Instance.selected_agent.ClearPlanning(); //Add clear editor planning SecurityAcceptMenu_GS.on_accept_delegate += () => NodeEditor_GS.Instance.ClearPlanning(); //Add repaint target window SecurityAcceptMenu_GS.on_accept_delegate += () => NodeEditor_GS.Instance.Repaint(); //Get mouse current position Vector2 mousePos = Event.current.mousePosition; //Open security accept menu on mouse position PopupWindow.Show(new Rect(mousePos.x, mousePos.y, 0, 0), new SecurityAcceptMenu_GS()); } //Close agent canvas button if (GUILayout.Button(new GUIContent("Close Agent Canvas", "Close GoapSystem agent canvas"), GUILayout.ExpandWidth(true), GUILayout.Height(25))) { //Close node editor NodeEditor_GS.Instance.Close(); NodePlanning_GS.Instance.Close(); //Close this window editorWindow.Close(); } //Remove agent button GUI.backgroundColor = new Color(1.0f, 0.2f, 0.2f, 1.0f); if (GUILayout.Button("Remove Agent", GUILayout.ExpandWidth(true), GUILayout.Height(25))) { //Add remove this agent to accept menu delegates callback SecurityAcceptMenu_GS.on_accept_delegate += () => Object.DestroyImmediate((Agent_GS)NodeEditor_GS.Instance.selected_agent); //Add mark scene dirty to accept menu delegates callback SecurityAcceptMenu_GS.on_accept_delegate += () => EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); //Blackboard will detect that there's no agent and will destroy itself //Add node planning repaint SecurityAcceptMenu_GS.on_accept_delegate += () => NodePlanning_GS.Instance.Repaint(); //Add node editor repaint SecurityAcceptMenu_GS.on_accept_delegate += () => NodeEditor_GS.Instance.Repaint(); //Get mouse current position Vector2 mousePos = Event.current.mousePosition; //Open security accept menu on mouse position PopupWindow.Show(new Rect(mousePos.x, mousePos.y, 0, 0), new SecurityAcceptMenu_GS()); } GUI.backgroundColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); }
private void OnGUI() { //Draw background texture GUI.DrawTexture(new Rect(0, 0, position.width, position.height), back_texture, ScaleMode.StretchToFill); //Check if there is an agent selected if (_selected_agent == null) { //Handle no agent input HandleNoAgentInput(); return; } //Zoomable layout BeginZoomableLayout(); //Zoomable layout area Rect area_rect = new Rect(-_zoom_position.x, -_zoom_position.y, ProTools.NODE_EDITOR_CANVAS_SIZE, ProTools.NODE_EDITOR_CANVAS_SIZE); GUILayout.BeginArea(area_rect); //Temp for guide for (int k = 0; k < area_rect.width; k += 200) { for (int y = 0; y < area_rect.height; y += 200) { GUI.Label(new Rect(y, k, 120.0f, 25.0f), y + "||" + k); } } //Mark the beginning area of the popup windows BeginWindows(); //Draw action nodes for (int k = 0; k < _action_node_editors_num; k++) { //Focus action node ActionNode_GS node = _selected_agent.action_nodes[k]; //Focus action node editor ActionNode_GS_Editor node_editor = _action_node_editors[k]; //Show node window node.window_rect = GUILayout.Window(node.id, node.window_rect, node_editor.DrawUI, node.name, UIConfig_GS.Instance.node_window_style, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); //Show description label GUI.Label(new Rect(node.window_position.x - node_editor.label_size.x, node.window_position.y, node_editor.label_size.x, node_editor.label_size.y), node.description, UIConfig_GS.left_white_style); } //Reset matrix to keep blackboard window scale GUI.matrix = Matrix4x4.identity; //Selection change can generate null blackboard if (_blackboard_editor == null) { GenerateTargetAgentUI(); } else { //Update blackboard window to simulate static position _blackboard_editor.window_position = new Vector2(_zoom_position.x + position.width - ProTools.BLACKBOARD_MARGIN, 0 + _zoom_position.y); //Display blackboard window GUILayout.Window(_blackboard_editor.id, _blackboard_editor.window, _blackboard_editor.DrawUI, "Blackboard", UIConfig_GS.canvas_window_style, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); } //End area of popup windows EndWindows(); //End zoomable layout area GUILayout.EndArea(); //End zoomable layout EndZoomableLayout(); //Handle input HandleInput(); }
//Planning Methods ================ public Stack <ActionNode_GS> GeneratePlan(Agent_GS agent) { //First get the world state states //Current WorldState_GS current_world_state = agent.blackboard.GenerateWorldState(); WorldState_GS current_global_world_state = GlobalBlackboard_GS.blackboard.GenerateWorldState(); current_world_state.MixGoals(current_global_world_state); //Goal //Get current as base world state WorldState_GS goal_world_state = new WorldState_GS(current_world_state); //Apply the goals on the current to get the goal world state goal_world_state.MixGoals(agent.goal_world_state); //Check if the current world state and the goal world state coincide float start_goal_distance = current_world_state.DistanceTo(goal_world_state); if (start_goal_distance < ProTools.MIN_PROPERTY_DISTANCE) { Debug.LogWarning("The current world state coincides with the goal world state: " + goal_world_state.name + " !"); return(new Stack <ActionNode_GS>()); } //Allocate plan start node PlannerNode_GS start_node = new PlannerNode_GS(0, start_goal_distance, new_id_number, 0, current_world_state, null); //Clear open and close dictionaries _open.Clear(); _closed.Clear(); //Reset iterations count _current_iterations = 0; //Add start node to the open list _open.Add(start_node.f, new List <PlannerNode_GS> { start_node }); //Iterate open list till there are no nodes to check while (_open.Count > 0) { //Check and update iterations count if (ProTools.ITERATION_LIMIT < _current_iterations) { Debug.LogWarning("Planning generation for agent: " + agent.name + " failed"); break; } else { _current_iterations += 1; } //Current closed node PlannerNode_GS current_node = CloseNode(); //Check if the resultant world state of the current node is the goal world state if (current_node.resultant_world_state.DistanceTo(goal_world_state) < ProTools.MIN_PROPERTY_DISTANCE) { //Allocate a new queue of actions to store the plan Stack <ActionNode_GS> action_plan = new Stack <ActionNode_GS>(); //Enqueue the goal action action_plan.Push(new ActionNode_GS(current_node.action)); //Iterate goal node "childs" to start node using the parent id while (current_node.parent_id != 0) { //Update current node current_node = _closed[current_node.parent_id]; //Check if the node has an action assigned if (current_node.action != null) { //Enqueue the new current node action_plan.Push(new ActionNode_GS(current_node.action)); } } //Flip the generated queue //Return the generated actions queue return(action_plan); } //Iterate all the avaliable actions for (int k = 0; k < agent.action_nodes_num; k++) { if (agent.action_nodes[k].action == null) { continue; } //Scoped action ActionNode_GS scoped_action = agent.action_nodes[k]; //Check if this action is reachable from the current world state if (scoped_action.ValidateWorldState(current_node.resultant_world_state) == false) { //If the current world state is not valid for this actions we discard it and keep iterating the others continue; } //If this action can be executed in the current world state, action effects are applied in the current world state WorldState_GS new_current_world_state = scoped_action.EffectWorldState(current_node.resultant_world_state); //Check if there is an action in the open list that can also reach the new current world state PlannerNode_GS in_open_node = null; if (IsInOpen(new_current_world_state, out in_open_node) == true) { //In true case check if the new node is better if (current_node.g + scoped_action.action_cost > in_open_node.g) { //The old node is better than this new one continue; } //The new node is better than the old, lets update the node data in_open_node.parent_id = current_node.id; in_open_node.g = current_node.g + scoped_action.action_cost; in_open_node.h = new_current_world_state.DistanceTo(goal_world_state); in_open_node.action = scoped_action; } else { //In false case generate a new open node PlannerNode_GS new_node = new PlannerNode_GS(current_node.g + scoped_action.action_cost, new_current_world_state.DistanceTo(goal_world_state), new_id_number, current_node.id, new_current_world_state, scoped_action); //Add the new node to the open list AddToOpen(new_node); } } } //In no plan found case we return an empty plan return(new Stack <ActionNode_GS>()); }