win condition

main
Evan Hemsley 2020-07-19 20:16:15 -07:00
parent b2198f448b
commit 5eb92804f4
16 changed files with 261 additions and 99 deletions

View File

@ -0,0 +1,16 @@
using Encompass;
namespace PongFE.Components
{
public struct BallParametersComponent : IComponent
{
public int Speed { get; }
public double Delay { get; }
public BallParametersComponent(int speed, double delay)
{
Speed = speed;
Delay = delay;
}
}
}

View File

@ -1,16 +0,0 @@
using Encompass;
namespace PongFE.Components
{
public struct SpawnBallAfterDestroyComponent : IComponent
{
public float Speed { get; }
public float Seconds { get; }
public SpawnBallAfterDestroyComponent(float speed, float seconds)
{
Speed = speed;
Seconds = seconds;
}
}
}

View File

@ -0,0 +1,17 @@
using Encompass;
using SpriteFontPlus;
namespace PongFE.Components
{
public struct UITextComponent : IComponent
{
public DynamicSpriteFont Font { get; }
public string Text { get; }
public UITextComponent(DynamicSpriteFont font, string text)
{
Font = font;
Text = text;
}
}
}

View File

@ -5,35 +5,16 @@ using PongFE.Messages;
namespace PongFE.Engines
{
[Reads(
typeof(SpawnBallAfterDestroyComponent),
typeof(IncreaseScoreAfterDestroyComponent)
)]
[Receives(typeof(DestroyMessage))]
[Sends(
typeof(BallSpawnMessage),
typeof(ScoreMessage)
)]
[Sends(typeof(ScoreMessage))]
public class DestroyEngine : Engine
{
public override void Update(double dt)
{
foreach (ref readonly var message in ReadMessages<DestroyMessage>())
{
if (HasComponent<SpawnBallAfterDestroyComponent>(message.Entity))
{
ref readonly var respawnComponent = ref GetComponent<SpawnBallAfterDestroyComponent>(message.Entity);
SendMessage(
new BallSpawnMessage(
new MoonTools.Structs.Position2D(640, 360),
respawnComponent.Speed,
16,
16
),
respawnComponent.Seconds
);
}
if (HasComponent<IncreaseScoreAfterDestroyComponent>(message.Entity))
{
SendMessage(new ScoreMessage(message.DestroyedBy));

View File

@ -1,22 +1,39 @@
using Encompass;
using Microsoft.Xna.Framework.Input;
using MoonTools.Structs;
using PongFE.Components;
using PongFE.Enums;
using PongFE.Messages;
using SpriteFontPlus;
namespace PongFE.Engines
{
[Reads(typeof(GameStateComponent), typeof(PlayAreaComponent))]
[Reads(
typeof(PositionComponent),
typeof(GameStateComponent),
typeof(PlayAreaComponent),
typeof(UITextComponent)
)]
[Receives(typeof(ChangeGameStateMessage))]
[Sends(
typeof(BallSpawnMessage),
typeof(PaddleSpawnMessage),
typeof(BoundarySpawnMessage),
typeof(GoalBoundarySpawnMessage)
typeof(GoalBoundarySpawnMessage),
typeof(UITextSpawnMessage)
)]
[Writes(typeof(GameStateComponent))]
public class GameStateEngine : Engine
{
private DynamicSpriteFont TitleFont { get; }
private DynamicSpriteFont InstructionFont { get; }
public GameStateEngine(DynamicSpriteFont titleFont, DynamicSpriteFont instructionFont)
{
TitleFont = titleFont;
InstructionFont = instructionFont;
}
public override void Update(double dt)
{
ref readonly var gameStateEntity = ref ReadEntity<GameStateComponent>();
@ -42,15 +59,12 @@ namespace PongFE.Engines
return;
}
if (gameStateComponent.GameState == GameState.Game)
if (changeGameStateMessage.GameState == GameState.Title)
{
if (changeGameStateMessage.GameState == GameState.Title)
{
EndGame();
StartTitle();
EndGame();
StartTitle();
SetComponent(gameStateEntity, new GameStateComponent(GameState.Title));
}
SetComponent(gameStateEntity, new GameStateComponent(GameState.Title));
}
}
}
@ -137,12 +151,36 @@ namespace PongFE.Engines
private void StartTitle()
{
ref readonly var playAreaComponent = ref ReadComponent<PlayAreaComponent>();
var titleDimensions = TitleFont.MeasureString("PongFE");
var titlePosition = new Position2D(
(playAreaComponent.Width - titleDimensions.X) / 2,
(playAreaComponent.Height - titleDimensions.Y) / 4
);
SendMessage(new UITextSpawnMessage(
titlePosition,
TitleFont,
"PongFE"
));
var instructionDimensions = InstructionFont.MeasureString("Press Enter to begin");
var instructionPosition = new Position2D(
(playAreaComponent.Width - instructionDimensions.X) / 2,
playAreaComponent.Height * 2 / 3
);
SendMessage(new UITextSpawnMessage(
instructionPosition,
InstructionFont,
"Press Enter to play"
));
}
private void EndTitle()
{
DestroyAllWith<UITextComponent>();
}
}
}

View File

@ -0,0 +1,55 @@
using Encompass;
using PongFE.Components;
using PongFE.Enums;
using PongFE.Messages;
using SpriteFontPlus;
namespace PongFE.Engines
{
[Reads(typeof(PlayAreaComponent))]
[Receives(typeof(GameWinMessage))]
[Sends(typeof(UITextSpawnMessage), typeof(ChangeGameStateMessage))]
public class GameWinEngine : Engine
{
public DynamicSpriteFont Font { get; }
private readonly string _playerOneWinText = "Player 1 Wins!";
private readonly string _playerTwoWinText = "Player 2 Wins!";
public GameWinEngine(DynamicSpriteFont font)
{
Font = font;
}
public override void Update(double dt)
{
if (SomeMessage<GameWinMessage>())
{
ref readonly var gameWinMessage = ref ReadMessage<GameWinMessage>();
ref readonly var playAreaComponent = ref ReadComponent<PlayAreaComponent>();
string winText;
if (gameWinMessage.PlayerIndex == PlayerIndex.One)
{
winText = _playerOneWinText;
}
else
{
winText = _playerTwoWinText;
}
var textDimensions = Font.MeasureString(winText);
SendMessage(new UITextSpawnMessage(
new MoonTools.Structs.Position2D(
(playAreaComponent.Width - textDimensions.X) / 2,
playAreaComponent.Height / 4
),
Font,
winText
));
SendMessage(new ChangeGameStateMessage(GameState.Title), 2);
}
}
}
}

View File

@ -4,8 +4,13 @@ using PongFE.Messages;
namespace PongFE.Engines
{
[Reads(typeof(ScoreComponent))]
[Reads(
typeof(ScoreComponent),
typeof(PlayerComponent),
typeof(BallParametersComponent)
)]
[Receives(typeof(ScoreMessage))]
[Sends(typeof(GameWinMessage), typeof(BallSpawnMessage))]
[Writes(typeof(ScoreComponent))]
public class ScoreEngine : Engine
{
@ -17,6 +22,26 @@ namespace PongFE.Engines
{
ref readonly var scoreComponent = ref GetComponent<ScoreComponent>(scoreMessage.Entity);
SetComponent(scoreMessage.Entity, new ScoreComponent(scoreComponent.Score + 1));
if (scoreComponent.Score + 1 >= 2)
{
ref readonly var playerComponent = ref GetComponent<PlayerComponent>(scoreMessage.Entity);
SendMessage(new GameWinMessage(playerComponent.PlayerIndex));
}
else
{
ref readonly var ballParametersComponent = ref ReadComponent<BallParametersComponent>();
SendMessage(
new BallSpawnMessage(
new MoonTools.Structs.Position2D(640, (int)MathHelper.RandomFloat(20, 700)),
ballParametersComponent.Speed,
16,
16
),
ballParametersComponent.Delay
);
}
}
}
}

View File

@ -32,7 +32,6 @@ namespace PongFE.Spawners
AddComponent(ball, new BounceResponseComponent());
AddComponent(ball, new CanBeTrackedComponent());
AddComponent(ball, new CanBeDestroyedComponent());
AddComponent(ball, new SpawnBallAfterDestroyComponent(message.Speed, 0.5f));
AddComponent(ball, new IncreaseScoreAfterDestroyComponent());
}
}

View File

@ -0,0 +1,17 @@
using Encompass;
using PongFE.Components;
using PongFE.Messages;
namespace PongFE.Spawners
{
public class UITextSpawner : Spawner<UITextSpawnMessage>
{
protected override void Spawn(UITextSpawnMessage message)
{
var entity = CreateEntity();
AddComponent(entity, new PositionComponent(message.Position));
AddComponent(entity, new UITextComponent(message.Font, message.Text));
}
}
}

View File

@ -26,6 +26,7 @@ namespace PongFE.Enums
public enum GameState
{
Init,
Title,
Game
}

View File

@ -0,0 +1,15 @@
using Encompass;
using PongFE.Enums;
namespace PongFE.Messages
{
public struct GameWinMessage : IMessage
{
public PlayerIndex PlayerIndex { get; }
public GameWinMessage(PlayerIndex playerIndex)
{
PlayerIndex = playerIndex;
}
}
}

View File

@ -0,0 +1,20 @@
using Encompass;
using MoonTools.Structs;
using SpriteFontPlus;
namespace PongFE.Messages
{
public struct UITextSpawnMessage : IMessage
{
public Position2D Position { get; }
public string Text { get; }
public DynamicSpriteFont Font { get; }
public UITextSpawnMessage(Position2D position, DynamicSpriteFont font, string text)
{
Position = position;
Font = font;
Text = text;
}
}
}

View File

@ -69,7 +69,7 @@ namespace PongFE
48
);
WorldBuilder.AddEngine(new GameStateEngine());
WorldBuilder.AddEngine(new GameStateEngine(ScoreFont, InstructionFont));
WorldBuilder.AddEngine(new InputEngine());
WorldBuilder.AddEngine(new PaddleMovementEngine());
WorldBuilder.AddEngine(new VelocityEngine());
@ -82,23 +82,29 @@ namespace PongFE
WorldBuilder.AddEngine(new UpdatePositionEngine());
WorldBuilder.AddEngine(new UpdateVelocityEngine());
WorldBuilder.AddEngine(new ComputerControlEngine());
WorldBuilder.AddEngine(new GameWinEngine(ScoreFont));
WorldBuilder.AddEngine(new BallSpawner(WhitePixel));
WorldBuilder.AddEngine(new BoundarySpawner());
WorldBuilder.AddEngine(new GoalBoundarySpawner());
WorldBuilder.AddEngine(new PaddleSpawner(WhitePixel));
WorldBuilder.AddEngine(new UITextSpawner());
WorldBuilder.AddOrderedRenderer(new Texture2DRenderer(SpriteBatch));
WorldBuilder.AddGeneralRenderer(new CenterLineRenderer(SpriteBatch, WhitePixel), 0);
WorldBuilder.AddGeneralRenderer(new ScoreRenderer(SpriteBatch, ScoreFont), 0);
WorldBuilder.AddGeneralRenderer(new TitleRenderer(SpriteBatch, ScoreFont, InstructionFont), 0);
WorldBuilder.AddGeneralRenderer(new UITextRenderer(SpriteBatch), 0);
var playAreaEntity = WorldBuilder.CreateEntity();
WorldBuilder.SetComponent(playAreaEntity, new PlayAreaComponent(PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT));
var gameStateEntity = WorldBuilder.CreateEntity();
WorldBuilder.SetComponent(gameStateEntity, new GameStateComponent(GameState.Title));
WorldBuilder.SetComponent(gameStateEntity, new GameStateComponent(GameState.Init));
var ballParametersEntity = WorldBuilder.CreateEntity();
WorldBuilder.SetComponent(ballParametersEntity, new BallParametersComponent(500, 0.5));
WorldBuilder.SendMessage(new ChangeGameStateMessage(GameState.Title));
World = WorldBuilder.Build();
}

