Bashin my head trying to figure how to make this work! help

Sep 5, 2009 at 5:03 PM

Hi,

Could you have coded this any more confusing? I am trying to recreate your example but all I am getting is white screen when I call UpdateEnd() after UpdateBegin and game freezes waiting for some event I think...

What are the most necessary components to make the basic code run? What is GameExtension class and how do I refernce it within my game? Why are you using GetContent() method? Is it not easier to just do "Content.Load"?

Is it necessary to load ui componet, framerate, gamecomponent, viepoints etc or just physics alone is enough?

Coordinator
Sep 8, 2009 at 2:48 AM

The AsyncGameComponent is used to "update" a GameComponent (i.e., call the Update(GameTime) method) on a thread different from the main game thread.  Right now,  the PhysicsComponent is the only component in the framework that inherits from it.  See the ExampleScreen.cs file for an example.

The correct usage of the AsyncGameComponent is to call EndUpdate first to block/wait for the previous frame to finish processing.  After that you can use data from the AsyncGameComponent in a thread-safe manner.  When finished accessing the data, call BeginUpdate(GameTime) to start the update process on the component for the current frame. So:

public void Update(GameTime gameTime)
{
     this.physics.EndUpdate();
    
     // TODO : Access to data from physics component is thread-safe here.

    this.physics.BeginUpdate(gameTime);
}


There are no necessary components of the framework.  Just use what you need.  If you don't need camera support, or don't want to use what I created, don't use the ViewpointComponent.  If you don't want ui, don't use the UIComponent.  There is a small chance that some components have dependancies on other components, but for the most part, all components can operate atomically.

The GameExtension class uses the extension method feature of the .NET Framework 3.0 to add methods to the Microsoft.Xna.Framework.Game class while in Visual Studio.  To make sure those extension methods show up for the Game class, add "using Oops.Xna.Framework" to the file that needs them.

I use GameExtension.GetContent() instead of Game.Content.Load<> because in my own usage of the framework, I make use of the GameStateComponent to allow for game screen-specific content that can be loaded and unloaded when the game screen activates/deactivates.  Inside GetContent(), it determines what screen is active and uses that screen's ContentManager to load the content.  Just using Game.Content.Load<> would only give one resource pool for content and everything in the entire game would have to be unloaded if anything.  You can still use Game.Contnent.Load if you like.


You can use the PhysicsComponent alone if you'd like, just make sure you're building the Oops.Xna.Framework dll under the "Release" configuration.  Otherwise it requires a service added to the Game.Services collection of type IViewpointService.  You can also modify the code in PhysicsComponent by removing all #if DEBUG blocks to remove that dependancy.

Let me know if there's anything else I can help with.

Sep 8, 2009 at 3:25 AM

Hey thanks a bunches for some clarification.

But I still get white screen after 2nd UpdateEnd() and game freezes. Here's a basic program I tried to run (it builds with no errors but when ran all I see is white screen and UpdateEnd() (I believe) is waiting(?) until some event is fired. (I tried to do it on single game screen without any fancy stuff)

I am using my own models (soldier and floor)

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using Oops.Xna.Framework.Audio;
using Oops.Xna.Framework.Diagnostics;
using Oops.Xna.Framework.GameState;
using Oops.Xna.Framework.Input;
using Oops.Xna.Framework.UI;
using Oops.Xna.Framework.Viewpoint;
using Oops.Xna.Framework.Physics;
using Oops.Xna.Framework.Graphics;
using Oops.Xna.Framework.Physics.CollisionSystems;

namespace OopsPhysTest
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        PhysicsComponent physics;

        CollisionBox soldierC;
        Model soldier;
        Model floor;

        float aspectRatio;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <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 base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            soldier = Content.Load<Model>(@"Models\soldier");
            floor = Content.Load<Model>(@"Models\grid");


            physics = new PhysicsComponent(this, new GridCollisionSystem(20.0f));

            aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;


            Reset();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }


        void Reset()
        {

            



            // Clear the physics service of rigid bodies and static collision shapes.
            this.physics.RigidBodies.Clear();
            this.physics.CollisionSystem.CollisionGroups.Clear();


                // Create the collision box.
                soldierC = new CollisionBox();
                soldierC.Extents = new Vector3(5,5,5);
                soldierC.StaticFriction = 0.5f;
                soldierC.DynamicFriction = 0.5f;
                soldierC.Restitution = 0.6f;

                // Create the rigid body for the collision box.
                RigidBody soldierR = new RigidBody();

                // Add collision sphere to the rigid body.
                soldierR.CollisionGroup.CollisionShapes.Add(soldierC);
                soldierR.CalculateMassProperties(1.0f);

                // Determine the position and orientation of the box.
                Vector3 position = new Vector3(5, 5, 5);
                Matrix orientation = Matrix.CreateFromQuaternion(
                    Quaternion.Normalize(Quaternion.Identity));

                soldierR.UpdateTransform(ref position, ref orientation);

                soldierR.Rotation = Vector3.Zero;

                // Assign the box to the quad-tree and shape list.
                
                this.physics.RigidBodies.Add(soldierR);

                // Create the ground plane.  
                CollisionPlane plane = new CollisionPlane();
                plane.Normal = Vector3.UnitY;

                // Create a collision group and add the plane.
                CollisionGroup collisionGroup = new CollisionGroup();
                collisionGroup.CollisionShapes.Add(plane);

                // Add the plane's collision group to the collision system.
                this.physics.CollisionSystem.CollisionGroups.Add(collisionGroup);
        }


        /// <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 override void Update(GameTime gameTime)
        {
            this.physics.EndUpdate();

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            physics.BeginUpdate(gameTime);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // Draw the model.
            Matrix[] transforms = new Matrix[soldier.Bones.Count];
            soldier.CopyAbsoluteBoneTransformsTo(transforms);

            foreach (ModelMesh mesh in soldier.Meshes)
            {
                // This is where the mesh orientation is set, as well 
                // as our camera and projection.
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = transforms[mesh.ParentBone.Index] *
                        Matrix.CreateRotationY(0f)
                        * Matrix.CreateTranslation(soldierC.Position)
                        * Matrix.CreateScale(0.2f);
                    effect.View = Matrix.CreateLookAt(new Vector3(0, 400, 500),
                        Vector3.Zero, Vector3.Up);
                    effect.Projection = Matrix.CreatePerspectiveFieldOfView(
                        MathHelper.ToRadians(45.0f), aspectRatio,
                        1.0f, 10000.0f);
                }
                // Draw the mesh, using the effects set above.
                mesh.Draw();
            }


            base.Draw(gameTime);
        }
    }
}

