[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.7.1 Doing Collision Detection

Collision detection in CS is one of the more complicated issues. In this section I give a quick description of all the classes and interfaces in CS and what you should do to use them.

Loading the `iCollideSystem'

The basis of the collision detection system is the `iCollideSystem'. This is an interface which implemented by some collision detection plugin. At this moment we only have an implementation of the RAPID collision detection system but it would be a simple matter to add a new plugin for another system.

To load a collision detection system you can use the following code:

 
iPluginManager* plugmgr =
  CS_QUERY_REGISTRY (object_reg, iPluginManager);
iConfigManager* config =
  CS_QUERY_REGISTRY (object_reg, iConfigManager);
const char* p = config->GetStr ("MyGame.Settings.CollDetPlugin",
  	"crystalspace.collisiondetection.rapid");
iCollideSystem* cd_sys =
  CS_LOAD_PLUGIN (plugmgr, p, iCollideSystem);
if (!cd_sys)
{
  csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
	"crystalspace.application.myapp",
  	"No Collision Detection plugin found!");
  return false;
}

This is a very general example. It will first get the prefered collision detection plugin from the config file. If the config file doesn't specify it then it will use 'crystalspace.collisiondetection.rapid' which is the only one we have at the moment. If you don't want to let the users choose another plugin then you can also hardcode the string. The cd_sys should be stored somewhere central (i.e. your application class).

Initializing Geometry

Before you can use the collision detection system you have to make instances of `iCollider'. Only the collide system can do that. To create an `iCollider' you have to give an instance of `iPolygonMesh'. Several meshes in CS implement `iPolygonMesh'. If you have special geometry on your own you can make your own classes to implement `iPolygonMesh'. Here is some code on how to initialize the collider for a mesh:

 
iCollider* MyGame::InitCollider (iMeshWrapper* mesh)
{
  iPolygonMesh* polmesh = SCF_QUERY_INTERFACE (mesh->GetMeshObject (),
  	iPolygonMesh);
  if (polmesh)
  {
    iCollider* cd = cd_sys->CreateCollider (polmesh);
    polmesh->DecRef ();
    return cd;
  }
  else
    return NULL;
}

After that you need to store the returned collider somewhere so you can easily retrieve it later when you want to do the collision detection. Usually in a game you have entity classes which will have a pointer to the mesh. In that case you can easily store the collider in that entity class.

However, you can also use the `iObject' system to attach your collider to the mesh itself. An easy way to do this is to use the csColliderWrapper class that you can find in the cstool library. csColliderWrapper is a subclass of csObject which means that you can attach this object to any other csObject. csColliderWrapper additionally holds a pointer to an iCollider. This means that you can create a csColliderWrapper to hold your iCollider for some mesh object and then you can attach that csColliderWrapper to the mesh object itself. To do this use the following code instead of the InitCollider() routine above:

 
csColliderWrapper* colwrap =
  new csColliderWrapper(mymesh->QueryObject(), cd_sys, 

bool MyGame::InitCollider (iMeshWrapper* mesh)
{
  iPolygonMesh* polmesh = SCF_QUERY_INTERFACE (mesh->GetMeshObject (),
  	iPolygonMesh);
  if (polmesh)
  {
    new csColliderWrapper (mesh->QueryObject (), cd_sys, polmesh);
    polmesh->DecRef ();
    return true;
  }
  else
    return false;
}

This example creates a new instance of csColliderWrapper which is automatically stored with the iObject that belongs with the given mesh. So there is no need to store it otherwise. Later on you can retrieve the collider for some mesh by doing:

 
csColliderWrapper* colwrap = csColliderWrapper::GetColliderWrapper (
	mesh->QueryObject ());
iCollider* collider = colwrap->GetCollider ();

The Player Collider

Depending on the game your player might have a representation of geometry or not. If it doesn't you will have to make your own version of `iPolygonMesh' to create a collider for the player. Even if your player has geometry (i.e. a 3D sprite) it is sometimes still preferable to create your own special geometry for the player. The reason is gravity. When you would just use one collider for the player you can have problems moving around because the player would not be able to jump over even the tiniest elevation in height. Sometimes the edge between adjacent polygons can even cause the player to collide with that other polygon due to numerical inprecision. To solve this problem it is best to make one collider that is used for gravity only and another collider that is used to test if you can move around. The gravity collider will be used only to test if the player can go downwards or upwards. To avoid not being able to go over small height elevations, the player collider should float slightly above the ground.

The best way to make the gravity collider is to make your own implementation of `iPolygonMesh'. This is very efficient. To keep the returned collider I recommend storing them somewhere in the player class or else the main game class.

Doing Collision Detection

When everything is set up it is time to do collision detection. To test for collisions you use the Collide function in `iCollideSystem'. This will test the collisions between two colliders. The result of this will be true or false and in addition the collide system will keep a list of all triangle pairs for the hits. Those triangle pairs can be used to decide what to do on collision (i.e. slide on a wall for example).

Because collision detection works on two objects at a time it is a good idea to have some system on top of the collision detection system that detects when it is useful to do collision detection. You can use a bounding sphere for that. Also you should only do collision detection if the object moves.

Limitation of RAPID

The current RAPID collision detection implementation has one important limitation. It assumes that the transform from object to world space will not change the size of the object. i.e. you cannot scale the object using the object to world transformation (which is kept in the `iMovable') and expect collision detection to be ok. The only way aroud this limitation is to use HardTransform() to transform the object space vertices itself. But this can of course not be used dynamically as you would have to recalculate the collider every time the object changes.

Include Files

The include files useful for this section are:

 
#include "iobject/object.h"
#include "ivaria/collider.h"
#include "ivaria/polymesh.h"
#include "iengine/mesh.h"
#include "cstool/collider.h"


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated using texi2html