From 568c909ff01e0ba1e0133c623039e5f85a91671f Mon Sep 17 00:00:00 2001 From: Regalis Date: Wed, 30 Nov 2016 16:45:21 +0200 Subject: [PATCH] Improved wire editing logic: - wires have to be selected by clicking before any nodes can be moved - wires can be selected by clicking either the nodes or the sections - new nodes can be added by clicking a section while holding ctrl - the selected wire is drawn on top of all other entities --- .../Source/Items/Components/Signal/Wire.cs | 228 ++++++++++++++---- Subsurface/Source/Screens/EditMapScreen.cs | 14 +- Subsurface/Source/Utils/MathUtils.cs | 7 +- 3 files changed, 195 insertions(+), 54 deletions(-) diff --git a/Subsurface/Source/Items/Components/Signal/Wire.cs b/Subsurface/Source/Items/Components/Signal/Wire.cs index 412d16919..fbc3c2fd7 100644 --- a/Subsurface/Source/Items/Components/Signal/Wire.cs +++ b/Subsurface/Source/Items/Components/Signal/Wire.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; using System; using System.Collections.Generic; using System.Globalization; @@ -63,8 +64,11 @@ namespace Barotrauma.Items.Components private Vector2 newNodePos; + + private static Wire draggingWire; private static int? selectedNodeIndex; + private static int? highlightedNodeIndex; public bool Hidden, Locked; @@ -191,9 +195,15 @@ namespace Barotrauma.Items.Components CleanNodes(); } - Drawable = nodes.Any(); + if (!loading) + { + Item.NewComponentEvent(this, true, true); + //the wire is active if only one end has been connected + IsActive = connections[0] == null ^ connections[1] == null; + } + + Drawable = IsActive || nodes.Any(); - if (!loading) Item.NewComponentEvent(this, true, true); UpdateSections(); @@ -205,7 +215,6 @@ namespace Barotrauma.Items.Components ClearConnections(); IsActive = true; - //Drawable = true; } public override void Unequip(Character character) @@ -265,7 +274,7 @@ namespace Barotrauma.Items.Components item.NewComponentEvent(this, true, true); } - Drawable = sections.Count > 0; + Drawable = IsActive || sections.Count > 0; } public override bool Pick(Character picker) @@ -308,7 +317,7 @@ namespace Barotrauma.Items.Components { sections.Add(new WireSection(nodes[i], nodes[i + 1])); } - Drawable = sections.Count > 0; + Drawable = IsActive || sections.Count > 0; } private void ClearConnections() @@ -389,7 +398,7 @@ namespace Barotrauma.Items.Components public void Draw(SpriteBatch spriteBatch, bool editing) { - if (sections.Count == 0) + if (sections.Count == 0 && !IsActive) { Drawable = false; return; @@ -401,7 +410,7 @@ namespace Barotrauma.Items.Components drawOffset = item.Submarine.DrawPosition + item.Submarine.HiddenSubPosition; } - float depth = wireSprite.Depth + ((item.ID % 100) * 0.00001f); + float depth = item.IsSelected ? 0.0f : wireSprite.Depth + ((item.ID % 100) * 0.00001f); if (item.IsHighlighted) { @@ -422,7 +431,7 @@ namespace Barotrauma.Items.Components { section.Draw(spriteBatch, item.Color, drawOffset, depth, 0.3f); } - + if (IsActive && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance) { WireSection.Draw( @@ -433,78 +442,195 @@ namespace Barotrauma.Items.Components depth, 0.3f); } - - if (!editing || !PlayerInput.MouseInsideWindow || !GameMain.EditMapScreen.WiringMode) return; - if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null) return; + + if (!editing || !GameMain.EditMapScreen.WiringMode) return; for (int i = 0; i < nodes.Count; i++) { - Vector2 worldPos = nodes[i]; - if (item.Submarine != null) worldPos += item.Submarine.Position + item.Submarine.HiddenSubPosition; - worldPos.Y = -worldPos.Y; + Vector2 drawPos = nodes[i]; + if (item.Submarine != null) drawPos += item.Submarine.Position + item.Submarine.HiddenSubPosition; + drawPos.Y = -drawPos.Y; - GUI.DrawRectangle(spriteBatch, worldPos + new Vector2(-3, -3), new Vector2(6, 6), item.Color, true, 0.0f); - - if (IsActive) continue; - - if (GUIComponent.MouseOn != null || - Vector2.Distance(GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), new Vector2(worldPos.X, -worldPos.Y)) > 10.0f) + if (item.IsSelected) { - continue; + GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-5, -5), new Vector2(10, 10), item.Color, true, 0.0f); + + if (highlightedNodeIndex == i) + { + GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-10, -10), new Vector2(20, 20), Color.Red, false, 0.0f); + } } - - GUI.DrawRectangle(spriteBatch, worldPos + new Vector2(-10, -10), new Vector2(20, 20), Color.Red, false, 0.0f); - - if (selectedNodeIndex == null && draggingWire == null)// && !MapEntity.SelectedAny) + else { - if (PlayerInput.LeftButtonDown()) - { - MapEntity.DisableSelect = true; - MapEntity.SelectEntity(item); - draggingWire = this; - selectedNodeIndex = i; - break; - } - else if (PlayerInput.RightButtonClicked()) - { - nodes.RemoveAt(i); - break; - } + GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-3, -3), new Vector2(6, 6), item.Color, true, 0.0f); } } + } - if (PlayerInput.LeftButtonHeld()) + public static void UpdateEditing(List wires) + { + //dragging a node of some wire + if (draggingWire != null) { - if (selectedNodeIndex != null && draggingWire == this) + //cancel dragging + if (!PlayerInput.LeftButtonHeld()) + { + draggingWire = null; + selectedNodeIndex = null; + } + //update dragging + else { MapEntity.DisableSelect = true; - //Nodes[(int)selectedNodeIndex] = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition)-Submarine.HiddenSubPosition+Submarine.Loaded.Position; - Submarine sub = null; - if (connections[0] != null && connections[0].Item.Submarine != null) sub = connections[0].Item.Submarine; - if (connections[1] != null && connections[1].Item.Submarine != null) sub = connections[1].Item.Submarine; + if (draggingWire.connections[0] != null && draggingWire.connections[0].Item.Submarine != null) sub = draggingWire.connections[0].Item.Submarine; + if (draggingWire.connections[1] != null && draggingWire.connections[1].Item.Submarine != null) sub = draggingWire.connections[1].Item.Submarine; Vector2 nodeWorldPos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition) - sub.HiddenSubPosition - sub.Position;// Nodes[(int)selectedNodeIndex]; nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f); nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f); - //if (item.Submarine != null) nodeWorldPos += item.Submarine.Position; + draggingWire.nodes[(int)selectedNodeIndex] = nodeWorldPos; + draggingWire.UpdateSections(); - nodes[(int)selectedNodeIndex] = nodeWorldPos; - UpdateSections(); + MapEntity.SelectEntity(draggingWire.item); + } - MapEntity.SelectEntity(item); + return; + } + + //a wire has been selected -> check if we should start dragging one of the nodes + float nodeSelectDist = 10, sectionSelectDist = 5; + highlightedNodeIndex = null; + if (MapEntity.SelectedList.Count == 1 && MapEntity.SelectedList[0] is Item) + { + Wire selectedWire = ((Item)MapEntity.SelectedList[0]).GetComponent(); + + Vector2 mousePos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); + if (selectedWire.item.Submarine != null) mousePos -= (selectedWire.item.Submarine.Position + selectedWire.item.Submarine.HiddenSubPosition); + + //left click while holding ctrl -> check if the cursor is on a wire section, + //and add a new node if it is + if (PlayerInput.KeyDown(Keys.RightControl) || PlayerInput.KeyDown(Keys.LeftControl)) + { + if (PlayerInput.LeftButtonClicked()) + { + float temp = 0.0f; + int closestSectionIndex = selectedWire.GetClosestSectionIndex(mousePos, sectionSelectDist, out temp); + + if (closestSectionIndex > -1) + { + selectedWire.nodes.Insert(closestSectionIndex+1, mousePos); + selectedWire.UpdateSections(); + } + } + } + else + { + //check if close enough to a node + float temp = 0.0f; + int closestIndex = selectedWire.GetClosestNodeIndex(mousePos, nodeSelectDist, out temp); + if (closestIndex > -1) + { + highlightedNodeIndex = closestIndex; + //start dragging the node + if (PlayerInput.LeftButtonHeld()) + { + draggingWire = selectedWire; + selectedNodeIndex = closestIndex; + } + //remove the node + else if (PlayerInput.RightButtonClicked() && closestIndex > 0 && closestIndex < selectedWire.nodes.Count-1) + { + selectedWire.nodes.RemoveAt(closestIndex); + selectedWire.UpdateSections(); + } + } } } - else + + //check which wire is highlighted with the cursor + Wire highlighted = null; + float closestDist = 0.0f; + foreach (Wire w in wires) { - selectedNodeIndex = null; - draggingWire = null; + Vector2 mousePos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); + if (w.item.Submarine != null) mousePos -= (w.item.Submarine.Position + w.item.Submarine.HiddenSubPosition); + + float dist = 0.0f; + if (w.GetClosestNodeIndex(mousePos, highlighted == null ? nodeSelectDist : closestDist, out dist) > -1) + { + highlighted = w; + closestDist = dist; + } + + if (w.GetClosestSectionIndex(mousePos, highlighted == null ? sectionSelectDist : closestDist, out dist) > -1) + { + highlighted = w; + closestDist = dist; + } + + } + + + if (highlighted != null) + { + highlighted.item.IsHighlighted = true; + + if (PlayerInput.LeftButtonClicked()) + { + MapEntity.DisableSelect = true; + MapEntity.SelectEntity(highlighted.item); + } } } + private int GetClosestNodeIndex(Vector2 pos, float maxDist, out float closestDist) + { + closestDist = 0.0f; + int closestIndex = -1; + + for (int i = 0; i < nodes.Count; i++) + { + float dist = Vector2.Distance(nodes[i], pos); + if (dist > maxDist) continue; + + if (closestIndex == -1 || dist < closestDist) + { + closestIndex = i; + closestDist = dist; + } + } + + return closestIndex; + } + + private int GetClosestSectionIndex(Vector2 mousePos, float maxDist, out float closestDist) + { + closestDist = 0.0f; + int closestIndex = -1; + + for (int i = 0; i < nodes.Count-1; i++) + { + if ((Math.Abs(nodes[i].X - nodes[i + 1].X)<5 || Math.Sign(mousePos.X - nodes[i].X) != Math.Sign(mousePos.X - nodes[i + 1].X)) && + (Math.Abs(nodes[i].Y - nodes[i + 1].Y)<5 || Math.Sign(mousePos.Y - nodes[i].Y) != Math.Sign(mousePos.Y - nodes[i + 1].Y))) + { + float dist = MathUtils.LineToPointDistance(nodes[i], nodes[i + 1], mousePos); + if (dist > maxDist) continue; + + if (closestIndex == -1 || dist < closestDist) + { + closestIndex = i; + closestDist = dist; + } + } + } + + return closestIndex; + } + public override void FlipX() { for (int i = 0; i < nodes.Count; i++) diff --git a/Subsurface/Source/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs index 93e9ebc79..25579070e 100644 --- a/Subsurface/Source/Screens/EditMapScreen.cs +++ b/Subsurface/Source/Screens/EditMapScreen.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework; +using Barotrauma.Items.Components; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using System; @@ -920,6 +921,17 @@ namespace Barotrauma me.IsHighlighted = false; } + if (wiringMode) + { + List wires = new List(); + foreach (Item item in Item.ItemList) + { + var wire = item.GetComponent(); + if (wire != null) wires.Add(wire); + } + Wire.UpdateEditing(wires); + } + if (dummyCharacter.SelectedConstruction==null) { Vector2 mouseSimPos = FarseerPhysics.ConvertUnits.ToSimUnits(dummyCharacter.CursorPosition); diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs index 695be7904..f194bbc09 100644 --- a/Subsurface/Source/Utils/MathUtils.cs +++ b/Subsurface/Source/Utils/MathUtils.cs @@ -235,8 +235,11 @@ namespace Barotrauma public static float LineToPointDistance(Vector2 lineA, Vector2 lineB, Vector2 point) { - return (float)(Math.Abs((lineB.X-lineA.X)*(lineA.Y - point.Y) - (lineA.X - point.X)*(lineB.Y-lineA.Y)) / - Math.Sqrt(Math.Pow(lineB.X - lineA.X, 2) + Math.Pow(lineB.Y - lineA.Y, 2))); + float xDiff = lineB.X - lineA.X; + float yDiff = lineB.Y - lineA.Y; + + return (float)(Math.Abs(xDiff * (lineA.Y - point.Y) - yDiff * (lineA.X - point.X)) / + Math.Sqrt(xDiff * xDiff + yDiff * yDiff)); } public static bool CircleIntersectsRectangle(Vector2 circlePos, float radius, Rectangle rect)