/// <summary> /// Updates all moving entities in the game /// </summary> /// <param name="elapsedTime"> /// The time between this and the previous frame. /// </param> public void Update(float elapsedTime) { // Update all entities that have a movement component foreach (Movement movement in game.MovementComponent.All) { // Update the entity's position in the world Position position = game.PositionComponent[movement.EntityID]; position.Center += elapsedTime * movement.Speed * movement.Direction; game.PositionComponent[movement.EntityID] = position; // Update the entity's movement sprite if (game.MovementSpriteComponent.Contains(movement.EntityID)) { MovementSprite movementSprite = game.MovementSpriteComponent[movement.EntityID]; // Set the direction of movement float angle = (float)Math.Atan2(movement.Direction.Y, movement.Direction.X); if (angle > -MathHelper.PiOver4 && angle < MathHelper.PiOver4) { movementSprite.Facing = Facing.East; } else if (angle >= MathHelper.PiOver4 && angle <= 3f * MathHelper.PiOver4) { movementSprite.Facing = Facing.South; } else if (angle >= -3 * MathHelper.PiOver4 && angle <= -MathHelper.PiOver4) { movementSprite.Facing = Facing.North; } else { movementSprite.Facing = Facing.West; } // Update the timing movementSprite.Timer += elapsedTime; if (movementSprite.Timer > 0.1f) { movementSprite.Frame += 1; if (movementSprite.Frame > 2) { movementSprite.Frame = 0; } movementSprite.Timer -= 0.1f; } // Update the sprite bounds movementSprite.SpriteBounds.X = 64 * movementSprite.Frame; movementSprite.SpriteBounds.Y = 64 * (int)movementSprite.Facing; // Apply our updates game.MovementSpriteComponent[movement.EntityID] = movementSprite; } } }
/// <summary> /// Handles a player joining the game. The new gamer should be sent /// all the entity components it will need to synchonize with this /// peer (i.e. all the components this peer has authority over) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void GamerJoinedEventHandler(object sender, GamerJoinedEventArgs e) { // We only need to update remote gamers - local ones will share // our local game state if (!e.Gamer.IsLocal) { // Send components for all entitys that we have authority over // (i.e. those with a local component) foreach (Local local in game.LocalComponent.All) { // Send position if (game.PositionComponent.Contains(local.EntityID)) { Position position = game.PositionComponent[local.EntityID]; packetWriter.Write(position.EntityID); packetWriter.Write((short)PacketTypes.Position); packetWriter.Write(position.Center); packetWriter.Write(position.Radius); } // Send sprite if (game.SpriteComponent.Contains(local.EntityID)) { Sprite sprite = game.SpriteComponent[local.EntityID]; packetWriter.Write(sprite.EntityID); packetWriter.Write((short)PacketTypes.Sprite); packetWriter.Write(sprite.SpriteSheet.Name); packetWriter.Write(sprite.SpriteBounds.X); packetWriter.Write(sprite.SpriteBounds.Y); packetWriter.Write(sprite.SpriteBounds.Width); packetWriter.Write(sprite.SpriteBounds.Height); } // Send movement sprite if (game.MovementSpriteComponent.Contains(local.EntityID)) { MovementSprite sprite = game.MovementSpriteComponent[local.EntityID]; packetWriter.Write(sprite.EntityID); packetWriter.Write((short)PacketTypes.MovementSprite); packetWriter.Write(sprite.SpriteSheet.Name); packetWriter.Write(sprite.SpriteBounds.X); packetWriter.Write(sprite.SpriteBounds.Y); packetWriter.Write(sprite.SpriteBounds.Width); packetWriter.Write(sprite.SpriteBounds.Height); } // Send the data session.LocalGamers[0].SendData(packetWriter, SendDataOptions.InOrder, e.Gamer); } } }
/// <summary> /// Sends updates on all entities under local authority /// </summary> void SendLocalEntityUpdates() { try //Catch all errors since one keeps happening randomly { foreach (Local local in game.LocalComponent.All) { // Send position if (game.PositionComponent.Contains(local.EntityID)) { Position position = game.PositionComponent[local.EntityID]; packetWriter.Write(position.EntityID); packetWriter.Write((short)PacketTypes.Position); packetWriter.Write(position.Center); packetWriter.Write(position.Radius); session.LocalGamers[0].SendData(packetWriter, SendDataOptions.InOrder); } // Send sprite if (game.SpriteComponent.Contains(local.EntityID)) { Sprite sprite = game.SpriteComponent[local.EntityID]; packetWriter.Write(sprite.EntityID); packetWriter.Write((short)PacketTypes.Sprite); packetWriter.Write(sprite.SpriteSheet.Name); packetWriter.Write(sprite.SpriteBounds.X); packetWriter.Write(sprite.SpriteBounds.Y); packetWriter.Write(sprite.SpriteBounds.Width); packetWriter.Write(sprite.SpriteBounds.Height); session.LocalGamers[0].SendData(packetWriter, SendDataOptions.InOrder); } // Send movement sprite if (game.MovementSpriteComponent.Contains(local.EntityID)) { MovementSprite sprite = game.MovementSpriteComponent[local.EntityID]; packetWriter.Write(sprite.EntityID); packetWriter.Write((short)PacketTypes.MovementSprite); packetWriter.Write(sprite.SpriteSheet.Name); packetWriter.Write(sprite.SpriteBounds.X); packetWriter.Write(sprite.SpriteBounds.Y); packetWriter.Write(sprite.SpriteBounds.Width); packetWriter.Write(sprite.SpriteBounds.Height); session.LocalGamers[0].SendData(packetWriter, SendDataOptions.InOrder); } } } catch (Exception e) { } }
/// <summary> /// Update remote entity components based on network input /// TODO: Reloading the texture every frame may quickly /// become cost-prohibitive we may need a better option /// </summary> void RecieveRemoteEntityUpdates() { // Each local gamer recieves network messages - so process them all foreach(LocalNetworkGamer gamer in session.LocalGamers) { // Process all waiting packets while (gamer.IsDataAvailable) { NetworkGamer sender; // Read a single packet from the network gamer.ReceiveData(packetReader, out sender); // Discard local packets - we already know local state if (sender.IsLocal) continue; // Look up the entity associated with this network packet uint entityID = game.RemoteComponent.FindRemoteEntity(sender.Id, packetReader.ReadUInt32()); string textureName; // process the packet PacketTypes packetType = (PacketTypes)packetReader.ReadInt16(); switch (packetType) { case PacketTypes.Position: Position position = new Position() { EntityID = entityID, Center = packetReader.ReadVector2(), Radius = packetReader.ReadSingle(), }; game.PositionComponent[entityID] = position; break; case PacketTypes.Sprite: Sprite sprite = new Sprite(); textureName = packetReader.ReadString(); sprite.EntityID = entityID; sprite.SpriteSheet = game.Content.Load<Texture2D>(textureName); sprite.SpriteSheet.Name = textureName; sprite.SpriteBounds.X = packetReader.ReadInt32(); sprite.SpriteBounds.Y = packetReader.ReadInt32(); sprite.SpriteBounds.Width = packetReader.ReadInt32(); sprite.SpriteBounds.Height = packetReader.ReadInt32(); game.SpriteComponent[entityID] = sprite; break; case PacketTypes.MovementSprite: MovementSprite movementSprite = new MovementSprite(); textureName = packetReader.ReadString(); movementSprite.EntityID = entityID; movementSprite.SpriteSheet = game.Content.Load<Texture2D>(textureName); movementSprite.SpriteSheet.Name = textureName; movementSprite.SpriteBounds.X = packetReader.ReadInt32(); movementSprite.SpriteBounds.Y = packetReader.ReadInt32(); movementSprite.SpriteBounds.Width = packetReader.ReadInt32(); movementSprite.SpriteBounds.Height = packetReader.ReadInt32(); game.MovementSpriteComponent[entityID] = movementSprite; break; } } } }
/// <summary> /// Creates Entities from aggregates (collections of components) /// </summary> /// <param name="aggregate">The specific aggreage to create</param> public void CreateFromAggregate(Aggregate aggregate) { switch (aggregate) { case Aggregate.FairyPlayer: uint entityID = Entity.NextEntity(); Texture2D spriteSheet = game.Content.Load<Texture2D>("Spritesheets/wind_fae"); spriteSheet.Name = "Spritesheets/wind_fae"; Position position = new Position() { EntityID = entityID, Center = new Vector2(400, 50), Radius = 32f, }; game.PositionComponent[entityID] = position; Movement movement = new Movement() { EntityID = entityID, Direction = new Vector2(0, 1), Speed = 200f, }; game.MovementComponent[entityID] = movement; MovementSprite movementSprite = new MovementSprite() { EntityID = entityID, Facing = Facing.South, SpriteSheet = spriteSheet, SpriteBounds = new Rectangle(0, 0, 64, 64), Timer = 0f, }; game.MovementSpriteComponent[entityID] = movementSprite; Local local = new Local(){ EntityID = entityID, }; game.LocalComponent[entityID] = local; Player player = new Player() { EntityID = entityID, PlayerIndex = PlayerIndex.One, }; game.PlayerComponent[entityID] = player; break; case Aggregate.CultistPlayer: break; case Aggregate.CyborgPlayer: break; case Aggregate.EarthianPlayer: break; case Aggregate.GargranianPlayer: break; case Aggregate.SpacePiratePlayer: break; case Aggregate.ZombiePlayer: break; } }
/// <summary> /// Update remote entity components based on network input /// TODO: Reloading the texture every frame may quickly /// become cost-prohibitive we may need a better option /// </summary> void RecieveRemoteEntityUpdates() { // Each local gamer recieves network messages - so process them all foreach (LocalNetworkGamer gamer in session.LocalGamers) { // Process all waiting packets while (gamer.IsDataAvailable) { NetworkGamer sender; // Read a single packet from the network gamer.ReceiveData(packetReader, out sender); // Discard local packets - we already know local state if (sender.IsLocal) { continue; } // Look up the entity associated with this network packet uint entityID = game.RemoteComponent.FindRemoteEntity(sender.Id, packetReader.ReadUInt32()); string textureName; // process the packet PacketTypes packetType = (PacketTypes)packetReader.ReadInt16(); switch (packetType) { case PacketTypes.Position: Position position = new Position() { EntityID = entityID, Center = packetReader.ReadVector2(), Radius = packetReader.ReadSingle(), }; game.PositionComponent[entityID] = position; break; case PacketTypes.Sprite: Sprite sprite = new Sprite(); textureName = packetReader.ReadString(); sprite.EntityID = entityID; sprite.SpriteSheet = game.Content.Load <Texture2D>(textureName); sprite.SpriteSheet.Name = textureName; sprite.SpriteBounds.X = packetReader.ReadInt32(); sprite.SpriteBounds.Y = packetReader.ReadInt32(); sprite.SpriteBounds.Width = packetReader.ReadInt32(); sprite.SpriteBounds.Height = packetReader.ReadInt32(); game.SpriteComponent[entityID] = sprite; break; case PacketTypes.MovementSprite: MovementSprite movementSprite = new MovementSprite(); textureName = packetReader.ReadString(); movementSprite.EntityID = entityID; movementSprite.SpriteSheet = game.Content.Load <Texture2D>(textureName); movementSprite.SpriteSheet.Name = textureName; movementSprite.SpriteBounds.X = packetReader.ReadInt32(); movementSprite.SpriteBounds.Y = packetReader.ReadInt32(); movementSprite.SpriteBounds.Width = packetReader.ReadInt32(); movementSprite.SpriteBounds.Height = packetReader.ReadInt32(); game.MovementSpriteComponent[entityID] = movementSprite; break; } } } }
/// <summary> /// Creates Entities from aggregates (collections of components) /// </summary> /// <param name="aggregate">The specific aggreage to create</param> public void CreateFromAggregate(Aggregate aggregate) { switch (aggregate) { case Aggregate.FairyPlayer: uint entityID = Entity.NextEntity(); Texture2D spriteSheet = game.Content.Load <Texture2D>("Spritesheets/wind_fae"); spriteSheet.Name = "Spritesheets/wind_fae"; Position position = new Position() { EntityID = entityID, Center = new Vector2(400, 50), Radius = 32f, }; game.PositionComponent[entityID] = position; Movement movement = new Movement() { EntityID = entityID, Direction = new Vector2(0, 1), Speed = 200f, }; game.MovementComponent[entityID] = movement; MovementSprite movementSprite = new MovementSprite() { EntityID = entityID, Facing = Facing.South, SpriteSheet = spriteSheet, SpriteBounds = new Rectangle(0, 0, 64, 64), Timer = 0f, }; game.MovementSpriteComponent[entityID] = movementSprite; Local local = new Local() { EntityID = entityID, }; game.LocalComponent[entityID] = local; Player player = new Player() { EntityID = entityID, PlayerIndex = PlayerIndex.One, }; game.PlayerComponent[entityID] = player; break; case Aggregate.CultistPlayer: break; case Aggregate.CyborgPlayer: break; case Aggregate.EarthianPlayer: break; case Aggregate.GargranianPlayer: break; case Aggregate.SpacePiratePlayer: break; case Aggregate.ZombiePlayer: break; } }