Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Worm eating #69

Merged
merged 6 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,29 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone
## In Progress

- [ ] Satchel: Pick head, body, and tail texture for the sandworm
- [ ] Caden: Spice generation when we spawn
- [ ] Caden: Periodic spice generation throughout the game
- [ ] Max: Grow the worm on eating food.
- [ ] Satchel: Loading Screen while joining game
- [ ] Max: On collision, sandworm breaks apart and is available as food for other snakes

## Items to Develop

- [ ] Fix the ability to exit the game and come back in. Dean talked about what we need to do in Teams.
- [ ] 3 different animated sprites for the spice - Satchel
- [ ] Sound effects on the death of worm and when food is eaten - Satchel
- [ ] On collision, sandworm breaks apart and is available as food for other snakes
- [ ] Record players score, kills and highest position. Probably can be added to the `GameScores` object.
- [ ] Game over screen with score, kills, and highest position achieved. This is an overlay on the multiplayer game behind it.
- [ ] Particle system for the death of a sandworm
- [ ] Leaderboard to display top 5 players and client's score in corner of game.
- [ ] The new player should join as an invincible entity. Add this functionality and a system to update it after 3 seconds to be removed from the entity.
- [ ] Add a player status in leaderboard to show whether the player is currently invincible.
- [ ] Port Particle System - Satchel
- [ ] Connection View sprite font or visual indicator.
- [ ] Connection View sprite font or visual indicator.
- [ ] Message receiver for the client about collisions that can be used to call the particle system and sound effects.

## Done

- [x] Max: Grow the worm on eating food.
- [x] Satchel: Loading Screen while joining game
- [x] Caden: Spice generation when we spawn
- [x] Caden: Periodic spice generation throughout the game
- [x] Max: Collision Detection system.
- [x] Max: Keyboard support for left, right, up, down, diagonal up left and diagonal up right. Also add these to the wormMovement system.
- [x] Max: Snake Movement with the queue system
Expand All @@ -44,7 +45,7 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone
- [x] Caden: Map generation
- [x] Satchel: How to Play View
- [x] Satchel: Create Name View
- [x] Satchel: Create Connection View
- [x] Satchel: Create Connection View

## Debugging

Expand Down
10 changes: 5 additions & 5 deletions src/Client/GameModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class GameModel
private Systems.Interpolation m_systemInterpolation;
private Systems.Renderer m_renderer;
private Shared.Systems.WormMovement m_systemWormMovement;
private Shared.Systems.CollisionHandler m_systemCollisionHandler;
private Shared.Systems.GrowthHandler m_systemGrowthHandler;
private Controls m_controls;
private GraphicsDeviceManager m_graphics;
private SpriteFont m_font;
Expand All @@ -43,7 +43,7 @@ public void update(TimeSpan elapsedTime)
{
m_systemNetwork.update(elapsedTime, MessageQueueClient.instance.getMessages());
m_systemKeyboardInput.update(elapsedTime);
m_systemCollisionHandler.update(elapsedTime);
m_systemGrowthHandler.update(elapsedTime);
m_systemWormMovement.update(elapsedTime);
m_systemInterpolation.update(elapsedTime);
m_systemCamera.update(elapsedTime);
Expand Down Expand Up @@ -74,7 +74,7 @@ public bool initialize(ContentManager contentManager, Controls controls, Graphic
m_systemCamera = new Systems.Camera(new Vector2(graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight));

m_renderer = new Systems.Renderer(m_systemCamera, graphics, m_font, m_sand);
m_systemCollisionHandler = new Shared.Systems.CollisionHandler();
m_systemGrowthHandler = new Shared.Systems.GrowthHandler();
m_systemWormMovement = new Shared.Systems.WormMovement();
m_systemNetwork = new Systems.Network(m_playerName);

Expand Down Expand Up @@ -186,7 +186,7 @@ private void addEntity(Entity entity)
// NOTE: Update the systems we use here
m_entities[entity.id] = entity;
m_systemKeyboardInput.add(entity);
m_systemCollisionHandler.add(entity);
m_systemGrowthHandler.add(entity);
m_systemWormMovement.add(entity);
m_renderer.add(entity);
m_systemNetwork.add(entity);
Expand All @@ -203,7 +203,7 @@ private void removeEntity(uint id)
// NOTE: Update the systems we use here
m_entities.Remove(id);
m_systemKeyboardInput.remove(id);
m_systemCollisionHandler.remove(id);
m_systemGrowthHandler.remove(id);
m_systemWormMovement.remove(id);
m_systemNetwork.remove(id);
m_renderer.remove(id);
Expand Down
17 changes: 9 additions & 8 deletions src/Client/Menu/ChooseNameView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,16 @@ public override void render(GameTime gameTime)
m_spriteBatch.Begin();

// Calculate the center position for "Enter Your Name" text
string enterNameText = $"Enter Your Name: [ Using Keyboard ] \n {playerName}";
string enterNameText = $"Enter Your Name: \n {playerName}";
Vector2 textSize = font.MeasureString(enterNameText);
Vector2 textPosition = new Vector2(
(m_graphics.PreferredBackBufferWidth - textSize.X) / 2,
(m_graphics.PreferredBackBufferHeight - textSize.Y) / 2);
(m_graphics.PreferredBackBufferWidth) / 2,
(m_graphics.PreferredBackBufferHeight) / 2);

// Draw "Enter Your Name" text

m_spriteBatch.DrawString(font, enterNameText, textPosition, Colors.displayColor);
Drawing.CustomDrawString(font, enterNameText, textPosition, Colors.displayColor, m_spriteBatch, true, true, scale:.8f);
// m_spriteBatch.DrawString(font, enterNameText, textPosition, Colors.displayColor);


// Draw "Press Enter to proceed" below the name text if a name has been entered
Expand All @@ -91,11 +92,11 @@ public override void render(GameTime gameTime)
string proceedText = "Press Enter to proceed";
Vector2 proceedTextSize = font.MeasureString(proceedText);
Vector2 proceedTextPosition = new Vector2(
(m_graphics.PreferredBackBufferWidth - proceedTextSize.X) / 2,
textPosition.Y + textSize.Y + 20); // 20 pixels below the name text
textPosition.X,
textPosition.Y + 90); // 20 pixels below the name text


