Physics problems

Dec 9, 2009 at 1:17 PM

Hey, cheers for great work on the framework.

We are currently trying to implement the Oops! Framework into our game but are facing some interesting problems. Basically it does nothing :)

This is roughly how we are using it:

- Create our world component

- Create our entities (all entities have Collision box and a RigidBody for now..)

- After creating the entities we pass all of the RigidBodies to PhysicsComponent.

- in World components update loop we call physics.EndUpdate(); at the start of it and at the end of it we call physics.BeginUpdate().

 

Absolutely nothing happens. The game runs on fixedTimeStep (if that matters) and the Async is false in the Physics.

Are we missing out on something because seriously does feel like we are.

 

Cheers.

Coordinator
Dec 9, 2009 at 1:46 PM

I can think of two things to try:

1) Make sure the PhysicsComponent instance is added to the Game (or GameScreen if you're using the GameStateComponent) component collection - or - call PhysicsComponent.Initialize after creation of the PhysicsComponent and PhysicsComponent.Update during Game.Update (or GameScreen.Update if you're using the GameStateComponent).

2) Make sure PhysicsComponent.Enabled is equal to true when AsyncEnabled is equal to false.

Let me know if this works or not.  Good luck!

Dec 9, 2009 at 3:26 PM
Edited Dec 9, 2009 at 4:32 PM

Cheers, getting there. At least stuff started happening now, heh. Oh yeah, and so far Oops seems absolutely amazing.

 

We want to use the framework for is just basic Collision detection and Physics but seriously struggling at the moment with the framework. Basically we got a platformer game going on and we have static platforms where you jump around on(think Smash Bros Melee). Basically everything that you jump around on are made of these static platforms (the ground is just a streched platform), it's a 2.5D game. We got our own physics and collision detection going on but it's not coming along the way we wanted it to so that's why we are going to use Oops.

How do we create static CollisionShapes? The static shapes don't move(float in air in our case) and act as a platform for the players to jump on.

What's the normal way of creating a collision handler?

 

EDIT #1:

After spending enough time with it I figured that I can configure the RigidBody behaviour via the RigidBody.Flash variable and got the platforms to be static. But now we are faced with the second problem, how are we to go about the collision handling It's not like we need anything super fancy, just a way to handle the collisions via Oops. How is it generally done with Oops?

Thanks.

Coordinator
Dec 9, 2009 at 5:54 PM

A better approach for never moving objects is to create a CollisionGroup (instead of a RigidBody) and added them to the PhyicsComponent.CollisionSystem.CollisionGroup....but RigidBody.Flags = RigidBodyFlags.Static should work as well.  Just less performant.

you can get collision information two ways:

  1. Implement the ICollisionCallback interface on an object (Game class would work) and pass that to the constructor of the PhysicsComponent.  You'll get collisions as they happen and you can react as you want during a simulation step.
  2. Right after PhysicsComponent.EndUpdate is called, look at the RigidBody.CollisionGroup.Collisions collection to make determinations on what the next simulation step should do base on all collision with the interested CollisionGroup.

In my game, I use the second approach to determine if the player is on the ground and, if so, allow him/her to jump.  Movement is discussed in another discussion.  Remember to constrain movement to just the X and Y axis for 2.5d.  Good luck!

Dec 10, 2009 at 1:43 PM
Edited Dec 10, 2009 at 2:00 PM

Just realised that it's not working when I was playing around with it. I've got five platforms (set as RigidBody.Flags = Static) and one player starting form above the platforms. If we use these to init PhysicsComponent:

m_physics = new PhysicsComponent(World.m_game, new SweepAndPruneCollisionSystem());
m_physics.AsyncEnabled = false;
m_physics.Enabled = true;
// m_physics.Initialize();

Trying to use the PhysicsComponent.Initialize(); crashes the whole game because it tries t o use the GameExtensions getService, so we are not using it.
After that in our Update loop we have the:
 
public override void Update( random parameters ) 
{
// Wait for the last frame's physics simulation to finish.
this.m_physics.EndUpdate(); // do we have to call these since it seems to work without the endUpdate(); and BeginUpdate(); when we are calling the Update of PhysicsComponent?
// .. generic update stuff
m_physics.Update(gameTime);

// Start this frame's physics simulation

this
.m_physics.BeginUpdate(gameTime); }
And all the entities have their own CollisionShape and RigidBody which are initialised based on the examples in the Oops frame work (giving them static friction, dynamic friction, restitution and adding the CollisionShape to the RigidBody after that).
All the RigidBody objects are then added to the Physics objects collectiong of RigidBodies.

If I'm correct, basic SweepAndPrune collision handling should be working now (Between the Static platforms and our player character)?
Since if it should be, I'm seriously missing out on something because the character keeps falling throught the platforms and obviously out of the game world because of that :)
I even tried implemented the ICollisionCallback interface and tried using it but for some reason it never gets called. Not even when the objects are supposed to be colliding. Naturally when I implemented it, I passed the object as a parameters to the PhysicsComponent. I even looked at the examples and I was doing it the same way as the examples do but it just does not get called.

