Skip to content

Commit

Permalink
Office hours (#75)
Browse files Browse the repository at this point in the history
* Adds items

* new message type:

* Adds multiplayer anchor point updating

* Updates collision detection to be clearer

* Updates collision and game models

* Adds README
  • Loading branch information
MaxEdwards20 authored Apr 11, 2024
1 parent ecd4301 commit 4b45e16
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 111 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone

## In Progress

- [ ] Max: Sync the anchor points across clients.

## Items to Develop

- [ ] Fix the ability to exit the game and come back in. Dean talked about what we need to do in Teams.
Expand All @@ -24,6 +22,7 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone

## Done

- [x] Max: Sync the anchor points across clients.
- [x] Max: Collision message and its wiring for the client to then render its own effects.
- [x] Max: 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.
- [x] Max: On collision, sandworm breaks apart and is available as food for other snakes
Expand Down Expand Up @@ -54,3 +53,9 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone
- Use netcat on Mac or Linux to see whether the server is available.
`nc -vz 192.168.4.20 3000`
- Turn off your firewall. On macOS that is found in System Preferences > Security & Privacy > Firewall

### Client Prediction and Server Reconcilition

- When input occurs the client does that and send it to the server
- The server receives the client input and upates the game state
- Server Reconcilition happens on the client side for the items that have not been acknowledged by the server
23 changes: 21 additions & 2 deletions src/Client/GameModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Client.Components;
Expand Down Expand Up @@ -84,6 +85,7 @@ public bool initialize(ContentManager contentManager, Controls controls, Graphic
m_systemNetwork.registerNewEntityHandler(handleNewEntity);
m_systemNetwork.registerRemoveEntityHandler(handleRemoveEntity);
m_systemNetwork.registerCollisionHandler(handleCollision);
m_systemNetwork.registerNewAnchorPointHandler(handleNewAnchorPoint);
m_controls = controls;

m_systemKeyboardInput = new Systems.KeyboardInput(new List<Tuple<Shared.Components.Input.Type, Keys>>
Expand Down Expand Up @@ -240,11 +242,29 @@ private void handleRemoveEntity(Shared.Messages.RemoveEntity message)
removeEntity(message.id);
}


private void handleNewAnchorPoint(Shared.Messages.NewAnchorPoint message)
{
if (m_entities.ContainsKey(message.wormHeadId) && !m_entities.Values.ToArray()[0].id.Equals(message.wormHeadId))
{
var wormHead = m_entities[message.wormHeadId];
var worm = WormMovement.getWormFromHead(wormHead, m_entities);
foreach (var segment in worm.Skip(1))
{
segment.get<AnchorQueue>().m_anchorPositions.Enqueue( new Position(message.position, message.orientation));
}
}
}

private void handleCollision(Shared.Messages.Collision message)
{
// We need to know if the collision occurred on the screen of the client
if (m_entities.ContainsKey(message.entity1Id) && m_entities.ContainsKey(message.entity2Id))
{
// Check where our current client is and see if the collision is relevant
var player = m_entities.Values.ToArray()[0];
// TODO: Implement the check for the client's screen here. If it is in the screen then we will handle the collision


if (message.collisionType == Collision.CollisionType.HeadToSpice)
{
Expand All @@ -264,8 +284,7 @@ private void handleCollision(Shared.Messages.Collision message)
// Check the position
var position = message.position;

// Check where our current client is and see if the collision is relevant
// TODO: Implement this


// If it is relevant, we either send a boolean flag to the particle system and collision handling or we call those here.

Expand Down
1 change: 1 addition & 0 deletions src/Client/MessageQueueClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public bool initialize(string address, ushort port)
m_messageCommand[Shared.Messages.Type.UpdateEntity] = () => { return new UpdateEntity(); };
m_messageCommand[Shared.Messages.Type.RemoveEntity] = () => { return new RemoveEntity(); };
m_messageCommand[Shared.Messages.Type.Collision] = () => { return new Collision(); };
m_messageCommand[Shared.Messages.Type.NewAnchorPoint] = () => { return new NewAnchorPoint(); };

try
{
Expand Down
22 changes: 12 additions & 10 deletions src/Client/Systems/Network.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ public class Network : Shared.Systems.System
public delegate void RemoveEntityHandler(RemoveEntity message);
public delegate void NewEntityHandler(NewEntity message);
public delegate void CollisionHandler(Collision message);
public delegate void NewAnchorPointHandler(NewAnchorPoint message);

private Dictionary<Shared.Messages.Type, Handler> m_commandMap = new Dictionary<Shared.Messages.Type, Handler>();
private RemoveEntityHandler m_removeEntityHandler;
private NewEntityHandler m_newEntityHandler;
private CollisionHandler m_collisionHandler;
private NewAnchorPointHandler m_newAnchorPointHandler;
private uint m_lastMessageId = 0;
private HashSet<uint> m_updatedEntities = new HashSet<uint>();

Expand Down Expand Up @@ -61,6 +63,11 @@ public Network(String playerName) :
m_collisionHandler((Collision)message);
});

registerHandler(Shared.Messages.Type.NewAnchorPoint, (TimeSpan elapsedTime, Message message) =>
{
m_newAnchorPointHandler((NewAnchorPoint)message);
});

}

// Have to implement this because it is abstract in the base class
Expand Down Expand Up @@ -160,6 +167,11 @@ public void registerCollisionHandler(CollisionHandler handler)
{
m_collisionHandler = handler;
}

public void registerNewAnchorPointHandler(NewAnchorPointHandler handler)
{
m_newAnchorPointHandler = handler;
}

/// <summary>
/// Handler for the ConnectAck message. This records the clientId
Expand Down Expand Up @@ -222,15 +234,5 @@ private void handleUpdateEntity(TimeSpan elapsedTime, UpdateEntity message)
}

}

private void updateQueues(Entity head)
{
// var worm = WormMovement.getWormFromHead(head, m_entities);
// var headPos = head.get<Position>();
// foreach (var segment in worm.Skip(1))
// {
// segment.get<AnchorQueue>().m_anchorPositions.Enqueue(headPos);
// }
}
}
}
10 changes: 5 additions & 5 deletions src/Server/GameModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class GameModel
private readonly GrowthHandler m_SystemGrowthHandler = new();
private readonly Network m_systemNetwork = new();
private readonly SpiceGen m_systemSpiceGen = new(mapSize - 200, 300);
private const int wallSize = 100;
private const int mapSize = 3000;