m_spriteBatch.DrawString(font, proceedText, proceedTextPosition, Colors.displayColor);
Drawing.CustomDrawString(font, proceedText, proceedTextPosition, Colors.displayColor, m_spriteBatch, true, false, scale:.6f);
// m_spriteBatch.DrawString(font, proceedText, proceedTextPosition, Colors.displayColor);
}

m_spriteBatch.End();
Expand Down
4 changes: 2 additions & 2 deletions src/Client/Menu/ConnectingView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class ConnectingView : GameStateView
private SpriteFont font;
private string connectingMessage = "Connecting to Server";
private bool isConnected = false;
private double elapsedTimeSinceLastAttempt = 0;
private double elapsedTimeSinceLastAttempt = 1500; // Start at 1500 so we only need to wait 500ms before first attempt
private const double attemptInterval = 2000; // Attempt to connect every 2 seconds
private double periodUpdateTime = 500; // Update period for visual

Expand Down Expand Up @@ -51,7 +51,7 @@ public override void render(GameTime gameTime)
m_spriteBatch.Begin();
Vector2 position = new Vector2(m_graphics.PreferredBackBufferWidth / 2, m_graphics.PreferredBackBufferHeight / 2);
Vector2 origin = font.MeasureString(connectingMessage) / 2;
m_spriteBatch.DrawString(font, connectingMessage, position - origin, Colors.displayColor);
Drawing.CustomDrawString(font, connectingMessage, position, Colors.displayColor, m_spriteBatch, true, true, true);
m_spriteBatch.End();
}

Expand Down
41 changes: 3 additions & 38 deletions src/Client/Menu/GamePlayView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ namespace Client.Menu
public class GamePlayView : GameStateView
{
private ContentManager m_contentManager;
private bool m_isSetup;
private bool m_isKeyboardRegistered;
private MenuStateEnum m_newState;
private GameModel m_gameModel;
private TimeSpan m_connectToServerTime = TimeSpan.Zero;
private Controls m_controls;
private StringBuilder playerName;

Expand All @@ -34,7 +32,6 @@ public override void initialize()
{
m_gameModel = new GameModel(playerName);
m_gameModel.initialize(m_contentManager, m_controls, m_graphics);
m_isSetup = false;
m_isKeyboardRegistered = false;
m_newState = MenuStateEnum.GamePlay;
}
Expand All @@ -50,38 +47,12 @@ public override MenuStateEnum processInput(GameTime gameTime)
RegisterCommands();
m_isKeyboardRegistered = true;
}

//if (!m_isSetup)
//{
// setup(gameTime);
//}


MenuKeyboardInput.Update(gameTime); // essentially just checking for whether we have escaped to the main menu
if (m_newState != MenuStateEnum.GamePlay){return handleSwitchToMainMenu();}
return MenuStateEnum.GamePlay;
}

