Game Development Community

MWaterCoverage bug

by Ian Omroth Hardingham · in Torque Game Engine · 10/02/2004 (10:10 am) · 13 replies

Hey everyone.

I have a problem with Player::mWaterCoverage, and a quick forum search has come up with nothing. I'm posting on the bugs forum because I got the impression from IRC that this was a general problem, so if it's not and it's just my dodgy build I apologise.

Player::mWaterCoverage seems to be zero when I'm underwater. It works fine at the top of the water block, for instance if I'm only half in it shows 0.5 etc, but after a few feet down it suddenly switches to zero.

If this is a general problem, does anyone know how to fix it?

Any help is much appreciated.
Ian

#1
12/17/2007 (8:09 pm)
I know this post is old ... but it seems as good a place as any to put this... I just ran up against this as well. After a quick search of my own, I found this: www.garagegames.com/mg/forums/result.thread.php?qt=9523 that nominally addressed the issue but didn't really give a fix. Here's what I came up with:

The failure is really in the shapebase::updateContainer() function. This seems to only detect the waterblock if you are actually intersecting the surface. This happens with any ShapeBase derived object class - I tested with the Item class. It makes the entire bouyency/drag system fail(bouyancy becomes 0 beneath the surface). I made this patch to fix it at the shapebase level.

if you want to try this, MAKE A BACKUP ... ok now,

in ShapeBase.h add the line in BOLD
/// Update bouyency and drag properties
   void updateContainer();
[b]   bool checkInLiquid();	// KGB: So that the updateContainer function works [/b]
   /// @name Events
   /// @{
   virtual void onDeleteNotify(SimObject*);

Next, in shapeBase.cc, find:

//----------------------------------------------------------------------------

static F32 sWaterDensity   = 1;
static F32 sWaterViscosity = 15;
static F32 sWaterCoverage  = 0;
static U32 sWaterType      = 0;
static F32 sWaterHeight    = 0.0f;

static void waterFind(SceneObject* obj, void* key)

Now you want to REPLACE THIS AND EVERYTHING DOWN TO THE NEXT

//----------------------------------------------------------------------------
This should be just before the "void ShapeBase::applyRepair(F32 amount)" function.

Replace the entire section with this:
//----------------------------------------------------------------------------

void physicalZoneFind(SceneObject* obj, void *key)
{
   ShapeBase* shape = reinterpret_cast<ShapeBase*>(key);
   PhysicalZone* pz = dynamic_cast<PhysicalZone*>(obj);
   AssertFatal(pz != NULL, "Error, not a physical zone!");
   if (pz == NULL || pz->testObject(shape) == false) {
      return;
   }

   if (pz->isActive()) {
      shape->mGravityMod   *= pz->getGravityMod();
      shape->mAppliedForce += pz->getForce();
   }
}

// KGB: Bug fix - Modified this function to check for water differently.  The
// "findObjects" method only seemed to work when the player actually intersected
// the water surface - standing on the bottom of the lake, the player::pointInWater
// function said "yes", but this function said "no" (well, mWaterCoverage = 0).
// 
// Player::pointInWater() was combined with ShapeBase::waterFind() to make
// a new ShapeBase::checkInLiquid() function.  I'm not great at C, so I kind of hacked
// the water out of the findObjects loop and eliminated the findRouter function because 
// findObjects() is now only looking for physical zones - why route? (seems to work)

void ShapeBase::updateContainer()
{
   // Update container drag and buoyancy properties
   mDrag = mDataBlock->drag;
   mBuoyancy = 0;
   mWaterCoverage = 0;
   mLiquidType = 0;
   mLiquidHeight = 0.0f;
   mGravityMod = 1.0;
   mAppliedForce.set(0, 0, 0);
   
   mContainer->findObjects(getWorldBox(), PhysicalZoneObjectType,physicalZoneFind,this);

   checkInLiquid();
}

// KGB: 
// This is based on the player::pointInWater function.  It gets a list of all water blocks,
// and checks each to see if the object is in the water.  If so, it sets up the various 
// water-related variables like the old waterFind()/updateContainer()  functions.
// 
bool ShapeBase::checkInLiquid()
{
   SimpleQueryList sql;
   if (isServerObject())
      gServerSceneGraph->getWaterObjectList(sql);
   else
      gClientSceneGraph->getWaterObjectList(sql);

   for (U32 i = 0; i < sql.mList.size(); i++)
   {
      WaterBlock* pBlock = dynamic_cast<WaterBlock*>(sql.mList[i]);      
      if (pBlock)
      {
         Point3F pos = getPosition();         
         if (pBlock->isPointSubmergedSimple(pos)){            
            // This is the water block we are submerged in. Do the calculations - and drop them
            // into the object variables

            const Box3F& wbox = pBlock->getWorldBox();   // Waterblock box to compare with
            const Box3F& sbox = getWorldBox();           // Object box and see if the object's
            if (wbox.max.z < sbox.max.z)                 // top is higher than the waterblock's
               // If so - figure out how deep we are
               mWaterCoverage = mClampF((wbox.max.z - sbox.min.z) / (sbox.max.z - sbox.min.z),0,1);
            else
               // Otherwise, we're over our head
               mWaterCoverage = 1.0f;

            if (mWaterCoverage >= 0.1f) {
               // If we are deep enough - calculate the density and viscocity
               F32 viscosity = pBlock->getViscosity();
               F32 density = pBlock->getDensity();

               mDrag = mDataBlock->drag * viscosity * mWaterCoverage;
               mBuoyancy = (density / mDataBlock->density) * mWaterCoverage;
            }
            // Look up the liquid's particulars for the object's pleasure.
            mLiquidType = pBlock->getLiquidType();
            mLiquidHeight = pBlock->getSurfaceHeight();
            return true;
         }         
      }

   }
   return false;
}


//----------------------------------------------------------------------------

OK, that's it - now jump from the top of that cliff, and pop right back up to the surface (if your density/mass ratio so allows). Don't blame me if you can't move ;-)

Update: fixed stupid typos
#2
12/18/2007 (7:56 am)
NOTE: This is really a problem with the findObjects() function. So in that respect, even after this patch the engine is still somewhat broken. You can expect that any other place in the engine that uses the Container::findObjects() to find water in a similar fashion should also fail.
#3
12/18/2007 (8:19 am)
Hi Kent, thanks for the three-year-late help ;)
#4
12/19/2007 (6:39 pm)
Hey, better late than never!

Replying here was easier (for me) than figuring out where to post it as a new issue.
#5
01/12/2008 (1:38 pm)
Kent, thank you. I owe you one.

Robert
#6
03/02/2008 (3:41 pm)
Does this need to be done in TGEA?
#7
03/16/2008 (11:40 pm)
Nobody got an answer? Or tried this for TGEA?
#8
03/17/2008 (3:08 am)
Yes it applies to TGEA, Ron.
#9
03/17/2008 (1:02 pm)
Stefan, there are a few differences in this from the current TGEA code. There are no longer certain functions like:

isPointSubmergedSimple
getViscosity
getDensity
getSurfaceHeight

Have you managed to get these back into the TGEA waterblock? If so could you send me a copy?

RJNelson68@cox.net
#10
04/15/2008 (4:44 am)
I'm interested in this as well for TGEA 1.7. Do you guys have any news on this?
#11
04/15/2008 (5:26 pm)
Yeah my attempt at adding this just got the player to shake aorund alot. Obviously I did something wrong.
#12
05/20/2008 (2:55 pm)
Anyone done this yet in TGEA?
#13
05/20/2008 (11:13 pm)
Ron, maybe this helps.