Jump to content

Temporarily Disable Player v Player Collision: Fixed


Steve_Yorkshire

Recommended Posts

So I've been trying to temporarily disable PlayerObjectMask vs PlayerObjectMask. The idea was set a flag in shapeBase.cpp or Player.cpp, check for the flag when a player bumps into another and then ignore the collision ...

... but it's not been going well ...


First off I went looking for the collision object versus mask function and tried to disable collision by getting the colMask in shapebase's QueueCollision. I could get the object's mask but telling it to stop collision was a no no. So I went looking elsewhere ...


Then I went hunting through convex and in workingListUpdate added an ignore value which is the ID of the object set in Player's updateWorkingCollisionSet. nah ...


Then I went back into convex and caused rather a lot of crashing. Then I disabled ALL player collisions and fell through the floor.


Any thoughts, pointers, hints on what function I should be looking in, etc welcome. :?:


So, I'm a bit stumped on this. Next plan is to try and add a collisionTimeOut to shapebase like projectiles have when they first spawn so they don't their shooting object, to see if that will work.



========================================

[edit] okay I think I got this working see below! :idea:

========================================



After much barking up the wrong tree and following the spilled spaghetti of collision functions through the various Cthulhuesque innards of the engine ... it turns out simpler than it seems (effin' typical :evil: ).


Anyhow this is what I've got, I had no idea whether it is the best thing or not, but it seems to work (at least on local server - other PC is in bits so can't test multiplayer).


Turns out the magic all happens in Player::updateWorkingCollisionSet. Here it looks for either the client (for triggers) or server (for triggers and everything else) collisionContactMasks. Server collision that pulls in the moveMask which has the playerObjectType. So I created a new set of modified server collision and move masks (minus the playerObjectMask) which get used instead, if the toggle value is set to true (in this case mNoClip).