//private void setup(GameTime gameTime)
//{
// if (m_connectToServerTime == TimeSpan.Zero)
// {
// m_connectToServerTime = TimeSpan.FromSeconds(2); // Try to connect every 2 seconds
// var res = connectToServer();
// if (res)
// {
// m_isSetup = true;
// }
// }
// else
// {
// m_connectToServerTime -= gameTime.ElapsedGameTime;
// if (m_connectToServerTime <= TimeSpan.Zero)
// {
// m_connectToServerTime = TimeSpan.Zero;
// }
// }
//}


public override void update(GameTime gameTime)
{
m_gameModel.update(gameTime.ElapsedGameTime);
Expand All @@ -97,12 +68,7 @@ public override void RegisterCommands()
{
MenuKeyboardInput.registerCommand(MenuKeyboardInput.Escape, true, escape);
}

//private bool connectToServer()
//{
// return MessageQueueClient.instance.initialize("localhost", 3000);
//}


private void escape(GameTime gameTime, float scale)
{
m_newState = MenuStateEnum.MainMenu;
Expand All @@ -111,7 +77,6 @@ private void escape(GameTime gameTime, float scale)
private MenuStateEnum handleSwitchToMainMenu()
{
MenuKeyboardInput.ClearAllCommands();
m_isSetup = false;
var temp = m_newState;
m_newState = MenuStateEnum.GamePlay;
try
Expand Down
41 changes: 29 additions & 12 deletions src/Client/Menu/HowToPlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ namespace Client.Menu
public class HowToPlayView : GameStateView
{
private SpriteFont font;

private string howToPlayMessage =
"Control a snake to eat food and grow. Use arrow keys for movement. \n" +
"(Custom controls in Main Menu) \n" +
"Avoid wall and other players!. How long can you grow? Try to beat the high score!";
"Control a worm to eat spice and grow.\nUse configured keys for movement." +
"\nAvoid walls and other players!\nTry to beat the high score!" +
"\n(Custom controls in Main Menu)\n";
private string titleMessage = "HOW TO PLAY";
private string continueMessage = "Press Enter to continue";
private KeyboardState oldState;
Expand All @@ -34,6 +35,12 @@ public override MenuStateEnum processInput(GameTime gameTime)
KeyboardState newState = Keyboard.GetState();

timeSinceLastEnterPress += gameTime.ElapsedGameTime.TotalMilliseconds;

// Check for Escape key press to return to MainMenu
if (newState.IsKeyDown(Keys.Escape))
{
return MenuStateEnum.Controls; // Immediately return to MainMenu when Escape is pressed
}

// Proceed to the next game state if the player presses Enter and enough time has passed since the last Enter press
if (newState.IsKeyDown(Keys.Enter) && oldState.IsKeyUp(Keys.Enter) && timeSinceLastEnterPress >= enterKeyDelay)
Expand All @@ -60,30 +67,40 @@ public override void render(GameTime gameTime)
m_spriteBatch.Begin();

// Define text scale
Vector2 textScale = new Vector2(0.5f, 0.5f);
Vector2 textScale = new Vector2(0.5f, 0.5f);

// Background Rectangle
var recPosition = new Vector2(m_graphics.PreferredBackBufferWidth / 5 - 20,
m_graphics.PreferredBackBufferHeight / 4 - 50);
Drawing.DrawBlurredRectangle(m_spriteBatch, recPosition, new Vector2(700, 400), 5, 0.6f);


// Title
Vector2 titlePosition = new Vector2(m_graphics.PreferredBackBufferWidth / 2, m_graphics.PreferredBackBufferHeight / 4);
Vector2 titleOrigin = font.MeasureString(titleMessage) / 2;
m_spriteBatch.DrawString(font, titleMessage, titlePosition - (titleOrigin * textScale), Colors.displayColor, 0f, Vector2.Zero, textScale, SpriteEffects.None, 0f);


Vector2 titleOrigin = font.MeasureString(titleMessage) / 2;
Drawing.CustomDrawString(font, titleMessage, titlePosition, Colors.displayColor, m_spriteBatch, true, false, scale: 1.0f);
// m_spriteBatch.DrawString(font, titleMessage, titlePosition - (titleOrigin * textScale), Colors.displayColor, 0f, Vector2.Zero, textScale, SpriteEffects.None, 0f);

// How to Play Instructions
Vector2 instructionsPosition = new Vector2(m_graphics.PreferredBackBufferWidth / 2, m_graphics.PreferredBackBufferHeight / 2.5f);
Vector2 instructionsPosition = new Vector2(m_graphics.PreferredBackBufferWidth / 5, m_graphics.PreferredBackBufferHeight / 2.5f);
string[] lines = howToPlayMessage.Split('\n');
foreach (string line in lines)
{
Vector2 lineSize = font.MeasureString(line) * textScale;

m_spriteBatch.DrawString(font, line, instructionsPosition - new Vector2(lineSize.X / 2, 0), Colors.displayColor, 0f, Vector2.Zero, textScale, SpriteEffects.None, 0f);
instructionsPosition.Y += lineSize.Y + 5; // Adjust spacing between lines if necessary, taking scale into account
Drawing.CustomDrawString(font, line, instructionsPosition,
Colors.displayColor, m_spriteBatch, false, false, scale: 0.75f);
// m_spriteBatch.DrawString(font, line, instructionsPosition - new Vector2(lineSize.X / 2, 0), Colors.displayColor, 0f, Vector2.Zero, textScale, SpriteEffects.None, 0f);
instructionsPosition.Y += lineSize.Y + 20; // Adjust spacing between lines if necessary, taking scale into account
}

// Continue Prompt
Vector2 continuePosition = new Vector2(m_graphics.PreferredBackBufferWidth / 2, (m_graphics.PreferredBackBufferHeight / 4) * 3);
Vector2 continuePosition = new Vector2(m_graphics.PreferredBackBufferWidth / 2, (m_graphics.PreferredBackBufferHeight / 4) * 3 + 50);
Vector2 continueOrigin = font.MeasureString(continueMessage) / 2;

m_spriteBatch.DrawString(font, continueMessage, continuePosition - (continueOrigin * textScale), Colors.displayColor, 0f, Vector2.Zero, textScale, SpriteEffects.None, 0f);
Drawing.CustomDrawString( font, continueMessage, continuePosition, Colors.displayColor, m_spriteBatch, true, true, scale: 1f);
// m_spriteBatch.DrawString(font, continueMessage, continuePosition - (continueOrigin * textScale), Colors.displayColor, 0f, Vector2.Zero, textScale, SpriteEffects.None, 0f);


m_spriteBatch.End();
Expand Down
18 changes: 16 additions & 2 deletions src/Client/Systems/Network.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ private void handleConnectAck(TimeSpan elapsedTime, ConnectAck message, string n
/// actually has the entity, and if it does, updates the components
/// that are in common between the message and the entity.
/// </summary>
private void handleUpdateEntity(TimeSpan elapsedTime, UpdateEntity message)
{
private void handleUpdateEntity(TimeSpan elapsedTime, UpdateEntity message)
{
if (m_entities.ContainsKey(message.id))
{
var entity = m_entities[message.id];
Expand Down Expand Up @@ -191,7 +191,21 @@ private void handleUpdateEntity(TimeSpan elapsedTime, UpdateEntity message)
{
entity.get<SpicePower>().setPower(message.spicePower);
}
if (entity.contains<ParentId>() && message.hasParent)
{
entity.remove<ParentId>();
entity.add(new ParentId(message.parentId));
// NOTE: This would trigger an update of everyone's anchor points

}
if (entity.contains<ChildId>() && message.hasChild)
{
entity.remove<ChildId>();
entity.add(new ChildId(message.childId));
// NOTE: This would trigger an update of everyone's anchor points
}
}

}
}
}
25 changes: 12 additions & 13 deletions src/Client/Systems/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Client.Components;
using Client.Menu;
using System.Runtime.CompilerServices;
using Shared.Systems;

namespace Client.Systems;

Expand Down Expand Up @@ -67,31 +68,29 @@ public void render(TimeSpan elapsedTime, SpriteBatch spriteBatch)
);

var heads = new List<Entity>();
var bodies = new List<Entity>();
var tails = new List<Entity>();
var others = new List<Entity>();

foreach (Entity entity in m_entities.Values)
{
if (entity.contains<Head>())
heads.Add(entity);
else if (entity.contains<Tail>())
tails.Add(entity);
else if (entity.contains<Worm>())
bodies.Add(entity);
continue;
else
others.Add(entity);
}

foreach (Entity entity in others)
renderEntity(elapsedTime, spriteBatch, entity);
foreach (Entity entity in tails)
renderEntity(elapsedTime, spriteBatch, entity);
foreach (Entity entity in bodies)
renderEntity(elapsedTime, spriteBatch, entity);
foreach (Entity entity in heads)
renderEntity(elapsedTime, spriteBatch, entity);

// We want to sort bodies by their position in the worm

foreach (Entity head in heads)
{
var worm = WormMovement.getWormFromHead(head, m_entities);
for (int i = worm.Count - 1; i >= 0; i--)
renderEntity(elapsedTime, spriteBatch, worm[i]);
}
spriteBatch.End();
}

Expand Down
Loading
Loading