diff --git a/Game/Assembly-CSharp-vs.csproj b/Game/Assembly-CSharp-vs.csproj index 887885f..5ae48f8 100644 --- a/Game/Assembly-CSharp-vs.csproj +++ b/Game/Assembly-CSharp-vs.csproj @@ -58,29 +58,29 @@ + - - - - - - - + + + + + + - + diff --git a/Game/Assembly-CSharp.csproj b/Game/Assembly-CSharp.csproj index c5ff87b..baac44c 100644 --- a/Game/Assembly-CSharp.csproj +++ b/Game/Assembly-CSharp.csproj @@ -58,29 +58,29 @@ + - - - - - - - + + + + + + - + diff --git a/Game/Assets/Scripts/Business/Generator/BuildingGenerator.cs b/Game/Assets/Scripts/Business/Generator/BuildingGenerator.cs index 967b41d..45599ca 100644 --- a/Game/Assets/Scripts/Business/Generator/BuildingGenerator.cs +++ b/Game/Assets/Scripts/Business/Generator/BuildingGenerator.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using TransportGame.Business; using TransportGame.Model; +using TransportGame.Primitives; using TransportGame.Model.Road; using TransportGame.Utils; @@ -112,7 +113,7 @@ namespace TransportGame.Generator foreach (var lot in lotTree.Query(lotArea)) { - if (BuildingLot.DoesIntersect(lot0, lot)) + if (Polygon.Intersect(lot0, lot)) return false; } diff --git a/Game/Assets/Scripts/Business/Generator/PopulationCentersGenerator.cs b/Game/Assets/Scripts/Business/Generator/PopulationCentersGenerator.cs index 13edfd5..220cb92 100644 --- a/Game/Assets/Scripts/Business/Generator/PopulationCentersGenerator.cs +++ b/Game/Assets/Scripts/Business/Generator/PopulationCentersGenerator.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using TransportGame.Model; using TransportGame.Noise; +using TransportGame.Primitives; namespace TransportGame.Generator { diff --git a/Game/Assets/Scripts/Business/Generator/RoadGenerator.cs b/Game/Assets/Scripts/Business/Generator/RoadGenerator.cs index ca86a1c..05b78be 100644 --- a/Game/Assets/Scripts/Business/Generator/RoadGenerator.cs +++ b/Game/Assets/Scripts/Business/Generator/RoadGenerator.cs @@ -5,8 +5,9 @@ using System.Text; using TransportGame.Business; using TransportGame.Model; using TransportGame.Model.Road; +using TransportGame.Primitives; using TransportGame.Utils; -using Vector2 = TransportGame.Model.Vector2; +using Vector2 = TransportGame.Primitives.Vector2; namespace TransportGame.Generator { @@ -259,8 +260,7 @@ namespace TransportGame.Generator } // Filter & sort the segments by distance - segmentIds = segmentIds.Distinct().OrderBy(id => - LineSegment.Distance(map.RoadNetwork.ArticulationSegments[id].AsLineSegment(), segment.Terminal2Pos)); + segmentIds = segmentIds.Distinct().OrderBy(id => map.RoadNetwork.ArticulationSegments[id].AsLineSegment().Distance(segment.Terminal2Pos)); foreach (var segmentId in segmentIds) { diff --git a/Game/Assets/Scripts/Business/Generator/TerrainGenerator.cs b/Game/Assets/Scripts/Business/Generator/TerrainGenerator.cs index 7fd3fe5..68bdf71 100644 --- a/Game/Assets/Scripts/Business/Generator/TerrainGenerator.cs +++ b/Game/Assets/Scripts/Business/Generator/TerrainGenerator.cs @@ -47,7 +47,7 @@ namespace TransportGame.Generator GenerateElevation(map); // Generate water level - float waterAmount = random.NextSingle(map.Biome.Moisture.Minimum, map.Biome.Moisture.Maximum); + float waterAmount = random.NextSingle(map.Biome.Moisture.Min, map.Biome.Moisture.Max); map.WaterLevel = Mathf.Pow(waterAmount, ConfigManager.Tergen.WaterNonLinearPower) * map.Biome.Height; return map; diff --git a/Game/Assets/Scripts/Model/Biome.cs b/Game/Assets/Scripts/Model/Biome.cs index 269cd3c..3a10021 100644 --- a/Game/Assets/Scripts/Model/Biome.cs +++ b/Game/Assets/Scripts/Model/Biome.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; +using TransportGame.Primitives; using TransportGame.Utils; namespace TransportGame.Model @@ -33,13 +34,13 @@ namespace TransportGame.Model /// Value is a probability, should be between 0 and 1. /// [XmlElement("moisture")] - public Range Moisture { get; set; } + public Interval Moisture { get; set; } /// /// Gets or sets the vegetation density of the biome /// [XmlElement("vegetationDensity")] - public Range VegetationDensity { get; set; } + public Interval VegetationDensity { get; set; } /// /// Gets or sets an array of textures to use diff --git a/Game/Assets/Scripts/Model/Building.cs b/Game/Assets/Scripts/Model/Building.cs index 3295b13..cbdf767 100644 --- a/Game/Assets/Scripts/Model/Building.cs +++ b/Game/Assets/Scripts/Model/Building.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using TransportGame.Primitives; namespace TransportGame.Model { diff --git a/Game/Assets/Scripts/Model/BuildingLot.cs b/Game/Assets/Scripts/Model/BuildingLot.cs index 2f34cab..91fb7e3 100644 --- a/Game/Assets/Scripts/Model/BuildingLot.cs +++ b/Game/Assets/Scripts/Model/BuildingLot.cs @@ -3,17 +3,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; using TransportGame.Business; +using TransportGame.Primitives; using TransportGame.Utils; namespace TransportGame.Model { - public class BuildingLot : IPositionable + /// + /// Building lot + /// + public class BuildingLot : Polygon { - /// - /// Gets or sets the list of points - /// - public Vector2[] Points { get; set; } - /// /// Gets or sets the size of the lot /// @@ -23,8 +22,8 @@ namespace TransportGame.Model /// Initializes the building lot /// public BuildingLot() + : base(new Vector2[4]) { - Points = new Vector2[4]; } /// @@ -32,8 +31,8 @@ namespace TransportGame.Model /// /// size public BuildingLot(float size) + : base(new Vector2[4]) { - Points = new Vector2[4]; Size = size; } @@ -43,8 +42,8 @@ namespace TransportGame.Model /// Size /// Points public BuildingLot(float size, params Vector2[] points) + : base(points) { - Points = points; Size = size; } @@ -54,30 +53,11 @@ namespace TransportGame.Model /// Size /// Points public BuildingLot(float size, IEnumerable points) + : base(points) { - Points = points.ToArray(); Size = size; } - /// - /// Gets the lot position - /// - public Vector2 Position - { - get { return Points.Aggregate((x, y) => x + y) / Points.Length; } - } - - /// - /// Tests if two building lots intersect - /// - /// First lot - /// Second lot - /// - public static bool DoesIntersect(BuildingLot a, BuildingLot b) - { - return Algorithmss.DoPolygonsIntersect(a.Points, b.Points); - } - /// /// Tests if a building lot intersects a line segment (such as a road segment) /// diff --git a/Game/Assets/Scripts/Model/CityMap.cs b/Game/Assets/Scripts/Model/CityMap.cs index f78e16b..d379e49 100644 --- a/Game/Assets/Scripts/Model/CityMap.cs +++ b/Game/Assets/Scripts/Model/CityMap.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using System.Xml.Serialization; using TransportGame.Model.Road; +using TransportGame.Primitives; using TransportGame.Utils; -using UnityEngine; namespace TransportGame.Model { @@ -256,8 +256,8 @@ namespace TransportGame.Model if (dist < PopulationCenterRange * PopulationCenterRange) { float influence = 1 - (float)dist / (float)(PopulationCenterRange * PopulationCenterRange); - influence = Mathf.Pow(influence, 6) * 0.7f; // Ease - value = Mathf.Clamp01(value + influence); + influence = (float)Math.Pow(influence, 6) * 0.7f; // Ease + value = MathHelper.Clamp01(value + influence); } } diff --git a/Game/Assets/Scripts/Model/IPositionable.cs b/Game/Assets/Scripts/Model/IPositionable.cs deleted file mode 100644 index 18b684c..0000000 --- a/Game/Assets/Scripts/Model/IPositionable.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace TransportGame.Model -{ - public interface IPositionable - { - Vector2 Position { get; } - } -} diff --git a/Game/Assets/Scripts/Model/LineSegment.cs b/Game/Assets/Scripts/Model/LineSegment.cs deleted file mode 100644 index 5eb33da..0000000 --- a/Game/Assets/Scripts/Model/LineSegment.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace TransportGame.Model -{ - public struct LineSegment - { - public float X0 { get; private set; } - public float Y0 { get; private set; } - public float X1 { get; private set; } - public float Y1 { get; private set; } - - public Vector2 P0 - { - get - { - return new Vector2(X0, Y0); - } - } - public Vector2 P1 - { - get - { - return new Vector2(X1, Y1); - } - } - - public float Length - { - get - { - return (P1 - P0).Length; - } - } - - public float LengthSq - { - get - { - return (P1 - P0).LengthSq; - } - } - - public Vector2 Direction - { - get - { - return (P1 - P0).Normalized; - } - } - - public LineSegment(Vector2 p0, Vector2 p1) - : this() - { - X0 = p0.X; Y0 = p0.Y; - X1 = p1.X; Y1 = p1.Y; - } - - public LineSegment(float x0, float y0, float x1, float y1) - : this() - { - X0 = x0; Y0 = y0; - X1 = x1; Y1 = y1; - } - - public static Vector2? Intersect(LineSegment a, LineSegment b) - { - float s1x = a.X1 - a.X0, s1y = a.Y1 - a.Y0; - float s2x = b.X1 - b.X0, s2y = b.Y1 - b.Y0; - - float det = (-s2x * s1y + s1x * s2y); - - // Avoid division by zero - // Note: this is an edge case, the vectors might be parallel or colliniar - if (det == 0) return null; - - float s = (-s1y * (a.X0 - b.X0) + s1x * (a.Y0 - b.Y0)) / det; - float t = (s2x * (a.Y0 - b.Y0) - s2y * (a.X0 - b.X0)) / det; - - // Collision detected - if (s >= 0 && s <= 1 && t >= 0 && t <= 1) - return new Vector2(a.X0 + t * s1x, a.Y0 + t * s1y); - - // No collision - return null; - } - - /// - /// Calculates the distance from point p to line segment - /// - /// Line - /// Point - /// Distance - public static float Distance(LineSegment line, Vector2 p) - { - float det = (line.Y1 - line.Y0) * p.X - (line.X1 - line.X0) * p.Y - + line.X1 * line.Y0 - line.Y1 * line.X0; - return Math.Abs(det) / line.Length; - } - - public override string ToString() - { - return string.Format("({0}, {1})->({2}, {3})", X0, Y0, X1, Y1); - } - } -} diff --git a/Game/Assets/Scripts/Model/Range.cs b/Game/Assets/Scripts/Model/Range.cs deleted file mode 100644 index 8275306..0000000 --- a/Game/Assets/Scripts/Model/Range.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml.Serialization; - -namespace TransportGame.Model -{ - public class Range - { - [XmlAttribute("min")] - public float Minimum { get; set; } - - [XmlAttribute("max")] - public float Maximum { get; set; } - - public Range() - { - Minimum = 0; - Maximum = 1; - } - - public Range(float min, float max) - { - Minimum = min; - Maximum = max; - } - - public override string ToString() - { - return String.Format("[{0}, {1}]", Minimum, Maximum); - } - } -} diff --git a/Game/Assets/Scripts/Model/Rectangle.cs b/Game/Assets/Scripts/Model/Rectangle.cs deleted file mode 100644 index ecbf0f3..0000000 --- a/Game/Assets/Scripts/Model/Rectangle.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace TransportGame.Model -{ - public struct Rectangle - { - public float Left { get; set; } - public float Top { get; set; } - public float Right { get; set; } - public float Bottom { get; set; } - - public Rectangle(float left, float top, float right, float bottom) - : this() - { - Left = left; - Top = top; - Right = right; - Bottom = bottom; - - if (left > right) - throw new ArgumentException("Left must be smaller than right."); - - if (top > bottom) - throw new ArgumentException("Top must be smaller than bottom."); - } - - public float Width - { - get - { - return Right - Left; - } - set - { - Right = Left + value; - } - } - - public float Height - { - get - { - return Bottom - Top; - } - set - { - Bottom = Top + value; - } - } - - public bool Contains(float x, float y) - { - return x >= Left && x <= Right && y >= Top && y <= Bottom; - } - - public bool Contains(Vector2 p) - { - return Contains(p.X, p.Y); - } - - public static bool Intersects (Rectangle a, Rectangle b) - { - return !(b.Left > a.Right || - b.Right < a.Left || - b.Top > a.Bottom || - b.Bottom < a.Top); - } - - public override string ToString() - { - return string.Format("({0}, {1}, {2}, {3})", Left, Top, Right, Bottom); - } - } -} diff --git a/Game/Assets/Scripts/Model/Road/RoadNetwork.cs b/Game/Assets/Scripts/Model/Road/RoadNetwork.cs index 832aac0..dd8ece2 100644 --- a/Game/Assets/Scripts/Model/Road/RoadNetwork.cs +++ b/Game/Assets/Scripts/Model/Road/RoadNetwork.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; +using TransportGame.Primitives; using TransportGame.Utils; namespace TransportGame.Model.Road diff --git a/Game/Assets/Scripts/Model/Road/RoadNode.cs b/Game/Assets/Scripts/Model/Road/RoadNode.cs index 4a9c2d3..c198455 100644 --- a/Game/Assets/Scripts/Model/Road/RoadNode.cs +++ b/Game/Assets/Scripts/Model/Road/RoadNode.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; +using TransportGame.Primitives; namespace TransportGame.Model.Road { diff --git a/Game/Assets/Scripts/Model/Road/RoadSegment.cs b/Game/Assets/Scripts/Model/Road/RoadSegment.cs index 4008dd9..ab65f4a 100644 --- a/Game/Assets/Scripts/Model/Road/RoadSegment.cs +++ b/Game/Assets/Scripts/Model/Road/RoadSegment.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; +using TransportGame.Primitives; namespace TransportGame.Model.Road { diff --git a/Game/Assets/Scripts/Primitives.meta b/Game/Assets/Scripts/Primitives.meta new file mode 100644 index 0000000..b719ced --- /dev/null +++ b/Game/Assets/Scripts/Primitives.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 38c9355be2e20d242ab7047cac952101 +folderAsset: yes +timeCreated: 1434538689 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Game/Assets/Scripts/Primitives/IPositionable.cs b/Game/Assets/Scripts/Primitives/IPositionable.cs new file mode 100644 index 0000000..92f2409 --- /dev/null +++ b/Game/Assets/Scripts/Primitives/IPositionable.cs @@ -0,0 +1,14 @@ + +namespace TransportGame.Primitives +{ + /// + /// Object can be positioned using a point + /// + public interface IPositionable + { + /// + /// Gets the position of the object + /// + Vector2 Position { get; } + } +} diff --git a/Game/Assets/Scripts/Model/IPositionable.cs.meta b/Game/Assets/Scripts/Primitives/IPositionable.cs.meta similarity index 76% rename from Game/Assets/Scripts/Model/IPositionable.cs.meta rename to Game/Assets/Scripts/Primitives/IPositionable.cs.meta index a28da09..c640240 100644 --- a/Game/Assets/Scripts/Model/IPositionable.cs.meta +++ b/Game/Assets/Scripts/Primitives/IPositionable.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: cdecfb69b7ca68446910d0a607e934e6 -timeCreated: 1432824088 +guid: b1f8e20ab1416e64aa689620b275d16e +timeCreated: 1434538689 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Game/Assets/Scripts/Primitives/Interval.cs b/Game/Assets/Scripts/Primitives/Interval.cs new file mode 100644 index 0000000..1e283da --- /dev/null +++ b/Game/Assets/Scripts/Primitives/Interval.cs @@ -0,0 +1,98 @@ +using System; +using System.Xml.Serialization; + +namespace TransportGame.Primitives +{ + /// + /// Interval + /// + public class Interval + { + #region Properties + + /// + /// Gets the minimum value of the interval + /// + [XmlAttribute("min")] + public float Min { get; set; } + + /// + /// Gets the maximum value of the interval + /// + [XmlAttribute("max")] + public float Max { get; set; } + + #endregion + + #region Other properties + + /// + /// Gets or sets the length of the interval + /// + [XmlIgnore] + public float Length + { + get + { + return Max - Min; + } + set + { + Max = Min + value; + } + } + + #endregion + + #region Constructors + + /// + /// Initializes interval + /// + public Interval() + { + Min = 0; + Max = 1; + } + + /// + /// Initializes interval + /// + /// Minimum value + /// Maximum value + public Interval(float min, float max) + { + Min = min; + Max = max; + } + + #endregion + + #region Operations + + /// + /// Tests if interval contains value + /// + /// + /// + public bool Contains(float value) + { + return (value >= Min && value <= Max); + } + + #endregion + + #region Object overrides + + /// + /// Gets string representation + /// + /// + public override string ToString() + { + return String.Format("[{0}, {1}]", Min, Max); + } + + #endregion + } +} diff --git a/Game/Assets/Scripts/Utils/Algorithms.cs.meta b/Game/Assets/Scripts/Primitives/Interval.cs.meta similarity index 52% rename from Game/Assets/Scripts/Utils/Algorithms.cs.meta rename to Game/Assets/Scripts/Primitives/Interval.cs.meta index 8c43c03..205f5ad 100644 --- a/Game/Assets/Scripts/Utils/Algorithms.cs.meta +++ b/Game/Assets/Scripts/Primitives/Interval.cs.meta @@ -1,8 +1,12 @@ fileFormatVersion: 2 -guid: 67f24adfb8b21234184d0caf81f424ea +guid: e3c02b6aafb292640a692c9ea354adb1 +timeCreated: 1434538689 +licenseType: Free MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: + assetBundleName: + assetBundleVariant: diff --git a/Game/Assets/Scripts/Primitives/LineSegment.cs b/Game/Assets/Scripts/Primitives/LineSegment.cs new file mode 100644 index 0000000..bbb58c0 --- /dev/null +++ b/Game/Assets/Scripts/Primitives/LineSegment.cs @@ -0,0 +1,178 @@ +using System; + +namespace TransportGame.Primitives +{ + /// + /// A line segment + /// + public struct LineSegment + { + #region Properties + + /// + /// X coordinate of first point + /// + public float X0 { get; private set; } + + /// + /// Y coordinate of first point + /// + public float Y0 { get; private set; } + + /// + /// X coordinate of second point + /// + public float X1 { get; private set; } + + /// + /// Y coordinate of second point + /// + public float Y1 { get; private set; } + + /// + /// Gets the first point + /// + public Vector2 P0 + { + get + { + return new Vector2(X0, Y0); + } + } + + /// + /// Gets the second point + /// + public Vector2 P1 + { + get + { + return new Vector2(X1, Y1); + } + } + + /// + /// Gets the length of the segment + /// + public float Length + { + get + { + return (P1 - P0).Length; + } + } + + /// + /// Gets the length squared of the segment + /// + public float LengthSq + { + get + { + return (P1 - P0).LengthSq; + } + } + + /// + /// Gets the direction vector of the segment + /// + public Vector2 Direction + { + get + { + return (P1 - P0).Normalized; + } + } + + #endregion + + #region Constructors + + /// + /// Initializes line segment + /// + /// First point + /// Second point + public LineSegment(Vector2 p0, Vector2 p1) + : this() + { + X0 = p0.X; Y0 = p0.Y; + X1 = p1.X; Y1 = p1.Y; + } + + /// + /// Initializes line segment + /// + /// X coordinate of first segment + /// Y coordinate of first segment + /// X coordinate of second segment + /// Y coordinate of second segment + public LineSegment(float x0, float y0, float x1, float y1) + : this() + { + X0 = x0; Y0 = y0; + X1 = x1; Y1 = y1; + } + + #endregion + + #region Operations + + /// + /// Calculates the intersection between two line segments. + /// + /// + /// Ignores case where intersection is a line. + /// + /// First line segment + /// Second line segment + /// Intersection point, or null if segments don't intersect. + public static Vector2? Intersect(LineSegment a, LineSegment b) + { + float s1x = a.X1 - a.X0, s1y = a.Y1 - a.Y0; + float s2x = b.X1 - b.X0, s2y = b.Y1 - b.Y0; + + float det = (-s2x * s1y + s1x * s2y); + + // Avoid division by zero + // Note: this is an edge case, the vectors might be parallel or colliniar + if (det == 0) return null; + + float s = (-s1y * (a.X0 - b.X0) + s1x * (a.Y0 - b.Y0)) / det; + float t = (s2x * (a.Y0 - b.Y0) - s2y * (a.X0 - b.X0)) / det; + + // Collision detected + if (s >= 0 && s <= 1 && t >= 0 && t <= 1) + return new Vector2(a.X0 + t * s1x, a.Y0 + t * s1y); + + // No collision + return null; + } + + /// + /// Calculates the distance from a point p to a line segment + /// + /// Point + /// Distance + public float Distance(Vector2 p) + { + float det = (Y1 - Y0) * p.X - (X1 - X0) * p.Y + X1 * Y0 - Y1 * X0; + return Math.Abs(det) / Length; + } + + #endregion + + #region ToString + + /// + /// Gets string representation of line segment + /// + /// + public override string ToString() + { + return string.Format("({0}, {1})->({2}, {3})", X0, Y0, X1, Y1); + } + + #endregion + } +} diff --git a/Game/Assets/Scripts/Model/LineSegment.cs.meta b/Game/Assets/Scripts/Primitives/LineSegment.cs.meta similarity index 76% rename from Game/Assets/Scripts/Model/LineSegment.cs.meta rename to Game/Assets/Scripts/Primitives/LineSegment.cs.meta index a68ae4b..8b6ee46 100644 --- a/Game/Assets/Scripts/Model/LineSegment.cs.meta +++ b/Game/Assets/Scripts/Primitives/LineSegment.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: eaabdeeb068e1dc46a7a9da6fd47f393 -timeCreated: 1432847695 +guid: a6b34c7e4ed62b04fbb44b61fbb7bc23 +timeCreated: 1434538689 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Game/Assets/Scripts/Model/Polygon.cs b/Game/Assets/Scripts/Primitives/Polygon.cs similarity index 80% rename from Game/Assets/Scripts/Model/Polygon.cs rename to Game/Assets/Scripts/Primitives/Polygon.cs index 74a5796..50c8006 100644 --- a/Game/Assets/Scripts/Model/Polygon.cs +++ b/Game/Assets/Scripts/Primitives/Polygon.cs @@ -1,17 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using TransportGame.Utils; -namespace TransportGame.Model +namespace TransportGame.Primitives { /// /// Represents a polygon /// public class Polygon : IPositionable { - #region Private types + #region Private data types private struct Edge { @@ -26,11 +24,17 @@ namespace TransportGame.Model #endregion + #region Properties + /// /// Gets or sets the points that define the polygon /// public Vector2[] Points { get; set; } + #endregion + + #region Other properties + /// /// Gets the gravitational center /// @@ -39,6 +43,10 @@ namespace TransportGame.Model get { return Points.Aggregate((x, y) => x + y) / Points.Length; } } + #endregion + + #region Constructors + /// /// Initializes polygon /// @@ -65,28 +73,9 @@ namespace TransportGame.Model Points = points; } - /// - /// Compares angle between two NORMALIZED vectors. - /// - /// - /// - /// - private static float CompareAngle(Vector2 a, Vector2 b) - { - float sin = Vector2.Cross(a, b); - float cos = Vector2.Dot(a, b); + #endregion - if (sin >= 0 && cos >= 0) - return sin; - - else if (sin >= 0 && cos <= 0) - return 1 + Math.Abs(cos); - - else if (sin <= 0 && cos <= 0) - return 2 + Math.Abs(sin); - - else return 3 + cos; - } + #region Operations /// /// Returns the union between given polygons @@ -173,7 +162,6 @@ namespace TransportGame.Model union.Add(vertices[v]); int newV = -1; - float smallestAngle = -1; Vector2 smallestDir = Vector2.Zero; foreach (var edge in edges) @@ -184,11 +172,9 @@ namespace TransportGame.Model Vector2 dir = (vertices[otherv] - vertices[v]).Normalized; // Find smallest angle - float cmpAngle = CompareAngle(-prev, dir); - if (cmpAngle < smallestAngle || smallestAngle < 0) + if (newV == -1 || Vector2.TrigonometricComparer.Compare(dir, smallestDir) < 0) { newV = otherv; - smallestAngle = cmpAngle; smallestDir = dir; } } @@ -204,7 +190,13 @@ namespace TransportGame.Model return new Polygon(union); } - public static bool DoPolygonsIntersect(Polygon a, Polygon b) + /// + /// Tests if two polygons intersect + /// + /// + /// + /// + public static bool Intersect(Polygon a, Polygon b) { foreach (var poly in new[] { a, b }) { @@ -242,6 +234,42 @@ namespace TransportGame.Model return true; } + /// + /// Tests if polygon contains point + /// + /// + /// + public bool Contains(Vector2 point) + { + // Quick bounding box check + Vector2 min = Points[0], max = Points[0]; + for (int i = 0; i < Points.Length; i++) + { + min.X = Math.Min(min.X, Points[i].X); + min.Y = Math.Min(min.Y, Points[i].Y); + max.X = Math.Max(max.X, Points[i].X); + max.Y = Math.Max(max.Y, Points[i].Y); + } + + if (point.X < min.X || point.Y < min.Y || point.X > max.X || point.Y > max.Y) + return false; + + // Ray casting method + int j = Points.Length - 1; + bool result = false; + for (int i = 0; i < Points.Length; i++) + { + if ((Points[i].Y > point.Y) != (Points[j].Y > point.Y) && + (point.X < (Points[j].X - Points[i].X) * (point.Y - Points[i].Y) / (Points[j].Y - Points[i].Y) + Points[i].X)) + result = !result; + + j = i; + } + + return result; + } + + #endregion } } diff --git a/Game/Assets/Scripts/Model/Polygon.cs.meta b/Game/Assets/Scripts/Primitives/Polygon.cs.meta similarity index 76% rename from Game/Assets/Scripts/Model/Polygon.cs.meta rename to Game/Assets/Scripts/Primitives/Polygon.cs.meta index 52cc98b..fbc2784 100644 --- a/Game/Assets/Scripts/Model/Polygon.cs.meta +++ b/Game/Assets/Scripts/Primitives/Polygon.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: ee96020375a8f3d4bb7a04e9f7a6b05e -timeCreated: 1433489979 +guid: 3e0bb5f9b3dd2d84a9996806e2048f9d +timeCreated: 1434538689 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Game/Assets/Scripts/Primitives/Rectangle.cs b/Game/Assets/Scripts/Primitives/Rectangle.cs new file mode 100644 index 0000000..6dee7ea --- /dev/null +++ b/Game/Assets/Scripts/Primitives/Rectangle.cs @@ -0,0 +1,156 @@ +using System; + +namespace TransportGame.Primitives +{ + /// + /// Rectangle + /// + public struct Rectangle + { + #region Properties + + /// + /// Gets or sets the left boundary + /// + public float Left { get; set; } + + /// + /// Gets or sets the top boundary + /// + public float Bottom { get; set; } + + /// + /// Gets or sets the right boundary + /// + public float Right { get; set; } + + /// + /// Gets or sets the bottom boundary + /// + public float Top { get; set; } + + #endregion + + #region Constructor + + /// + /// Initializes this rectangle + /// + /// Left boundary + /// Bottom boundary + /// Right boundary + /// Top boundary + public Rectangle(float left, float bottom, float right, float top) + : this() + { + Left = left; + Bottom = bottom; + Right = right; + Top = top; + + if (left > right) + throw new ArgumentException("Left must be smaller than right."); + + if (bottom > top) + throw new ArgumentException("Bottom must be smaller than top."); + } + + #endregion + + #region Other properties + + /// + /// Gets or sets the width of the rectangle + /// + public float Width + { + get + { + return Right - Left; + } + set + { + Right = Left + value; + } + } + + /// + /// Gets or sets the height of the rectangle + /// + public float Height + { + get + { + return Top - Bottom; + } + set + { + Top = Bottom + value; + } + } + + /// + /// Gets the area of the rectangle + /// + public float Area + { + get + { + return Width * Height; + } + } + + #endregion + + #region Operations + + /// + /// Tests if rectangle contains given point + /// + /// x coordinate + /// y coordinate + /// True if point is inside + public bool Contains(float x, float y) + { + return x >= Left && x <= Right && y >= Bottom && y <= Top; + } + + /// + /// Tests if rectangle contains given point + /// + /// Vector + /// True if point is inside + public bool Contains(Vector2 p) + { + return Contains(p.X, p.Y); + } + + /// + /// Tests if two rectangles intersect + /// + /// + /// + /// True if rectangles intersect + public static bool Intersect (Rectangle a, Rectangle b) + { + return !(b.Left > a.Right || + b.Right < a.Left || + b.Bottom > a.Top || + b.Top < a.Bottom); + } + #endregion + + #region Object overrides + + /// + /// Gets string representation + /// + /// + public override string ToString() + { + return string.Format("({0}, {1}, {2}, {3})", Left, Bottom, Right, Top); + } + + #endregion + } +} diff --git a/Game/Assets/Scripts/Model/Rectangle.cs.meta b/Game/Assets/Scripts/Primitives/Rectangle.cs.meta similarity index 76% rename from Game/Assets/Scripts/Model/Rectangle.cs.meta rename to Game/Assets/Scripts/Primitives/Rectangle.cs.meta index bae31f6..9112362 100644 --- a/Game/Assets/Scripts/Model/Rectangle.cs.meta +++ b/Game/Assets/Scripts/Primitives/Rectangle.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 01c02a9fd2c3d0142905c23fb3142b6f -timeCreated: 1432824087 +guid: 089c6381ade2028499552d764dcdaa25 +timeCreated: 1434538689 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Game/Assets/Scripts/Model/Vector2.cs b/Game/Assets/Scripts/Primitives/Vector2.cs similarity index 88% rename from Game/Assets/Scripts/Model/Vector2.cs rename to Game/Assets/Scripts/Primitives/Vector2.cs index 3cb33b6..ef0b5af 100644 --- a/Game/Assets/Scripts/Model/Vector2.cs +++ b/Game/Assets/Scripts/Primitives/Vector2.cs @@ -1,13 +1,16 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml.Serialization; -namespace TransportGame.Model +namespace TransportGame.Primitives { + /// + /// 2D vector + /// public struct Vector2 { + #region Constant vectors + /// /// Zero vector /// @@ -18,6 +21,10 @@ namespace TransportGame.Model /// public static readonly Vector2 Unit = new Vector2(1, 0); + #endregion + + #region Properties + /// /// Gets the X component /// @@ -30,6 +37,10 @@ namespace TransportGame.Model [XmlAttribute("y")] public float Y { get; set; } + #endregion + + #region Constructor + /// /// Initializes a vector2 /// @@ -42,6 +53,31 @@ namespace TransportGame.Model Y = y; } + /// + /// Gets the vector corresponding with specified angle (in radians) + /// + /// Radians + /// Vector + public static Vector2 FromRadians(float rads) + { + return new Vector2((float)Math.Cos(rads), (float)Math.Sin(rads)); + } + + /// + /// Gets the vector corresponding with specified angle (in degrees) + /// + /// Degrees + /// Vector + public static Vector2 FromDegrees(float degs) + { + float rads = (degs * (float)Math.PI / 180f); + return FromRadians(rads); + } + + #endregion + + #region Properties (length, normalized) + /// /// Gets the length of the vector /// @@ -93,6 +129,10 @@ namespace TransportGame.Model } } + #endregion + + #region Operations + /// /// Rotates vector by given number of radians /// @@ -234,33 +274,25 @@ namespace TransportGame.Model { return Math.Abs(Cross(a, b)) < 1e-12; } + + #endregion + + #region Object overrides /// - /// Gets the vector corresponding with specified angle (in radians) + /// Gets string representation of vector2 /// - /// Radians - /// Vector - public static Vector2 FromRadians(float rads) - { - return new Vector2((float)Math.Cos(rads), (float)Math.Sin(rads)); - } - - /// - /// Gets the vector corresponding with specified angle (in degrees) - /// - /// Degrees - /// Vector - public static Vector2 FromDegrees(float degs) - { - float rads = (degs * (float)Math.PI / 180f); - return FromRadians(rads); - } - + /// public override string ToString() { return String.Format("({0}, {1})", X, Y); } + /// + /// Tests if two vectors are equal. + /// + /// + /// public override bool Equals(object obj) { if (obj is Vector2) @@ -272,11 +304,19 @@ namespace TransportGame.Model return false; } + /// + /// Gets hash code of vector2 + /// + /// public override int GetHashCode() { - return X.GetHashCode() * 7 + Y.GetHashCode(); + return X.GetHashCode() * 29 + Y.GetHashCode(); } + #endregion + + #region Comparers + private class LengthComparerImpl : IComparer { public int Compare(Vector2 a, Vector2 b) @@ -338,7 +378,16 @@ namespace TransportGame.Model } } - public static IComparer LengthComparer = new LengthComparerImpl(); - public static IComparer TrigonomicComparer = new TrigonometricComparerImpl(); + /// + /// Length comparer - compares vectors by length + /// + public static readonly IComparer LengthComparer = new LengthComparerImpl(); + + /// + /// Trigonometric comparer - compares vectors by angle + /// + public static readonly IComparer TrigonometricComparer = new TrigonometricComparerImpl(); + + #endregion } } diff --git a/Game/Assets/Scripts/Model/Vector2.cs.meta b/Game/Assets/Scripts/Primitives/Vector2.cs.meta similarity index 76% rename from Game/Assets/Scripts/Model/Vector2.cs.meta rename to Game/Assets/Scripts/Primitives/Vector2.cs.meta index 050e95e..6e8773d 100644 --- a/Game/Assets/Scripts/Model/Vector2.cs.meta +++ b/Game/Assets/Scripts/Primitives/Vector2.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 94117dad82214b44382141a14825994e -timeCreated: 1432281052 +guid: e100b9a2be8bd3243b55552195f6ce14 +timeCreated: 1434538689 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Game/Assets/Scripts/Unity/RoadMeshGenerator.cs b/Game/Assets/Scripts/Unity/RoadMeshGenerator.cs index 75468b2..ab35997 100644 --- a/Game/Assets/Scripts/Unity/RoadMeshGenerator.cs +++ b/Game/Assets/Scripts/Unity/RoadMeshGenerator.cs @@ -8,7 +8,7 @@ using TransportGame.Model; using TransportGame.Model.Road; using TransportGame.Utils; using UnityEngine; -using Vector2 = TransportGame.Model.Vector2; +using Vector2 = TransportGame.Primitives.Vector2; //#define DEBUG_ROAD_MESH_GENERATOR @@ -144,7 +144,7 @@ namespace TransportGame.Unity vindex += 1; // Sort adjacent segments in trigonometric order - var segs = node.ArticulationSegments.OrderBy(segment => DirectionFrom(segment, node), Vector2.TrigonomicComparer).ToArray(); + var segs = node.ArticulationSegments.OrderBy(segment => DirectionFrom(segment, node), Vector2.TrigonometricComparer).ToArray(); Vector2[] sideCrns = new Vector2[segs.Length]; Vector2[] strCrns = new Vector2[segs.Length]; diff --git a/Game/Assets/Scripts/Utils/Algorithms.cs b/Game/Assets/Scripts/Utils/Algorithms.cs deleted file mode 100644 index 012ce7e..0000000 --- a/Game/Assets/Scripts/Utils/Algorithms.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using TransportGame.Model; - -namespace TransportGame.Utils -{ - public static class Algorithmss - { - public static bool DoPolygonsIntersect(Vector2[] a, Vector2[] b) - { - foreach (var poly in new[] {a, b}) - { - for (int i = 0; i < poly.Length; i++) - { - int j = (i + 1) % poly.Length; - - var normal = new Vector2(poly[j].Y - poly[i].Y, poly[i].X - poly[j].X); - - double? minA = null, maxA = null; - foreach (var p in a) - { - var projected = Vector2.Dot(normal, p); - if (minA == null || projected < minA) - minA = projected; - if (maxA == null || projected > maxA) - maxA = projected; - } - - double? minB = null, maxB = null; - foreach (var p in b) - { - var projected = Vector2.Dot(normal, p); - if (minB == null || projected < minB) - minB = projected; - if (maxB == null || projected > maxB) - maxB = projected; - } - - if (maxA <= minB || maxB <= minA) - return false; - } - } - - return true; - } - } -} diff --git a/Game/Assets/Scripts/Utils/MathHelper.cs b/Game/Assets/Scripts/Utils/MathHelper.cs new file mode 100644 index 0000000..7156fd5 --- /dev/null +++ b/Game/Assets/Scripts/Utils/MathHelper.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TransportGame.Utils +{ + public static class MathHelper + { + /// + /// Clamps given value in the [0,1] interval + /// + /// Value + /// Clamped value + public static float Clamp01(float value) + { + return Clamp(value, 0, 1); + } + + /// + /// Clamps given value in the [min,max] interval + /// + /// Value + /// Minimum value + /// Maximum value + /// Clamped value + public static float Clamp(float value, float min, float max) + { + if (value < min) + return min; + + if (value > max) + return max; + + return value; + } + } +} diff --git a/Game/Assets/Scripts/Model/Range.cs.meta b/Game/Assets/Scripts/Utils/MathHelper.cs.meta similarity index 52% rename from Game/Assets/Scripts/Model/Range.cs.meta rename to Game/Assets/Scripts/Utils/MathHelper.cs.meta index 6692273..b28e372 100644 --- a/Game/Assets/Scripts/Model/Range.cs.meta +++ b/Game/Assets/Scripts/Utils/MathHelper.cs.meta @@ -1,8 +1,12 @@ fileFormatVersion: 2 -guid: b436281f9c7d49f4d935ae009d4559a8 +guid: 29212ca52a4f0a64bbc8cffe74a3f4b7 +timeCreated: 1434538689 +licenseType: Free MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: + assetBundleName: + assetBundleVariant: diff --git a/Game/Assets/Scripts/Utils/QuadTree.cs b/Game/Assets/Scripts/Utils/QuadTree.cs index 642ee67..8bbd532 100644 --- a/Game/Assets/Scripts/Utils/QuadTree.cs +++ b/Game/Assets/Scripts/Utils/QuadTree.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using TransportGame.Model; +using TransportGame.Primitives; namespace TransportGame.Utils { @@ -62,12 +63,12 @@ namespace TransportGame.Utils private void Subdivide() { float midx = Boundary.Left + Boundary.Width / 2f; - float midy = Boundary.Top + Boundary.Height / 2f; + float midy = Boundary.Bottom + Boundary.Height / 2f; - NorthWest = new QuadTree(Boundary.Left, Boundary.Top, midx, midy); - NorthEast = new QuadTree(midx, Boundary.Top, Boundary.Right, midy); - SouthEast = new QuadTree(midx, midy, Boundary.Right, Boundary.Bottom); - SouthWest = new QuadTree(Boundary.Left, midy, midx, Boundary.Bottom); + NorthWest = new QuadTree(Boundary.Left, Boundary.Bottom, midx, midy); + NorthEast = new QuadTree(midx, Boundary.Bottom, Boundary.Right, midy); + SouthEast = new QuadTree(midx, midy, Boundary.Right, Boundary.Top); + SouthWest = new QuadTree(Boundary.Left, midy, midx, Boundary.Top); foreach (var point in points) Add(point); @@ -258,7 +259,7 @@ namespace TransportGame.Utils public IEnumerable Query(Rectangle rect) { // No intersection - if (!Rectangle.Intersects(rect, Boundary)) + if (!Rectangle.Intersect(rect, Boundary)) return Enumerable.Empty(); if (NorthWest == null) diff --git a/Game/Game-csharp.sln b/Game/Game-csharp.sln index 2d38414..9012803 100644 --- a/Game/Game-csharp.sln +++ b/Game/Game-csharp.sln @@ -23,7 +23,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution + GlobalSection(MonoDevelopProperties) = preSolution StartupItem = Assembly-CSharp.csproj Policies = $0 $0.TextStylePolicy = $1 diff --git a/Game/Game.sln b/Game/Game.sln index 5c83234..584f99b 100644 --- a/Game/Game.sln +++ b/Game/Game.sln @@ -29,7 +29,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution + GlobalSection(MonoDevelopProperties) = preSolution StartupItem = Assembly-CSharp.csproj Policies = $0 $0.TextStylePolicy = $1 diff --git a/Game/UnityVS.Game.CSharp.csproj b/Game/UnityVS.Game.CSharp.csproj index d11fc8f..d02f2fd 100644 --- a/Game/UnityVS.Game.CSharp.csproj +++ b/Game/UnityVS.Game.CSharp.csproj @@ -85,26 +85,26 @@ - - + + - - - + + + - + - + @@ -118,5 +118,6 @@ + \ No newline at end of file