Поделиться через


Windows Phone Peer-to-Peer Multiplayer Game using Sockets in XNA

One of the new features for the app platform in Windows Phone Mango is TCP and UDP Sockets.  In this blog post, I'll talk about using this to augment an existing game to add peer-to-peer multiplayer over WiFi using UdpAnySourceMulticastClient.  Phones running the game on the same WiFi network automatically discover one another and the players just appear on the screen.

The game itself is from another sample, the Windows Phone 7 Platformer Starter Kit from David Rousset's blog.

The changes are to add code to run UDP Multicast sockets and to enable multiplayer. 

The source code for the full project is attached in the zip file below.

PlatformerGame.cs:  This contains the game code and is where the sockets are initialized, and where the sends and receives are handled. 

UdpAnySourceMulticastChannel.cs: This contains the UDP multicast sockets code for joining the group, sending and receiving data.

OtherPlayer.cs:  This is a modification of Player.cs to add other players to the game.

Sockets Initialization in PlatformerGame.cs:

 private void InitializeSockets() { this.Channel = new UdpAnySourceMulticastChannel(IPAddress.Parse("224.109.108.107"), 3007); this.Channel.PacketReceived += new EventHandler<UdpPacketReceivedEventArgs>(Channel_PacketReceived); this.Channel.Open(); } 

 

This joins the UdpAnySourceMulticastClient group and sets it up to receive data: 

 

 

  public void Open() { if (!IsJoined) { this.Client.BeginJoinGroup( result => { try { this.Client.EndJoinGroup(result); IsJoined = true; this.OnAfterOpen(); this.Receive(); } catch { } }, null); } } private void Receive() { if (IsJoined) { Array.Clear(this.ReceiveBuffer, 0, this.ReceiveBuffer.Length); this.Client.BeginReceiveFromGroup(this.ReceiveBuffer, 0, this.ReceiveBuffer.Length, result => { if (!IsDisposed) { IPEndPoint source; try { this.Client.EndReceiveFromGroup(result, out source); this.OnReceive(source, this.ReceiveBuffer); this.Receive(); } catch { IsJoined = false; this.Open(); } } }, null); } }

 

Each time a player moves, it sends its new position and velocity to the multicast group.

 

  private void SendPosition(string position) { if (level.Player.Position.X != oldPosition.X || level.Player.Position.Y != oldPosition.Y) { oldPosition = level.Player.Position; this.Channel.Send(position); } }

 

This sends the packet to the multicast group.

 

  public void Send(string format, params object[] args) { if (IsJoined) { byte[] data = Encoding.UTF8.GetBytes(string.Format(format, args)); this.Client.BeginSendToGroup(data, 0, data.Length, result => { this.Client.EndSendToGroup(result); }, null); } }

 

