using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input.Touch; using MLEM.Extensions; using MLEM.Misc; using MLEM.Startup; using MLEM.Textures; using ThemeParkClicker.Attractions; namespace ThemeParkClicker { [DataContract] public class ParkMap { [DataMember] public readonly int Width; [DataMember] public readonly int Height; [DataMember] private readonly List<(Point, Attraction)> attractions = new List<(Point, Attraction)>(); public Attraction PlacingAttraction; public Point PlacingPosition; private bool draggingAttraction; public ParkMap(int width, int height) { this.Width = width; this.Height = height; } public void Update(GameTime time, TimeSpan passed) { foreach (var (_, attraction) in this.attractions) attraction.Update(time, passed); // map movement if (GameImpl.Instance.DrawMap) { var camera = GameImpl.Instance.Camera; if (MlemGame.Input.GetGesture(GestureType.Pinch, out var pinch)) { var startDiff = pinch.Position2 - pinch.Position; var endDiff = pinch.Position2 + pinch.Delta2 - (pinch.Position + pinch.Delta); if (startDiff.LengthSquared() < endDiff.LengthSquared()) { // zooming in camera.Zoom(pinch.Delta.Length() / camera.Scale); } else { // zooming out camera.Zoom(-pinch.Delta.Length() / camera.Scale); } } else if (MlemGame.Input.GetGesture(GestureType.FreeDrag, out var drag)) { if (this.draggingAttraction) { // move the current placing position var nextPos = (camera.ToWorldPos(drag.Position + drag.Delta) / Attraction.TileSize).ToPoint(); if (nextPos.X >= 0 && nextPos.Y >= 0 && nextPos.X < this.Width && nextPos.Y < this.Height) this.PlacingPosition = nextPos; } else { // move the camera camera.Position -= drag.Delta / camera.Scale; } } else if (this.PlacingAttraction != null) { foreach (var touch in MlemGame.Input.TouchState) { if (touch.State != TouchLocationState.Pressed) continue; // when first pressing down, go into attraction drag mode if we're touching the place location var offset = (camera.ToWorldPos(touch.Position) / Attraction.TileSize).ToPoint(); this.draggingAttraction = this.PlacingAttraction.GetCoveredTiles() .Any(p => this.PlacingPosition + p == offset); } } } } public void Draw(GameTime time, SpriteBatch batch, Vector2 position, float scale, float alpha) { var tileSize = Attraction.TileSize * scale; // draw ground batch.Draw(batch.GetBlankTexture(), new RectangleF(position, new Vector2(this.Width, this.Height) * tileSize), ColorExtensions.FromHex(0xff53a662) * alpha); // draw attractions foreach (var (pos, attraction) in this.attractions) batch.Draw(attraction.Type.TextureRegion, position + pos.ToVector2() * tileSize, Color.White * alpha, 0, Vector2.Zero, scale, SpriteEffects.None, 0); // placing attraction if (this.PlacingAttraction != null) { var placingPos = position + this.PlacingPosition.ToVector2() * tileSize; foreach (var pos in this.PlacingAttraction.GetCoveredTiles()) batch.Draw(batch.GetBlankTexture(), new RectangleF(placingPos + pos.ToVector2() * tileSize, tileSize), Color.Black * 0.15F * alpha); batch.Draw(this.PlacingAttraction.Type.TextureRegion, placingPos, Color.White * alpha * 0.5F, 0, Vector2.Zero, scale, SpriteEffects.None, 0); } } public bool CanPlace(Point position, Attraction attraction) { foreach (var offset in attraction.GetCoveredTiles()) { if (this.GetAttractionAt(position + offset) != null) return false; } return true; } public void Place(Point position, Attraction attraction) { this.attractions.RemoveAll(pa => pa.Item1 == position); this.attractions.Add((position, attraction)); } public Attraction GetAttractionAt(Point position) { foreach (var (pos, attraction) in this.attractions) { if (attraction.GetCoveredTiles().Any(p => pos + p == position)) return attraction; } return null; } public int GetAttractionAmount(AttractionType type) { return this.attractions.Count(a => a.Item2.Type == type); } } }