hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

XNA game studio

Last post 05-18-2007, 13:20 by Andyman. 17 replies.
Page 2 of 2 (18 items)   < Previous 1 2
Sort Posts: Previous Next
  •  09-18-2006, 0:50 655 in reply to 653

    Re: XNA game studio

    That looks nice.

    I think you made a typo: 'let VPC(pos,color) = VPC(pos,color)' should be 'let VPC(pos,color) = new VertexPositionColor(pos,color)'.

    Where is this coming? In the next release?
  •  09-18-2006, 8:56 657 in reply to 655

    Re: XNA game studio

    Thanks - have fixed that now, and the HTML formatting problems too.

    All going well it will be in the next major external release containing new functionality (we will in all likelihood do a few bug fixing stabilization releases before then).

    Cheers!

    Don

  •  05-18-2007, 13:20 3151 in reply to 571

    Re: XNA game studio

    Well, it's been a while but I have finally had a chance to have a proper play around with XNA  ... and it's great fun!  To start with I have ported the Primitives Sample across to F#.  The complete project, which will compile for PC and XBox 360, is here.  It was an interesting job and a couple of things came up;

    * The new class syntax is really nice, but it can't always, it seems, be used with XNA.  It seems to be a requiment imposed by the framework that you construct objects within a class constructor which must refer to the class itself - I can't see how to do that.  I think you'd need a syntax like

    type PrimitiveBatch(device : GraphicsDevice) = class as x

    to do this, but I am not sure what the consequences would be.  Either way the old syntax with "new(..) = {...} then" works fine.

    * I ported a class that needs to be constructed after the creation of the main game object, but also needs to be a member variable of said game.  This worked OK from C# but from F# the magic of null needed for initialisation disappeared.  To get round it I made the object an Option type - works fine, and I am happy with the results, but did take a bit of thinking about.

    * The sample manages an array of VertexPositionColor structs.  In C# the code started out as

    VertexPositionColor[] vertices = new VertexPositionColor[DefaultBufferSize];

    and was used like so;

    vertices[positionInBuffer].Position = new Vector3(vertex, 0);
    vertices[positionInBuffer].Color = color;


    In F# what I came up with is;

        Array.create DefaultBufferSize
          (new VertexPositionColor(new Vector3(0.0f,0.0f,0.0f), new Color(0uy,0uy,0uy)))


    and;

        let set_vertex idx =
          let mutable t = vertices.[idx]
          t.Position <- new Vector3(vertex, 0.0f)
          t.Color <- color
          vertices.[idx] <- t
        set_vertex positionInBuffer


    I am wondering whether these two bits of code really do the same things under the hood.  My impression is the C# version creates a flat array and copys data into it.  It's not clear to me that the F# version is doing the same thing.  I tried playing around with struct types in fsi.exe, but kept coming up errors like;

    error: forceM: envGetConsB: failed: x = {mrefParent = {trefScope = ScopeRef_local;
         trefNested = ["FSI_0003"];
         trefName = "ts";};
     mrefCallconv = Callconv (CC_instance,CC_default);
     mrefArity = 0;
     mrefName = ".ctor";

    In particular, I cant seem to update a mutable value in a struct.  It's quite probable I am doing something silly, but I cant seem to find much in the way of an example for using them.

    Anyhow, here's a version of the code which will compile and run directly - it's pretty much the same as the full XNA Game Studio example except the one dependacy on the content pipeline is commented out.

    Cheers,

    Andy.


    (**************************************************************************)
    #light
    #if XBOX360
    #I @"C:\Program Files\Microsoft XNA\XNA Game Studio Express\v1.0\References\Xbox360"
    #else
    #I @"C:\Program Files\Microsoft XNA\XNA Game Studio Express\v1.0\References\Windows\x86"
    #endif
    #r "Microsoft.Xna.Framework.dll"
    #r "Microsoft.Xna.Framework.Game.dll"
    open System
    open System.Collections.Generic
    open Microsoft.Xna.Framework
    open Microsoft.Xna.Framework.Audio
    open Microsoft.Xna.Framework.Content
    open Microsoft.Xna.Framework.Graphics
    open Microsoft.Xna.Framework.Input
    open Microsoft.Xna.Framework.Storage
    (**************************************************************************)
    type PrimitiveBatch(device : GraphicsDevice) = class
      let DefaultBufferSize = 500
      let vertices =
        Array.create DefaultBufferSize
          (new VertexPositionColor(new Vector3(0.0f,0.0f,0.0f), new Color(0uy,0uy,0uy)))
      let mutable positionInBuffer = 0
      let vertexDeclaration = new VertexDeclaration(device, VertexPositionColor.VertexElements);
      let basicEffect =
        let b = new BasicEffect(device, null)
        b.Projection <-
          Matrix.CreateOrthographicOffCenter(0.0f,
                                             float32 device.Viewport.Width,
                                             float32 device.Viewport.Height,
                                             0.0f, 0.0f, 1.0f)
        b
      let mutable primitiveType = PrimitiveType.TriangleList
      let mutable numVertsPerPrimitive = 3
      let mutable hasBegun = false
      let mutable isDisposed = false
      let NumVertsPerPrimitive(primitive) =
        match primitive with
        | PrimitiveType.PointList -> 1
        | PrimitiveType.LineList -> 2
        | PrimitiveType.TriangleList -> 3
        | _ -> raise (new InvalidOperationException("primitive is not valid"))
      let Dispose' disposing =
        if (disposing && not isDisposed) then
          if (vertexDeclaration <> null) then
            vertexDeclaration.Dispose()
          if (basicEffect <> null) then
            basicEffect.Dispose()
          isDisposed <- true
     
      interface IDisposable with
        member x.Dispose () =
          Dispose' true
          GC.SuppressFinalize(x);
      end
      member x.Begin primType =
        if hasBegun then
          raise (new InvalidOperationException ("End must be called before Begin can be called again."))
        if (primitiveType = PrimitiveType.LineStrip ||
            primitiveType = PrimitiveType.TriangleFan ||
            primitiveType = PrimitiveType.TriangleStrip) then
          raise (new NotSupportedException
                  ("The specified primitiveType is not supported by PrimitiveBatch."))
        primitiveType <- primType
        numVertsPerPrimitive <- NumVertsPerPrimitive(primitiveType)
        device.VertexDeclaration <- vertexDeclaration
        basicEffect.Begin()
        basicEffect.CurrentTechnique.Passes.get_Item(0).Begin() (* ??? get_Item instead of .[0] ??? *)
        hasBegun <- true
      member x.AddVertex(vertex:Vector2, color:Color) =
        if not hasBegun then
          raise (new InvalidOperationException
                  ("Begin must be called before AddVertex can be called."))
        let newPrimitive = (positionInBuffer % numVertsPerPrimitive) = 0
         
        if (newPrimitive &&
            (positionInBuffer + numVertsPerPrimitive) >= vertices.Length) then
          x.Flush()
        let set_vertex idx =
          let mutable t = vertices.[idx]
          t.Position <- new Vector3(vertex, 0.0f)
          t.Color <- color
          vertices.[idx] <- t
        set_vertex positionInBuffer
        positionInBuffer <- positionInBuffer + 1
      member x.End() =
        if (not hasBegun) then
          raise (new InvalidOperationException
                  ("Begin must be called before End can be called."))
        x.Flush()
        basicEffect.CurrentTechnique.Passes.get_Item(0).End()
        basicEffect.End()
        hasBegun <- false
      member x.Flush() =
        if (not hasBegun) then
          raise (new InvalidOperationException
                  ("Begin must be called before Flush can be called."))
        if (positionInBuffer <> 0) then
          let primitiveCount = positionInBuffer / numVertsPerPrimitive
          device.DrawUserPrimitives<VertexPositionColor>(primitiveType, vertices, 0, primitiveCount)
          positionInBuffer <- 0
    end
    (**************************************************************************)
           
    let (|Opt|) = function
      | Some x -> x
      | None -> failwith "Expecting something"
    type MyGame = class
      inherit Game as base
     
      val NumStars : int;
      val PercentBigStars : float;
      val MinimumStarBrightness : int;
      val MaximumStarBrightness : int;
      val ShipSizeX : float32;
      val ShipSizeY : float32;
      val ShipCutoutSize : float32;
      val SunSize : float32;
      val mutable graphics : GraphicsDeviceManager;
      val mutable content : ContentManager;
      val mutable primitiveBatch : PrimitiveBatch option;
     
      val stars : List<Vector2>;
      val starColors : List<Color>;
     
      val mutable courierNew : SpriteFont
      val mutable fgBatch : SpriteBatch
      new () as x =
        {
          NumStars = 500
          PercentBigStars = 0.2
          MinimumStarBrightness = 56
          MaximumStarBrightness = 255
          ShipSizeX = 10.0f
          ShipSizeY = 15.0f
          ShipCutoutSize = 5.0f
          SunSize = 30.0f
          primitiveBatch = None
          graphics = null
          content = null
          stars = new List<Vector2>();
          starColors = new List<Color>();
          courierNew = null
          fgBatch = null
        }
        then
          x.graphics <- new GraphicsDeviceManager(x)
          x.graphics.PreferredBackBufferWidth <- 853
          x.graphics.PreferredBackBufferHeight <- 480
          x.content <- new ContentManager(x.Services);
      override x.Initialize() =
        base.Initialize();
        x.CreateStars();
         
      member x.CreateStars() =
        let random = new Random()
        let screenWidth = x.graphics.GraphicsDevice.Viewport.Width
        let screenHeight = x.graphics.GraphicsDevice.Viewport.Height
        for i=0 to x.NumStars-1 do
          let where = new Vector2(float32 (random.Next(0, screenWidth)), float32 (random.Next(0, screenHeight)));
          let greyValue = byte (random.Next(x.MinimumStarBrightness, x.MaximumStarBrightness))
          let color = new Color(greyValue, greyValue, greyValue);
          if (((random.NextDouble())) > x.PercentBigStars) then
            x.starColors.Add(color);
            x.stars.Add(where);
          else
            for j=0 to 3 do
              x.starColors.Add(color);
            x.stars.Add(where);
            x.stars.Add(where + Vector2.UnitX);
            x.stars.Add(where + Vector2.UnitY);
            x.stars.Add(where + Vector2.One);  
      override x.LoadGraphicsContent(loadAllContent) =
        if loadAllContent then
          x.primitiveBatch <- Some(new PrimitiveBatch(x.graphics.GraphicsDevice))
          //x.courierNew <- x.content.Load<SpriteFont>("Courier New")
          x.fgBatch <- new SpriteBatch( x.graphics.GraphicsDevice )
      override x.UnloadGraphicsContent(unloadAllContent) =
          if (unloadAllContent) then
              x.content.Unload()
      override x.Update(gameTime) =
        if ((GamePad.GetState(PlayerIndex.One).Buttons.Back = ButtonState.Pressed) || Keyboard.GetState().IsKeyDown(Keys.Escape)) then
            x.Exit();
        base.Update(gameTime);
      override x.Draw(gameTime) =
          x.graphics.GraphicsDevice.Clear(Color.Black)
          let screenWidth = float32 x.graphics.GraphicsDevice.Viewport.Width
          let screenHeight = float32 x.graphics.GraphicsDevice.Viewport.Height
          x.DrawSun(new Vector2(screenWidth / 2.0f, screenHeight / 2.0f))
          x.DrawShip(new Vector2(100.0f, screenHeight / 2.0f))
          x.DrawShip(new Vector2(screenWidth - 100.0f, screenHeight / 2.0f))
          x.DrawStars()
          //x.DrawText gameTime
          base.Draw(gameTime)
      member x.DrawText (time : GameTime) =
        let ms = float time.ElapsedGameTime.Milliseconds
        let str = "ms = " ^ string_of_float ms ^ " fps = " ^ string_of_float (1000.0 / ms)
        let FontRotation = 0.0f
        let FontOrigin = Vector2(0.0f,0.0f)
        let FontPos = Vector2(100.0f, 100.0f)
        x.fgBatch.Begin()
        x.fgBatch.DrawString(x.courierNew, str, FontPos, Color.LightGreen, FontRotation, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);
        x.fgBatch.End()
      member x.DrawStars() =
        let Opt primitiveBatch = x.primitiveBatch
        primitiveBatch.Begin(PrimitiveType.PointList)
        for i=0 to x.stars.Count - 1 do
            primitiveBatch.AddVertex(x.stars.[ i ], x.starColors.[ i ])
        primitiveBatch.End()
                 
      member x.DrawShip(where) =
        let Opt primitiveBatch = x.primitiveBatch
        primitiveBatch.Begin(PrimitiveType.LineList);
        primitiveBatch.AddVertex(where + new Vector2(0.0f, -x.ShipSizeY), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(-x.ShipSizeX, x.ShipSizeY), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(-x.ShipSizeX, x.ShipSizeY), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(0.0f, x.ShipSizeY - x.ShipCutoutSize), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(0.0f, x.ShipSizeY - x.ShipCutoutSize), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(x.ShipSizeX, x.ShipSizeY), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(x.ShipSizeX, x.ShipSizeY), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(0.0f, -x.ShipSizeY), Color.White);
        primitiveBatch.End();
      member x.DrawSun(where) =
        let Opt primitiveBatch = x.primitiveBatch
        primitiveBatch.Begin(PrimitiveType.LineList)
        primitiveBatch.AddVertex(where + new Vector2(0.0f, x.SunSize), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(0.0f, -x.SunSize), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(x.SunSize, 0.0f), Color.White);
        primitiveBatch.AddVertex(where + new Vector2(-x.SunSize, 0.0f), Color.White);
        let sunSizeDiagonal = (float32 (Math.Cos(float MathHelper.PiOver4)) * x.SunSize)
        primitiveBatch.AddVertex(where + new Vector2(-sunSizeDiagonal, sunSizeDiagonal), Color.Gray);
        primitiveBatch.AddVertex(where + new Vector2(sunSizeDiagonal, -sunSizeDiagonal), Color.Gray);
        primitiveBatch.AddVertex(where + new Vector2(sunSizeDiagonal, sunSizeDiagonal), Color.Gray);
        primitiveBatch.AddVertex(where + new Vector2(-sunSizeDiagonal, -sunSizeDiagonal), Color.Gray);
        primitiveBatch.End();
    end
    (**************************************************************************)
    let main() =
        let game = new MyGame()
        game.Run()
    (**************************************************************************)
    do main()

Page 2 of 2 (18 items)   < Previous 1 2
View as RSS news feed in XML
Powered by Community Server, by Telligent Systems