When a packet gets received, the receive handler updates the other player so that it looks like the other player is moving. Each phone in the multicast group receives this and updates accordingly.

 

  void Channel_PacketReceived(object sender, UdpPacketReceivedEventArgs e) { string data = e.Message; Console.WriteLine(data); string[] pos = data.Split(','); //Discard packets that do not match if (pos.Length != 5) { return; } try { if (pos[0] != identifier.ToString()) //if not originated from this phone { if (pos[1].Contains("ReachedExit")) { level.TimeRemaining = TimeSpan.Zero; } else { Vector2 position = new Vector2(float.Parse(pos[1]), float.Parse(pos[2])); Vector2 velocity = new Vector2(float.Parse(pos[3]), float.Parse(pos[4])); level.UpdateOtherPlayer(int.Parse(pos[0]), position, velocity); } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Caught unexpected exception: " + ex.Message); } }

 

To play, use the accelerometer to move left or right. Tap on the screen to jump. Multiplayer requires WiFi network.

 

 

To get the Windows Phone Mango Developer Tools Beta: https://www.microsoft.com/downloads/en/details.aspx?FamilyID=77586864-ab15-40e1-bc38-713a95a56a05&displaylang=en

Hope this helps show a simple way to communicate from phone to phone and demonstrate the power of sockets.  Happy developing!

Ricky

WindowsPhonePlatformer.zip

Comments

  • Anonymous
    June 15, 2011
    Where did 224.0.1.100 come from for the IPAddress?

  • Anonymous
    June 15, 2011
    224.0.1.100 is a multicast address.  Multicast addresses are in the range of 224.0.0.0 to 239.255.255.255 (en.wikipedia.org/.../Multicast_address).

  • Anonymous
    June 15, 2011
    That's my other Live ID above. After some reading, that address falls in the IANA-governed Internetwork Control Block.  That particular address is currently assigned to NASDAQ.  The IANA also states that addresses in this range should not be used unless assigned. So, what are the rules on choosing an address to use?  Was that address picked at random?

  • Anonymous
    June 16, 2011
    Thanks for pointing that out.  That address was picked at random.  I've changed it to one that is not in the reserved list, 224.109.108.107.

  • Anonymous
    June 16, 2011
    The comment has been removed

  • Anonymous
    July 25, 2011
    Hi, tried implementing this into a new game I am working on to see if I could get it to work outside the demo. I am running it on my phone and in the emulator to represent two seperate devices, this works on your demo. The problem I am having is that one of them freezes at random, doesn't matter if I am running it or selecting from the phone menu. Any ideas? I know its difficult to say without seeing the code. I have tried using "lock" (around the variables) in the event raised for receiving data but still dont know what is causing it. Cheers Red

  • Anonymous
    July 27, 2011
    Does this only work with XNA or can Silverlight games take advantage of this? Many thanks, Karl

  • Anonymous
    July 27, 2011
    @Redtalon:  This is a known issue, and should be fixed for the final release. @Karl:  The Socket APIs are from Silverlight.  So Silverlight games can definitely take advantage of this.

  • Anonymous
    July 27, 2011
    Rick, Thank you for confirming. Best, Karl

  • Anonymous
    July 27, 2011
    The comment has been removed

  • Anonymous
    July 28, 2011
    The PacketReceived event comes in on a background thread.  To access the UI thread from a background thread, you can use the Dispatcher: this.Dispatcher.BeginInvoke(() => textBlock1.Text = text);

  • Anonymous
    August 01, 2011
    Are there any plans for Sockets support on the XBOX 360, where players can join in with their phones?

  • Anonymous
    August 02, 2011
    That would be really cool.  I don't know about plans for XBOX 360.  You could check on the XBOX 360 forums.

  • Anonymous
    August 02, 2011
    I think the ability to play an XBOX game and have a WP7 friend jump in would be crazily addictive. I will ask about.

  • Anonymous
    August 02, 2011
    Would I use this code if I wanted a game where a user could choose to join up with a specific phone, whether or not that phone is on the same WiFi? For example, a two-player tic-tac-toe where users choose their opponents from a list of friends, or another random phone.

  • Anonymous
    August 02, 2011
    Would I use this code if I wanted a game where a user could choose to join up with a specific phone, whether or not that phone is on the same WiFi? For example, a two-player tic-tac-toe where users choose their opponents from a list of friends, or another random phone.

  • Anonymous
    August 02, 2011
    Multicast is limited to the same network only.  For your scenario, you could use TCP sockets.  Earlier this year in MIX 2011, there was a demo of a simple IRC client that does this scenario where your phone could talk to random people on the IRC channel.

  • Anonymous
    September 02, 2011
    Ricky_T thankyou very much for this... I'm trying to create a simple test with a texture2d player and Vector2 positions test on Emulater and Phone running mango.. No such luck.. Anyway you can create a quick source code just for us people who isnt so great in programming?

  • Anonymous
    September 03, 2011
    Another question is would it be possible to have say Mango Phone control a character using sockets to a Windows Xna game??

  • Anonymous
    September 06, 2011
    Hi Tishawn, I'm using Texture2D and Vector2 in this sample.  You can download the source code which is attached to this blog. Yes, it's possible.  Your Windows XNA game needs to have a socket open for listening.  Then have your Mango Phone control the character and send the information to the Windows XNA game via the socket. Regards, Ricky

  • Anonymous
    September 07, 2011
    The comment has been removed

  • Anonymous
    October 02, 2011
    Hi, is there any way to do a Peer-to-Peer Multiplayer Game with ad-hoc wifi or bluetooth?

  • Anonymous
    October 03, 2011
    @Tishawn:  You could use a sprite to draw the projectile using a png image, similar to drawing a player sprite. @mercator:  At this time, I don't think there's a way to do this with ad-hoc wifi or bluetooth.

  • Anonymous
    January 03, 2012
    Is there a way to implement this in a simple game of pong? my code all takes place in one class and the example uses 3 (OtherPlayer, level, and PlatformerGame)

  • Anonymous
    January 03, 2012
    Yes, you can implement this in a simple game of pong, with your code in one class.  You can follow the sample code in PlatformerGame.cs.

  • Anonymous
    January 03, 2012
    Thanks for the lighting fast response but i've been working on this i few days now and i can't get it to work. I was wondering: 1).  Do I need to create a class for OtherPlayer 2). If not should all the references in the sample code for OtherPlayer simply changed to the name i am using for my paddle's Vector2 position? 3). since everything is in the same class do i still need to call Dictionary?

  • Anonymous
    January 03, 2012
    What issue are you seeing?  It might be easier for you to create a new project, and follow the code in UdpAnySourceMulticastChannel to get simple Send and Receive working.  Then put the code into your app to update the paddle's position on Receive.

  1. No.  I just found it easier to different the local player vs the other player.
  2. Yes, change the logic to update your paddle's Vector2 position.
  3. No, Dictionary is just a data structure used to store key value pairs.
  • Anonymous
    January 03, 2012
    Thanks again i was also wondering if i should put the logic for controlling the paddle inside the Channel_PacketReceived method? the project deploys and running properly but there is no interaction from the other device

  • Anonymous
    January 03, 2012
    You're welcome. Yes, you should put that logic in the Channel_PacketReceived method.

  • Anonymous
    January 18, 2012
    hey thanks for the example, you rock! one question how would i go about starting the players at different positions

  • Anonymous
    March 08, 2012
    Hi, I admire your work ! Looks very simple but effective but I need to ask this lines of codes:                this.Client.BeginSendTo(data, 0, data.Length,endPoint,                    result =>                    {                        this.Client.EndSendToGroup(result);                    }, null); I wonder if your code should be like Client.EndSendTo()  not Client.EndSendToGroup() ?

  • Anonymous
    March 09, 2012
    @Mike:  You can change the starting positions in the txt file at WindowsPhonePlatformerContentLevels. @jun:  In this case, we want to send the same data to all players in the group, so we use EndSendToGroup().  If we wanted to send a private message to a specific player, then we can use EndSendTo().

  • Anonymous
    December 17, 2012
    Do the players have to be on the same network to play ??

  • Anonymous
    December 17, 2012
    Yes, players need to be on the same WiFi network to play. To play across different networks, you'll need to set up a TCP or UDP server, and have the different players connect to the server.  

  • Anonymous
    December 17, 2012
    Do you have a tutorial or sample on how to do that??

  • Anonymous
    December 18, 2012
    It's published as an official MSDN topic:  msdn.microsoft.com/.../hh202858(v=vs.105).aspx

  • Anonymous
    December 18, 2012
    Hi Ricky, and congrats on getting published =) I would like to use your project to make my own multiplayer app on Windows Phone, but when I extract the archive, I get the following error: !   D:DownloadsWindowsPhonePlatformer (1).zip: The archive is corrupt !   D:DownloadsWindowsPhonePlatformer (1).zip: The archive is corrupt !   D:DownloadsWindowsPhonePlatformer (1).zip: CRC failed in WindowsPhonePlatformerWindowsPhonePlatformerContentSoundsExitReached.wma. The file is corrupt !   D:DownloadsWindowsPhonePlatformer (1).zip: The archive is corrupt

  • Anonymous
    December 18, 2012
    Thanks.  I'm not sure what happened to the zip package that caused it to stop working.  I've re-uploaded the zip file.