Well basically this just freezes. Am I missing something here? Thanks.

 

Sep 8, 2009 at 3:26 AM

yeah just in case you ask this, Ive got both oops reference in References and oops' pipeline in content like in the example

Coordinator
Sep 9, 2009 at 4:23 AM

Thanks for the example code.  This will help diagnose the issue.   From just a glance, I'm seeing that the PhysicsComponent is never added to the Game.Components collection which means that PhysicsComponent.Initialize is never called.  Can you try either adding the PhysicsComponent to the Game.Components or calling phyiscs.Initialize in the Game.Initialize method?

If that doesn't fix it, I'll be taking a look at this tomorrow and I'll let you know what I find.

Sep 9, 2009 at 4:57 AM
Edited Sep 9, 2009 at 4:57 AM

Ok I tried both ways.

Calling

protected override void Initialize()
        {

            base.Initialize();
            physics.Initialize();
        }

(note physics is defined in loadcontent) raises an exception Resources.GameServiceNotFound inside GameExtension.cs line 186.

if I just add game component without calling initialize,

protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            soldier = Content.Load<Model>(@"Models\soldier");
            floor = Content.Load<Model>(@"Models\grid");


            physics = new PhysicsComponent(this, new GridCollisionSystem(20.0f));
            this.Components.Add(physics);
            aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;


            Reset();
        }


nothin changes and I still get game freezing and white screen.

If I do both add component and initialize I get the same exception as above.

Thanks,

Cheb.

Coordinator
Sep 9, 2009 at 11:27 PM
Edited Sep 10, 2009 at 2:35 AM

Okay, this is how I got it to work.  I dowloaded the code from the Source Code tab here on this site and opened the .sln file.  I, then created a new Windows Game (3.1) project and copied the code above into the Game1.cs and fixed the Program.cs file (because of the namespace).  I then added references like you stated before to Oops.Xna.Framework and the Oops.Xna.Framework.Content.Pipeline projects as project references.  I compiled and hit run.  The issue you stated happened.

To fix:

-Open the PhysicsComponent.cs file and add #undef DEBUG to the top of it. 

- Inside PhysicsComponent.cs, I accidently included the "using Oops.Xna.Framework.Physics.CollisionSystems;" line inside a"#define DEBUG" block so you'll have to move it outside of the block.

- Move the creation of the PhysicsComponent to the constructor of the Game1 class and then added it to the Components collection.

	public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            physics = new PhysicsComponent(this, new GridCollisionSystem(20.0f));
            this.Components.Add(physics);
        }

 That's it, everything worked (I used a model of mine).  The reason for the modification to the PhysicsComponent is to remove the requirement for the IViewpointService.

Let me know if this works for you.

Sep 11, 2009 at 5:50 PM

great it runs now! Except the bugger (my model) doesnt want to fall anywhere. Do i need to set gravity or is it on by default?

Also I draw my model using coordinates of its CollisionBox. Is that correct?

 

Thanks

Coordinator
Sep 11, 2009 at 6:31 PM

It's not falling anywhere because the sphere is already in contact with the plane.  Move the rigidbody ofr the sphere up a hight to see it react with the plane.

You can use RigidBody.Position/Orientation, CollisionGroup.Position/Orientation or CollisionShape.Position/Orientation.  Just depends on the context.  In your example's case, all the values will be the same so it's okay to use the CollisionBox.

Sep 11, 2009 at 7:05 PM

oh right, I am stupid sorry!

 

Now can I ask you one more question? I saw in your example code you have a working surface collision. Would this work for two objects with some irregular shape (not box), colliding with with each other?

I figured I would have to define a CollisionShape instead of CollisionBox? And how do I pass my model's verticies?

thanks!

Coordinator
Sep 13, 2009 at 5:35 AM

Unfortunately,two irregular shapes (CollisionMesh) can't collide with each other.  Only a non-moving CollisionMesh can collide with moving CollisionSpheres and CollisionBoxes. 

You can try to create a RigidBody with many CollisionBoxes/CollisionShapes attached to it and offet (RigidBody.CollisionGroup.CollisionShapes.Add(<shape>)).  Set the Offset properties on the CollisionBox/CollisionSphere in relation to the RigidBody's Position/Orientation. 

For example, a table might have 5 CollisionBoxes - 1 for the table top and 4 for the legs.  These all would be attached to the same RigidBody with RigidBody.CollisionGroup.CollisionShapes.Add().  In this case, you may want to calculate the InertiaTensor manually(there are issues with CalculateMassProperties for multiple shapes that I haven't got to fix yet).  You can set RigidBody.InteriaTensor to the same InertiaTensor for a RigidBody with just one CollisionBox the size of the table.  It won't be perfect but it'll get you going.