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:
Enjoy!