Sei sulla pagina 1di 25

Picture Hunt Silverlight Socket Demo

Storyboard controlled animation Automatic connection retry Network Status Indicator

About the game LINQ to simplify coding

Data Binding to update scores

Async socket code

Multiple players in one game

Running the Picture Hunt game demo


Simplest way: start the RunDemo.bat file It starts the three components of the demo:
the Silverlight Policy Server
Go to directory (cd) SilverlightPolicyServer Start Run.bat

Start the Picture Hunt Game Server


Go to directory (cd) PictureHunt\PictureHuntServer Start PictureHuntServer.exe

Start the Silverlight game


Go to directory (cd) PictureHunt\PictureHunt\Bin\Debug Start PictureHuntTestPage.html

Overall Architecture

On the client computers: A running Web browser with the Silverlight game

The server computer has more pieces: 1. The game HTML file served up by a running web server 2. The running game server program 3. A bunch of marked-up images in the right directory 4. The running socket policy server program

Programming hint: Common files for clients and servers


The Silverlight IDE (Microsoft Visual Web Developers 2010 Express) will copy files into the project directory when you add existing item to your Silverlight project That s not what I wanted! I wanted a single file in both the Server and Game projects. In the end, I edited the .csproj file by hand to reference files in the server project.

Policy Server details


Like many web-facing technologies, Silverlight imposed some security restrictions on Sockets. You need to run a Silverlight Policy Server on port 943 (or other ports). The System.Net team has a simple policy server as a code snippet at
http://msdn.microsoft.com/library/cc645032.aspx

Multiple Players
Multiplayer games are ideal for sockets: Anyone can click at any time The server can update anyone at any time Http style request/response doesn t work well for these types of problems. It s the server that has most multiplayer code; each client of course only handles itself

Async Socket Code

Connect

Read and Write

Closing

Async Socket Code

Connecting

var s = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var e = new SocketAsyncEventArgs(); e.RemoteEndPoint = new DnsEndPoint(serverName, 4529); e.Completed += OnConnected; s.ConnectAsync(e);

Async Socket Code

Writing

Picture Hunt makes a list of ArraySegments, and then writes them out with SendAsync . The WriteCompleted doesn t actually do anything for this application var senddata = new List<ArraySegment<byte>>(); senddata.Add(new ArraySegment<byte>(header)); if (data != null) senddata.Add(new ArraySegment<byte>(data)); var writeEventArgs = new SocketAsyncEventArgs(); writeEventArgs.Completed += WriteCompleted; writeEventArgs.BufferList = senddata; socket.SendAsync(writeEventArgs);

Handling message Async Socket Code boundaries


TCP/IP is a stream protocol: it doesn t respect your game message boundaries. For example: the game server sends three messages:

But the game might get these messages:


Why? TCP/IP data doesn t preserve message boundaries: it s a stream of data (like a file: you can write 10 bytes and 10 bytes and 10 bytes, and then read 8 bytes and 15 bytes and 7 bytes) Solution: Your program has to track the message boundaries

Async Socket Code

Serializing Data over a Network

Different people have different styles for serializing data. Picture Hunt has hand-made code for serialization. Each Command that has extra header fields has to implement InitHeader() to write them out into a BinaryWriter. Data is read in with the CommandReader class (which also handles message boundaries). CommandReader has to know about every class and every opcode; this is written by hand htonl converts host to native format (this lets my program work on any system)

Async Socket Code

Closing

Close your socket when you re done:


closingSocket.Shutdown(SocketShutdown.Both); closingSocket.Close(); closingSocket = null;

Network Status Style: Discrete Network Status


Network Status Indicator Picture Hunt uses a Discrete Network Status: a little icon of the network conditions with no text and absolutely no dialog boxes

The Discrete style is often a good choice. Other choices are Per-task dialog: show multiple activities related to a task (e.g., downloading) User-selected dialog: similar, but is shown only when user asks. Is appropriate when networking isn t a primary part of the user s work UI replacement: when offline, switch interface. Is appropriate when the app has no off-line capabilities (which is rare)