View File

@ -1,47 +0,0 @@
using Encompass;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using PongFE.Components;
using PongFE.Enums;
using SpriteFontPlus;
namespace PongFE.Renderers
{
public class TitleRenderer : GeneralRenderer
{
private SpriteBatch SpriteBatch { get; }
private DynamicSpriteFont TitleFont { get; }
private DynamicSpriteFont InstructionFont { get; }
public TitleRenderer(SpriteBatch spriteBatch, DynamicSpriteFont titleFont, DynamicSpriteFont instructionFont)
{
SpriteBatch = spriteBatch;
TitleFont = titleFont;
InstructionFont = instructionFont;
}
public override void Render()
{
ref readonly var gameStateComponent = ref ReadComponent<GameStateComponent>();
ref readonly var playAreaComponent = ref ReadComponent<PlayAreaComponent>();
if (gameStateComponent.GameState == GameState.Title)
{
var titleDimensions = TitleFont.MeasureString("PongFE");
var titlePosition = new Vector2(
(playAreaComponent.Width - titleDimensions.X) / 2,
(playAreaComponent.Height - titleDimensions.Y) / 4
);
var instructionDimensions = InstructionFont.MeasureString("Press Enter to begin");
var instructionPosition = new Vector2(
(playAreaComponent.Width - instructionDimensions.X) / 2,
playAreaComponent.Height * 2 / 3
);
SpriteBatch.DrawString(TitleFont, "PongFE", titlePosition, Color.White);
SpriteBatch.DrawString(InstructionFont, "Press Enter to begin", instructionPosition, Color.White);
}
}
}
}

View File

@ -0,0 +1,35 @@
using Encompass;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using PongFE.Components;
using PongFE.Extensions;
using SpriteFontPlus;
namespace PongFE.Renderers
{
public class UITextRenderer : GeneralRenderer
{
private SpriteBatch SpriteBatch { get; }
public UITextRenderer(SpriteBatch spriteBatch)
{
SpriteBatch = spriteBatch;
}
public override void Render()
{
foreach (ref readonly var entity in ReadEntities<UITextComponent>())
{
ref readonly var uiTextComponent = ref GetComponent<UITextComponent>(entity);
ref readonly var positionComponent = ref GetComponent<PositionComponent>(entity);
SpriteBatch.DrawString(
uiTextComponent.Font,
uiTextComponent.Text,
positionComponent.Position.ToXNAVector(),
Color.White
);
}
}
}
}

@ -1 +1 @@
Subproject commit 59014c7a9e7c3c90b902c8025d907a33a0ffb75c
Subproject commit b4a5a4c66adb1fe268954acdfb6839bd21189b1d