Skip to content

Commit

Permalink
Worm movement system (#47)
Browse files Browse the repository at this point in the history
* Fixes crash

* Adds worm movement system

* render

* Adds movement as we go

* Snake is moving, but just the head.

* updates comments:

* A

* updates worm to all be mvoing

* updates readme

* Adds queues for movement tracking

* Snake movement is close. Now we need to adjust for the offset

* Adds note for what to do next on movement

* Keeps them separated at least

* a
  • Loading branch information
MaxEdwards20 authored Apr 8, 2024
1 parent 850619c commit 6fe4642
Show file tree
Hide file tree
Showing 19 changed files with 232 additions and 162 deletions.
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 @@ -137,61 +137,69 @@ private void handleJoin(int clientId, Shared.Messages.Message message)

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 Down Expand Up @@ -99,23 +100,17 @@ private void registerHandler(Shared.Messages.Type type, Handler handler)
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

0 comments on commit 6fe4642

Please sign in to comment.