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 movement system #47

Merged
merged 21 commits into from
Apr 8, 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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone
- [ ] Satchel: Keyboard vs. Mouse input menu screen - Satchel
- [ ] Caden: Map generation
- [ ] Max: Snake Movement with the queue system

- [ ] Caden: Spice generation when we spawn
- [ ] Caden: Periodic spice generation throughout the game

Expand Down
15 changes: 7 additions & 8 deletions src/Client/ClientMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class ClientMain : Game
private Texture2D m_background;
private GameModel m_gameModel;
private Controls m_controls;
private ControlsPersistence _mControlsPersistence;
private ControlsPersistence m_ControlsPersistence;

public ClientMain()
{
Expand All @@ -38,22 +38,21 @@ public ClientMain()
IsMouseVisible = true;
m_gameModel = new GameModel();
m_controls = new Controls();
_mControlsPersistence = new ControlsPersistence();

m_ControlsPersistence = new ControlsPersistence();
}

protected override void Initialize()
{
// For Graders: You can change the resolution here
// m_graphics.PreferredBackBufferWidth = 1920;
// m_graphics.PreferredBackBufferHeight = 1080;
m_graphics.PreferredBackBufferWidth = 1000;
m_graphics.PreferredBackBufferHeight = 750;
m_graphics.PreferredBackBufferWidth = 1920;
m_graphics.PreferredBackBufferHeight = 1080;
// m_graphics.PreferredBackBufferWidth = 1000;
// m_graphics.PreferredBackBufferHeight = 750;
m_graphics.ApplyChanges();

// Load the controls
// We pass in our own controls so we always have them as a default if they were not saved
_mControlsPersistence.LoadControls(m_controls);
m_ControlsPersistence.LoadControls(m_controls);

// Create all the game states here
m_states = new Dictionary<MenuStateEnum, IGameState>
Expand Down
24 changes: 18 additions & 6 deletions src/Client/Content/Content.mgcb
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
/processorParam:TextureFormat=Color
/build:Textures/body.png

#begin Textures/head.png
#begin Textures/circleBody.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
Expand All @@ -97,9 +97,21 @@
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:Textures/head.png
/build:Textures/circleBody.png

#begin Textures/circleTail.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:Textures/circleTail.png

#begin Textures/playerShip1_blue.png
#begin Textures/circleHead.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
Expand All @@ -109,9 +121,9 @@
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:Textures/playerShip1_blue.png
/build:Textures/circleHead.png

#begin Textures/playerShip1_red.png
#begin Textures/head.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
Expand All @@ -121,7 +133,7 @@
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:Textures/playerShip1_red.png
/build:Textures/head.png

#begin Textures/SandTile.png
/importer:TextureImporter
Expand Down
Binary file added src/Client/Content/Textures/circleBody.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Client/Content/Textures/circleHead.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Client/Content/Textures/circleTail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/Client/Content/Textures/playerShip1_blue.png
Binary file not shown.
Binary file removed src/Client/Content/Textures/playerShip1_red.png
Binary file not shown.
2 changes: 2 additions & 0 deletions src/Client/GameModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public bool initialize(ContentManager contentManager, Controls controls, Graphic
m_entities = new Dictionary<uint, Entity>();
m_systemInterpolation = new Systems.Interpolation();
m_systemCamera = new Systems.Camera(new Vector2(graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight));

m_renderer = new Systems.Renderer(m_systemCamera, graphics, m_font, m_sand);
m_systemWormMovement = new Shared.Systems.WormMovement();
m_systemNetwork = new Systems.Network();
Expand Down Expand Up @@ -145,6 +146,7 @@ private Entity createEntity(Shared.Messages.NewEntity message)
if (message.hasWorm)
{
entity.add(new Worm());
entity.add(new AnchorQueue()); // We implicitly need this because every worm part has it
}

if (message.hasName)
Expand Down
9 changes: 5 additions & 4 deletions src/Client/Systems/KeyboardInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using Shared.Components;
using Client.Components;
using Shared.Systems;

namespace Client.Systems
{
Expand All @@ -14,7 +15,7 @@ public class KeyboardInput : Shared.Systems.System
private KeyboardState m_statePrevious = Keyboard.GetState();
private Controls m_controls;

public KeyboardInput(List<Tuple<Shared.Components.Input.Type, Keys>> mapping, Controls controls) : base(typeof(Shared.Components.Input))
public KeyboardInput(List<Tuple<Shared.Components.Input.Type, Keys>> mapping, Controls controls) : base(typeof(Shared.Components.Worm))
{
m_controls = controls;
}
Expand All @@ -41,16 +42,16 @@ public override void update(TimeSpan elapsedTime)
continue;
}
var inputs = new List<Input.Type>();
var worm = WormMovement.getWormFromHead(entity.Value, m_entities);
if (keyNewlyPressed(m_controls.SnakeLeft.key))
{
inputs.Add(Input.Type.RotateLeft);
Shared.Systems.WormMovement.ninetyLeft(entity.Value, elapsedTime);

Shared.Systems.WormMovement.ninetyLeft(worm, elapsedTime);
}
if (keyNewlyPressed(m_controls.SnakeRight.key))
{
inputs.Add(Input.Type.RotateRight);
Shared.Systems.WormMovement.ninetyRight(entity.Value, elapsedTime);
Shared.Systems.WormMovement.ninetyRight(worm, elapsedTime);
}
if (inputs.Count > 0)
{
Expand Down
8 changes: 6 additions & 2 deletions src/Client/Systems/Network.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
using Shared.Messages;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Mail;
using System.Runtime.InteropServices;
using Shared.Systems;
using Input = Shared.Components.Input;

namespace Client.Systems
Expand Down Expand Up @@ -91,17 +93,19 @@ public void update(TimeSpan elapsedTime, Queue<Message> messages)
if (message.type == Shared.Messages.Type.Input)
{
var entity = m_entities[message.entityId];
Debug.Assert(entity.contains<Head>());
var worm = WormMovement.getWormFromHead(entity, m_entities);
if (m_updatedEntities.Contains(entity.id))
{
foreach (var input in message.inputs)
{
switch (input)
{
case Shared.Components.Input.Type.RotateLeft:
Shared.Systems.WormMovement.ninetyLeft(entity, message.elapsedTime);
Shared.Systems.WormMovement.ninetyLeft(worm, message.elapsedTime);
break;
case Shared.Components.Input.Type.RotateRight:
Shared.Systems.WormMovement.ninetyRight(entity, message.elapsedTime);
Shared.Systems.WormMovement.ninetyRight(worm, message.elapsedTime);
break;
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/Client/Systems/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class Renderer : Shared.Systems.System
private GraphicsDeviceManager m_graphics;
private SpriteFont m_font;
private Texture2D m_sand;

public Renderer(Systems.Camera camera, GraphicsDeviceManager graphics, SpriteFont font, Texture2D sand) :
base(
typeof(Position), typeof(Sprite)
Expand All @@ -45,6 +45,7 @@ public void render(TimeSpan elapsedTime, SpriteBatch spriteBatch)
matrix *= Matrix.CreateTranslation(new Vector3(offset, 0));
matrix *= Matrix.CreateScale(scaleX, scaleY, 1);


//spriteBatch.Begin();
spriteBatch.Begin(transformMatrix: matrix);

Expand All @@ -59,7 +60,7 @@ public void render(TimeSpan elapsedTime, SpriteBatch spriteBatch)
SpriteEffects.None,
0
);

var heads = new List<Entity>();
var bodies = new List<Entity>();
var tails = new List<Entity>();
Expand Down
78 changes: 43 additions & 35 deletions src/Server/GameModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
/// </summary>
public void update(TimeSpan elapsedTime)
{
m_systemNetwork.update(elapsedTime, MessageQueueServer.instance.getMessages());

Check warning on line 26 in src/Server/GameModel.cs

View workflow job for this annotation

GitHub Actions / buildProject

Possible null reference argument for parameter 'messages' in 'void Network.update(TimeSpan elapsedTime, Queue<Tuple<int, Message>> messages)'.
m_systemWormMovement.update(elapsedTime);
}

Expand Down Expand Up @@ -137,61 +137,69 @@

private void createNewWorm(int clientId, string name)
{
var startLocation = getLeastDenseStartLocation();
var headStartLocation = getLeastDenseStartLocation();
var segmentStartLocation = new Vector2(headStartLocation.X + 75, headStartLocation.Y);
var rotationRate = (float) Math.PI / 1000;
var moveRate = 0.1f;
var headSize = 100;
var bodySize = 80;

// Create the head
Entity player = WormHead.create(startLocation, 100, moveRate, rotationRate, name);

// Create a body segment
Entity segment = WormSegment.create( new Vector2(startLocation.X + 75, startLocation.Y - 20) , bodySize, moveRate, rotationRate, player.id);
player.add(new ChildId(segment.id));

// Create a tail segment
Entity tail = WormTail.create(new Vector2(startLocation.X + 130, startLocation.Y), bodySize, moveRate, rotationRate, segment.id);
segment.add(new ChildId(tail.id));

addEntity(player);
Entity segment = WormHead.create(headStartLocation, headSize, moveRate, rotationRate, name);
// Create X number of body segments
var parent = segment;
var numToCreate = 5;
for (int i = 0; i < numToCreate; i++)
{
segment = WormSegment.create(segmentStartLocation, bodySize, moveRate, rotationRate, parent.id);
if (i == numToCreate - 1)
{
segment = WormTail.create(segmentStartLocation, bodySize, moveRate, rotationRate, parent.id);
}
parent.add(new ChildId(segment.id));
addEntity(parent);
m_clientToEntityId[clientId] = parent.id;
MessageQueueServer.instance.sendMessage(clientId, new NewEntity(parent));
segmentStartLocation = new Vector2(segmentStartLocation.X + 50, segmentStartLocation.Y);
parent = segment;
}
addEntity(segment);
addEntity(tail);

m_clientToEntityId[clientId] = player.id;
m_clientToEntityId[clientId] = segment.id;
m_clientToEntityId[clientId] = tail.id;

// Step 3: Send the new player entity to the newly joined client
MessageQueueServer.instance.sendMessage(clientId, new NewEntity(player));
MessageQueueServer.instance.sendMessage(clientId, new NewEntity(segment));
MessageQueueServer.instance.sendMessage(clientId, new NewEntity(tail));

// Step 4: Let all other clients know about this new player entity
// Remove components not needed for "other" players
player.remove<Shared.Components.Input>();

// Now send the new entities to all other clients
Message playerMessage = new NewEntity(player);
Message segmentMessage = new NewEntity(segment);
Message tailMessage = new NewEntity(tail);
foreach (int otherId in m_clients)
// Step 4: Let all other clients know about this new player
while (segment != null)
{
if (otherId != clientId)
// Don't need to send the input component to other clients
if (segment.contains<Shared.Components.Input>())
{
segment.remove<Shared.Components.Input>();
}
// Send to each of the other clients
foreach (int otherId in m_clients)
{
if (otherId != clientId)
{
var message = new NewEntity(segment);
MessageQueueServer.instance.sendMessage(otherId, message);
}
}
// Move up the linked list
if (segment.contains<ParentId>())
{
MessageQueueServer.instance.sendMessage(otherId, playerMessage);
MessageQueueServer.instance.sendMessage(otherId, segmentMessage);
MessageQueueServer.instance.sendMessage(otherId, tailMessage);
segment = m_entities[segment.get<ParentId>().id];
}
else
{
segment = null;

Check warning on line 194 in src/Server/GameModel.cs

View workflow job for this annotation

GitHub Actions / buildProject

Converting null literal or possible null value to non-nullable type.
}
}

}

private Vector2 getLeastDenseStartLocation()
{
// We want to start the player in the least dense area of the screen
// For now, we'll just start them randomly generated location

Random random = new Random();
return new Vector2(random.Next(0, 800), random.Next(0, 600));
}
Expand Down
13 changes: 4 additions & 9 deletions src/Server/Systems/Network.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Shared.Entities;
using Shared.Messages;
using Shared.Systems;

namespace Server.Systems
{
Expand All @@ -20,7 +21,7 @@
/// Primary activity in the constructor is to setup the command map
/// that maps from message types to their handlers.
/// </summary>
public Network() :

Check warning on line 24 in src/Server/Systems/Network.cs

View workflow job for this annotation

GitHub Actions / buildProject

Non-nullable field 'm_joinHandler' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 24 in src/Server/Systems/Network.cs

View workflow job for this annotation

GitHub Actions / buildProject

Non-nullable field 'm_disconnectHandler' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
base(
typeof(Shared.Components.Movement),
typeof(Shared.Components.Position)
Expand Down Expand Up @@ -99,23 +100,17 @@
private void handleInput(Shared.Messages.Input message)
{
var entity = m_entities[message.entityId];
var worm = WormMovement.getWormFromHead(entity, m_entities);
foreach (var input in message.inputs)
{
switch (input)
{
// case Shared.Components.Input.Type.SnakeUp:
// var snake = Shared.Entities.Utility.thrust(entity, message.elapsedTime, m_entities);
// foreach (var part in snake)
// {
// m_reportThese.Add(part.id);
// }
// break;
case Shared.Components.Input.Type.RotateLeft:
Shared.Systems.WormMovement.ninetyLeft(entity, message.elapsedTime);
Shared.Systems.WormMovement.ninetyLeft(worm, message.elapsedTime);
m_reportThese.Add(message.entityId);
break;
case Shared.Components.Input.Type.RotateRight:
Shared.Systems.WormMovement.ninetyRight(entity, message.elapsedTime);
Shared.Systems.WormMovement.ninetyRight(worm, message.elapsedTime);
m_reportThese.Add(message.entityId);
break;
}
Expand Down
9 changes: 9 additions & 0 deletions src/Shared/Components/AnchorQueue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.Xna.Framework;

namespace Shared.Components;

public class AnchorQueue: Component
{
public Queue<Position> m_anchorPositions = new Queue<Position>();

}
3 changes: 1 addition & 2 deletions src/Shared/Entities/WormHead.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@

namespace Shared.Entities;

// This is the Player. We only move the head, all the other parts of the snake follow.
public class WormHead
{
public static Entity create(Vector2 position, float size, float moveRate, float rotateRate, string name)
{
Entity entity = new Entity();
entity.add(new Position(position));
entity.add(new Appearance("Textures/head"));
entity.add(new Appearance("Textures/circleHead"));
entity.add(new Size(new Vector2(size, size)));
entity.add(new Movement(moveRate, rotateRate));
entity.add(new Collision());
Expand Down
Loading
Loading