Network Status States


Unstarted
Goes to Started when the user clicks Connected ; program is told to StartNetworkConnection()

Started
Goes to OK if a connection can be made Goes to FailNl if a connection cannot be made

Ok
Goes to Fail if a socket read fails to read

Fail
Sets a timer to switch to Retry

Retry
The program is told to StartNeworkConnection() Goes to Ok if the connection works and Fail if it does not

FailNl
Sets a timer to switch into RetryNl

RetryNl
The program is told to StartNetworkConnection() Goes to Ok if the connection works and FailNl if it does not

Automatic Connection Retry

People move their laptop computers a lot more than they used to. Your program has to handle Network Transitions smoothly: Always retry on failures Use the network status (and not an emergency dialog) Transitions are common: the user doesn t need a big reminder

Adjust the retry times when there s no connection


At start: retry every 2 seconds Then every 15 seconds Later, retry every hour Why? The game doesn t want to overuse the network. There s a validation routine to make sure the table of adjustments is reasonable.
All this is in NetworkStatus.cs the GetRetryTime() and the associated RetryTime list and DelayTime class. There is also a validation routine.

And one more thing: Network Transitions


You should also detect NetworkAddressChanged and proactively set up a new socket. New socket usable? Use it and drop to the old one New socket not usable? Drop it and keep the old one. Just be careful when you ve got two sockets open at once. The NetworkAddressChanged event is pretty chatty; you ll need to de-bounce it with a small timer. With a discrete network status style, you don t tell the user that you re even trying it.

Hints: debugging new connections


Quick test (laptop): start with Wi-Fi and no Ethernet and run the game. Then plug in Ethernet, wait five seconds, and turn off your WiFi. The game should already be connected to Ethernet. I made life easier for myself by adding in a New Network button for debugging. Every time I clicked it, it would try a new network. I also added a server command to reject all new players this helps validate that the code is robust. The game should accept the new connection failure and keep on using the old one. Not all new connections work!

LINQ to simplify coding


The game demo uses LINQ in several places to make the code easier to write and understand. For example, when the user can asks for a hint for an area to click; the following game server code finds an area to show:
Area a = (from area in areas where area.HitBy == null && area.Name == CurrLookFor select area).DefaultIfEmpty(null).FirstOrDefault();

The resulting single Area is now either a good candidate to return, or is null. Reading a LINQ book really helped me get started.

Data Binding to Update Score


Data Binding is a way to automatically link your data to a UI element When you update your data, the UI is updated, too! Can work the other way as well (UI Data)

Data Binding Code


public class PlayerScore { public int index { get; set; } public string name { get; set; } public int score { get; set; } } public ObservableCollection<PlayerScore> playerScores { get; set; }

Data Binding Code (part 2)


About that code 1. Everything needs to be public 2. Everything needs to be a property 3. PlayerScore does not implement INotifyPropertyChange, so only clear+replace will show up (e.g., can t take an existing score and change it; have to remove all and add back in) I couldn t have done it without Petzold s Windows Phone book (free download; got to http://www.charlespetzold.com/phone/ )

XAML (UI) part of Data Binding


<ListBox Name="playerScoreList" ItemsSource="{Binding Path=playerScores}" Width="207" Height="190" Opacity="0.8" IsHitTestVisible="True"> <ItemsControl.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="50" /> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="{Binding name}" FontSize="20" /> <TextBlock Grid.Column="1" Text=" " FontSize="20" /> <TextBlock Grid.Column="2" Text="{Binding score}" FontSize="20" /> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ListBox>

Storyboard Controlled Animation


Adding animation was easy and made a big improvement in the game Add <Storyboard> items in the XAML; set the TargetName to the thing to animate and the TargetProperty to the property to animate (usually opacity or position) In the game code, call ___Storyboard.Begin() to trigger the animation

Storyboard Controlled Animation


Animations include: The title The instructions The player list The look for (both new words and when there s a winner) The winner text MSDN was enough to make it work

Potrebbero piacerti anche