diff --git a/CityGame/CityGame.csproj b/CityGame/CityGame.csproj index a921639..6212e42 100644 --- a/CityGame/CityGame.csproj +++ b/CityGame/CityGame.csproj @@ -13,6 +13,18 @@ + + Always + + + Always + + + Always + + + Always + Always @@ -110,7 +122,7 @@ PreserveNewest - + Always diff --git a/CityGame/Classes/Entities/Car.cs b/CityGame/Classes/Entities/Car.cs index 22769c3..1b18165 100644 --- a/CityGame/Classes/Entities/Car.cs +++ b/CityGame/Classes/Entities/Car.cs @@ -11,12 +11,14 @@ using System.Threading; using AStar; using System.Threading.Tasks; using System.Collections.Concurrent; +using NAudio.Wave; namespace CityGame.Classes.Entities { public class Car : Entity { public int grid = 1; + public bool mightSwitchLane = false; public long TimeUntilReroute = 5000; protected long RerouteTimePassed = 0; public static List Cars = new List(); @@ -41,10 +43,10 @@ namespace CityGame.Classes.Entities } public float Speed { get; set; } = 128; float currentSpeed = 0; - public static ConcurrentDictionary OccupiedTilesFill = new ConcurrentDictionary(); - public static ConcurrentDictionary OccupiedTiles = new ConcurrentDictionary(); - public static ConcurrentDictionary OccupiedTilesFill2 = new ConcurrentDictionary(); - public static ConcurrentDictionary OccupiedTiles2 = new ConcurrentDictionary(); + public static ConcurrentDictionary> OccupiedTilesFill = new ConcurrentDictionary>(); + public static ConcurrentDictionary> OccupiedTiles = new ConcurrentDictionary>(); + public static ConcurrentDictionary> OccupiedTilesFill2 = new ConcurrentDictionary>(); + public static ConcurrentDictionary> OccupiedTiles2 = new ConcurrentDictionary>(); protected string PNGFile = "NPCCar.png"; protected ColoredRectangle debugRect; protected Tile lastTile; @@ -101,6 +103,12 @@ namespace CityGame.Classes.Entities private float curveModePixelDuration; private int curveModeStartedAt; private bool pathfindingInProgress; + LaneMode laneMode = LaneMode.Default; + private long laneSwitchCooldown = 0; + enum LaneMode + { + WrongLane = -1, Parked = 0, Default = 1 + } private async Task CalculatePathAsync(Point start, Point target, PathFinder pathfinder) { return await Task.Run(() => @@ -110,18 +118,19 @@ namespace CityGame.Classes.Entities } public override async void Tick(long deltaTime) { - //deltaTime /= 10; - //deltaTime *= 500; - Tuple[] fullBlockTiles = new Tuple[] + visualX = X; + visualY = Y; + visualRotation = Rotation; + UseVisualPosition = true; + float r = Rotation; + if (laneMode == LaneMode.WrongLane) { - new Tuple(TileType.Road, "4c"), - new Tuple(TileType.Road, "3c"), - new Tuple(TileType.Road, "1"), - new Tuple(TileType.Garage, null) - }; - //if (this == MainWindow.Selected) Debug.WriteLine("Selected."); + r = (r + 180) % 360; + Vector2 offsetVector = new Vector2(0,-1).RotateBy(Rotation - 90) * MainWindow.TileSize / 3; + visualX += offsetVector.X; + visualY += offsetVector.Y; + } Tile myTile = MainWindow.Grid[Point.X, Point.Y]; - bool fullBlock = fullBlockTiles.Any(x => (x.Item1 == myTile.Type || (x.Item1 == TileType.Road && (myTile.Type == TileType.Path || myTile.Type == TileType.Highway || myTile.Type == TileType.Bridge || myTile.Type == TileType.HighwayBridge))) && (x.Item2 == myTile.Pattern.PatternCode || x.Item2 is null)); if (myTile.Type == TileType.Garage) { Rotation = ((Canvas)myTile.Element).Children[1].Rotation - 90; @@ -163,16 +172,7 @@ namespace CityGame.Classes.Entities Path = null; NextTarget = 0; JourneyFinished(this); - if (Math.Round(Rotation) == 0 || Math.Round(Rotation) == 90) - { - if (!OccupiedTilesFill.ContainsKey(myTile)) OccupiedTilesFill.TryAdd(myTile, this); - if (!OccupiedTilesFill2.ContainsKey(myTile) && fullBlock) OccupiedTilesFill2.TryAdd(myTile, this); - } - if (Math.Round(Rotation) == 180 || Math.Round(Rotation) == 270) - { - if (!OccupiedTilesFill2.ContainsKey(myTile)) OccupiedTilesFill2.TryAdd(myTile, this); - if (!OccupiedTilesFill.ContainsKey(myTile) && fullBlock) OccupiedTilesFill.TryAdd(myTile, this); - } + DoLaneBlockades(); return; } if (X.CloselyEquals(nextTarget.X * MainWindow.TileSize) && Y.CloselyEquals(nextTarget.Y * MainWindow.TileSize)) @@ -189,30 +189,35 @@ namespace CityGame.Classes.Entities Tile targetTile = MainWindow.Grid[nextTarget.X, nextTarget.Y]; Car blockingCar = null; - if (Math.Round(Rotation) == 0 || Math.Round(Rotation) == 90) + DoLaneBlockades(); + if (Math.Round(r) == 0 || Math.Round(r) == 90) { - if (!OccupiedTilesFill.ContainsKey(myTile)) OccupiedTilesFill.TryAdd(myTile, this); - if (!OccupiedTilesFill2.ContainsKey(myTile) && fullBlock) OccupiedTilesFill2.TryAdd(myTile, this); - if (OccupiedTiles.ContainsKey(targetTile) && OccupiedTiles[targetTile] != this) + if (OccupiedTiles.ContainsKey(targetTile) && OccupiedTiles[targetTile].Any(x => x != this)) { SpeedMulti = 0; - blockingCar = OccupiedTiles[targetTile]; + blockingCar = OccupiedTiles[targetTile].First(x => x != this); + if (blockingCar is null) blockingCar = this; } } - if (Math.Round(Rotation) == 180 || Math.Round(Rotation) == 270) + if (Math.Round(r) == 180 || Math.Round(r) == 270) { - if (!OccupiedTilesFill2.ContainsKey(myTile)) OccupiedTilesFill2.TryAdd(myTile, this); - if (!OccupiedTilesFill.ContainsKey(myTile) && fullBlock) OccupiedTilesFill.TryAdd(myTile, this); - if (OccupiedTiles2.ContainsKey(targetTile) && OccupiedTiles2[targetTile] != this) + if (OccupiedTiles2.ContainsKey(targetTile) && OccupiedTiles2[targetTile].Any(x => x != this)) { SpeedMulti = 0; - blockingCar = OccupiedTiles2[targetTile]; + blockingCar = OccupiedTiles2[targetTile].First(x => x != this); + if (blockingCar is null) blockingCar = this; } } + laneSwitchCooldown -= (long)Speed * deltaTime; if (SpeedMulti == 0 && blockingCar is not null) { RerouteTimePassed += deltaTime; + if (mightSwitchLane && laneSwitchCooldown <= 0) + { + laneMode = (LaneMode)((int)laneMode * -1); + laneSwitchCooldown = MainWindow.TileSize * 3 * 1000; + } if (RerouteTimePassed > TimeUntilReroute) { var resetFunc = MainWindow.UpdatePathfinding(targetTile, 0, 3); @@ -221,6 +226,7 @@ namespace CityGame.Classes.Entities } else { + if (laneSwitchCooldown <= 0) laneMode = LaneMode.Default; RerouteTimePassed = 0; } @@ -251,11 +257,11 @@ namespace CityGame.Classes.Entities } } + if (this is CriminalCar && SpeedMulti > 0 && deltaTime > 0) Debug.WriteLine("running"); var possibleDistance = Speed * deltaTime / 1000 * SpeedMulti; var finalDistance = Math.Min(possibleDistance, travel.Length()); Vector2 travelFinal = direction * finalDistance; - UseVisualPosition = false; if (curveMode != 0) { float rotationStart = MainWindow.TileSize * 1.25f; @@ -265,8 +271,6 @@ namespace CityGame.Classes.Entities if (curveModePixelDuration <= rotationEnd) curveMode = 0; else { - UseVisualPosition = true; - if (curveModePixelDuration < rotationStart && curveModePixelDuration > rotationEnd) { float percentage = (curveModePixelDuration - rotationEnd) / (rotationStart - rotationEnd); @@ -284,15 +288,10 @@ namespace CityGame.Classes.Entities vRotDeg = (-45 * percentage2) * curveMode; } if (this == MainWindow.Selected) Debug.WriteLine(vRotDeg); - visualX = X; - visualY = Y; - visualRotation = Rotation + vRotDeg; + visualRotation += vRotDeg; } else { - visualX = X; - visualY = Y; - visualRotation = Rotation; } } } @@ -302,16 +301,33 @@ namespace CityGame.Classes.Entities } else { - if (Math.Round(Rotation) == 0 || Math.Round(Rotation) == 90) - { - if (!OccupiedTilesFill.ContainsKey(myTile)) OccupiedTilesFill.TryAdd(myTile, this); - if (!OccupiedTilesFill2.ContainsKey(myTile) && fullBlock) OccupiedTilesFill2.TryAdd(myTile, this); - } - if (Math.Round(Rotation) == 180 || Math.Round(Rotation) == 270) - { - if (!OccupiedTilesFill2.ContainsKey(myTile)) OccupiedTilesFill2.TryAdd(myTile, this); - if (!OccupiedTilesFill.ContainsKey(myTile) && fullBlock) OccupiedTilesFill.TryAdd(myTile, this); - } + DoLaneBlockades(); + } + } + public void DoLaneBlockades() + { + Tuple[] fullBlockTiles = new Tuple[] + { + new Tuple(TileType.Road, "4c"), + new Tuple(TileType.Road, "3c"), + new Tuple(TileType.Road, "1"), + new Tuple(TileType.Garage, null) + }; + //if (this == MainWindow.Selected) Debug.WriteLine("Selected."); + Tile myTile = MainWindow.Grid[Point.X, Point.Y]; + bool fullBlock = fullBlockTiles.Any(x => (x.Item1 == myTile.Type || (x.Item1 == TileType.Road && (myTile.Type == TileType.Path || myTile.Type == TileType.Highway || myTile.Type == TileType.Bridge || myTile.Type == TileType.HighwayBridge))) && (x.Item2 == myTile.Pattern.PatternCode || x.Item2 is null)); + if (laneMode == LaneMode.Parked) return; + float r = Rotation; + if (laneMode == LaneMode.WrongLane) r = (r + 180) % 360; + if (Math.Round(r) == 0 || Math.Round(r) == 90) + { + if (!OccupiedTilesFill.ContainsKey(myTile)) OccupiedTilesFill.WeirdAddToList(myTile, this); + if (!OccupiedTilesFill2.ContainsKey(myTile) && fullBlock) OccupiedTilesFill2.WeirdAddToList(myTile, this); + } + if (Math.Round(r) == 180 || Math.Round(r) == 270) + { + if (!OccupiedTilesFill2.ContainsKey(myTile)) OccupiedTilesFill2.WeirdAddToList(myTile, this); + if (!OccupiedTilesFill.ContainsKey(myTile) && fullBlock) OccupiedTilesFill.WeirdAddToList(myTile, this); } } } diff --git a/CityGame/Classes/Entities/CriminalCar.cs b/CityGame/Classes/Entities/CriminalCar.cs new file mode 100644 index 0000000..3e25b04 --- /dev/null +++ b/CityGame/Classes/Entities/CriminalCar.cs @@ -0,0 +1,89 @@ +using CityGame.Classes.Rendering; +using CityGame.Classes.World; +using Microsoft.Xna.Framework; +using OrpticonGameHelper; +using OrpticonGameHelper.Classes.Elements; +using SixLabors.ImageSharp.Processing; +using System; +using System.Collections.Generic; + +namespace CityGame.Classes.Entities +{ + public class CriminalCar : Car + { + public long CaughtTimer { get; set; } + public bool GotAway { get; set; } = false; + public bool Caught { get; set; } = false; + public static List targetTiles = new List(); + public static List CCars = new List(); + public CriminalCar() : base() + { + CCars.Add(this); + if (targetTiles.Count == 0) + { + for (int x = 0; x < MainWindow.Grid.GetLength(0); x++) + { + targetTiles.Add(MainWindow.Grid[x, 0]); + targetTiles.Add(MainWindow.Grid[x, MainWindow.Grid.GetLength(1) - 1]); + } + for (int y = 0; y < MainWindow.Grid.GetLength(1); y++) + { + targetTiles.Add(MainWindow.Grid[0, y]); + targetTiles.Add(MainWindow.Grid[MainWindow.Grid.GetLength(0) - 1, y]); + } + } + grid = 2; + //mightSwitchLane = true; + Speed = 160; + PNGFile = "CriminalCar.png"; + TimeUntilReroute = 1000; + } + public override OCanvas Render() + { + OCanvas canvas = base.Render(); + + return canvas; + } + public override void Tick(long deltaTime) + { + if (!Caught && !GotAway) + { + if (CaughtTimer >= 0) + { + if (Path is null || Path.Length == 0) + { + var myTile = MainWindow.Grid[(int)X / MainWindow.TileSize, (int)Y / MainWindow.TileSize]; + Target = MainWindow.FindNearestTile(myTile, MainWindow.Grids[grid], targetTiles.ToArray()); + if (Target is Tile tile && tile.X == myTile.X && tile.Y == myTile.Y) + { + GotAway = true; + Window.FireSound("missing"); + Object.Visible = false; + } + } + + base.Tick(deltaTime); + + if (Path is null || Path.Length == 0) + { + CaughtTimer -= deltaTime; + } + else + { + CaughtTimer = 10000; + } + } + else + { + ((SourcedImage)Object.Children[0]).Source = Environment.CurrentDirectory + "\\Resources\\CaughtCar.png"; + Caught = true; + Window.FireSound("in_custody"); + } + } + if(Caught) + { + DoLaneBlockades(); + } + } + } +} \ No newline at end of file diff --git a/CityGame/Classes/Entities/Entity.cs b/CityGame/Classes/Entities/Entity.cs index a9154e4..4d8a5ec 100644 --- a/CityGame/Classes/Entities/Entity.cs +++ b/CityGame/Classes/Entities/Entity.cs @@ -48,13 +48,14 @@ namespace CityGame.Classes.Entities if (pipe.Exploded > 0) return false; Explosion x = new Explosion(); pipe.canvas.Children.Add(x); - Canvas.SetLeft(x, pipe.GetParticleOrigin().X); - Canvas.SetTop(x, pipe.GetParticleOrigin().Y); + Canvas.SetLeft(x, pipe.GetParticleOrigin().X - 8); + Canvas.SetTop(x, pipe.GetParticleOrigin().Y - 8); x.RotationOrigin = new Microsoft.Xna.Framework.Point(MainWindow.TileSize / 2); x.Size = 16; x.MaxParticleDistance = 32; x.Emit(); pipe.Exploded = 1; + pipe.image.Source = pipe.image.Source.Replace("ManholeCover", "ExplosionHole"); return true; } return false; diff --git a/CityGame/Classes/Entities/GasPipe.cs b/CityGame/Classes/Entities/GasPipe.cs index 4b97e8f..98d9cd5 100644 --- a/CityGame/Classes/Entities/GasPipe.cs +++ b/CityGame/Classes/Entities/GasPipe.cs @@ -1,5 +1,7 @@ -using CityGame.Classes.Rendering; +using AStar.Collections.MultiDimensional; +using CityGame.Classes.Rendering; using CityGame.Classes.Rendering.Particles; +using CityGame.Classes.World; using Microsoft.Xna.Framework; using OrpticonGameHelper.Classes.Elements; @@ -8,9 +10,9 @@ namespace CityGame.Classes.Entities public class GasPipe : Entity { public long Exploded { get; set; } + public long LastSmoke { get; set; } public Image image { get; set; } public OCanvas canvas { get; set; } - public Explosion Smoke { get; set; } public GasPipe() { if (MainWindow.random.Next(0, 2) == 0) Rotation += 180; @@ -32,31 +34,36 @@ namespace CityGame.Classes.Entities if (Exploded > 0) { Exploded += deltaTime; - if(Smoke is null) + LastSmoke += deltaTime; + if (LastSmoke > 0 && Exploded < 6500) { + LastSmoke -= 500; CreateSmoke(); } + Tile tile = MainWindow.Grid[(int)(X / MainWindow.TileSize), (int)(Y / MainWindow.TileSize)]; + Car.OccupiedTilesFill.WeirdAddToList(tile, null); + Car.OccupiedTilesFill2.WeirdAddToList(tile, null); } } - void CreateSmoke() + Explosion CreateSmoke() { Explosion smoke = new Explosion(); smoke.DirectionTendency = MainWindow.Wind; smoke.DirectionVariance = 22.5f; - smoke.MinColor = Color.LightGray; - smoke.MaxColor = Color.DarkGray; + smoke.MinColor = new Color(225, 225, 225); + smoke.MaxColor = new Color(30, 30, 30); smoke.MaxParticleDistance = MainWindow.TileSize * 3; - smoke.EmissionTime = 3; + smoke.EmissionTime = 6; smoke.ParticleCountMin = 1; smoke.ParticleCountMax = 2; smoke.Size = 16; smoke.RotationOrigin = new Microsoft.Xna.Framework.Point(MainWindow.TileSize / 2); smoke.EaseMovement = false; - Smoke = smoke; - Object.Children.Add(Smoke); - Canvas.SetLeft(Smoke, GetParticleOrigin().X); - Canvas.SetTop(Smoke, GetParticleOrigin().Y); + Object.Children.Add(smoke); + Canvas.SetLeft(smoke, GetParticleOrigin().X - 8); + Canvas.SetTop(smoke, GetParticleOrigin().Y - 8); smoke.Emit().ContinueWith(t => CreateSmoke()); + return smoke; } } } diff --git a/CityGame/Classes/Entities/PoliceCar.cs b/CityGame/Classes/Entities/PoliceCar.cs index bebc257..8fbbc72 100644 --- a/CityGame/Classes/Entities/PoliceCar.cs +++ b/CityGame/Classes/Entities/PoliceCar.cs @@ -12,6 +12,7 @@ namespace CityGame.Classes.Entities public PoliceCar() : base() { grid = 2; + mightSwitchLane = true; PCars.Add(this); Speed = 192; PNGFile = "PoliceCar.png"; diff --git a/CityGame/Classes/Misc/Extensions.cs b/CityGame/Classes/Misc/Extensions.cs index 6fc534c..15b958d 100644 --- a/CityGame/Classes/Misc/Extensions.cs +++ b/CityGame/Classes/Misc/Extensions.cs @@ -1,5 +1,8 @@ -using Microsoft.Xna.Framework; +using CityGame.Classes.Entities; +using CityGame.Classes.World; +using Microsoft.Xna.Framework; using System; +using System.Collections.Concurrent; using System.Numerics; using System.Reflection.Metadata; @@ -45,5 +48,10 @@ namespace CityGame float rotatedY = v.X * sin + v.Y * cos; return new System.Numerics.Vector2(rotatedX, rotatedY); } + public static void WeirdAddToList(this ConcurrentDictionary> list, T1 myTile, T2 car) + { + if(!list.ContainsKey(myTile)) list.TryAdd(myTile, new ConcurrentBag()); + list[myTile].Add(car); + } } } \ No newline at end of file diff --git a/CityGame/Classes/Rendering/ColorConversionMaps.cs b/CityGame/Classes/Rendering/ColorConversionMaps.cs index 4e90312..ff37bc6 100644 --- a/CityGame/Classes/Rendering/ColorConversionMaps.cs +++ b/CityGame/Classes/Rendering/ColorConversionMaps.cs @@ -69,5 +69,11 @@ namespace CityGame.Classes.Rendering { "#fc4141", "#4141fc" }, { "#b80000", "#0000b8" } }; + public static Dictionary CarToCaughtCar = new Dictionary() + { + { "#ff0000", "#00ff00" }, + { "#fc4141", "#41fc41" }, + { "#b80000", "#00b800" } + }; } } diff --git a/CityGame/Classes/Rendering/IntPoint.cs b/CityGame/Classes/Rendering/IntPoint.cs index ff3a1af..7afe630 100644 --- a/CityGame/Classes/Rendering/IntPoint.cs +++ b/CityGame/Classes/Rendering/IntPoint.cs @@ -1,4 +1,6 @@ -namespace CityGame.Classes.Rendering +using Microsoft.Xna.Framework; + +namespace CityGame.Classes.Rendering { public struct IntPoint { @@ -13,6 +15,14 @@ { return new IntPoint(a.X + b.X, a.Y + b.Y); } + public static IntPoint operator -(IntPoint a, Vector2 b) + { + return new IntPoint(a.X - (int)b.X, a.Y - (int)b.Y); + } + public static IntPoint operator +(IntPoint a, Vector2 b) + { + return new IntPoint(a.X + (int)b.X, a.Y + (int)b.Y); + } public static IntPoint operator *(IntPoint a, int b) { return new IntPoint(a.X * b, a.Y * b); diff --git a/CityGame/Classes/World/TileType.cs b/CityGame/Classes/World/TileType.cs index f140721..0189c2d 100644 --- a/CityGame/Classes/World/TileType.cs +++ b/CityGame/Classes/World/TileType.cs @@ -2,6 +2,8 @@ { public enum TileType { + Invalid = -100, + Skyscraper = 100, House = 101, Helipad = 102, diff --git a/CityGame/MainWindow.cs b/CityGame/MainWindow.cs index 4d71a1d..0f8f7d6 100644 --- a/CityGame/MainWindow.cs +++ b/CityGame/MainWindow.cs @@ -16,6 +16,7 @@ using OrpticonGameHelper; using OrpticonGameHelper.Classes.Elements; using static CityGame.Classes.Entities.Car; using OrpticonGameHelper.Classes.Misc; +using System.Diagnostics; namespace CityGame { @@ -78,9 +79,60 @@ namespace CityGame internal static Canvas GameCanvas = new OCanvas(); Canvas CameraCanvas = new OCanvas(); Canvas UICanvas = new OCanvas(); + public static Tile FindNearestTile(Tile startPoint, short[,] pfGrid, params Tile[] targets) + { + var t = FindNearestTarget(new IntPoint(startPoint.X, startPoint.Y), pfGrid, targets.Select(x => new IntPoint(x.X, x.Y)).ToArray()); + if (t.X == -1 && t.Y == -1) return new Tile { Type = TileType.Invalid }; + return Grid[t.X, t.Y]; + } + public static Tile FindNearestTile(Tile startPoint, short[,] pfGrid, TileType targetTile) + { + var targets = new List(); + for (int i = 0; i < Grid.Length; i++) + { + if (Grid[i % Grid.GetLength(0), i / Grid.GetLength(0)].Type == targetTile) targets.Add(Grid[i % Grid.GetLength(0), i / Grid.GetLength(0)]); + } + return FindNearestTile(startPoint, pfGrid, targets.ToArray()); + } + public static IntPoint FindNearestTarget(IntPoint startPoint, short[,] pfGrid, params IntPoint[] targets) + { + var directions = new Vector2[] { new Vector2(0, 1), new Vector2(1, 0), new Vector2(0, -1), new Vector2(-1, 0) }; + IntPoint result = new IntPoint(0, 0); + bool resultFound = false; + var searchers = new List(); + var processed = new List(); + searchers.Add(startPoint); + while (!resultFound) + { + if (searchers.Count == 0) return new IntPoint(-1, -1); + var s = searchers.ToList(); + searchers = new List(); + foreach (var searcher in s) + { + if (targets.Contains(searcher)) + { + result = searcher; + resultFound = true; + break; + } + foreach (var direction in directions) + { + var p = searcher + direction; + if (p.X < 0 || p.Y < 0) continue; + if (p.X >= pfGrid.GetLength(1)) continue; + if (p.Y >= pfGrid.GetLength(0)) continue; + if (processed.Contains(p)) continue; + if (pfGrid[p.Y, p.X] == 0) continue; + processed.Add(p); + searchers.Add(p); + } + } + } + return result; + } /// - /// Updates the pathfinding grids of all grid numbers includes in the "grids" parameter + /// Updates the pathfinding grids of all grid numbers included in the "grids" parameter /// /// The tile to update /// The value to update the tile to @@ -163,16 +215,18 @@ namespace CityGame ImageConverter.ChangeColor("Error", "ErrorRed", new Dictionary { { "#000000", "#ff0000" } }); ImageConverter.ChangeColor("Car", "NPCCar", ColorConversionMaps.CarToNPCCar); ImageConverter.ChangeColor("Car", "PoliceCar", ColorConversionMaps.CarToPoliceCar); + ImageConverter.ChangeColor("Car", "CaughtCar", ColorConversionMaps.CarToCaughtCar); + ImageConverter.ChangeColor("Car", "CriminalCar", new Dictionary()); #endregion - + LoadableContent.Add(ShaderLoader.Create()); - int seed = 8; + int seed = (int)(DateTime.Now.Ticks % int.MaxValue); Noise.Seed = seed; - int mapHeight = 100; - int mapWidth = 200; + int mapHeight = 50; + int mapWidth = 50; float[,] lakeMap = Noise.Calc2D(mapWidth, mapHeight, 0.05f); @@ -194,6 +248,7 @@ namespace CityGame int minBlockWidth = 3; int NPCCount = (int)Math.Ceiling(mapHeight * mapWidth / 100f); + int CriminalCount = 1; //NPCCount = 1; //NPCCount = 0; //NPCCount /= 2; @@ -310,6 +365,22 @@ namespace CityGame if (IntermediateGrid[x, y].Type == TileType.Park) changeTo = TileType.Path; if (x < doubleWidth - 1 && IntermediateGrid[x + 1, y].BlockID != myID) IntermediateGrid[x, y].Type = changeTo; if (y < doubleHeight - 1 && IntermediateGrid[x, y + 1].BlockID != myID) IntermediateGrid[x, y].Type = changeTo; + var type = IntermediateGrid[x, y].Type; + if (type == TileType.Bridge) bridgeTiles.Add(IntermediateGrid[x, y]); + if (type == TileType.Road) roadTiles.Add(IntermediateGrid[x, y]); + bool walkable = ((int)type) / 100 == 4; + Grids[2][y, x] = (short)(walkable ? 1 : 0); + if (type == TileType.Path) walkable = false; + Grids[1][y, x] = (short)(walkable ? 1 : 0); + } + } + bool checkBridges = true; + if (checkBridges) + { + foreach (var tile in bridgeTiles) + { + IntPoint road = FindNearestTarget(new IntPoint(tile.X, tile.Y), Grids[1], roadTiles.Select(x => new IntPoint(x.X, x.Y)).ToArray()); + if (road.X == -1 && road.Y == -1) IntermediateGrid[tile.X, tile.Y].Type = TileType.Lake; } } @@ -355,9 +426,21 @@ namespace CityGame startPoint += step; } } - #endregion + for (int y = 0; y < doubleHeight; y++) + { + for (int x = 0; x < doubleWidth; x++) + { + var type = IntermediateGrid[x, y].Type; + bool walkable = ((int)type) / 100 == 4; + Grids[2][y, x] = (short)(walkable ? 1 : 0); + if (type == TileType.Path) walkable = false; + Grids[1][y, x] = (short)(walkable ? 1 : 0); + if (type == TileType.Road || type == TileType.Bridge) npcWalkable.Add(IntermediateGrid[x, y]); + } + } Grid = IntermediateGrid; + #endregion //for(int y = 0; y < mapHeight; y++) //{ // for(int x = 0; x < mapWidth; x++) @@ -400,20 +483,6 @@ namespace CityGame GameCanvas.Children.Add(image); } } - for (int y = 0; y < doubleHeight; y++) - { - for (int x = 0; x < doubleWidth; x++) - { - var type = IntermediateGrid[x, y].Type; - bool walkable = ((int)type) / 100 == 4; - Grids[2][y, x] = (short)(walkable ? 1 : 0); - if (type == TileType.Path) walkable = false; - Grids[1][y, x] = (short)(walkable ? 1 : 0); - if (type == TileType.Bridge) bridgeTiles.Add(IntermediateGrid[x, y]); - if (type == TileType.Road) roadTiles.Add(IntermediateGrid[x, y]); - if (type == TileType.Road || type == TileType.Bridge) npcWalkable.Add(IntermediateGrid[x, y]); - } - } foreach (var kvp in Grids) WorldGrids.Add(kvp.Key, new WorldGrid(kvp.Value)); InstantiatePathfinders(); @@ -436,7 +505,7 @@ namespace CityGame Entities.Add(new PoliceCar { X = x, Y = y }); } var roads = SourcedImage.GetObjectsBySourceFile("Road1.png", "Road2.png", "Road2c.png", "Road3c.png", "Road4c.png"); - var pipeCount = NPCCount; + var pipeCount = NPCCount * 2; var pipeRoads = roads.OrderBy(x => random.Next(0, roads.Count)).Take(pipeCount).ToArray(); foreach (Image image in pipeRoads) { @@ -464,19 +533,35 @@ namespace CityGame Entities.Add(car); } + for (int n = 0; n < CriminalCount; n++) + { + CriminalCar car = new CriminalCar(); + bool foundStartPoint = false; + Tile startTile = Grid[0, 0]; + while(!foundStartPoint) + { + startTile = npcWalkable[random.Next(0, npcWalkable.Count)]; + if (startTile.X > doubleWidth / 3 && startTile.Y > doubleHeight / 3 && startTile.X < doubleWidth / 3 * 2 && startTile.Y < doubleHeight / 3 * 2) foundStartPoint = true; + } + + car.Point = new Point(startTile.X, startTile.Y); + Entities.Add(car); + } SoundEffectListener = new AudioListener { Position = new Vector3(0, 0, 100) }; Show(); } int swv; + public bool PauseEntities = true; protected override Color SkyColor(long SpeedFactor) { - return base.SkyColor(180); + return Color.Gray; } protected override void Update(GameTime time) { MouseState state = Mouse.GetState(); + KeyboardState kstate = Keyboard.GetState(); if (state.MiddleButton == ButtonState.Pressed) { @@ -522,12 +607,15 @@ namespace CityGame Selected.RunAction(select); } } + if (kstate.IsKeyDown(Keys.Space)) PauseEntities = !PauseEntities; + PauseParticles = PauseEntities; long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; foreach (Entity entity in Entities) { long deltaTime = milliseconds - entity.Time; deltaTime = (long)time.ElapsedGameTime.TotalMilliseconds; + if (PauseEntities) deltaTime = 0; entity.Time = milliseconds; entity.Tick(deltaTime); entity.BaseTick(deltaTime); @@ -542,9 +630,9 @@ namespace CityGame Canvas.SetTop(entity.Object, entity.VisualY); } Car.OccupiedTiles = Car.OccupiedTilesFill; - Car.OccupiedTilesFill = new System.Collections.Concurrent.ConcurrentDictionary(); + Car.OccupiedTilesFill = new System.Collections.Concurrent.ConcurrentDictionary>(); Car.OccupiedTiles2 = Car.OccupiedTilesFill2; - Car.OccupiedTilesFill2 = new System.Collections.Concurrent.ConcurrentDictionary(); + Car.OccupiedTilesFill2 = new System.Collections.Concurrent.ConcurrentDictionary>(); } } } \ No newline at end of file diff --git a/CityGame/Resources/Audio/helicopter.mp3 b/CityGame/Resources/Audio/helicopter0.mp3 similarity index 100% rename from CityGame/Resources/Audio/helicopter.mp3 rename to CityGame/Resources/Audio/helicopter0.mp3 diff --git a/CityGame/Resources/Audio/in_custody0.mp3 b/CityGame/Resources/Audio/in_custody0.mp3 new file mode 100644 index 0000000..8434868 Binary files /dev/null and b/CityGame/Resources/Audio/in_custody0.mp3 differ diff --git a/CityGame/Resources/Audio/missing0.mp3 b/CityGame/Resources/Audio/missing0.mp3 new file mode 100644 index 0000000..b9b7e4e Binary files /dev/null and b/CityGame/Resources/Audio/missing0.mp3 differ diff --git a/CityGame/Resources/Audio/missing1.mp3 b/CityGame/Resources/Audio/missing1.mp3 new file mode 100644 index 0000000..de2d743 Binary files /dev/null and b/CityGame/Resources/Audio/missing1.mp3 differ diff --git a/CityGame/Resources/ExplosionHole.png b/CityGame/Resources/ExplosionHole.png new file mode 100644 index 0000000..2707a31 Binary files /dev/null and b/CityGame/Resources/ExplosionHole.png differ