Cow Pong: A simple Xna game in F#


F# is akin of melting pot language, including some interesting features from various functional languages like Haskell, OCaml and so on. It is very succint, readable and it is ML-based.
I’ve realized a simple Pong-clone game using the XNA framework in F#, and this is the result:

// A semiserious game // Learn more about F# at http://fsharp.net open System open Microsoft.Xna.Framework open Microsoft.Xna.Framework.Graphics open Microsoft.Xna.Framework.Input open Microsoft.Xna.Framework.Content type Paddle(posX : int, posY : int) =     let speed = 10     let x = posX     let mutable y = posY     static member W = 50     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 - 100, 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     let mutable number_of_bounce = 10     static member W = 20     static member H = 20     member this.Number_of_bounce         with get() = number_of_bounce and set v = number_of_bounce <- v     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() =         this.Number_of_bounce <- this.Number_of_bounce + 1         vx <- -vx     member this.BounceY() = vy <- -vy     member this.Start (velX : int) (velY : int) =         vx <- velX         vy <- velY     member this.Update() =         x <- x + (int (this.Number_of_bounce/10))*vx         y <- y + (int (this.Number_of_bounce/10))*vy     member this.Collide (p : Paddle) = this.Bounds.Intersects(p.Bounds) type Game1() as this =     inherit Game()     let graphics = new GraphicsDeviceManager(this)     let contentManager = new ContentManager(this.Services)     let mutable spriteBatch = null     let mutable texture = null     let mutable left_paddle = null     let mutable background = null     let mutable ball_texture = null     let left = new Paddle(Paddle.W * 2, 300)     let right = new Paddle(820, 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.Number_of_bounce <- 10         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 > 480 - Ball.H / 2 then             b.Y <- 480 - Ball.H / 2             b.BounceY()     override Game.LoadContent() =         spriteBatch <- new SpriteBatch(this.GraphicsDevice)         background <- contentManager.Load<Texture2D>("xnb/green-field")         left_paddle <- contentManager.Load<Texture2D>("xnb/cow")         ball_texture <- contentManager.Load<Texture2D>("xnb/sheep")         texture <- new Texture2D(this.GraphicsDevice, 1, 1);         texture.SetData([| Color.White |])         reset ball     override Game.Update gameTime =         left.Move Keys.W Keys.S         right.Move Keys.Up Keys.Down         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.Beige)         spriteBatch.Begin()         spriteBatch.Draw(background, new Vector2(0.0f, 0.0f), Color.White)         spriteBatch.Draw(left_paddle, left.Bounds, Color.White)         spriteBatch.Draw(left_paddle, right.Bounds, Color.White)         spriteBatch.Draw(ball_texture, ball.Bounds, Color.White)         for i in 1 .. leftScore do             let r = new Rectangle(50 + i * 10, 5, 5, 5)             spriteBatch.Draw(texture, r, Color.Black);         for i in 1 .. rightScore do             let r = new Rectangle(750 - i * 10 - 5, 5, 5, 5)             spriteBatch.Draw(texture, r, Color.Black);         spriteBatch.End()         base.Draw(gameTime) let g = new Game1() try g.Run() finally g.Dispose()

At the end of the post I will link the entire project as well. As you can see it’s very easy to create a game from scratch, thanks to the support of the XNA Framework. The only tangible problem is related to the creation of the sprites file, due to the lack of support for Contents creation in Visual Studio F#.
A possible workaround is to create a dummy C# project, load all your images there and then compile. You will find all the created .xnb files inside the project directory. Finally, you need to copy the generated files into your bin directory. Here is a screenshot:

And there you can download the entire project:

CowPong.zip

Enjoy!

5 thoughts on “Cow Pong: A simple Xna game in F#

  1. As a total stranger to functional programming, in the past few months I have been constantly amazed by this type of examples (not to mention scared :p). More and more examples are surfacing, some of them mixed with Rx Framework…

    If it is not too much to ask:
    – Is this the future? Can we expect in the near future to be programming the functional way?
    – When declaring a variable (I bet these are not the terms in F# world, I mean “let speed = 0”) the operator is “=” but when used anywhere else is “<-".
    – "let x = posX", but "let mutable y = posY". Is this like "x won't change" but "y will", as in "y" will "mutate" ?

  2. Hi, and thanks for posting that.

    1) I hope so. Indeed, the OOP it’s a great way to programming, but is not the only one. For years, the functional programmers used to “hide” from others, due to the lack of support for his preferred programming paradigm. F# is the first language officially supported by a huge company as Microsoft, and it’s fully compatible with the XNA framework and the .NET APIs. Yes, the future is near.

    2) The main difference between = and <- is in the let keyword. When we define for the first time a variable or a mutable or even a function, we use the let keyword. We can define both variable:

    let a = 3

    or functions:

    let square x = x * x

    Obviously we can't modify neither a nor square, as you may know, the functional programming is almost free by side effects. In order to introduce them, we need a special keyword, mutable:

    let mutable b = 5;;
    b <- 10;;

    Now b evaluates to 10.
    Bye!
    Alfredo

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...