diff --git a/README.md b/README.md index af8b099..4db922e 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/Client/ClientMain.cs b/src/Client/ClientMain.cs index 4584040..d655910 100644 --- a/src/Client/ClientMain.cs +++ b/src/Client/ClientMain.cs @@ -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() { @@ -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 diff --git a/src/Client/Content/Content.mgcb b/src/Client/Content/Content.mgcb index 9b70229..964a796 100644 --- a/src/Client/Content/Content.mgcb +++ b/src/Client/Content/Content.mgcb @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/src/Client/Content/Textures/circleBody.png b/src/Client/Content/Textures/circleBody.png new file mode 100644 index 0000000..8cdbdb1 Binary files /dev/null and b/src/Client/Content/Textures/circleBody.png differ diff --git a/src/Client/Content/Textures/circleHead.png b/src/Client/Content/Textures/circleHead.png new file mode 100644 index 0000000..62a65ad Binary files /dev/null and b/src/Client/Content/Textures/circleHead.png differ diff --git a/src/Client/Content/Textures/circleTail.png b/src/Client/Content/Textures/circleTail.png new file mode 100644 index 0000000..9c53501 Binary files /dev/null and b/src/Client/Content/Textures/circleTail.png differ diff --git a/src/Client/Content/Textures/playerShip1_blue.png b/src/Client/Content/Textures/playerShip1_blue.png deleted file mode 100644 index 173f044..0000000 Binary files a/src/Client/Content/Textures/playerShip1_blue.png and /dev/null differ diff --git a/src/Client/Content/Textures/playerShip1_red.png b/src/Client/Content/Textures/playerShip1_red.png deleted file mode 100644 index 6b67bf3..0000000 Binary files a/src/Client/Content/Textures/playerShip1_red.png and /dev/null differ diff --git a/src/Client/GameModel.cs b/src/Client/GameModel.cs index 3bb1344..97e3364 100644 --- a/src/Client/GameModel.cs +++ b/src/Client/GameModel.cs @@ -63,6 +63,7 @@ public bool initialize(ContentManager contentManager, Controls controls, Graphic m_entities = new Dictionary(); 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(); @@ -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) diff --git a/src/Client/Systems/KeyboardInput.cs b/src/Client/Systems/KeyboardInput.cs index cc22dea..74cc104 100644 --- a/src/Client/Systems/KeyboardInput.cs +++ b/src/Client/Systems/KeyboardInput.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Shared.Components; using Client.Components; +using Shared.Systems; namespace Client.Systems { @@ -14,7 +15,7 @@ public class KeyboardInput : Shared.Systems.System private KeyboardState m_statePrevious = Keyboard.GetState(); private Controls m_controls; - public KeyboardInput(List> mapping, Controls controls) : base(typeof(Shared.Components.Input)) + public KeyboardInput(List> mapping, Controls controls) : base(typeof(Shared.Components.Worm)) { m_controls = controls; } @@ -41,16 +42,16 @@ public override void update(TimeSpan elapsedTime) continue; } var inputs = new List(); + 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) { diff --git a/src/Client/Systems/Network.cs b/src/Client/Systems/Network.cs index 2d52f53..ae280c7 100644 --- a/src/Client/Systems/Network.cs +++ b/src/Client/Systems/Network.cs @@ -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 @@ -91,6 +93,8 @@ public void update(TimeSpan elapsedTime, Queue messages) if (message.type == Shared.Messages.Type.Input) { var entity = m_entities[message.entityId]; + Debug.Assert(entity.contains()); + var worm = WormMovement.getWormFromHead(entity, m_entities); if (m_updatedEntities.Contains(entity.id)) { foreach (var input in message.inputs) @@ -98,10 +102,10 @@ public void update(TimeSpan elapsedTime, Queue messages) 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; } } diff --git a/src/Client/Systems/Renderer.cs b/src/Client/Systems/Renderer.cs index a9604cd..aae7602 100644 --- a/src/Client/Systems/Renderer.cs +++ b/src/Client/Systems/Renderer.cs @@ -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) @@ -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); @@ -59,7 +60,7 @@ public void render(TimeSpan elapsedTime, SpriteBatch spriteBatch) SpriteEffects.None, 0 ); - + var heads = new List(); var bodies = new List(); var tails = new List(); diff --git a/src/Server/GameModel.cs b/src/Server/GameModel.cs index 52dbdb9..2ccfb2c 100644 --- a/src/Server/GameModel.cs +++ b/src/Server/GameModel.cs @@ -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(); - - // 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()) + { + segment.remove(); + } + // 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()) { - MessageQueueServer.instance.sendMessage(otherId, playerMessage); - MessageQueueServer.instance.sendMessage(otherId, segmentMessage); - MessageQueueServer.instance.sendMessage(otherId, tailMessage); + segment = m_entities[segment.get().id]; + } + else + { + segment = null; } } - } 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)); } diff --git a/src/Server/Systems/Network.cs b/src/Server/Systems/Network.cs index a0097da..91c9f07 100644 --- a/src/Server/Systems/Network.cs +++ b/src/Server/Systems/Network.cs @@ -1,5 +1,6 @@ using Shared.Entities; using Shared.Messages; +using Shared.Systems; namespace Server.Systems { @@ -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; } diff --git a/src/Shared/Components/AnchorQueue.cs b/src/Shared/Components/AnchorQueue.cs new file mode 100644 index 0000000..10bc4b3 --- /dev/null +++ b/src/Shared/Components/AnchorQueue.cs @@ -0,0 +1,9 @@ +using Microsoft.Xna.Framework; + +namespace Shared.Components; + +public class AnchorQueue: Component +{ + public Queue m_anchorPositions = new Queue(); + +} \ No newline at end of file diff --git a/src/Shared/Entities/WormHead.cs b/src/Shared/Entities/WormHead.cs index 98edcce..6b08dc4 100644 --- a/src/Shared/Entities/WormHead.cs +++ b/src/Shared/Entities/WormHead.cs @@ -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()); diff --git a/src/Shared/Entities/WormSegment.cs b/src/Shared/Entities/WormSegment.cs index b761f5d..c975d2b 100644 --- a/src/Shared/Entities/WormSegment.cs +++ b/src/Shared/Entities/WormSegment.cs @@ -1,23 +1,24 @@ using Microsoft.Xna.Framework; using Shared.Components; using Shared.Components.Appearance; -using Shared.Systems; -namespace Shared.Entities +namespace Shared.Entities; + +public class WormSegment { - public class WormSegment + public static Entity create(Vector2 position, float size, float moveRate, float rotateRate, uint parent) { - public static Entity create(Vector2 position, float size, float moveRate, float rotateRate, uint parent) - { - Entity entity = new Entity(); - entity.add(new Position(position)); - entity.add(new Appearance("Textures/body")); - entity.add(new Size(new Vector2(size, size))); - entity.add(new Movement(moveRate, rotateRate)); - entity.add(new ParentId(parent)); - entity.add(new Collision()); - entity.add(new Worm()); - return entity; - } + Entity entity = new Entity(); + entity.add(new Position(position)); + entity.add(new Appearance("Textures/circleBody")); + entity.add(new Size(new Vector2(size, size))); + entity.add(new Movement(moveRate, rotateRate)); + entity.add(new ParentId(parent)); + entity.add(new Collision()); + entity.add(new Worm()); + entity.add(new AnchorQueue()); + + return entity; } } + diff --git a/src/Shared/Entities/WormTail.cs b/src/Shared/Entities/WormTail.cs index e474403..3a7cb14 100644 --- a/src/Shared/Entities/WormTail.cs +++ b/src/Shared/Entities/WormTail.cs @@ -11,12 +11,13 @@ public static Entity create(Vector2 position, float size, float moveRate, float { Entity entity = new Entity(); entity.add(new Position(position)); - entity.add(new Appearance("Textures/tail")); + entity.add(new Appearance("Textures/circleTail")); entity.add(new Size(new Vector2(size, size))); entity.add(new ParentId(parent)); entity.add(new Movement(moveRate, rotateRate)); entity.add(new Collision()); entity.add(new Tail()); + entity.add(new AnchorQueue()); entity.add(new Worm()); return entity; } diff --git a/src/Shared/Systems/WormMovement.cs b/src/Shared/Systems/WormMovement.cs index aca91dd..7958870 100644 --- a/src/Shared/Systems/WormMovement.cs +++ b/src/Shared/Systems/WormMovement.cs @@ -11,37 +11,137 @@ public WormMovement() : base(typeof(Shared.Components.Worm)) { } - public override void update(TimeSpan elapsedTime) + public override void update(TimeSpan elapsedTime) { // Get all of the heads of the worms + var heads = getHeads(); + // Apply thrust to all of the worms + foreach (var head in heads) + { + applyThrust(head, elapsedTime); + } + } + + private List getHeads() + { var heads = new List(); foreach (var entityPair in m_entities) { var entity = entityPair.Value; if (entity.contains()) { - heads.Add(entity);; + heads.Add(entity); } } + return heads; + } + + public static void ninetyLeft(List snake, TimeSpan elapsedTime) + { + applyLeftRotation(snake, MathHelper.PiOver2); + } + + public static void ninetyRight(List snake, TimeSpan elapsedTime) + { + applyRightRotation(snake, MathHelper.PiOver2); + } + + // TODO: Adjust this to get the parent's virtual position, not their screen position + private void applyThrust(Entity wormHead, TimeSpan elapsedTime) + { + // Setup variables + var snake = getWormFromHead(wormHead, m_entities); + var head = snake[0]; + var movement = head.get(); + var headPosition = head.get(); + var frameTotalMovement = movement.moveRate * (float)elapsedTime.TotalMilliseconds; + var orientation = headPosition.orientation; + var threshold = 10f; - // Apply thrust to all of the worms - foreach (var head in heads) + // Move the head + var direction = new Vector2((float)Math.Cos(orientation), (float)Math.Sin(orientation)); + direction.Normalize(); + headPosition.position += direction * frameTotalMovement; + + // Move the rest of the worm + for (int i = 1; i < snake.Count; i++) { - applyThrust(head, elapsedTime); + var entity = snake[i]; + var queueComponent = entity.get(); + var positionComponent = entity.get(); + if (queueComponent != null) + { + if (queueComponent.m_anchorPositions.Count == 0) + { + continue; + // // Add the current parent position to the queue if I don't have one of my own + // var parent = snake[i - 1]; + // queueComponent.m_anchorPositions.Enqueue(parent.get()); + } + + // Check where we want to move towards + var target = queueComponent.m_anchorPositions.Peek(); + + // Move towards that target + var directionToTarget = target.position - positionComponent.position; + directionToTarget.Normalize(); + positionComponent.position += directionToTarget * frameTotalMovement; + + // Check if we have hit the target + if (Vector2.Distance(positionComponent.position, target.position) <= threshold) + { + // Remove the target from the queue + queueComponent.m_anchorPositions.Dequeue(); + } + } } } - - public static void ninetyLeft(Entity head, TimeSpan elapsedTime) + private static void applyLeftRotation(List snake, float radians) { - applyLeftRotation(head, -MathHelper.PiOver2); + applyRotation(snake, -radians); } - - public static void ninetyRight(Entity head, TimeSpan elapsedTime) + + private static void applyRightRotation(List snake, float radians) { - applyRightRotation(head, MathHelper.PiOver2); + applyRotation(snake, radians); } + private static void applyRotation(List snake, float radians) + { + if (snake == null || snake.Count == 0) return; + + // Assuming the first entity in the list is the head + var head = snake[0]; + var headPosition = head.get(); + + // Adjust the head's orientation by the specified radians + headPosition.orientation += radians; + + // Normalize the orientation to ensure it stays within a valid range (e.g., 0 to 2*PI) + // This step is important if your system expects orientations within a specific range + headPosition.orientation = (float)(headPosition.orientation % (2 * Math.PI)); + if (headPosition.orientation < 0) headPosition.orientation += (float)(2 * Math.PI); + + // For each segment, add the current head position to its queue for following + // Skip the head itself, start with the first segment following the head + for (int i = 1; i < snake.Count; i++) + { + var segment = snake[i]; + var queueComponent = segment.get(); + + if (queueComponent != null) + { + // Here, we're adding the head's current position as the new target for each segment + // This mimics the behavior where, upon rotation, each segment should aim to move + // towards the position where the head was at the time of rotation + queueComponent.m_anchorPositions.Enqueue(new Position(headPosition.position, headPosition.orientation)); + } + } + } + + + private static Entity getHead(Entity entity, Dictionary entities) { var current = entity; @@ -52,7 +152,7 @@ private static Entity getHead(Entity entity, Dictionary entities) return current; } - private List getSnakeFromHead(Entity head, Dictionary entities) + public static List getWormFromHead(Entity head, Dictionary entities) { var snakeEntities = new List(); var current = head; @@ -71,16 +171,16 @@ private List getSnakeFromHead(Entity head, Dictionary enti return snakeEntities; } - private List getSnakeFromTail(Entity tail) + public static List getSnakeFromTail(Entity tail, Dictionary entities) { var snakeEntities = new List(); var current = tail; while (current != null) { snakeEntities.Add(current); - if (current.contains() && m_entities.ContainsKey(current.get().id)) + if (current.contains() && entities.ContainsKey(current.get().id)) { - current = m_entities[current.get().id]; + current = entities[current.get().id]; } else { @@ -89,68 +189,5 @@ private List getSnakeFromTail(Entity tail) } return snakeEntities; } - - - // TODO: Add a periodic 2/second or maybe 10/second updates of the position to the server - // TODO: Transition to using the queue of positions each entity should move towards - private void applyThrust(Entity wormHead, TimeSpan elapsedTime) - { - // Get the movement component of the head to determine the direction and speed - var movementComponent = wormHead.get(); - var positionComponent = wormHead.get(); - - // Calculate the new position of the head based on its direction and speed - Vector2 direction = new Vector2((float) Math.Cos(positionComponent.orientation), - (float) Math.Sin(positionComponent.orientation)); - direction.Normalize(); // Ensure the direction vector is normalized - Vector2 newPosition = positionComponent.position - direction * movementComponent.moveRate * (float)elapsedTime.TotalMilliseconds; - - // Update the head's position - positionComponent.position = newPosition; - - // Now, update each following segment to move towards the position of its preceding segment - Entity currentSegment = wormHead; // Start with the head - Vector2 previousPosition = newPosition; // Position to move towards, start with the new head position - - while (true) - { - // Assuming each segment has a ParentId component that points to its preceding segment - if (!currentSegment.contains()) - { - break; // No more segments in the chain - } - - // Get the next segment in the chain - uint childId = currentSegment.get().id; - var nextSegment = m_entities[childId]; - - // Temporarily store the current segment's position to use for the next segment - Vector2 tempPosition = nextSegment.get().position; - - // Move the current segment towards the previous position - nextSegment.get().position = previousPosition; - - // Prepare for the next iteration - previousPosition = tempPosition; - currentSegment = nextSegment; - } - } - - - - // We don't need to update the entire worm with these because it will be updated in the next frame when thrust is applied - private static void applyLeftRotation(Entity head, float radians) - { - var position = head.get(); - var movement = head.get(); - position.orientation += radians; - } - - private static void applyRightRotation(Entity head, float radians) - { - var position = head.get(); - var movement = head.get(); - position.orientation += radians; - } } \ No newline at end of file