This blog is no longer updated. Feel free to copy any useful information to other blogs or wikis as this site may not exist for much longer. Thanks.


Pong in F# with XNA Game Studio

February 2nd, 2010 | 1 comment

A few of my colleagues were discussing F# today and when/where/how it is/isn’t better than C#. I haven’t ever really used F# beyond a very, very brief look at the syntax, so tonight I decided to see what it was all about. As a little project, I decided to make Pong with XNA Game Studio using F# with Visual Studio 2010. :P

F# Pong

I will say that I’ve determined that F# probably has good uses, but my mind is still riding the object oriented train so it’s pretty hard to see how I could do more functional programming for game development. Even my F# is very much standard OO but with a new syntax. In that respect it’s hardly worth showing off, but in the interest of humor (I’ll go with that), I’ve decided to go ahead and talk about the project and the issues to overcome.

First I wanted to use VS 2010. This immediately means no (easy) way to build content. Therefore I needed to do any graphics in code. Not a terribly big deal until I wanted to display a score, but I opted to just show dots representing points (which, by the way, are not clamped in my game so I’m sure after a dozen or two there’ll be a mess up there).

Next I wanted to target .NET 4.0 (since that’s a good part of the reason to use VS 2010). But since the XNA Framework is compiled with the .NET 2.0 CLR in mind and .NET 4.0 has a whole new CLR, there’s a bit of an issue right out of the game if you add your XNA references and hit build. This is easily solved by adding an App.config file with the following in it:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<startup useLegacyV2RuntimeActivationPolicy="true">
		<supportedRuntime version="v4.0"/>
	</startup>
</configuration>

I’m not a CLR person, but from what I’ve read, this allows me to use v2 runtime libraries with a v4 runtime (and no, there is no v3 runtime from what I’ve read; .NET 3.0 and 3.5 use the v2 runtime. But again, I’m not a big CLR person so correct me if I’m wrong :) ).

From there it was all just hacking away. Keeping in mind I learned F# just a few hours ago, here’s the entirety of my code, with no syntax highlighting since my code pasting stuff doesn’t support F#:

open System
open Microsoft.Xna.Framework
open Microsoft.Xna.Framework.Graphics
open Microsoft.Xna.Framework.Input

type Paddle(posX : int, posY : int) =
    let speed = 5
    let x = posX
    let mutable y = posY

    static member W = 10
    static member H = 80

    member this.X with get() = x
    member this.Y with get() = y and set v = y <- v
    member this.Bounds
        with get() = new Rectangle(x - Paddle.W / 2, y - Paddle.H / 2, Paddle.W, Paddle.H)

    member this.Move (keyUp : Keys) (keyDown : Keys) =
        let ks = Keyboard.GetState()
        if ks.IsKeyDown(keyUp)
            then y <- y - speed
        if ks.IsKeyDown(keyDown)
            then y <- y + speed

type Ball() =
    let mutable x = 0
    let mutable y = 0

    let mutable vx = 0
    let mutable vy = 0

    static member W = 10
    static member H = 10

    member this.X with get() = x and set v = x <- v
    member this.Y with get() = y and set v = y <- v
    member this.Bounds
        with get() = new Rectangle(x - Ball.W / 2, y - Ball.H / 2, Ball.W, Ball.H)

    member this.BounceX() = vx <- -vx
    member this.BounceY() = vy <- -vy

    member this.Start (velX : int) (velY : int) =
        vx <- velX
        vy <- velY

    member this.Update() =
        x <- x + vx
        y <- y + vy

    member this.Collide (p : Paddle) = this.Bounds.Intersects(p.Bounds)

type Game1() as this =
    inherit Game()
    let graphics = new GraphicsDeviceManager(this)

    let mutable spriteBatch = null
    let mutable texture = null

    let left = new Paddle(Paddle.W * 2, 300)
    let right = new Paddle(800 - (Paddle.W * 2), 300)
    let ball = new Ball()

    let rand = new Random()

    let mutable leftScore = 0
    let mutable rightScore = 0

    let clampY x : int =
        if x < Paddle.H / 2 then Paddle.H / 2
        else if x > 600 - (Paddle.H / 2) then 600 - (Paddle.H / 2)
        else x

    let reset (b : Ball) =
        let mutable x = 0
        let mutable y = 0

        if rand.Next() % 2 = 0 then x <- -3 else x <- 3
        if rand.Next() % 2 = 0 then y <- -3 else y <- 3

        b.X <- 400
        b.Y <- 300
        b.Start x y

    let bounce (b : Ball) =
        if b.X < Ball.W / 2 then
            rightScore <- rightScore + 1
            reset b
        else if b.X > 800 - Ball.W / 2 then
            leftScore <- leftScore + 1
            reset b

        if b.Y < Ball.H / 2 then
            b.Y <- Ball.H / 2
            b.BounceY()
        else if b.Y > 600 - Ball.H / 2 then
            b.Y <- 600 - Ball.H / 2
            b.BounceY()

    override Game.LoadContent() =
        spriteBatch <- new SpriteBatch(this.GraphicsDevice)
        texture <- new Texture2D(this.GraphicsDevice, 1, 1);
        texture.SetData([| Color.White |])
        reset ball

    override Game.Update gameTime =
        left.Move Keys.Q Keys.A
        right.Move Keys.O Keys.L
        ball.Update()
        bounce ball
        left.Y <- clampY left.Y
        right.Y <- clampY right.Y

        if ball.Collide(left) || ball.Collide(right) then
            ball.BounceX()

    override Game.Draw gameTime =
        this.GraphicsDevice.Clear(Color.Black)
        spriteBatch.Begin()
        spriteBatch.Draw(texture, left.Bounds, Color.Lime)
        spriteBatch.Draw(texture, right.Bounds, Color.Lime)
        spriteBatch.Draw(texture, ball.Bounds, Color.Lime)

        for i in 1 .. leftScore do
            let r = new Rectangle(50 + i * 10, 5, 5, 5)
            spriteBatch.Draw(texture, r, Color.White);
        for i in 1 .. rightScore do
            let r = new Rectangle(750 - i * 10 - 5, 5, 5, 5)
            spriteBatch.Draw(texture, r, Color.White);

        spriteBatch.End()
        base.Draw(gameTime)

let g = new Game1()
try g.Run()
finally g.Dispose()

So there you go. If you’ve ever wanted to make a game with XNA Game Studio using F#, it can be done. It’s interesting, to say the least, but I’m sticking with my C# for now. :)


Possibly Related Posts

(Automatically Generated)
Editing The Default XNA Game Studio Project Templates
XNA Game Studio 3.0 Dated for October 30th
Sprite Sheet Packer Tool – XNA GS Example
How Not To Write A Game – The Reports of the Xbox 360 GC Are Greatly Exaggerated
Dynamically Refreshed Assets in XNA

  1. July 2nd, 2010 at 00:14
    Quote | #1

    Not sure if you’ve spotted it, but it looks like you’re using syntax highlighter. In that case here’s a pretty good F# brush someone made that you can just dump into the folder that holds the brushes for the other languages. I use it here, for example: http://codernub.blogspot.com/2010/05/bowling-kata-in-f-yup-more-bowling.html

    That being said, I’m guessing you won’t be tossing up that many more F# posts. ;)

Comments are closed.