Game Development Community

Exempt Two Objects from Collision with ContainerRayCast

by Rubes · 04/02/2006 (10:29 am) · 5 comments

I have come across situations where I'd like to exempt an object from collision detection with ContainerRayCast, but the method only allows for one exempt object and I'm already exempting the player object. This resource allows you to specify an optional second exempt object with ContainerRayCast.

It's a pretty simple modification of the ContainerRayCast method in sceneObject.cc. Below is the ContainerRayCast method from that file, with necessary changes highlighted in bold:

[b]// MAR: The define below was changed from 5 arguments to 6 to allow for the extra exempt object.[/b]
ConsoleFunction( containerRayCast, const char*, 4, [b]6[/b], "( Point3F start, Point3F end, bitset mask, SceneObject exempt1=NULL [b]SceneObject exempt2=NULL[/b])"
                "Cast a ray from start to end, checking for collision against items matching mask.\n\n"
                "If exempt1 (and exempt2) is specified, then it is temporarily excluded from collision checks (For "
                "instance, you might want to exclude the player if said player was firing a weapon.)\n"
                "@returns A string containing either null, if nothing was struck, or these fields:\n"
                "            - The ID of the object that was struck.\n"
                "            - The x, y, z position that it was struck.\n"
                "            - The x, y, z of the normal of the face that was struck.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   Point3F start, end;
   dSscanf(argv[1], "%g %g %g", &start.x, &start.y, &start.z);
   dSscanf(argv[2], "%g %g %g", &end.x,   &end.y,   &end.z);
   U32 mask = dAtoi(argv[3]);

   SceneObject* pExempt = NULL;
[b]   SceneObject* pExempt2 = NULL;		// MAR: added this statement for second exempt object[/b]

   if (argc > 4) {
      U32 exemptId = dAtoi(argv[4]);
      Sim::findObject(exemptId, pExempt);
   }
   if (pExempt)
      pExempt->disableCollision();

[b]   // MAR: [begin] This was added to allow for the second exempted object
   if (argc > 5) {
	   U32 exemptId = dAtoi(argv[5]);
	   Sim::findObject(exemptId, pExempt2);
   }
   if (pExempt2)
	   pExempt2->disableCollision();
   // MAR: [end]
[/b]
   
   RayInfo rinfo;
   S32 ret = 0;
   if (gServerContainer.castRay(start, end, mask, &rinfo) == true)
      ret = rinfo.object->getId();

   if (pExempt)
      pExempt->enableCollision();
[b]   // MAR: added this statement for the second exempt object
   if (pExempt2)
	   pExempt2->enableCollision();[/b]

   // add the hit position and normal?
   if(ret)
   {
      dSprintf(returnBuffer, 256, "%d %g %g %g %g %g %g",
               ret, rinfo.point.x, rinfo.point.y, rinfo.point.z,
               rinfo.normal.x, rinfo.normal.y, rinfo.normal.z);
   }
   else
   {
      returnBuffer[0] = '0';
      returnBuffer[1] = '[[4f3990013afdc]]';
   }

   return(returnBuffer);
}

That should do it. Recompile, and you should be good to go. Here's a brief sample of code where I take advantage of this:

if ($selectedObjID) %exempt = $selectedObjID;
	
	if (%exempt) %object = ContainerRayCast(%startPoint, %endPoint, %searchMasks, %player, %exempt);
	else %object = ContainerRayCast(%startPoint, %endPoint, %searchMasks, %player);

Basically, it checks to see if there is an object that should be exempt, and if so, sets %exempt to it and makes the call to ContainerRayCast with that parameter.

Simple fix but thought I'd throw it out there as my first real resource.

#1
04/02/2006 (3:35 pm)
Nice, thanks for the code. I can see quite a few uses for it.
#2
04/02/2006 (4:45 pm)
No problem...of course, you can exempt as many as you want, just modify it the same way with more exemptions.
#3
04/03/2006 (4:24 pm)
Not sure what this accomplishes...
Is there a reason that you couldn't just use the mask bits?

i.e. gServerContainer.castRay(start, end, InteriorObjectType | StaticTSObjectType | PlayerObjectType, &riinfo)
etc.

That allows for way more than 2 ignores already, without any code changes....

Unless it's only the script method, as it appears, that you are referring to....
#4
04/03/2006 (4:32 pm)
If I understand it correctly, the mask bits allow you to exempt different types of objects. In my game, I want to be able to select any ItemObjectType (for instance), but not if that object is currently the "selected" object. So I want to exclude that object, as well as the Player object, but not other Item objects.

I'm not sure how you'd do that with just the masks.
#5
07/12/2006 (10:38 am)
Yeah Rubes, that would not be possible with typeMasks.

Very nice resource, thank you!