Files
tianrunCRM/Assets/CoolapeFrame/3rd/Hivemind/Editor/View.cs
2020-07-04 14:41:25 +08:00

488 lines
15 KiB
C#

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
namespace Hivemind
{
enum Mode
{
NodeAction,
CanvasAction,
DragNode,
PanCanvas,
ConnectParent,
ConnectChild,
ConnectKillChild,
ConnectLeftChild,
ConnectLeftKillChild,
ConnectRightChild,
ConnectRightKillChild,
InvokeMenu,
None
}
public class View
{
GridRenderer gridRenderer;
Rect canvas;
public Vector2 scrollPoint = Vector2.zero;
NodeRenderer nodeRenderer;
public Editor nodeInspector;
BTEditorWindow editorWindow;
Mode currentMode = Mode.None;
Node contextNode;
Vector2 initialMousePosition = Vector2.zero;
public List<Node> selectedNodes = new List<Node> ();
Vector2 nodeActionOffset = Vector2.zero;
public View (BTEditorWindow owner)
{
editorWindow = owner;
canvas = new Rect (0, 0, owner.position.width, owner.position.height);
}
void DrawNodes (List<Node> nodes)
{
if (nodeRenderer == null)
nodeRenderer = new NodeRenderer ();
int count = nodes.Count;
for (int i = 0; i < count; i++) {
if (nodes [i] != null) {
nodeRenderer.Draw (nodes [i], selectedNodes.Contains (nodes [i]));
}
}
}
public bool Draw (Rect position)
{
bool needsRepaint = HandleMouseEvents (position, BTEditorManager.Manager.behaviorTree.nodes);
scrollPoint = GUI.BeginScrollView (new Rect (0, 0, position.width, position.height), scrollPoint, canvas);
if (gridRenderer == null)
gridRenderer = new GridRenderer ();
gridRenderer.Draw (scrollPoint, canvas);
DrawNodes (BTEditorManager.Manager.behaviorTree.nodes);
if (currentMode == Mode.ConnectChild || currentMode == Mode.ConnectParent
|| currentMode == Mode.ConnectLeftChild || currentMode == Mode.ConnectRightChild) {
DrawConnectionLine (Color.white);
needsRepaint = true;
} else if (currentMode == Mode.ConnectKillChild
|| currentMode == Mode.ConnectRightKillChild
|| currentMode == Mode.ConnectLeftKillChild) {
DrawConnectionLine (Color.red);
needsRepaint = true;
}
GUI.EndScrollView ();
return needsRepaint;
}
void DrawConnectionLine (Color color)
{
Vector3 startPos = Vector3.zero;
Vector3 startTan = Vector3.zero;
Vector3 endPos = new Vector3 (Event.current.mousePosition.x, Event.current.mousePosition.y, 0);
Vector3 endTan = Vector3.zero;
if (currentMode == Mode.ConnectParent) {
startPos = new Vector3 (contextNode.editorPosition.x + (NodeRenderer.Width / 2), contextNode.editorPosition.y, 0);
startTan = startPos + Vector3.down * GridRenderer.step.x * 2;
endTan = endPos + Vector3.up * GridRenderer.step.x * 2;
} else if (currentMode == Mode.ConnectChild || currentMode == Mode.ConnectKillChild) {
startPos = new Vector3 (contextNode.editorPosition.x + (NodeRenderer.Width / 2), contextNode.editorPosition.y + NodeRenderer.Height, 0);
startTan = startPos + Vector3.up * GridRenderer.step.x * 2;
endTan = endPos + Vector3.down * GridRenderer.step.x * 2;
} else if (currentMode == Mode.ConnectLeftChild || currentMode == Mode.ConnectLeftKillChild) {
startPos = new Vector3 (contextNode.editorPosition.x + (NodeRenderer.Width / 2) - (NodeRenderer.Width / 4), contextNode.editorPosition.y + NodeRenderer.Height, 0);
startTan = startPos + Vector3.up * GridRenderer.step.x * 2;
endTan = endPos + Vector3.down * GridRenderer.step.x * 2;
} else if (currentMode == Mode.ConnectRightChild || currentMode == Mode.ConnectRightKillChild) {
startPos = new Vector3 (contextNode.editorPosition.x + (NodeRenderer.Width / 2) + (NodeRenderer.Width / 4), contextNode.editorPosition.y + NodeRenderer.Height, 0);
startTan = startPos + Vector3.up * GridRenderer.step.x * 2;
endTan = endPos + Vector3.down * GridRenderer.step.x * 2;
}
Handles.DrawBezier (startPos, endPos, startTan, endTan, color, null, 4);
// Handles.ArrowCap(0, endPos, Quaternion.FromToRotation(startPos, endPos), 54);
Handles.DrawWireCube (endPos, Vector3.one * 10);
}
// Returns true if needs a repaint
bool HandleMouseEvents (Rect position, List<Node> nodes)
{
// MouseDown //
// Identify the control being clicked
if (Event.current.type == EventType.MouseDown) {
// Do nothing for MouseDown on the horizontal scrollbar, if present
if (canvas.width > position.width && Event.current.mousePosition.y >= position.height - 20) {
currentMode = Mode.None;
}
// Do nothing for MouseDown on the vertical scrollbar, if present
else if (canvas.height > position.height && Event.current.mousePosition.x >= position.width - 20) {
currentMode = Mode.None;
}
// MouseDown in the canvas, check if in a node or on background
else {
// Store the mouse position
initialMousePosition = Event.current.mousePosition;
// Loop through nodes and check if their rects contain the mouse position
for (int i = 0; i < nodes.Count; i++) {
if (nodes [i] != null && nodeRenderer.rectForNode (nodes [i], scrollPoint).Contains (Event.current.mousePosition)) {
// Connect a parent to a child
if (contextNode is NodeBranch) {
if (currentMode == Mode.ConnectLeftChild) {
BTEditorManager.Manager.ConnectLeft ((NodeBranch)contextNode, nodes [i]);
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
break;
} else if (currentMode == Mode.ConnectLeftKillChild) {
BTEditorManager.Manager.ConnectLeftKill ((NodeBranch)contextNode, nodes [i]);
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
break;
} else if (currentMode == Mode.ConnectRightChild) {
BTEditorManager.Manager.ConnectRight ((NodeBranch)contextNode, nodes [i]);
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
break;
} else if (currentMode == Mode.ConnectRightKillChild) {
BTEditorManager.Manager.ConnectRightKill ((NodeBranch)contextNode, nodes [i]);
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
break;
} else if (currentMode == Mode.ConnectParent) {
BTEditorManager.Manager.Connect (nodes [i], contextNode);
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
break;
}
// Perform a node action at key up
else {
currentMode = Mode.NodeAction;
contextNode = nodes [i];
nodeActionOffset = Event.current.mousePosition - nodes [i].editorPosition;
}
} else {
if (currentMode == Mode.ConnectChild) {
BTEditorManager.Manager.Connect (contextNode, nodes [i]);
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
break;
} else if (currentMode == Mode.ConnectKillChild) {
BTEditorManager.Manager.ConnectKill (contextNode, nodes [i]);
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
break;
}
// Connect a child to a parent
else if (currentMode == Mode.ConnectParent) {
BTEditorManager.Manager.Connect (nodes [i], contextNode);
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
break;
}
// Perform a node action at key up
else {
currentMode = Mode.NodeAction;
contextNode = nodes [i];
nodeActionOffset = Event.current.mousePosition - nodes [i].editorPosition;
}
}
}
}
// Cancel the connection
if (currentMode == Mode.ConnectParent || currentMode == Mode.ConnectChild
|| currentMode == Mode.ConnectLeftChild || currentMode == Mode.ConnectRightChild
|| currentMode == Mode.ConnectKillChild || currentMode == Mode.ConnectLeftKillChild
|| currentMode == Mode.ConnectRightKillChild) {
editorWindow.wantsMouseMove = false;
currentMode = Mode.None;
}
// MouseDown on the canvas background enables panning the view
if (currentMode == Mode.None) {
currentMode = Mode.CanvasAction;
}
}
}
// Mouse Up //
// MouseUp resets the current interaction mode to None
if (Event.current.type == EventType.MouseUp) {
// Select node
if (currentMode == Mode.NodeAction && Event.current.button == 0) {
currentMode = Mode.None;
SelectNode (contextNode);
return true;
}
// Deselect node
else if (currentMode == Mode.CanvasAction && Event.current.button == 0) {
SelectNode (null);
currentMode = Mode.None;
return true;
}
// Context Menu
else if (Event.current.button == 1) {
if (currentMode == Mode.NodeAction) {
editorWindow.ShowContextMenu (Event.current.mousePosition, contextNode);
} else if (currentMode == Mode.CanvasAction) {
editorWindow.ShowContextMenu (Event.current.mousePosition, null);
}
currentMode = Mode.None;
}
// Resize canvas after a drag
else if (currentMode == Mode.DragNode) {
ResizeCanvas ();
currentMode = Mode.None;
return true;
} else {
currentMode = Mode.None;
}
}
// Mouse Drag //
if (Event.current.type == EventType.MouseDrag && Event.current.button == 0) {
// Switch to Pan mode
if (currentMode == Mode.CanvasAction) {
currentMode = Mode.PanCanvas;
}
// Switch to node dragging mode
if (currentMode == Mode.NodeAction && contextNode != null) {
float deltaX = Mathf.Abs (Event.current.mousePosition.x - initialMousePosition.x);
float deltaY = Mathf.Abs (Event.current.mousePosition.y - initialMousePosition.y);
// Ignore mouse drags inside nodes lesser than the grid step. These would be rounded,
// and make selecting a node slightly more difficult.
if (deltaX >= GridRenderer.step.x || deltaY >= GridRenderer.step.y) {
currentMode = Mode.DragNode;
}
}
// Pan if the mouse drag initiated by MouseDown outside any windows
if (currentMode == Mode.PanCanvas) {
scrollPoint.x += -Event.current.delta.x;
scrollPoint.y += -Event.current.delta.y;
currentMode = Mode.PanCanvas;
return true;
}
// Drag a node
if (currentMode == Mode.DragNode) {
Vector2 newPositionAbs = Event.current.mousePosition - nodeActionOffset;
float x = newPositionAbs.x - (newPositionAbs.x % GridRenderer.step.x);
float y = newPositionAbs.y - (newPositionAbs.y % GridRenderer.step.y);
DragNode (contextNode, new Vector2 (x, y));
currentMode = Mode.DragNode;
return true;
}
}
return false;
}
public void ResizeCanvas ()
{
Rect newCanvas = new Rect (0, 0, editorWindow.position.width, editorWindow.position.height);
foreach (Node node in BTEditorManager.Manager.behaviorTree.nodes) {
float xOffset = node.editorPosition.x + NodeRenderer.Width + GridRenderer.step.x * 2;
if (xOffset > newCanvas.width) {
newCanvas.width = xOffset;
}
float yOffset = node.editorPosition.y + NodeRenderer.Height + GridRenderer.step.y * 2;
if (yOffset > newCanvas.height) {
newCanvas.height = yOffset;
}
canvas = newCanvas;
}
}
public void SelectNode (Node node)
{
if (node == null) {
selectedNodes.Clear ();
} else {
if (Event.current != null && (Event.current.command || Event.current.control)) {
if (!selectedNodes.Contains (node)) {
selectedNodes.Add (node);
}
} else {
selectedNodes.Clear ();
selectedNodes.Add (node);
}
}
Editor nodeInspector = Editor.CreateEditor (node);
if (nodeInspector != null) {
BTEditorManager.Manager.nodeInspector = nodeInspector;
BTEditorManager.Manager.nodeInspector.Repaint ();
} else if (BTEditorManager.Manager.btInspector != null) {
BTEditorManager.Manager.nodeInspector = null;
BTEditorManager.Manager.btInspector.Repaint ();
}
}
private void DragNode (Node node, Vector2 newPosition)
{
// if (Application.isPlaying) {
// return;
// }
Hashtable map = new Hashtable ();
doDragNode (node, newPosition, ref map);
map.Clear ();
map = null;
}
private void doDragNode (Node node, Vector2 newPosition, ref Hashtable map)
{
Node _node;
map [node] = true;
if (Event.current.shift) {
if (node.ChildCount > 0) {
for (int i = 0; i < node.ChildCount; i++) {
_node = node.Children [i];
Vector2 childOffset = _node.editorPosition - node.editorPosition;
Vector2 newChildPosition = newPosition + childOffset;
if (map [_node] == null) {
doDragNode (_node, newChildPosition, ref map);
}
}
}
for (int i = 0; i < node.KillNodes.Count; i++) {
_node = node.KillNodes [i];
Vector2 childOffset = _node.editorPosition - node.editorPosition;
Vector2 newChildPosition = newPosition + childOffset;
if (map [_node] == null) {
doDragNode (_node, newChildPosition, ref map);
}
}
if (node is NodeBranch) {
for (int i = 0; i < ((NodeBranch)node).ChildrenLeft.Count; i++) {
_node = ((NodeBranch)node).ChildrenLeft [i];
Vector2 childOffset = _node.editorPosition - node.editorPosition;
Vector2 newChildPosition = newPosition + childOffset;
if (map [_node] == null) {
doDragNode (_node, newChildPosition, ref map);
}
}
for (int i = 0; i < ((NodeBranch)node).KillLeftNodes.Count; i++) {
_node = ((NodeBranch)node).KillLeftNodes [i];
Vector2 childOffset = _node.editorPosition - node.editorPosition;
Vector2 newChildPosition = newPosition + childOffset;
if (map [_node] == null) {
doDragNode (_node, newChildPosition, ref map);
}
}
for (int i = 0; i < ((NodeBranch)node).ChildrenRight.Count; i++) {
_node = ((NodeBranch)node).ChildrenRight [i];
Vector2 childOffset = _node.editorPosition - node.editorPosition;
Vector2 newChildPosition = newPosition + childOffset;
if (map [_node] == null) {
doDragNode (_node, newChildPosition, ref map);
}
}
for (int i = 0; i < ((NodeBranch)node).KillRightNodes.Count; i++) {
_node = ((NodeBranch)node).KillRightNodes [i];
Vector2 childOffset = _node.editorPosition - node.editorPosition;
Vector2 newChildPosition = newPosition + childOffset;
if (map [_node] == null) {
doDragNode (_node, newChildPosition, ref map);
}
}
}
}
BTEditorManager.Manager.SetEditorPosition (node, newPosition);
}
public void ConnectParent (Node node)
{
editorWindow.wantsMouseMove = true;
contextNode = node;
currentMode = Mode.ConnectParent;
}
public void ConnectChild (Node node)
{
editorWindow.wantsMouseMove = true;
contextNode = node;
currentMode = Mode.ConnectChild;
}
public void ConnectKillChild (Node node)
{
editorWindow.wantsMouseMove = true;
contextNode = node;
currentMode = Mode.ConnectKillChild;
}
public void ConnectLeftChild (Node node)
{
editorWindow.wantsMouseMove = true;
contextNode = node;
currentMode = Mode.ConnectLeftChild;
}
public void ConnectLeftKillChild (Node node)
{
editorWindow.wantsMouseMove = true;
contextNode = node;
currentMode = Mode.ConnectLeftKillChild;
}
public void ConnectRightChild (Node node)
{
editorWindow.wantsMouseMove = true;
contextNode = node;
currentMode = Mode.ConnectRightChild;
}
public void ConnectRightKillChild (Node node)
{
editorWindow.wantsMouseMove = true;
contextNode = node;
currentMode = Mode.ConnectRightKillChild;
}
}
}