This worked, though the last playerObject to collide with would need 2 collisions before it updated because it was still on the old collision list. Adding a flag to say that mNoClip had changed and we need to refresh the collision list. After that the player could move through other ai/players fine (though there is a barely visible shake when this happens but it doesn't affect speed and to be honest might just be me hallucinating I have been staring at it all for so long).


Here's the list of what happens:

set noClip true and also resetClip true

bool noClip? true;

is the collision a player? true;

has noClip just changed? then resetClip is true;

if resetClip is true, rebuild the collision list to clear out the last playerObject stored

if noClip and collision is a player, use the new collisionContactMask, else just use the old one.


Here's what it looks like in code:

player.h

class Player: public ShapeBase
{
   typedef ShapeBase Parent;
 
public:
//..
 
protected:
//...
 
//yorks at the end of protected
   bool mNoClip = false;//yorks no collision vs players
   bool mRetestClip = false;//yorks mNoClip state has changed
 
//..
public:
   DECLARE_CONOBJECT(Player);
 
//...
//yorks new at the end
   bool getClipState();//yorks the state of mNoClip
   void setClipState(bool val);//yorks set mNoClip
   void resetClipState();//yorks set to false
   bool toggleClipState(bool val);//yorks defineEngineMethod not a real toggle either, just a bool
   bool getRetestClipState();//yorks do we need to retest if mNoClip state has changed?
   void clearResetClipState();//yorks reset the reset for the clip state
 
   //yorks end
};

 

player.cpp

//...
 
static U32 sCollisionMoveMask =  TerrainObjectType       |
                                 WaterObjectType         | 
                                 PlayerObjectType        |
                                 StaticShapeObjectType   | 
                                 VehicleObjectType       |
                                 PhysicalZoneObjectType;
 
static U32 sServerCollisionContactMask = sCollisionMoveMask |
                                         ItemObjectType     |
                                         TriggerObjectType  |
                                         CorpseObjectType;
 
static U32 sClientCollisionContactMask = sCollisionMoveMask |
                                         TriggerObjectType;
 
//yorks new CollisionMasks up near the top
static U32 sCollisionMoveMaskMod = TerrainObjectType |//yorks playerObjectTypeRemoved
WaterObjectType |
StaticShapeObjectType |
VehicleObjectType |
PhysicalZoneObjectType;
 
static U32 sServerCollisionContactMaskMod = sCollisionMoveMaskMod |//yorks to call above collisionMoveMaskMod
ItemObjectType |
TriggerObjectType |
CorpseObjectType;
 
//...
 
void Player::updateWorkingCollisionSet()
{
	//yorks
	bool noClip = false;
	bool isPlayer = false;
	bool retest = false;
 
	if (getClipState() == true)
	{
		noClip = true;
 
		if (mConvex.getObject()->getTypeMask() & PlayerObjectType)
			isPlayer = true;
 
		if (getRetestClipState() == true)
			retest = true;
	}
	//yorks
 
   // First, we need to adjust our velocity for possible acceleration.  It is assumed
   // that we will never accelerate more than 20 m/s for gravity, plus 10 m/s for
   // jetting, and an equivalent 10 m/s for jumping.  We also assume that the
   // working list is updated on a Tick basis, which means we only expand our
   // box by the possible movement in that tick.
   Point3F scaledVelocity = mVelocity * TickSec;
   F32 len    = scaledVelocity.len();
   F32 newLen = len + (10.0f * TickSec);
 
   // Check to see if it is actually necessary to construct the new working list,
   // or if we can use the cached version from the last query.  We use the x
   // component of the min member of the mWorkingQueryBox, which is lame, but
   // it works ok.
   bool updateSet = false;
 
   Box3F convexBox = mConvex.getBoundingBox(getTransform(), getScale());
   F32 l = (newLen * 1.1f) + 0.1f;  // from Convex::updateWorkingList
   const Point3F  lPoint( l, l, l );
   convexBox.minExtents -= lPoint;
   convexBox.maxExtents += lPoint;
 
   // Check containment
   if (mWorkingQueryBox.minExtents.x != -1e9f)
   {
      if (mWorkingQueryBox.isContained(convexBox) == false)
         // Needed region is outside the cached region.  Update it.
         updateSet = true;
   }
   else
   {
      // Must update
      updateSet = true;
   }
 
   //yorks new
   if (updateSet != true && retest == true)
   {
	   updateSet = true;
	   clearResetClipState();
   }
 
   // Actually perform the query, if necessary
   if (updateSet == true) {
	   const Point3F  twolPoint(2.0f * l, 2.0f * l, 2.0f * l);
	   mWorkingQueryBox = convexBox;
	   mWorkingQueryBox.minExtents -= twolPoint;
	   mWorkingQueryBox.maxExtents += twolPoint;
 
	   disableCollision();
 
	   //yorks new start
	   if (noClip == true && isPlayer == true)
	   {
			mConvex.updateWorkingList(mWorkingQueryBox,
				isGhost() ? sClientCollisionContactMask : sServerCollisionContactMaskMod);
			enableCollision();
	   }
	   else
	   {
		   //yorks this is the original bit
		   mConvex.updateWorkingList(mWorkingQueryBox,
			   isGhost() ? sClientCollisionContactMask : sServerCollisionContactMask);
		   enableCollision();
		   //yorks this is the original bit
	   }
	   //yorks new end
   }
}

 

And finally add our new working functions near the bottom of player.cpp:

 

bool Player::getClipState()
{
	return mNoClip;
}
 
void Player::setClipState(bool val)
{
	bool cur = getClipState();
	if (cur == true && val == false)
	{
		mNoClip = false;
		mRetestClip = true;
	}
	else
	{
		if (cur == false && val == true)
		{
			mNoClip = true;
			mRetestClip = true;
		}
		else
			mRetestClip = false;
	}
 
}
 
bool Player::getRetestClipState()
{
	return mRetestClip;
}
 
void Player::clearResetClipState()
{
	mRetestClip = false;
}
 
DefineEngineMethod(Player, resetClipState, void, (), ,
	"Set the object's clip State to false.\n"
	"@returns nothing\n")
{
	object->setClipState(false);
}
 
DefineEngineMethod(Player, toggleClipState, void, (bool val), ,
	"Set the object's clip State.\n"
	"@returns nothing\n")
{
	object->setClipState(val);
}
 
DefineEngineMethod(Player, getClipState, bool, (), ,
	"@brief Check if the object has mClipState state.\n\n"
 
	"@return true if mNoClip state is \"Enabled\", false if not\n")
{
	return object->getClipState();
}

 

Now spawn some Ai - keep them still it helps when you're trying to collide with them ;)

yourPlayerID.toggleClipState(true);//to set the player v player clip state

Now run through the AiPlayers!

yourPlayerID.resetClipState();//to turn it off again


As I say, I am not sure if this is all the best way to do it, but it certainly seems to work okay.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...