1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- Created by texi2html 1.64 -->
<!--
Written by: Lionel Cons <Lionel.Cons@cern.ch> (original author)
Karl Berry <karl@freefriends.org>
Olaf Bachmann <obachman@mathematik.uni-kl.de>
and many others.
Maintained by: Olaf Bachmann <obachman@mathematik.uni-kl.de>
Send bugs and suggestions to <texi2html@mathematik.uni-kl.de>
-->
<HTML>
<HEAD>
<TITLE>Crystal Space: HOWTO Collision Detection</TITLE>
<META NAME="description" CONTENT="Crystal Space: HOWTO Collision Detection">
<META NAME="keywords" CONTENT="Crystal Space: HOWTO Collision Detection">
<META NAME="resource-type" CONTENT="document">
<META NAME="distribution" CONTENT="global">
<META NAME="Generator" CONTENT="texi2html 1.64">
</HEAD>
<BODY LANG="" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#800080" ALINK="#FF0000">
<A NAME="SEC226"></A>
<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_116.html#SEC225"> < </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_118.html#SEC233"> > </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_108.html#SEC209"> << </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_116.html#SEC225"> Up </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_128.html#SEC290"> >> </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="index.html#SEC_Top">Top</A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_toc.html#SEC_Contents">Contents</A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_285.html#SEC711">Index</A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_abt.html#SEC_About"> ? </A>]</TD>
</TR></TABLE>
<HR SIZE=1>
<H3> 5.8.1 Doing Collision Detection </H3>
<!--docid::SEC226::-->
<P>
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.
</P><P>
<A NAME="SEC227"></A>
<H4> Loading the `<SAMP>iCollideSystem</SAMP>' </H4>
<!--docid::SEC227::-->
<P>
The basis of the collision detection system is the `<SAMP>iCollideSystem</SAMP>'.
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.
</P><P>
To load a collision detection system you can use the following code:
</P><P>
<TABLE><tr><td> </td><td class=example><pre>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;
}
</pre></td></tr></table></P><P>
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).
</P><P>
<A NAME="SEC228"></A>
<H4> Initializing Geometry </H4>
<!--docid::SEC228::-->
<P>
Before you can use the collision detection system you have to make
instances of `<SAMP>iCollider</SAMP>'. Only the collide system can do that. To
create an `<SAMP>iCollider</SAMP>' you have to give an instance of `<SAMP>iPolygonMesh</SAMP>'.
Several meshes in CS implement `<SAMP>iPolygonMesh</SAMP>'. If you have special
geometry on your own you can make your own classes to implement
`<SAMP>iPolygonMesh</SAMP>'. Here is some code on how to initialize the collider
for a mesh:
</P><P>
<TABLE><tr><td> </td><td class=example><pre>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;
}
</pre></td></tr></table></P><P>
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.
</P><P>
However, you can also use the `<SAMP>iObject</SAMP>' system to attach your collider
to the mesh itself. An easy way to do this is to use the
<CODE>csColliderWrapper</CODE> class that you can find in the <CODE>cstool</CODE>
library. <CODE>csColliderWrapper</CODE> is a subclass of <CODE>csObject</CODE> which
means that you can attach this object to any other <CODE>csObject</CODE>.
<CODE>csColliderWrapper</CODE> additionally holds a pointer to an <CODE>iCollider</CODE>.
This means that you can create a <CODE>csColliderWrapper</CODE> to hold your
<CODE>iCollider</CODE> for some mesh object and then you can attach
that <CODE>csColliderWrapper</CODE> to the mesh object itself. To do this
use the following code instead of the <CODE>InitCollider()</CODE> routine
above:
</P><P>
<TABLE><tr><td> </td><td class=example><pre>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;
}
</pre></td></tr></table></P><P>
This example creates a new instance of <CODE>csColliderWrapper</CODE> which
is automatically stored with the <CODE>iObject</CODE> 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:
</P><P>
<TABLE><tr><td> </td><td class=example><pre>csColliderWrapper* colwrap = csColliderWrapper::GetColliderWrapper (
mesh->QueryObject ());
iCollider* collider = colwrap->GetCollider ();
</pre></td></tr></table></P><P>
<A NAME="SEC229"></A>
<H4> The Player Collider </H4>
<!--docid::SEC229::-->
<P>
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 `<SAMP>iPolygonMesh</SAMP>' 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.
</P><P>
The best way to make the gravity collider is to make your own implementation
of `<SAMP>iPolygonMesh</SAMP>'. This is very efficient. To keep the returned
collider I recommend storing them somewhere in the player class or else the
main game class.
</P><P>
<A NAME="SEC230"></A>
<H4> Doing Collision Detection </H4>
<!--docid::SEC230::-->
<P>
When everything is set up it is time to do collision detection. To test
for collisions you use the <CODE>Collide</CODE> function in `<SAMP>iCollideSystem</SAMP>'.
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).
</P><P>
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.
</P><P>
<A NAME="SEC231"></A>
<H4> Limitation of RAPID </H4>
<!--docid::SEC231::-->
<P>
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
`<SAMP>iMovable</SAMP>') and expect collision detection to be ok. The only way
aroud this limitation is to use <CODE>HardTransform()</CODE> 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.
</P><P>
<A NAME="SEC232"></A>
<H4> Include Files </H4>
<!--docid::SEC232::-->
<P>
The include files useful for this section are:
</P><P>
<TABLE><tr><td> </td><td class=example><pre>#include "iutil/object.h"
#include "iutil/plugin.h"
#include "ivaria/collider.h"
#include "ivaria/polymesh.h"
#include "iengine/mesh.h"
#include "cstool/collider.h"
</pre></td></tr></table></P><P>
<A NAME="HOWTO Mesh LightAnim"></A>
<HR SIZE=1>
<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_116.html#SEC225"> < </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_118.html#SEC233"> > </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_108.html#SEC209"> << </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_116.html#SEC225"> Up </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_128.html#SEC290"> >> </A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="index.html#SEC_Top">Top</A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_toc.html#SEC_Contents">Contents</A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_285.html#SEC711">Index</A>]</TD>
<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="cs_abt.html#SEC_About"> ? </A>]</TD>
</TR></TABLE>
<BR>
<FONT SIZE="-1">
This document was generated
using <A HREF="http://www.mathematik.uni-kl.de/~obachman/Texi2html
"><I>texi2html</I></A>
</BODY>
</HTML>
|