What am I missing here? Obviously I'm kind of wobbling towards what I want to do but for some reason it just does not react on the collision. Other than that everything seems to be working. I have to admit I'm starting to feel pretty stupid about myself because it cannot be that hard to get this thing up and running, heh.

Coordinator
Dec 10, 2009 at 4:46 PM

You are adding the platforms' RigidBody to the PhysicsComponent.RigidBodies collection as well, right?  Try these things:

  1. When setting a RigidBody's position and orientation use the RigidBody.UpdateTransform method instead of just setting the RigidBody.Position and RigidBody.Orientation fields.  Using UpdateTransform updates the associated CollisionGroup and CollisionShapes of the RigidBody as well, along with some other physics related values (AABB, tensors, etc)...AND also notifies the CollisionSystem to update sweep and prune information.
  2. Try doing the above after adding the RigidBody to the PhysicsComponent.RigidBodies collection.

You're right, EndUpdate and BeginUpdate don't need to be called when not using Asynchronous processing.

Dec 11, 2009 at 11:49 AM

For the most randomest reasons if I add a plane in to the game world, the players RigidBody collides with it and calls the collision function. But it does not call the collision for the static platforms. Any ideas why?

 

The init of the Platforms:

 UpdateEntityBoundingBox();

 BoundingBox bb = m_modelBoundingBox.getBoundingBox();
 Vector3 size = bb.Max - bb.Min;
 size.X = Math.Abs(size.X);
 size.Y = Math.Abs(size.Y);
 size.Z = Math.Abs(size.Z);


 m_collisionbox = new CollisionBox();
 m_collisionbox.Extents = size / 2;
 m_collisionbox.StaticFriction = 0.5f;
 m_collisionbox.DynamicFriction = 0.5f;
 m_collisionbox.Restitution = 0.6f;

 m_rigidBody = new RigidBody();
              m_rigidBody.CollisionGroup.CollisionShapes.Add(m_collisionbox);
 m_rigidBody.CalculateMassProperties(1.0f);


 Matrix orientation = Matrix.CreateFromYawPitchRoll(m_rotation.Y, m_rotation.X, m_rotation.Z); 

 m_rigidBody.UpdateTransform(ref m_currentPosition, ref orientation);

 m_previousPosition = m_rigidBody.Position;

m_rigidBody.Flags = RigidBodyFlags.Static;
m_physics.RigidBodies.Add(m_rigidBody);

m_physics.RigidBodies[ m_physics.RigidBodies.Count - 1 ].UpdateTransform(ref m_currentPosition, ref orientation);

So currently doing what you suggested and still no change. Strange. Any advice would be welcome. Cheers.

Coordinator
Dec 11, 2009 at 7:47 PM

It's really hard to tell what's wrong so I just created a bare-bones step, similar to what you are trying to do.  Here are the steps I took:

  • Downloaded Change Set 43328 and extracted it to my hard drive.
  • Opened OopsSolution.sln and added a new XNA 3.1 Game project for windows.  Called it TestProject.
  • Added a project reference to Oops.Xna.Framework (Windows).csproj and made it the Startup project.
  • Added the code below to Game1.cs.
  • Ran the project.
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Oops.Xna.Framework;
using Oops.Xna.Framework.Physics;
using Oops.Xna.Framework.Viewpoint;
using Oops.Xna.Framework.Viewpoint.Cameras;

namespace TestProject
{
	public class Game1 : Microsoft.Xna.Framework.Game
	{
		GraphicsDeviceManager graphics;
		PhysicsComponent physics;
		ViewpointComponent viewpoint;

		Random random = new Random();

		public Game1()
		{
			// Create graphics device manager.
			this.graphics = new GraphicsDeviceManager(this);

			// Create viewpoint component.
			this.viewpoint = new ViewpointComponent(this);
			this.Components.Add(this.viewpoint);

			// Create physics component.
			this.physics = new PhysicsComponent(this);
			this.Components.Add(this.physics);
		}

		protected override void Initialize()
		{
			// Initialize the viewpoint component.
			this.viewpoint.Cameras.Add(
				new StaticCamera(this, "Static") 
				{ 
					IsViewUpdated = false, 
					View = Matrix.CreateLookAt(Vector3.One * 50.0f, Vector3.Zero, Vector3.Up) 
				});
			
			// Initialize the physics component.
			this.physics.AsyncEnabled = false;
			this.physics.Enabled = true;
			this.physics.DrawAABBs = true;

			// Create a sphere.
			CollisionSphere sphere = new CollisionSphere();
			sphere.Radius = 1.5f;

			// Create a rigid body for the sphere.
			RigidBody rigidBody = new RigidBody();
			rigidBody.CollisionGroup.CollisionShapes.Add(sphere);
			Vector3 position = this.random.NextVector3(-10.0f, 10.0f, 40.0f, 50.0f, -10.0f, 10.0f);
			rigidBody.UpdateTransform(ref position);
			rigidBody.CalculateMassProperties(1.0f);

			// Add the sphere's rigid body to the physics component.
			this.physics.RigidBodies.Add(rigidBody);

			// Create 100 "platforms".
			for (int i = 0; i < 100; i++)
			{
				// Create a box.
				CollisionBox box = new CollisionBox();
				box.Extents = Vector3.One * 2.0f;

				// Create a rigid body for the box.
				rigidBody = new RigidBody();
				rigidBody.CollisionGroup.CollisionShapes.Add(box);
				position = this.random.NextVector3(-10.0f, 10.0f);
				rigidBody.UpdateTransform(ref position);
				rigidBody.CalculateMassProperties(1.0f);

				// Mark the rigid body as immovable.
				rigidBody.Flags = RigidBodyFlags.Static;

				// Add the box's rigid body to the physics component.
				this.physics.RigidBodies.Add(rigidBody);
			}

			// Call inherited method.
			base.Initialize();
		}