/// <summary>
Expand Down Expand Up @@ -145,7 +146,6 @@ private void generateWalls()
{
// We want to create wall entities around the entire map. 5000x5000 is the size of the map
// We'll create a wall every 100 units
var wallSize = 100;
for (int i = 0; i < mapSize / 100; i++)
{
// Top wall
Expand Down Expand Up @@ -178,6 +178,7 @@ private void createNewWorm(int clientId, string name)
// Create the head
Entity segment = WormHead.create(headStartLocation, name);
segment.add(new Invincible());
m_clientToEntityId[clientId] = segment.id; // Associate the client with the head of the worm

// Create X number of body segments
var parent = segment;
Expand All @@ -192,13 +193,11 @@ private void createNewWorm(int clientId, string name)
}
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);
m_clientToEntityId[clientId] = segment.id;
MessageQueueServer.instance.sendMessage(clientId, new NewEntity(segment));

// Step 4: Let all other clients know about this new player
Expand Down Expand Up @@ -235,8 +234,9 @@ 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();
var lowerBound = (int)(300);
var upperBound = (int)(mapSize - 300);
var offset = wallSize * 5;
var lowerBound = offset;
var upperBound = mapSize - offset;
return new Vector2(random.Next(lowerBound, upperBound), random.Next(lowerBound, upperBound));
}
}
Expand Down
Loading

0 comments on commit 4b45e16

Please sign in to comment.