struct Dirty_Dashers_Code {
Welcome to my Dirty Dashers Code page. Here you can see a few snippets of code that I wrote for my game Dirty Dashers.
Dirty Dashers was my first (and only) venture into network programming. The game required the networking of players who needed to know about teammates and other enemies. For more info about the game see it project page.
I set up my networking such that every player class would be in charge of their own read and writing of network packets, in order to avoid having to replicate code for every player. Then in the main game update loop we had functions that would tell each player to read or write a packet of data. Our biggest problem came from the networking of player before the actual game started, mainly because our lobby system was not set up until later in development. In order to fix this, we used a series of flags that would be sent to other clients and the server telling them if they are ready or not. These “Ready flags” could only be sent if they have sent off their team indicator and received and reply from all other clients saying that they in fact received it.
Dirty_Dashers_Code_1 shows off the player read/write network packet functions, and Dirty_Dasher_Code_2 shows the update functions in the game loop that tells all the players to read and write, and also sends off the packet.
Dirty_Dashers_Code_1: player read and write packet functions
public void WriteNetworkPacket(PacketWriter packetWriter, GameTime gameTime) { packetWriter.Write(PhysicsBody.Velocity); packetWriter.Write(PhysicsBody.Position); packetWriter.Write(PhysicsBody.Orientation); packetWriter.Write(amShooting); packetWriter.Write(chargePower); packetWriter.Write(amSupering); if (amSupering) { amSupering = false; chargePower = 0; } //this will be tested for true, but assumed to be false packetWriter.Write(amTeleporting); packetWriter.Write((Int16)teleporter); //thus we make sure it defaults to false after sending amTeleporting = false; teleporter = ETeleporter.NONE; } internal void ReadNetworkPacket(PacketReader packetReader, GameTime gameTime) { //NOTE: ReadSingle is apparenty ReadFloat...way to break the naming scheme XNA!!! try { ApplySmoothing(packetReader.ReadVector3(), packetReader.ReadVector3(), packetReader.ReadMatrix()); if (packetReader.ReadBoolean()) //amShooting? Shoot(); this.chargePower = packetReader.ReadSingle(); if (packetReader.ReadBoolean()) //amSupering? SuperRelease(chargePower, false); amTeleporting = packetReader.ReadBoolean(); teleporter = (ETeleporter)packetReader.ReadInt16(); } catch { packetReader.Position = packetReader.Length; } }
Dirty_Dashers_Code_2: game loop read and write functions
private void ReadIncomingPackets(LocalNetworkGamer gamer, GameTime gameTime) { //read all packet while (gamer.IsDataAvailable) { NetworkGamer sender; //read single packet form networked gamer, and store it in the sender gamer.ReceiveData(packetReader, out sender); // if the sender's Tag is null then his team has not been set. // But the only way us to even know about the sender in the first place, is if the sender had sent what team they choose. // So simply read the packet to get and set the team if (sender.Tag is Int32) { if (packetReader.ReadString() == "READY") { SpawnAvatar(sender); } } else if (sender.Tag is Player) { //make sure its not the local player if (sender.IsLocal) continue; //get the sudsy under control by the sender Player senderAvatar = sender.Tag as Player; //update the sudsy according to he packet senderAvatar.ReadNetworkPacket(packetReader, gameTime); if (senderAvatar.amTeleporting) { if (senderAvatar.teleporter == ETeleporter.TELEPORTER1 || senderAvatar.teleporter == ETeleporter.TELEPORTER2) { for (int i = 0; i < 50; i++) { teleporter.particles.AddParticle(teleporter.locationOne, senderAvatar.PhysicsBody.Velocity); teleporter.particles.AddParticle(teleporter.locationTwo, senderAvatar.PhysicsBody.Velocity); } } teleportOther(senderAvatar.teleporter); } try { //read the huds NodeValue float hudVal = packetReader.ReadSingle(); bool clean = packetReader.ReadBoolean(); bool dirty = packetReader.ReadBoolean(); if (sender.IsHost) { hud.NodeValue = hudVal; if (hudVal <= 0) cleanScores = true; if (hudVal >= 1) dirtyScores = true; } } catch { packetReader.Position = packetReader.Length; } } } } private void UpdateLocalGamer(LocalNetworkGamer gamer, GameTime gameTime) { // make sure the Tag is set if (gamer.Tag is Player) { //get the player this gamer is controlling Player gamerAvatar = gamer.Tag as Player; //camera camera.ChasePosition = gamerAvatar.PhysicsBody.Position; //gamerAvatar.PhysicsBody.Position; camera.Up = Vector3.Up; camera.ChaseDirection = gamerAvatar.PhysicsBody.Orientation.Forward; audioMan.UpdateListener(gamerAvatar.PhysicsBody.Orientation.Up, gamerAvatar.PhysicsBody.Orientation.Forward, gamerAvatar.PhysicsBody.Position, gamerAvatar.PhysicsBody.Velocity); //give the sudsy the packet write and have it write the data it needs to send gamerAvatar.WriteNetworkPacket(packetWriter, gameTime); //write the huds NodeVale packetWriter.Write(hud.NodeValue); packetWriter.Write(cleanScores); packetWriter.Write(dirtyScores); //send it off! gamer.SendData(packetWriter, SendDataOptions.InOrder); } }