		protected override void Update(GameTime gameTime)
		{
			// Allows the game to exit
			if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
				this.Exit();

			// Pressing 'A' resets the sphere's position.
			if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed ||
				Keyboard.GetState().IsKeyDown(Keys.A))
			{
				this.physics.RigidBodies[0].Deactivate();

				Vector3 position = this.random.NextVector3(-10.0f, 10.0f, 40.0f, 50.0f, -10.0f, 10.0f);
				this.physics.RigidBodies[0].UpdateTransform(ref position);

				this.physics.RigidBodies[0].Activate();
			}

			// Call inherited method.
			base.Update(gameTime);
		}

		protected override void Draw(GameTime gameTime)
		{
			// Clear back buffer.
			this.GraphicsDevice.Clear(Color.CornflowerBlue);

			// Call inherited method.
			base.Draw(gameTime);
		}
	}
}

 This worked for me.  You could compare your code to the above and see if anything sticks out.  Right now, it just draw the bounding boxes of the collision shapes but you get the idea.  Press 'A' to reset the dropping sphere.

Let me know if this helps.

Jan 1, 2010 at 5:46 PM

if I change the order of declaration  (first the platforms and THEN the sphere), like this:

      protected override void Initialize()
      {
         // Initialize the viewpoint component.
         this.viewpoint.Cameras.Add(
            new StaticCamera(this, "Static")
            {
               IsViewUpdated = false,
               View = Matrix.CreateLookAt(Vector3.One * 50.0f, Vector3.Zero, Vector3.Up)
            });

         // Initialize the physics component.
         this.physics.AsyncEnabled = false;
         this.physics.Enabled = true;
         this.physics.DrawAABBs = true;
         // Create a rigid body for the sphere.
         RigidBody rigidBody = new RigidBody();
         Vector3 position = this.random.NextVector3(-10.0f, 10.0f, 40.0f, 50.0f, -10.0f, 10.0f);

         // Create 100 "platforms".
         for (int i = 0; i < 100; i++)
         {
            // Create a box.
            CollisionBox box = new CollisionBox();
            box.Extents = Vector3.One * 2.0f;

            // Create a rigid body for the box.
            rigidBody = new RigidBody();
            rigidBody.CollisionGroup.CollisionShapes.Add(box);
            position = this.random.NextVector3(-10.0f, 10.0f);
            rigidBody.UpdateTransform(ref position);
            rigidBody.CalculateMassProperties(1.0f);

            // Mark the rigid body as immovable.
            rigidBody.Flags = RigidBodyFlags.Static;

            // Add the box's rigid body to the physics component.
            this.physics.RigidBodies.Add(rigidBody);
         }

         // Create a sphere.
         CollisionSphere sphere = new CollisionSphere();
         sphere.Radius = 1.5f;

         rigidBody = new RigidBody();
         position = this.random.NextVector3(-10.0f, 10.0f, 40.0f, 50.0f, -10.0f, 10.0f);

         rigidBody.CollisionGroup.CollisionShapes.Add(sphere);
         rigidBody.UpdateTransform(ref position);
         rigidBody.CalculateMassProperties(1.0f);

         // Add the sphere's rigid body to the physics component.
         this.physics.RigidBodies.Add(rigidBody);


         // Call inherited method.
         base.Initialize();
      }

The sphere goes through the "platforms". Why? How can I avoid it?

I would want to add objects dynamically but the new objects don't "see" the static objects.

Jan 1, 2010 at 8:28 PM

It seems like one can use NoResponse and set the acceleration to zero :

            rigidBody.Flags = RigidBodyFlags.NoResponse;
            rigidBody.Acceleration = new Vector3(0, 0, 0);

and the platforms will "behave".

What is the intended difference between RigidBodyFlags.Static and RigidBodyFlags.NoResponse+Zero acceleration ?

 

Coordinator
Jan 2, 2010 at 4:05 AM

There was an issue in the CollisionSystem that prevented any rigid bodies added after a static rigid body to collide.  The latest source code update (on the Source Code tab) has the fix.  Thanks for finding and letting me know about this.

a "Static" rigid body doesn't move.  A "No Repsonse" rigid body can still move and cause collision but is not affected by collisions itself.