From b493ed2b390dc0e4d87a45e38057cd843ea56479 Mon Sep 17 00:00:00 2001 From: Regalis Date: Mon, 29 Jun 2015 23:51:01 +0300 Subject: [PATCH] ItemComponent GUIFrames, functional steering, radar, separate power and signals, improved d.gz, tweak swimming --- .../Characters/HumanoidAnimController.cs | 44 ++++-- Subsurface/Characters/Limb.cs | 11 +- Subsurface/Content/Items/Engine/engine.xml | 16 ++- Subsurface/Content/Items/MiniMap/item.xml | 4 +- Subsurface/Content/Items/Reactor/reactor.xml | 1 + Subsurface/Content/Items/poweritems.xml | 15 +- Subsurface/GUI/GUI.cs | 16 +-- Subsurface/GUI/GUIComponent.cs | 74 +++++----- Subsurface/GUI/GUIFrame.cs | 9 +- Subsurface/Game1.cs | 2 +- Subsurface/Items/Components/Door.cs | 2 +- .../Components/{ => Holdable}/Holdable.cs | 0 .../Components/{ => Holdable}/Pickable.cs | 0 .../Components/{ => Holdable}/RangedWeapon.cs | 4 +- .../Components/{ => Holdable}/RepairTool.cs | 0 .../Components/{ => Holdable}/Throwable.cs | 0 Subsurface/Items/Components/ItemComponent.cs | 43 +++++- .../Components/{ => Machines}/Controller.cs | 0 .../Items/Components/{ => Machines}/Engine.cs | 21 +-- .../Components/{ => Machines}/Fabricator.cs | 0 .../Components/{ => Machines}/MiniMap.cs | 9 +- .../{ => Machines}/OxygenGenerator.cs | 0 .../Items/Components/{ => Machines}/Pump.cs | 8 +- Subsurface/Items/Components/Machines/Radar.cs | 86 +++++++++++ .../Components/{ => Machines}/Reactor.cs | 8 +- .../Components/{ => Machines}/Steering.cs | 37 ++--- .../Items/Components/{ => Machines}/Vent.cs | 0 .../Components/{ => Power}/PowerContainer.cs | 0 .../Components/{ => Power}/PowerTransfer.cs | 23 ++- .../Items/Components/{ => Power}/Powered.cs | 10 +- .../Items/Components/Signal/AndComponent.cs | 2 +- .../Items/Components/Signal/Connection.cs | 4 +- .../Items/Components/Signal/LightComponent.cs | 2 +- .../Items/Components/Signal/NotComponent.cs | 4 +- .../Components/Signal/RegExFindComponent.cs | 6 +- Subsurface/Items/Item.cs | 5 +- Subsurface/Map/Level.cs | 133 +++++++++++++++--- Subsurface/Map/Submarine.cs | 15 +- Subsurface/Map/VoronoiElements.cs | 2 + Subsurface/Subsurface.csproj | 35 ++--- Subsurface/ToolBox.cs | 4 +- Subsurface_Solution.v12.suo | Bin 354304 -> 363520 bytes 42 files changed, 473 insertions(+), 182 deletions(-) rename Subsurface/Items/Components/{ => Holdable}/Holdable.cs (100%) rename Subsurface/Items/Components/{ => Holdable}/Pickable.cs (100%) rename Subsurface/Items/Components/{ => Holdable}/RangedWeapon.cs (95%) rename Subsurface/Items/Components/{ => Holdable}/RepairTool.cs (100%) rename Subsurface/Items/Components/{ => Holdable}/Throwable.cs (100%) rename Subsurface/Items/Components/{ => Machines}/Controller.cs (100%) rename Subsurface/Items/Components/{ => Machines}/Engine.cs (75%) rename Subsurface/Items/Components/{ => Machines}/Fabricator.cs (100%) rename Subsurface/Items/Components/{ => Machines}/MiniMap.cs (89%) rename Subsurface/Items/Components/{ => Machines}/OxygenGenerator.cs (100%) rename Subsurface/Items/Components/{ => Machines}/Pump.cs (95%) create mode 100644 Subsurface/Items/Components/Machines/Radar.cs rename Subsurface/Items/Components/{ => Machines}/Reactor.cs (98%) rename Subsurface/Items/Components/{ => Machines}/Steering.cs (70%) rename Subsurface/Items/Components/{ => Machines}/Vent.cs (100%) rename Subsurface/Items/Components/{ => Power}/PowerContainer.cs (100%) rename Subsurface/Items/Components/{ => Power}/PowerTransfer.cs (87%) rename Subsurface/Items/Components/{ => Power}/Powered.cs (89%) diff --git a/Subsurface/Characters/HumanoidAnimController.cs b/Subsurface/Characters/HumanoidAnimController.cs index 2ca0847f3..8946a8163 100644 --- a/Subsurface/Characters/HumanoidAnimController.cs +++ b/Subsurface/Characters/HumanoidAnimController.cs @@ -32,7 +32,7 @@ namespace Subsurface { case Physics.CollisionStairs: Structure structure = fixture.Body.UserData as Structure; - if (stairs == null && (!inWater || TargetMovement.Y>0.0f) && structure!=null) + if (stairs == null && !inWater && structure!=null) { if (LowestLimb.SimPosition.Y 20.0f) return; } - Limb leftFoot = GetLimb(LimbType.LeftFoot); - Limb rightFoot = GetLimb(LimbType.RightFoot); Limb torso = GetLimb(LimbType.Torso); Limb leftHand = GetLimb(LimbType.LeftHand); Limb rightHand = GetLimb(LimbType.RightHand); + Limb leftFoot = GetLimb(LimbType.LeftFoot); + Limb rightFoot = GetLimb(LimbType.RightFoot); + Limb leftLeg = GetLimb(LimbType.LeftLeg); + Limb rightLeg = GetLimb(LimbType.RightLeg); float rotation = MathHelper.WrapAngle(torso.Rotation); rotation = MathHelper.ToDegrees(rotation); @@ -397,9 +404,9 @@ namespace Subsurface if (TargetMovement.X == 0.0f) { head.body.ApplyForce(head.Mass * new Vector2(-Dir * 5.1f, -5.0f)); - torso.body.ApplyForce(torso.Mass *new Vector2(-Dir*5.1f, -15.0f)); - leftFoot.body.ApplyForce(leftFoot.Mass *new Vector2(0.0f, -80.0f)); - rightFoot.body.ApplyForce(rightFoot.Mass *new Vector2(0.0f, -80.0f)); + torso.body.ApplyForce(torso.Mass * new Vector2(-Dir * 5.1f, -15.0f)); + leftFoot.body.ApplyForce(leftFoot.Mass * new Vector2(0.0f, -80.0f)); + rightFoot.body.ApplyForce(rightFoot.Mass * new Vector2(0.0f, -80.0f)); } else { @@ -432,12 +439,19 @@ namespace Subsurface MoveLimb(leftFoot, footPos + transformedFootPos, 2.5f); MoveLimb(rightFoot, footPos - transformedFootPos, 2.5f); - Vector2 feetExtendForce = new Vector2( - (float)-Math.Sin(torso.body.Rotation), - (float)Math.Cos(torso.body.Rotation)); + float legCorrection = MathUtils.GetShortestAngle(leftLeg.Rotation, torso.body.Rotation); - leftFoot.body.ApplyForce(feetExtendForce); - rightFoot.body.ApplyForce(feetExtendForce); + leftLeg.body.ApplyTorque(legCorrection); + + legCorrection = MathUtils.GetShortestAngle(rightLeg.Rotation, torso.body.Rotation); + + rightLeg.body.ApplyTorque(legCorrection); + //Vector2 feetExtendForce = new Vector2( + // (float)-Math.Sin(torso.body.Rotation), + // (float)Math.Cos(torso.body.Rotation)); + + //leftFoot.body.ApplyForce(feetExtendForce); + //rightFoot.body.ApplyForce(feetExtendForce); leftFoot.body.ApplyTorque(leftFoot.body.Mass * -Dir); rightFoot.body.ApplyTorque(rightFoot.body.Mass * -Dir); diff --git a/Subsurface/Characters/Limb.cs b/Subsurface/Characters/Limb.cs index 9f0ed97b3..a17e19bb7 100644 --- a/Subsurface/Characters/Limb.cs +++ b/Subsurface/Characters/Limb.cs @@ -187,7 +187,16 @@ namespace Subsurface if (element.Attribute("type") != null) { - type = (LimbType)Enum.Parse(typeof(LimbType), element.Attribute("type").Value, true); + try + { + type = (LimbType)Enum.Parse(typeof(LimbType), element.Attribute("type").Value, true); + } + catch + { + type = LimbType.None; + DebugConsole.ThrowError("Error in "+element+"! ''"+element.Attribute("type").Value+"'' is not a valid limb type"); + } + Vector2 jointPos = ToolBox.GetAttributeVector2(element, "pullpos", Vector2.Zero); diff --git a/Subsurface/Content/Items/Engine/engine.xml b/Subsurface/Content/Items/Engine/engine.xml index 4f804353d..4a7a2aa76 100644 --- a/Subsurface/Content/Items/Engine/engine.xml +++ b/Subsurface/Content/Items/Engine/engine.xml @@ -7,14 +7,16 @@ pickdistance="150"> - - + + + + - + - + + + + + + + diff --git a/Subsurface/Content/Items/MiniMap/item.xml b/Subsurface/Content/Items/MiniMap/item.xml index 91be063eb..82e32f95c 100644 --- a/Subsurface/Content/Items/MiniMap/item.xml +++ b/Subsurface/Content/Items/MiniMap/item.xml @@ -6,7 +6,9 @@ - + + + diff --git a/Subsurface/Content/Items/Reactor/reactor.xml b/Subsurface/Content/Items/Reactor/reactor.xml index d794b8eee..51f98f343 100644 --- a/Subsurface/Content/Items/Reactor/reactor.xml +++ b/Subsurface/Content/Items/Reactor/reactor.xml @@ -9,6 +9,7 @@ + diff --git a/Subsurface/Content/Items/poweritems.xml b/Subsurface/Content/Items/poweritems.xml index 0718b56ea..907bc87f1 100644 --- a/Subsurface/Content/Items/poweritems.xml +++ b/Subsurface/Content/Items/poweritems.xml @@ -8,12 +8,15 @@ - + + + - - + + + @@ -23,8 +26,10 @@ pickdistance="150"> - - + + + + diff --git a/Subsurface/GUI/GUI.cs b/Subsurface/GUI/GUI.cs index 3f80d1b19..5c6ad18fd 100644 --- a/Subsurface/GUI/GUI.cs +++ b/Subsurface/GUI/GUI.cs @@ -264,15 +264,15 @@ namespace Subsurface public static void Draw(float deltaTime, SpriteBatch spriteBatch, Camera cam) { - spriteBatch.DrawString(font, - "FPS: " + (int)Game1.frameCounter.AverageFramesPerSecond - + " - render: " + Game1.renderTimeElapsed, - new Vector2(10, 10), Color.White); + //spriteBatch.DrawString(font, + // "FPS: " + (int)Game1.frameCounter.AverageFramesPerSecond + // + " - render: " + Game1.renderTimeElapsed, + // new Vector2(10, 10), Color.White); - spriteBatch.DrawString(font, - "Physics: " + Game1.world.UpdateTime - + " - bodies: " + Game1.world.BodyList.Count, - new Vector2(10, 30), Color.White); + //spriteBatch.DrawString(font, + // "Physics: " + Game1.world.UpdateTime + // + " - bodies: " + Game1.world.BodyList.Count, + // new Vector2(10, 30), Color.White); if (Character.Controlled != null && cam!=null) Character.Controlled.DrawHud(spriteBatch, cam); diff --git a/Subsurface/GUI/GUIComponent.cs b/Subsurface/GUI/GUIComponent.cs index a2fbf255c..966d97f2b 100644 --- a/Subsurface/GUI/GUIComponent.cs +++ b/Subsurface/GUI/GUIComponent.cs @@ -39,6 +39,11 @@ namespace Subsurface { get { return parent; } } + + public Vector2 Center + { + get { return new Vector2(rect.Center.X, rect.Center.Y); } + } public Rectangle Rect { @@ -192,43 +197,44 @@ namespace Subsurface } } - protected virtual void UpdateDimensions(GUIComponent parent) + protected virtual void UpdateDimensions(GUIComponent parent = null) { - if (parent!=null) + Rectangle parentRect = (parent==null) ? new Rectangle(0,0,Game1.GraphicsWidth, Game1.GraphicsHeight) : parent.rect; + + Vector4 padding = (parent == null) ? Vector4.Zero : parent.padding; + + if (rect.Width == 0) rect.Width = parentRect.Width - rect.X + - (int)padding.X - (int)padding.Z; + + if (rect.Height == 0) rect.Height = parentRect.Height - rect.Y + - (int)padding.Y - (int)padding.W; + + if (alignment.HasFlag(Alignment.CenterX)) { - if (rect.Width == 0) rect.Width = parent.Rect.Width - rect.X - - (int)parent.Padding.X - (int)parent.Padding.Z; - - if (rect.Height == 0) rect.Height = parent.Rect.Height - rect.Y - - (int)parent.Padding.Y - (int)parent.Padding.W; - - if (alignment.HasFlag(Alignment.CenterX)) - { - rect.X += parent.Rect.X + (int)parent.Rect.Width/2 - (int)rect.Width/2; - } - else if (alignment.HasFlag(Alignment.Right)) - { - rect.X += parent.Rect.X + (int)parent.Rect.Width - (int)parent.Padding.Z - (int)rect.Width; - } - else - { - rect.X += parent.Rect.X + (int)parent.Padding.X; - } - - if (alignment.HasFlag(Alignment.CenterY)) - { - rect.Y += parent.Rect.Y + (int)parent.Rect.Height / 2 - (int)rect.Height / 2; - } - else if (alignment.HasFlag(Alignment.Bottom)) - { - rect.Y += parent.Rect.Y + (int)parent.Rect.Height - (int)parent.Padding.W - (int)rect.Height; - } - else - { - rect.Y += parent.Rect.Y + (int)parent.Padding.Y; - } - + rect.X += parentRect.X + (int)parentRect.Width/2 - (int)rect.Width/2; } + else if (alignment.HasFlag(Alignment.Right)) + { + rect.X += parentRect.X + (int)parentRect.Width - (int)padding.Z - (int)rect.Width; + } + else + { + rect.X += parentRect.X + (int)padding.X; + } + + if (alignment.HasFlag(Alignment.CenterY)) + { + rect.Y += parentRect.Y + (int)parentRect.Height / 2 - (int)rect.Height / 2; + } + else if (alignment.HasFlag(Alignment.Bottom)) + { + rect.Y += parentRect.Y + (int)parentRect.Height - (int)padding.W - (int)rect.Height; + } + else + { + rect.Y += parentRect.Y + (int)padding.Y; + } + } public virtual void DrawChildren(SpriteBatch spriteBatch) diff --git a/Subsurface/GUI/GUIFrame.cs b/Subsurface/GUI/GUIFrame.cs index ecfee361d..06d726c25 100644 --- a/Subsurface/GUI/GUIFrame.cs +++ b/Subsurface/GUI/GUIFrame.cs @@ -23,8 +23,15 @@ namespace Subsurface this.alignment = alignment; this.color = color; - if (parent!=null) + + if (parent != null) + { parent.AddChild(this); + } + else + { + UpdateDimensions(); + } } public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) diff --git a/Subsurface/Game1.cs b/Subsurface/Game1.cs index 847a4062d..7f1d87d91 100644 --- a/Subsurface/Game1.cs +++ b/Subsurface/Game1.cs @@ -49,7 +49,7 @@ namespace Subsurface public static Random random; //private Stopwatch renderTimer; - public static int renderTimeElapsed; + //public static int renderTimeElapsed; public Camera Cam diff --git a/Subsurface/Items/Components/Door.cs b/Subsurface/Items/Components/Door.cs index 459cba8cd..2be769c5e 100644 --- a/Subsurface/Items/Components/Door.cs +++ b/Subsurface/Items/Components/Door.cs @@ -310,7 +310,7 @@ namespace Subsurface.Items.Components if (convexHull2 != null) convexHull2.Remove(); } - public override void ReceiveSignal(string signal, Connection connection, Item sender) + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f) { if (connection.name=="toggle") { diff --git a/Subsurface/Items/Components/Holdable.cs b/Subsurface/Items/Components/Holdable/Holdable.cs similarity index 100% rename from Subsurface/Items/Components/Holdable.cs rename to Subsurface/Items/Components/Holdable/Holdable.cs diff --git a/Subsurface/Items/Components/Pickable.cs b/Subsurface/Items/Components/Holdable/Pickable.cs similarity index 100% rename from Subsurface/Items/Components/Pickable.cs rename to Subsurface/Items/Components/Holdable/Pickable.cs diff --git a/Subsurface/Items/Components/RangedWeapon.cs b/Subsurface/Items/Components/Holdable/RangedWeapon.cs similarity index 95% rename from Subsurface/Items/Components/RangedWeapon.cs rename to Subsurface/Items/Components/Holdable/RangedWeapon.cs index 5affe69de..dfc0ec150 100644 --- a/Subsurface/Items/Components/RangedWeapon.cs +++ b/Subsurface/Items/Components/Holdable/RangedWeapon.cs @@ -35,8 +35,8 @@ namespace Subsurface.Items.Components public RangedWeapon(Item item, XElement element) : base(item, element) { - barrelPos = ToolBox.GetAttributeVector2(element, "barrelpos", Vector2.Zero); - barrelPos = ConvertUnits.ToSimUnits(barrelPos); + //barrelPos = ToolBox.GetAttributeVector2(element, "barrelpos", Vector2.Zero); + //barrelPos = ConvertUnits.ToSimUnits(barrelPos); } public override void Update(float deltaTime, Camera cam) diff --git a/Subsurface/Items/Components/RepairTool.cs b/Subsurface/Items/Components/Holdable/RepairTool.cs similarity index 100% rename from Subsurface/Items/Components/RepairTool.cs rename to Subsurface/Items/Components/Holdable/RepairTool.cs diff --git a/Subsurface/Items/Components/Throwable.cs b/Subsurface/Items/Components/Holdable/Throwable.cs similarity index 100% rename from Subsurface/Items/Components/Throwable.cs rename to Subsurface/Items/Components/Holdable/Throwable.cs diff --git a/Subsurface/Items/Components/ItemComponent.cs b/Subsurface/Items/Components/ItemComponent.cs index 5e7763ff8..58c5b5dcf 100644 --- a/Subsurface/Items/Components/ItemComponent.cs +++ b/Subsurface/Items/Components/ItemComponent.cs @@ -54,6 +54,8 @@ namespace Subsurface private List sounds; + private GUIFrame guiFrame; + public readonly Dictionary properties; public Dictionary ObjectProperties { @@ -96,6 +98,19 @@ namespace Subsurface get { return name; } } + protected GUIFrame GuiFrame + { + get + { + if (guiFrame==null) + { + DebugConsole.ThrowError("Error: the component "+name+" in "+item.Name+" doesn't have a guiFrame"); + guiFrame = new GUIFrame(new Rectangle(0, 0, 100, 100), Color.Black); + } + return guiFrame; + } + } + [HasDefaultValue("", false)] public string Msg { @@ -153,6 +168,32 @@ namespace Subsurface case "statuseffect": statusEffects.Add(StatusEffect.Load(subElement)); break; + case "guiframe": + Vector4 rect = ToolBox.GetAttributeVector4(subElement, "rect", Vector4.One); + rect.X *= Game1.GraphicsWidth; + rect.Y *= Game1.GraphicsHeight; + rect.Z *= Game1.GraphicsWidth; + rect.W *= Game1.GraphicsHeight; + + Vector4 color = ToolBox.GetAttributeVector4(subElement, "color", Vector4.One); + + Alignment alignment = Alignment.Center; + try + { + alignment = (Alignment)Enum.Parse(typeof(Alignment), + ToolBox.GetAttributeString(subElement, "alignment", "Center"), true); + } + catch + { + DebugConsole.ThrowError("Error in " + element + "! ''" + element.Attribute("type").Value + "'' is not a valid alignment"); + } + + guiFrame = new GUIFrame( + new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Z, (int)rect.W), + new Color(color.X, color.Y, color.Z), alignment); + guiFrame.Alpha = color.W; + + break; case "sound": string filePath = ToolBox.GetAttributeString(subElement, "file", ""); if (filePath=="") continue; @@ -284,7 +325,7 @@ namespace Subsurface return false; } - public virtual void ReceiveSignal(string signal, Connection connection, Item sender) { } + public virtual void ReceiveSignal(string signal, Connection connection, Item sender, float power = 0.0f) { } public virtual bool Combine(Item item) { diff --git a/Subsurface/Items/Components/Controller.cs b/Subsurface/Items/Components/Machines/Controller.cs similarity index 100% rename from Subsurface/Items/Components/Controller.cs rename to Subsurface/Items/Components/Machines/Controller.cs diff --git a/Subsurface/Items/Components/Engine.cs b/Subsurface/Items/Components/Machines/Engine.cs similarity index 75% rename from Subsurface/Items/Components/Engine.cs rename to Subsurface/Items/Components/Machines/Engine.cs index 4db0fa5bc..3c7b1e94c 100644 --- a/Subsurface/Items/Components/Engine.cs +++ b/Subsurface/Items/Components/Machines/Engine.cs @@ -71,17 +71,18 @@ namespace Subsurface.Items.Components public override void DrawHUD(SpriteBatch spriteBatch, Character character) { //isActive = true; + GuiFrame.Draw(spriteBatch); + + //int width = 300, height = 300; + //int x = Game1.GraphicsWidth / 2 - width / 2; + //int y = Game1.GraphicsHeight / 2 - height / 2 - 50; - int width = 300, height = 300; - int x = Game1.GraphicsWidth / 2 - width / 2; - int y = Game1.GraphicsHeight / 2 - height / 2 - 50; + //GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); - GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); + spriteBatch.DrawString(GUI.font, "Force: " + (int)targetForce + " %", new Vector2(GuiFrame.Rect.X + 30, GuiFrame.Rect.Y + 30), Color.White); - spriteBatch.DrawString(GUI.font, "Force: " + (int)targetForce+" %", new Vector2(x + 30, y + 30), Color.White); - - if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 30, 40, 40), "+", true)) targetForce += 1.0f; - if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 80, 40, 40), "-", true)) targetForce -= 1.0f; + if (GUI.DrawButton(spriteBatch, new Rectangle(GuiFrame.Rect.X + 280, GuiFrame.Rect.Y + 30, 40, 40), "+", true)) targetForce += 1.0f; + if (GUI.DrawButton(spriteBatch, new Rectangle(GuiFrame.Rect.X + 280, GuiFrame.Rect.Y + 80, 40, 40), "-", true)) targetForce -= 1.0f; item.NewComponentEvent(this, true); } @@ -91,9 +92,9 @@ namespace Subsurface.Items.Components force = MathHelper.Lerp(force, 0.0f, 0.1f); } - public override void ReceiveSignal(string signal, Connection connection, Item sender) + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f) { - base.ReceiveSignal(signal, connection, sender); + base.ReceiveSignal(signal, connection, sender, power); if (connection.name == "set_force") { diff --git a/Subsurface/Items/Components/Fabricator.cs b/Subsurface/Items/Components/Machines/Fabricator.cs similarity index 100% rename from Subsurface/Items/Components/Fabricator.cs rename to Subsurface/Items/Components/Machines/Fabricator.cs diff --git a/Subsurface/Items/Components/MiniMap.cs b/Subsurface/Items/Components/Machines/MiniMap.cs similarity index 89% rename from Subsurface/Items/Components/MiniMap.cs rename to Subsurface/Items/Components/Machines/MiniMap.cs index 1f501484d..cbc32393a 100644 --- a/Subsurface/Items/Components/MiniMap.cs +++ b/Subsurface/Items/Components/Machines/MiniMap.cs @@ -32,12 +32,13 @@ namespace Subsurface.Items.Components public override void DrawHUD(SpriteBatch spriteBatch, Character character) { - int width = 500, height = 400; - int x = Game1.GraphicsWidth / 2 - width / 2; - int y = Game1.GraphicsHeight / 2 - height / 2; + int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height; + int x = GuiFrame.Rect.X; + int y = GuiFrame.Rect.Y; + GuiFrame.Draw(spriteBatch); - GUI.DrawRectangle(spriteBatch, new Rectangle(x,y,width,height), Color.Black, true); + //GUI.DrawRectangle(spriteBatch, new Rectangle(x,y,width,height), Color.Black, true); Rectangle miniMap = new Rectangle(x + 20, y + 40, width - 40, height - 60); diff --git a/Subsurface/Items/Components/OxygenGenerator.cs b/Subsurface/Items/Components/Machines/OxygenGenerator.cs similarity index 100% rename from Subsurface/Items/Components/OxygenGenerator.cs rename to Subsurface/Items/Components/Machines/OxygenGenerator.cs diff --git a/Subsurface/Items/Components/Pump.cs b/Subsurface/Items/Components/Machines/Pump.cs similarity index 95% rename from Subsurface/Items/Components/Pump.cs rename to Subsurface/Items/Components/Machines/Pump.cs index 302a78c80..26b3db691 100644 --- a/Subsurface/Items/Components/Pump.cs +++ b/Subsurface/Items/Components/Machines/Pump.cs @@ -133,9 +133,11 @@ namespace Subsurface.Items.Components // } //} - public override void ReceiveSignal(string signal, Connection connection, Item sender) + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f) { - base.ReceiveSignal(signal, connection, sender); + base.ReceiveSignal(signal, connection, sender, power); + + isActive = true; if (connection.name == "toggle") { @@ -150,7 +152,7 @@ namespace Subsurface.Items.Components float tempSpeed; if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out tempSpeed)) { - flowPercentage = MathHelper.Clamp(flowPercentage, -100.0f, 100.0f); + flowPercentage = MathHelper.Clamp(tempSpeed, -100.0f, 100.0f); } } diff --git a/Subsurface/Items/Components/Machines/Radar.cs b/Subsurface/Items/Components/Machines/Radar.cs new file mode 100644 index 000000000..e38f65e58 --- /dev/null +++ b/Subsurface/Items/Components/Machines/Radar.cs @@ -0,0 +1,86 @@ +using FarseerPhysics; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Subsurface.Items.Components +{ + class Radar : ItemComponent + { + float range; + + float angle; + + //RenderTarget2D renderTarget; + + [HasDefaultValue(0.0f, false)] + public float Range + { + get { return ConvertUnits.ToDisplayUnits(range); } + set { range = ConvertUnits.ToSimUnits(value); } + } + + public Radar(Item item, XElement element) + : base(item, element) + { + //renderTarget = new RenderTarget2D(Game1.CurrGraphicsDevice, GuiFrame.Rect.Width, GuiFrame.Rect.Height); + } + + public override void Update(float deltaTime, Camera cam) + { + base.Update(deltaTime, cam); + + angle = (angle + deltaTime) % MathHelper.TwoPi; + } + + public override void DrawHUD(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch, Character character) + { + int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height; + int x = GuiFrame.Rect.X; + int y = GuiFrame.Rect.Y; + + GuiFrame.Draw(spriteBatch); + + if (GUI.DrawButton(spriteBatch, new Rectangle(x+20, y+20, 200, 30), "Activate Radar")) isActive = !isActive; + + Vector2 lineEnd = GuiFrame.Center; + lineEnd += new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle))*Math.Min(width,height)/2.0f; + GUI.DrawLine(spriteBatch, GuiFrame.Center, lineEnd, Color.Green); + + if (!isActive) return; + + float scale = 0.01f; + + List edges = Level.Loaded.GetCellEdges(-Level.Loaded.position, 5); + Vector2 offset = Vector2.Zero; //Level.Loaded.position; + //offset.Y = -offset.Y; + + for (int i = 0; i < edges.Count; i++) + { + GUI.DrawLine(spriteBatch, + GuiFrame.Center + (edges[i][0] - offset) * scale, + GuiFrame.Center + (edges[i][1] - offset) * scale, Color.Green); + } + + scale = ConvertUnits.ToDisplayUnits(scale); + for (int i = 0; i< Submarine.Loaded.HullVertices.Count; i++) + { + Vector2 start =Submarine.Loaded.HullVertices[i] * scale; + start.Y = -start.Y; + Vector2 end = Submarine.Loaded.HullVertices[(i+1)%Submarine.Loaded.HullVertices.Count] * scale; + end.Y = -end.Y; + + GUI.DrawLine(spriteBatch, GuiFrame.Center + start,GuiFrame.Center + end, Color.Green); + } + } + + private void UpdateRendertarget() + { + + } + } +} diff --git a/Subsurface/Items/Components/Reactor.cs b/Subsurface/Items/Components/Machines/Reactor.cs similarity index 98% rename from Subsurface/Items/Components/Reactor.cs rename to Subsurface/Items/Components/Machines/Reactor.cs index 433926992..2a34e610f 100644 --- a/Subsurface/Items/Components/Reactor.cs +++ b/Subsurface/Items/Components/Machines/Reactor.cs @@ -300,9 +300,11 @@ namespace Subsurface.Items.Components { isActive = true; - int width = 500, height = 420; - int x = Game1.GraphicsWidth / 2 - width / 2; - int y = Game1.GraphicsHeight / 2 - height / 2 - 50; + int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height; + int x = GuiFrame.Rect.X; + int y = GuiFrame.Rect.Y; + + GuiFrame.Draw(spriteBatch); float xOffset = (graphTimer / (float)updateGraphInterval); diff --git a/Subsurface/Items/Components/Steering.cs b/Subsurface/Items/Components/Machines/Steering.cs similarity index 70% rename from Subsurface/Items/Components/Steering.cs rename to Subsurface/Items/Components/Machines/Steering.cs index 43367febe..95b3d9721 100644 --- a/Subsurface/Items/Components/Steering.cs +++ b/Subsurface/Items/Components/Machines/Steering.cs @@ -23,24 +23,22 @@ namespace Subsurface.Items.Components { base.Update(deltaTime, cam); - item.SendSignal(targetVelocity.X.ToString(), "velocity_x_out", item); - item.SendSignal(targetVelocity.Y.ToString(), "velocity_y_out", item); + item.SendSignal(targetVelocity.X.ToString(), "velocity_x_out"); + item.SendSignal((-targetVelocity.Y).ToString(), "velocity_y_out"); } public override void DrawHUD(SpriteBatch spriteBatch, Character character) { - //isActive = true; + int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height; + int x = GuiFrame.Rect.X; + int y = GuiFrame.Rect.Y; - int width = 300, height = 300; - int x = Game1.GraphicsWidth / 2 - width / 2; - int y = Game1.GraphicsHeight / 2 - height / 2 - 50; + GuiFrame.Draw(spriteBatch); - GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); - - Rectangle velRect = new Rectangle(x+20, y+20, 100, 100); + Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40); GUI.DrawRectangle(spriteBatch, velRect, Color.White, false); - GUI.DrawLine(spriteBatch, + GUI.DrawLine(spriteBatch, new Vector2(velRect.Center.X,velRect.Center.Y), new Vector2(velRect.Center.X + currVelocity.X, velRect.Center.Y - currVelocity.Y), Color.Gray); @@ -65,20 +63,27 @@ namespace Subsurface.Items.Components } } - //spriteBatch.DrawString(GUI.font, "Force: " + (int)force + " %", new Vector2(x + 30, y + 30), Color.White); - - //if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 30, 40, 40), "+", true)) targetForce += 1.0f; - //if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 80, 40, 40), "-", true)) targetForce -= 1.0f; - item.NewComponentEvent(this, true); } - public override void ReceiveSignal(string signal, Connection connection, Item sender) + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f) { if (connection.name == "velocity_in") { currVelocity = ToolBox.ParseToVector2(signal, false); } } + + public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message) + { + message.Write(targetVelocity.X); + message.Write(targetVelocity.Y); + } + + public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message) + { + targetVelocity.X = message.ReadFloat(); + targetVelocity.Y = message.ReadFloat(); + } } } diff --git a/Subsurface/Items/Components/Vent.cs b/Subsurface/Items/Components/Machines/Vent.cs similarity index 100% rename from Subsurface/Items/Components/Vent.cs rename to Subsurface/Items/Components/Machines/Vent.cs diff --git a/Subsurface/Items/Components/PowerContainer.cs b/Subsurface/Items/Components/Power/PowerContainer.cs similarity index 100% rename from Subsurface/Items/Components/PowerContainer.cs rename to Subsurface/Items/Components/Power/PowerContainer.cs diff --git a/Subsurface/Items/Components/PowerTransfer.cs b/Subsurface/Items/Components/Power/PowerTransfer.cs similarity index 87% rename from Subsurface/Items/Components/PowerTransfer.cs rename to Subsurface/Items/Components/Power/PowerTransfer.cs index f8691148f..e8990bc83 100644 --- a/Subsurface/Items/Components/PowerTransfer.cs +++ b/Subsurface/Items/Components/Power/PowerTransfer.cs @@ -49,9 +49,8 @@ namespace Subsurface.Items.Components { pt.powerLoad += (fullLoad - pt.powerLoad) / inertia; pt.currPowerConsumption += (-fullPower - pt.currPowerConsumption) / inertia; - pt.Item.SendSignal( - (fullPower / Math.Max(fullLoad,1.0f)).ToString(CultureInfo.InvariantCulture), - "power_out"); + pt.Item.SendSignal("", + "power", fullPower / Math.Max(fullLoad, 1.0f)); } else @@ -126,9 +125,11 @@ namespace Subsurface.Items.Components public override void DrawHUD(SpriteBatch spriteBatch, Character character) { - int width = 300, height = 200; - int x = Game1.GraphicsWidth / 2 - width / 2; - int y = Game1.GraphicsHeight / 2 - height / 2; + int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height; + int x = GuiFrame.Rect.X; + int y = GuiFrame.Rect.Y; + + GuiFrame.Draw(spriteBatch); GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); @@ -136,5 +137,15 @@ namespace Subsurface.Items.Components spriteBatch.DrawString(GUI.font, "Load: " + (int)powerLoad, new Vector2(x + 30, y + 100), Color.White); } + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power) + { + base.ReceiveSignal(signal, connection, sender, power); + + if (connection.name=="signal") + { + connection.SendSignal(signal, item, 0.0f); + } + } + } } diff --git a/Subsurface/Items/Components/Powered.cs b/Subsurface/Items/Components/Power/Powered.cs similarity index 89% rename from Subsurface/Items/Components/Powered.cs rename to Subsurface/Items/Components/Power/Powered.cs index 1546f95a0..219b683f2 100644 --- a/Subsurface/Items/Components/Powered.cs +++ b/Subsurface/Items/Components/Power/Powered.cs @@ -59,15 +59,9 @@ namespace Subsurface.Items.Components set { voltage = Math.Max(0.0f, value); } } - public override void ReceiveSignal(string signal, Connection connection, Item sender) + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power) { - if (connection.name=="power_in") - { - if (!float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out voltage)) - { - voltage = 0.0f; - } - } + if (connection.name=="power_in") voltage = power; } public override void Update(float deltaTime, Camera cam) diff --git a/Subsurface/Items/Components/Signal/AndComponent.cs b/Subsurface/Items/Components/Signal/AndComponent.cs index 97bdc4385..085a4b896 100644 --- a/Subsurface/Items/Components/Signal/AndComponent.cs +++ b/Subsurface/Items/Components/Signal/AndComponent.cs @@ -53,7 +53,7 @@ namespace Subsurface.Items.Components } } - public override void ReceiveSignal(string signal, Connection connection, Item sender) + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f) { switch (connection.name) { diff --git a/Subsurface/Items/Components/Signal/Connection.cs b/Subsurface/Items/Components/Signal/Connection.cs index e7b6ef802..40685a15d 100644 --- a/Subsurface/Items/Components/Signal/Connection.cs +++ b/Subsurface/Items/Components/Signal/Connection.cs @@ -135,7 +135,7 @@ namespace Subsurface.Items.Components // return false; //} - public void SendSignal(string signal, Item sender) + public void SendSignal(string signal, Item sender, float power) { for (int i = 0; i(); if (panel == null) return; @@ -650,7 +649,7 @@ namespace Subsurface { if (c.name != connectionName) continue; - c.SendSignal(signal, this); + c.SendSignal(signal, this, power); } } diff --git a/Subsurface/Map/Level.cs b/Subsurface/Map/Level.cs index fd655d3af..a73ed17ef 100644 --- a/Subsurface/Map/Level.cs +++ b/Subsurface/Map/Level.cs @@ -181,10 +181,33 @@ namespace Subsurface cells.Remove(cell); } - //GenerateBodies(cells, pathCells); + for (int x = 0; x < cellGrid.GetLength(0); x++ ) + { + for (int y = 0; y < cellGrid.GetLength(1); y++ ) + { + cellGrid[x, y].Clear(); + } + } + + foreach (VoronoiCell cell in cells) + { + cellGrid[(int)Math.Floor(cell.Center.X / gridCellWidth), (int)Math.Floor(cell.Center.Y / gridCellWidth)].Add(cell); + } GeneratePolygons(cells, pathCells); + foreach (VoronoiCell cell in cells) + { + foreach (GraphEdge edge in cell.edges) + { + edge.cell1 = null; + edge.cell2 = null; + edge.site1 = null; + edge.site2 = null; + } + + } + Debug.WriteLine("Generatelevel: " + sw2.ElapsedMilliseconds + " ms"); sw2.Restart(); @@ -452,6 +475,8 @@ namespace Subsurface VoronoiCell adjacentCell = ge.AdjacentCell(cell); if (!emptyCells.Contains(adjacentCell)) continue; + ge.isSolid = true; + if (!bodyPoints.Contains(ge.point1)) bodyPoints.Add(ge.point1); if (!bodyPoints.Contains(ge.point2)) bodyPoints.Add(ge.point2); } @@ -624,39 +649,101 @@ namespace Subsurface // } //} - int gridPosX = (int)Math.Floor(-observerPosition.X / gridCellWidth); - int gridPosY = (int)Math.Floor(-observerPosition.Y / gridCellWidth); - int searchOffset = 2; + //int gridPosX = (int)Math.Floor(-observerPosition.X / gridCellWidth); + //int gridPosY = (int)Math.Floor(-observerPosition.Y / gridCellWidth); + //int searchOffset = 2; - int startX = Math.Max(gridPosX - searchOffset, 0); - int endX = Math.Min(gridPosX + searchOffset, cellGrid.GetLength(0) - 1); + //int startX = Math.Max(gridPosX - searchOffset, 0); + //int endX = Math.Min(gridPosX + searchOffset, cellGrid.GetLength(0) - 1); - int startY = Math.Max(gridPosY - searchOffset, 0); - int endY = Math.Min(gridPosY + searchOffset, cellGrid.GetLength(1) - 1); + //int startY = Math.Max(gridPosY - searchOffset, 0); + //int endY = Math.Min(gridPosY + searchOffset, cellGrid.GetLength(1) - 1); + + //for (int x = startX; x < endX; x++) + //{ + // for (int y = startY; y < endY; y++) + // { + // GUI.DrawRectangle(spriteBatch, + // new Rectangle(x * gridCellWidth + (int)position.X, borders.Y - borders.Height + y * gridCellWidth - (int)position.Y, gridCellWidth, gridCellWidth), + // Color.Cyan); + // } + //} + + List edges = GetCellEdges(-observerPosition); + + for (int i = 0; i < edges.Count; i++ ) + { + GUI.DrawLine(spriteBatch, edges[i][0], edges[i][1], Color.Green); + } + + //foreach (VoronoiCell cell in cells) + //{ + // for (int i = 0; i < cell.edges.Count; i++) + // { + // Vector2 start = cell.edges[i].point1 + position; + // start.Y = -start.Y; + + // Vector2 end = cell.edges[i].point2 + position; + // end.Y = -end.Y; + + // GUI.DrawLine(spriteBatch, start, end, (cell.body != null && cell.body.Enabled) ? Color.Green : Color.Red); + // } + //} + } + + public List GetCellEdges(Vector2 refPos, int searchDepth = 2, bool onlySolid = true) + { + + int gridPosX = (int)Math.Floor(refPos.X / gridCellWidth); + int gridPosY = (int)Math.Floor(refPos.Y / gridCellWidth); + + int startX = Math.Max(gridPosX - searchDepth, 0); + int endX = Math.Min(gridPosX + searchDepth, cellGrid.GetLength(0) - 1); + + int startY = Math.Max(gridPosY - searchDepth, 0); + int endY = Math.Min(gridPosY + searchDepth, cellGrid.GetLength(1) - 1); + + + List edges = new List(); for (int x = startX; x < endX; x++) { for (int y = startY; y < endY; y++) { - GUI.DrawRectangle(spriteBatch, - new Rectangle(x * gridCellWidth + (int)position.X, borders.Y - borders.Height + y * gridCellWidth - (int)position.Y, gridCellWidth, gridCellWidth), - Color.Cyan); + foreach (VoronoiCell cell in cellGrid[x,y]) + { + for (int i = 0; i < cell.edges.Count; i++) + { + if (onlySolid && !cell.edges[i].isSolid) continue; + Vector2 start = cell.edges[i].point1 + position; + start.Y = -start.Y; + + Vector2 end = cell.edges[i].point2 + position; + end.Y = -end.Y; + + edges.Add(new Vector2[] { start, end }); + //GUI.DrawLine(spriteBatch, start, end, (cell.body != null && cell.body.Enabled) ? Color.Green : Color.Red); + } + } } } - foreach (VoronoiCell cell in cells) - { - for (int i = 0; i HullVertices + { + get; + private set; + } + public Md5Hash Hash { get @@ -401,9 +407,7 @@ namespace Subsurface ApplyForce(-Vector2.Normalize(speed)*drag); } //hullBodies[0].body.LinearVelocity = -hullBodies[0].body.Position; - - - + hullBody.SetTransform(Vector2.Zero , 0.0f); if (collidingCell == null) @@ -697,6 +701,9 @@ namespace Subsurface } List convexHull = GenerateConvexHull(); + + HullVertices = convexHull; + for (int i = 0; i < convexHull.Count; i++) { convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]); @@ -718,7 +725,7 @@ namespace Subsurface var triangulatedVertices = Triangulate.ConvexPartition(_shapevertices, TriangulationAlgorithm.Bayazit); - Body hullBody = BodyFactory.CreateCompoundPolygon(Game1.world, triangulatedVertices, 5.0f); + hullBody = BodyFactory.CreateCompoundPolygon(Game1.world, triangulatedVertices, 5.0f); hullBody.BodyType = BodyType.Dynamic; hullBody.CollisionCategories = Physics.CollisionMisc; diff --git a/Subsurface/Map/VoronoiElements.cs b/Subsurface/Map/VoronoiElements.cs index e850c4053..b56c81d2d 100644 --- a/Subsurface/Map/VoronoiElements.cs +++ b/Subsurface/Map/VoronoiElements.cs @@ -143,6 +143,8 @@ namespace Voronoi2 public Site site1, site2; public VoronoiCell cell1, cell2; + public bool isSolid; + public VoronoiCell AdjacentCell(VoronoiCell cell) { if (cell1==cell) diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index c66b513c0..69cb96cab 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -78,10 +78,11 @@ - - - - + + + + + @@ -89,8 +90,8 @@ - - + + @@ -108,18 +109,18 @@ - + - - - - - - - - - + + + + + + + + + @@ -159,7 +160,7 @@ - + diff --git a/Subsurface/ToolBox.cs b/Subsurface/ToolBox.cs index b7a3e93d9..a97317a92 100644 --- a/Subsurface/ToolBox.cs +++ b/Subsurface/ToolBox.cs @@ -189,7 +189,7 @@ namespace Subsurface if (components.Length!=2) { if (!errorMessages) return vector; - DebugConsole.ThrowError("Failed to parse the string "+stringVector2+" to Vector2"); + DebugConsole.ThrowError("Failed to parse the string ''"+stringVector2+"'' to Vector2"); return vector; } @@ -212,7 +212,7 @@ namespace Subsurface if (components.Length < 3) { - DebugConsole.ThrowError("Failed to parse the string " + stringVector4 + " to Vector4"); + DebugConsole.ThrowError("Failed to parse the string ''" + stringVector4 + "'' to Vector4"); return vector; } diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index fb34813705aa0d928a92cd62fff19188e0b4afc4..221e16c3d2efd7c2e3bacccf5e73bae7d925e128 100644 GIT binary patch delta 18230 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