Simple F# Game using WPF

 

With the F# CTP out the door, let’s take a look at what it can do.

Ryan Cavanaugh, not the famous Banjo Player, the one on the VS Pro Tools Team, helped me put together an artillery game called BurnedLand. (Kudos if you can catch the subtle reference.)  To play the game you adjust the Power, Angle, and Mass of your cannon ball so that when you fire it will (hopefully) hit the red tank.

clip_image001

In this post I’d like to highlight how this project takes advantage of:

  • The F# Project System
  • Units of Measure
  • WPF and data binding

The F# Project System

Rather than lumping all the code together into a single project, I separated out the game logic into an F# library and left all the UI in a C# WPF application. Since the F# Project System now supports project-to-project references, this all ‘just works’ like you would expect. If you tried multi-project development in the previous MSR Research releases, you know just what a pain this used to be.

Also, check out the sexy new F# icons!

clip_image002

Units of Measure

For calculating the cannon ball’s trajectory, you have to factor in gravity, velocity, position, time, etc. Using Units of Measure ensures that logic errors are caught at compile time by double-checking your math. (Check out Andrew’s blog for more info.)

clip_image003

Here’s a simpler example. Notice that multiplying a value with unit <m/s^2> by <s> * <s> results in a value with unit <m>.

clip_image004

Windows Presentation Foundation

One of the best features of WPF is databinding. Rather than programmatically updating UI elements whenever a value changes in the game logic module, you can use WPF data binding and the UI will always be in sync with no manual intervention.

For example, the game logic module in F# adds three simple properties for describing aspects of the Wind.

 // ----- Wind -----
member this.Wind with get   = m_wind
                 and  set x = m_wind <- x
                              m_PropertyChanged.Trigger(this, new PropertyChangedEventArgs("Wind"))
                              m_PropertyChanged.Trigger(this, new PropertyChangedEventArgs("WindSpeed"))
                              m_PropertyChanged.Trigger(this, new PropertyChangedEventArgs("WindAngle"))

member this.WindAngle = Math.Atan2(float this.Wind.Y, float this.Wind.X) * (180.0 / Math.PI) 
   
member this.WindSpeed = String.Format("{0:0.0} m/s", this.Wind.Length)

 

By using data binding in WPF, the values are automatically up to date. In fact, if the Wind property ever changes, the UI elements will be updated via the PropertyChanged event in the game logic class.

                     <!-- Wind indicator -->
                    <Grid Width="{Binding DefaultBounds.Width}">
                        <Border Width="60" Height="60" BorderBrush="White" CornerRadius="60" RenderTransformOrigin="0.5,0.5">
                            <TextBlock Text="-->>>" HorizontalAlignment="Right" VerticalAlignment="Center"
                                       FontSize="6"
                                       Foreground="White" Margin="-8" />
                            <Border.RenderTransform>
                                <RotateTransform Angle="{Binding WindAngle}" />
                            </Border.RenderTransform>
                        </Border>
                        <TextBlock Text="{Binding WindSpeed}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
                    </Grid>

 

So the WPF value "{Binding WindSpeed}" is really a call to the F# code.

Disclaimer: All code samples are provided "AS IS" without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose. So in other words, if the attached source files cause you any grief whatsoever you can’t blame me or Microsoft.

BurnedLand-v1.0.zip