Farseer 3.3.1 - Bodies not colliding??

Topics: User Forum
Jan 28, 2012 at 10:49 PM

Hi all,

I'm using Farseer 3.3.1, and am working on a my own version of the "Hello World" sample with the only main difference being that I'm using my own textures and compound polygon shapes instead of the simple circle/rectangle shapes that Hello world uses. I have written the code in VB, and my problem seems to be that my player body simply passes through my terrain body without any collision. I have added "DebugView" in hopes that it woud help me out, but I cannot see the outlines of my terrain anywhere... Either I am missing something really obvious, or I am misunderstanding something... Here is my code - any pointers in the right direction would be appreciated:

Imports FarseerPhysics.Dynamics
Imports FarseerPhysics.Common
Imports FarseerPhysics.Common.Decomposition
Imports FarseerPhysics.Common.PolygonManipulation
Imports FarseerPhysics.Factories
Imports FarseerPhysics.DebugViews

''' <summary>
''' This is the main type for your game
''' </summary>
Public Class Game1
    Inherits Microsoft.Xna.Framework.Game

    Private DebugView As DebugViewXNA
    Private Const MeterInPixels As Single = 64.0F

    'Simple camera controls
    Private View As Matrix
    Private CameraPosition As Vector2
    Private ScreenCenter As Vector2

    Private WithEvents graphics As GraphicsDeviceManager
    Private WithEvents spriteBatch As SpriteBatch

    Dim CurrentKeyBoardState As KeyboardState
    Dim PreviousKeyBoardState As KeyboardState

    Private Origin As Vector2
    Private Scale As Single

    Private TerrainTexture As Texture2D
    Private TerrainFixture As Fixture
    Private PlayerTexture As Texture2D

    Private TerrainCompoundBody As Body
    Private PlayerCompoundBody As Body

    Private PlayerPosition As Vector2
    Private TerrainPosition As Vector2

    Private World As World

    Public Sub New()
        graphics = New GraphicsDeviceManager(Me)
        Content.RootDirectory = "Content"
    End Sub

    ''' <summary>
    ''' Allows the game to perform any initialization it needs to before starting to run.
    ''' This is where it can query for any required services and load any non-graphic
    ''' related content.  Calling MyBase.Initialize will enumerate through any components
    ''' and initialize them as well.
    ''' </summary>
    Protected Overrides Sub Initialize()
        World = New World(New Vector2(0, 1)) '9.81F

        'Initialize camera controls
        View = Matrix.Identity
        CameraPosition = Vector2.Zero
        ScreenCenter = New Vector2(GraphicsDevice.Viewport.Width / 2.0F, GraphicsDevice.Viewport.Height / 2.0F)

        PlayerPosition = (ScreenCenter / MeterInPixels) + New Vector2(0, -1.5F)
        TerrainPosition = (ScreenCenter / MeterInPixels) '+ New Vector2(0, -1.25F)


        Me.IsMouseVisible = True
        MyBase.Initialize()
    End Sub

    ''' <summary>
    ''' LoadContent will be called once per game and is the place to load
    ''' all of your content.
    ''' </summary>
    Protected Overrides Sub LoadContent()
        ' Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = New SpriteBatch(GraphicsDevice)

        'load texture that will represent the physics body
        TerrainTexture = Content.Load(Of Texture2D)("Images/Terrain11")
        'Create an array to hold the data from the texture
        Dim TerrainTextureData As UInteger() = New UInteger(TerrainTexture.Width * TerrainTexture.Height - 1) {}
        'Transfer the texture data to the array
        TerrainTexture.GetData(TerrainTextureData)
        'Find the vertices that makes up the outline of the shape in the texture
        Dim TerrainVertices As Vertices = PolygonTools.CreatePolygon(TerrainTextureData, TerrainTexture.Width)
        'For now we need to scale the vertices (result is in pixels, we use meters)
        Dim Scale As Vector2 = New Vector2(1.0F, 1.0F)
        TerrainVertices.Scale(Scale)
        'Since it is a concave polygon, we need to partition it into several smaller convex polygons
        Dim TerrainPolygonList As List(Of Vertices) = BayazitDecomposer.ConvexPartition(TerrainVertices)
        'Create a single body with multiple fixtures
        TerrainCompoundBody = BodyFactory.CreateCompoundPolygon(World, TerrainPolygonList, 1.0F, TerrainPosition)
        'TerrainCompoundBody.BodyType = BodyType.Static
        'TerrainCompoundBody.Position = TerrainPosition
        TerrainCompoundBody.IsStatic = True
        TerrainCompoundBody.Awake = True

        PlayerTexture = Content.Load(Of Texture2D)("Images/Player/Idle")
        'Create an array to hold the data from the texture
        Dim PlayerTextureData As UInteger() = New UInteger(PlayerTexture.Width * PlayerTexture.Height - 1) {}
        'Transfer the texture data to the array
        PlayerTexture.GetData(PlayerTextureData)
        'Find the vertices that makes up the outline of the shape in the texture
        Dim PlayerVertices As Vertices = PolygonTools.CreatePolygon(PlayerTextureData, PlayerTexture.Width)
        'For now we need to scale the vertices (result is in pixels, we use meters)
        'Dim Scale As Vector2 = New Vector2(0.0F, 0.0F)
        PlayerVertices.Scale(Scale)
        'Since it is a concave polygon, we need to partition it into several smaller convex polygons
        Dim PlayerPolygonList As List(Of Vertices) = BayazitDecomposer.ConvexPartition(PlayerVertices)
        'Create a single body with multiple fixtures
        PlayerCompoundBody = BodyFactory.CreateCompoundPolygon(World, PlayerPolygonList, 1.0F, PlayerPosition)
        PlayerCompoundBody.BodyType = BodyType.Dynamic
        'Convert screen center from pixels to meters
        'PlayerCompoundBody.Position = PlayerPosition
        PlayerCompoundBody.IsStatic = False
        PlayerCompoundBody.Awake = True

        'Debug View Code:
        DebugView = New DebugViewXNA(World)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.Shape)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.DebugPanel)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.PerformanceGraph)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.Joint)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.ContactPoints)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.ContactNormals)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.Controllers)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.CenterOfMass)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.AABB)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.PolygonPoints)
        DebugView.AppendFlags(FarseerPhysics.DebugViewFlags.Pair)

        DebugView.DefaultShapeColor = Color.White
        DebugView.SleepingShapeColor = Color.LightGray
        DebugView.LoadContent(GraphicsDevice, Content)
    End Sub

    ''' <summary>
    ''' UnloadContent will be called once per game and is the place to unload
    ''' all content.
    ''' </summary>
    Protected Overrides Sub UnloadContent()
        ' TODO: Unload any non ContentManager content here
    End Sub

    ''' <summary>
    ''' Allows the game to run logic such as updating the world,
    ''' checking for collisions, gathering input, and playing audio.
    ''' </summary>
    ''' <param name="gameTime">Provides a snapshot of timing values.</param>
    Protected Overrides Sub Update(ByVal gameTime As GameTime)
        ' Allows the game to exit
        If GamePad.GetState(PlayerIndex.One).Buttons.Back = ButtonState.Pressed Then
            Me.Exit()
        End If

        PreviousKeyBoardState = CurrentKeyBoardState

        CurrentKeyBoardState = Keyboard.GetState()
        If CurrentKeyBoardState.IsKeyDown(Keys.Up) And Not PreviousKeyBoardState.IsKeyDown(Keys.Up) Then
            'PlayerCompoundBody.ApplyLinearImpulse(New Vector2(0, -10)) 'ApplyAngularImpulse(20)
        End If

        'Switch between circle body and camera control
        If (CurrentKeyBoardState.IsKeyDown(Keys.LeftShift) Or CurrentKeyBoardState.IsKeyDown(Keys.RightShift)) Then
            'Move camera
            If (CurrentKeyBoardState.IsKeyDown(Keys.A)) Then
                CameraPosition.X += 2.0F
            End If
            If (CurrentKeyBoardState.IsKeyDown(Keys.D)) Then
                CameraPosition.X -= 2.0F
            End If
            If (CurrentKeyBoardState.IsKeyDown(Keys.W)) Then
                CameraPosition.Y += 2.0F
            End If
            If (CurrentKeyBoardState.IsKeyDown(Keys.S)) Then
                CameraPosition.Y -= 2.0F
            End If
            View = Matrix.CreateTranslation(New Vector3(CameraPosition - ScreenCenter, 0.0F)) *
                    Matrix.CreateTranslation(New Vector3(ScreenCenter, 0.0F))
        End If


        World.Step(CSng(gameTime.ElapsedGameTime.TotalSeconds))

        ' TODO: Add your update logic here
        MyBase.Update(gameTime)
    End Sub

    ''' <summary>
    ''' This is called when the game should draw itself.
    ''' </summary>
    ''' <param name="gameTime">Provides a snapshot of timing values.</param>
    Protected Overrides Sub Draw(ByVal gameTime As GameTime)
        GraphicsDevice.Clear(Color.CornflowerBlue)
        Dim TerrainOrigin As Vector2 = New Vector2(TerrainTexture.Width / 2.0F, TerrainTexture.Height / 2.0F)
        Dim PlayerOrigin As Vector2 = New Vector2(PlayerTexture.Width / 2.0F, PlayerTexture.Height / 2.0F)
        Dim PlayerPos As Vector2 = PlayerCompoundBody.Position * MeterInPixels
        Dim TerrainPos As Vector2 = TerrainCompoundBody.Position * MeterInPixels

        spriteBatch.Begin(SpriteSortMode.Deferred, Nothing, Nothing, Nothing, Nothing, Nothing, View)
        spriteBatch.Draw(TerrainTexture, TerrainPos, Nothing, Color.White, 0.0F, TerrainOrigin, 1.0F, SpriteEffects.None, 0.0F)
        spriteBatch.Draw(PlayerTexture, PlayerPos, Nothing, Color.White, 0.0F, PlayerOrigin, 1.0F, SpriteEffects.None, 0.0F)

        ' calculate the projection and view adjustments for the debug view
        Dim proj As Matrix = Matrix.CreateOrthographicOffCenter(0.0F, _graphics.GraphicsDevice.Viewport.Width / MeterInPixels, _graphics.GraphicsDevice.Viewport.Height / MeterInPixels, 0.0F, 0.0F, 1.0F)
        Dim dview As Matrix = Matrix.CreateTranslation(New Vector3((CameraPosition / MeterInPixels) - (ScreenCenter / MeterInPixels), 0.0F)) * Matrix.CreateTranslation(New Vector3((ScreenCenter / MeterInPixels), 0.0F))
        'Render Debug Data:
        DebugView.RenderDebugData(proj, dview)

        spriteBatch.End()
        ' TODO: Add your drawing code here
        MyBase.Draw(gameTime)
    End Sub

End Class