using System.Collections.Generic; using Coroutine; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using MLEM.Cameras; using MLEM.Extended.Extensions; using MLEM.Font; using MLEM.Startup; using MLEM.Ui; using MLEM.Ui.Elements; using MonoGame.Extended; using MonoGame.Extended.Tiled; using ColorHelper = MLEM.Extensions.ColorHelper; namespace GreatSpringGameJam { public class GameImpl : MlemGame { public static GameImpl Instance { get; private set; } public Map Map { get; private set; } public Player Player { get; private set; } public Camera Camera { get; private set; } public bool IsInCutscene { get; private set; } private ContentManager mapLoader; private int currentLevel; public GameImpl() { Instance = this; this.IsMouseVisible = true; } protected override void LoadContent() { this.GraphicsDeviceManager.PreferredBackBufferWidth = 1280; this.GraphicsDeviceManager.PreferredBackBufferHeight = 720; this.GraphicsDeviceManager.ApplyChanges(); base.LoadContent(); this.UiSystem.Style.Font = new GenericSpriteFont(LoadContent("Fonts/Regular")); this.UiSystem.Style.TextScale = 0.075F; this.UiSystem.Style.TextColor = ColorHelper.FromHexRgb(0xebd5bd); this.UiSystem.AutoScaleWithScreen = true; this.InputHandler.HandleKeyboardRepeats = false; this.mapLoader = new ContentManager(this.Services, this.Content.RootDirectory); this.Camera = new Camera(this.GraphicsDevice) { AutoScaleWithScreen = true, Scale = 4 }; this.StartLevel(1); } protected override void DoUpdate(GameTime gameTime) { base.DoUpdate(gameTime); this.Map.Update(gameTime); if (!this.IsInCutscene) this.FocusCameraOnPlayer(); } protected override void DoDraw(GameTime gameTime) { this.GraphicsDevice.Clear(ColorHelper.FromHexRgb(0x729cd4)); base.DoDraw(gameTime); this.Map.Draw(gameTime, this.SpriteBatch, this.Camera); } public void Finish() { IEnumerable Impl() { // scroll up var offset = 0F; while (offset < 1) { this.Camera.LookingPosition -= new Vector2(0, offset) * this.Map.TileSize; offset += 0.01F; yield return new Wait(CoroutineEvents.Update); } // display end of level info var snowRemoved = this.Map.TotalSnow - this.Map.GetTotalTiles("Snow"); var plantsGrown = this.Map.TotalSeeds - this.Map.GetTotalTiles("Seed"); // snow removal is less important var completion = (snowRemoved / 3F + plantsGrown) / (this.Map.TotalSnow / 3F + this.Map.TotalSeeds); var group = new Group(Anchor.Center, new Vector2(0.5F), false); this.UiSystem.Add("EndCard", group); group.AddChild(new Paragraph(Anchor.AutoCenter, 1, "Level Completed!", true) {TextScale = 0.125F}); group.AddChild(new VerticalSpace(15)); yield return new Wait(1); group.AddChild(new Paragraph(Anchor.AutoCenter, 1, $"Snow Removed: {snowRemoved} / {this.Map.TotalSnow}", true)); yield return new Wait(1); group.AddChild(new Paragraph(Anchor.AutoCenter, 1, $"Plants Watered: {plantsGrown} / {this.Map.TotalSeeds}", true)); yield return new Wait(1); // display score var completionCounter = 0; group.AddChild(new VerticalSpace(10)); const string scoreText = "Score: {0}%"; var score = group.AddChild(new Paragraph(Anchor.AutoCenter, 1, string.Format(scoreText, 0), true) {TextScale = 0.1F}); while (completionCounter < completion * 100) { completionCounter++; score.Text = string.Format(scoreText, completionCounter); yield return new Wait(0.03F); } yield return new Wait(3); // fade out and move to next level foreach (var wait in this.FadeAndStartLevel(this.currentLevel + 1, Color.White)) yield return wait; } this.IsInCutscene = true; CoroutineHandler.Start(Impl()); } public void RestartLevel() { this.IsInCutscene = true; CoroutineHandler.Start(this.FadeAndStartLevel(this.currentLevel, Color.Black)); } private IEnumerable FadeAndStartLevel(int level, Color color) { var fadeOverlay = new Group(Anchor.TopLeft, Vector2.One, false) { OnDrawn = (e, time, batch, a) => batch.FillRectangle(e.DisplayArea.ToExtended(), color * a), DrawAlpha = 0 }; this.UiSystem.Add("Fade", fadeOverlay); while (fadeOverlay.DrawAlpha < 1) { fadeOverlay.DrawAlpha += 0.04F; yield return new Wait(CoroutineEvents.Update); } yield return new Wait(0.25F); this.UiSystem.Remove("EndCard"); this.StartLevel(level); yield return new Wait(0.25F); while (fadeOverlay.DrawAlpha > 0) { fadeOverlay.DrawAlpha -= 0.04F; yield return new Wait(CoroutineEvents.Update); } this.UiSystem.Remove(fadeOverlay.Root.Name); this.IsInCutscene = false; } private void StartLevel(int level) { this.currentLevel = level; // dispose loaded maps so that edits don't persist this.mapLoader.Unload(); this.Map = new Map(this.mapLoader.Load($"Maps/Level{this.currentLevel}")); this.Player = new Player(this.Map, this.Map.SpawnPoint.ToVector2()); this.Map.AddEntity(this.Player); this.FocusCameraOnPlayer(1); } private void FocusCameraOnPlayer(float speed = 0.25F) { this.Camera.LookingPosition = Vector2.Lerp(this.Camera.LookingPosition, (this.Player.Position + Vector2.One / 2) * this.Map.TileSize, speed); this.Camera.ConstrainWorldBounds(Vector2.Zero, this.Map.SizeInPixels.ToVector2()); } } }