strangelights.com

Main F# Site

Edit Edit
Print Print
Recent Changes Recent Changes
Subscriptions Subscriptions
Lost and Found Lost and Found
Find References Find References
Rename Rename
Search
List all versions List all versions
Light Cycles
.

Compile code with --define DIRECTX to play with XBox 360 controllers - you will need the February 2006 DirectX SDK installed.

    //-----------------------------------------------------------------------------
    // LightCycles.fs  Mini game using windows forms
    //
    // 2007 written by Phillip Trelford
    //-----------------------------------------------------------------------------


    #light


    #if DIRECTX // February 2006 DirectX SDK
    #R @"C:\WINDOWS\assembly\GAC_32\Microsoft.DirectX\2.0.0.0__31bf3856ad364e35\Microsoft.DirectX.dll" 
    open Microsoft.DirectX.XInput   // Required to read XBox 360 controllers
    #endif


    open System
    open System.Drawing
    open System.Windows.Forms


    /// Game states
    type GameState = | Start | Play | Over


    /// Form key handler type
    type KeyHandler (form:Form) =
        do form.KeyPreview <- true   
        let keys = Enum.GetValues (type Keys) :?> (Keys [])
        let keysDown = Array.create keys.Length false
        let FindKeyIndex code = keys |> Array.find_index (fun x -> code = x)
        do  form.KeyDown.Add    (fun e -> keysDown.[FindKeyIndex e.KeyCode] <- true)
        do  form.KeyUp.Add      (fun e -> keysDown.[FindKeyIndex e.KeyCode] <- false)   
        member this.IsKeyDown (keyCode:Keys) = keysDown.[FindKeyIndex keyCode]   
        member this.AnyKeyDown () = keysDown |> Array.exists (fun x -> x)    


    /// Player direction type
    type Direction = | Left | Right | Up | Down


    /// Player type
    type Player (color,startX,startY,direction,keys,keyHandler:KeyHandler) =
        let mutable x = startX
        let mutable y = startY
        let mutable d = direction


        member this.Color = color
        member this.X = x
        member this.Y = y
        member this.Keys = keys


        /// Reset player to start values
        member this.Reset () = x <- startX; y <- startY; d <- direction   


        /// Updates player position       
        member this.Update i =
            // Read keyborad
            let mutable newD = d
            let up, down, left, right = keys
            if keyHandler.IsKeyDown(up) then newD <- Up
            if keyHandler.IsKeyDown(down) then newD <- Down
            if keyHandler.IsKeyDown(left) then newD <- Left
            if keyHandler.IsKeyDown(right) then newD <- Right
    #if DIRECTX        
            // Read XBox 360 controller 
            let state = Controller.GetState(i)
            if state.IsConnected then
                let pad = state.GamePad
                if pad.UpButton then newD <- Up
                if pad.DownButton then newD <- Down
                if pad.LeftButton then newD <- Left
                if pad.RightButton then newD <- Right
    #endif            
            /// Don't allow suicide move
            match (d,newD) with
                | (Left, Right) | (Right, Left) | (Up, Down) | (Down, Up) -> ()
                | _ -> d <- newD   
            /// Update position with direction                         
            match d with
                | Up    -> y <- y - 1
                | Down  -> y <- y + 1
                | Left  -> x <- x - 1
                | Right -> x <- x + 1


    /// Main form         
    let form = new Form (Text="Light Cycles", Width=680, Height=544)       


    do  /// Layout for game window and status panel
        let layout = new TableLayoutPanel(Dock=DockStyle.Fill, ColumnCount = 2)        
        layout.ColumnStyles.Add( ColumnStyle(SizeType = SizeType.Percent, Width = 100.0f ) ) |> ignore
        layout.ColumnStyles.Add( ColumnStyle(SizeType = SizeType.Absolute, Width = 128.0f) ) |> ignore
        /// Play area in pixels
        let playArea = 500
        /// Game play area bitmap
        let bm = new Bitmap(playArea, playArea)
        /// Clears screen
        let ClearScreen () = 
            using (Graphics.FromImage(bm)) (fun graphics -> graphics.Clear(Color.Black))
        /// Draws text to screen
        let DrawText s =
            using (Graphics.FromImage(bm)) (fun graphics -> 
                let rect = new RectangleF(0.0f,0.0f,float32 playArea,float32 playArea)
                let align = new StringFormat(Alignment=StringAlignment.Center, LineAlignment=StringAlignment.Center)
                graphics.DrawString(s, form.Font, Brushes.White, rect, align)
            )    
        // Initialise screen        
        ClearScreen ()
        DrawText "Press any key to start"                    
        /// PictureBox to contain game bitmap
        let pictureBox = new PictureBox(Dock=DockStyle.Fill)
        pictureBox.Image <- bm    
        layout.Controls.Add(pictureBox)    


        let keyHandler = KeyHandler (form)


        /// Players array        
        let players = 
            [|  Player (Color.Red,playArea/2+20,playArea/2,Down,(Keys.Q,Keys.A,Keys.Z,Keys.X),keyHandler); 
                Player (Color.LightBlue,playArea/2-20,playArea/2,Up,(Keys.P,Keys.L,Keys.N,Keys.M),keyHandler)  |]
        players |> Array.iter (fun player -> bm.SetPixel(player.X,player.Y,player.Color))  


        /// Display player controls
        let statusPanel = new TableLayoutPanel(Dock=DockStyle.Fill, ColumnCount=1, BackColor=Color.DarkGray)
        players |> Array.iteri (fun i player ->
            let name = 
                [| ((new Label (Text=sprintf "Player %d" i, ForeColor=player.Color)) :> Control) |]
            let up, down, left, right = player.Keys
            let controls = 
                Array.combine [|"Up";"Down";"Left";"Right"|] [|up;down;left;right|]
                |> Array.map (fun (name,key) -> (new Label (Text=sprintf "%s '%O'" name key)) :> Control )
            Array.append name controls
            |> statusPanel.Controls.AddRange
        )
        layout.Controls.Add(statusPanel)
        form.Controls.Add(layout)        


        /// Game play - returns true if there has been a collision otherwise false
        let PlayGame () = 
            let collisions = players |> Array.mapi (fun i player -> 
                player.Update i
                let x, y = (player.X, player.Y)
                let wall = x < 0 || x >= playArea || y < 0 || y >= playArea
                if wall then
                    true
                else      
                    let bgColor = bm.GetPixel(x, y)                
                    bm.SetPixel (x, y, player.Color)
                    players |> Array.exists (fun player -> let c = player.Color in c.R = bgColor.R && c.G = bgColor.G && c.B = bgColor.B )              
            ) 
            pictureBox.Refresh ()


            match collisions |> Array.tryfind_index (fun x -> x = true) with
            | Some(i) -> i
            | None -> (-1)     


        /// Current game state
        let gameState = ref GameState.Start
        let gameOverWaitCount = ref 200
        let r = new Random()


        /// Timer instance
        let timer = new Timer()
        timer.Interval <- 1000/50
        // Timer event
        timer.Tick.Add (fun _ ->
            match !gameState with
            | Start ->
                if keyHandler.AnyKeyDown () then 
                    ClearScreen ()           
                    gameState := GameState.Play


            | Play -> 
                let i = PlayGame ()
                if i>=0 then                 
                    gameState := GameState.Over
                    gameOverWaitCount := 200
                    DrawText (sprintf "Game Over - Play %d Lost" i)
                    pictureBox.Refresh ()                                                
            | Over ->            
                // Shake screen
                form.Left <- form.Left + if !gameOverWaitCount > 150 then r.Next(5) - 2 else 0
                // Decrement Game Over wait
                decr gameOverWaitCount
                if !gameOverWaitCount <= 0 then                 
                    gameState := GameState.Start
                    players |> Array.iter (fun player -> player.Reset ())
                    ClearScreen ()
                    DrawText "Press any key to start"
                    pictureBox.Refresh ()                
        )   
        timer.Start ()


    [<STAThread>]    
    do Application.Run(form)


Welcome to F Sharp Wiki, view the HomePage

This site supports the new NoFollow anti-spam initiative.

Recent Topics

Copyright 2005, Robert Pickering (Others where credited) | Terms of Use