📄 item.cc
字号:
{
// Need to clear out last updatePos or warp interpolation
delta.posVec.set(0,0,0);
}
}
}
void Item::interpolateTick(F32 dt)
{
// Client side interpolation
Parent::interpolateTick(dt);
Point3F pos = delta.pos + delta.posVec * dt;
MatrixF mat = mObjToWorld;
mat.setColumn(3,pos);
Parent::setRenderTransform(mat);
delta.dt = dt;
}
//----------------------------------------------------------------------------
void Item::setTransform(const MatrixF& mat)
{
Point3F pos;
mat.getColumn(3,&pos);
MatrixF tmat;
if (!mRotate)
{
// Forces all rotation to be around the z axis
VectorF vec;
mat.getColumn(1,&vec);
tmat.set(EulerF(0,0,-mAtan(-vec.x,vec.y)));
}
else
tmat.identity();
tmat.setColumn(3,pos);
Parent::setTransform(tmat);
if (!mStatic)
{
mAtRest = false;
mAtRestCounter = 0;
}
setMaskBits(RotationMask | PositionMask | NoWarpMask);
}
//----------------------------------------------------------------------------
void Item::updateWorkingCollisionSet(const U32 mask, const F32 dt)
{
// It is assumed that we will never accelerate more than 10 m/s for gravity...
//
Point3F scaledVelocity = mVelocity * dt;
F32 len = scaledVelocity.len();
F32 newLen = len + (10 * dt);
// 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.1) + 0.1; // from Convex::updateWorkingList
convexBox.min -= Point3F(l, l, l);
convexBox.max += Point3F(l, l, l);
// Check containment
{
if (mWorkingQueryBox.min.x != -1e9)
{
if (mWorkingQueryBox.isContained(convexBox) == false)
{
// Needed region is outside the cached region. Update it.
updateSet = true;
}
else
{
// We can leave it alone, we're still inside the cached region
}
}
else
{
// Must update
updateSet = true;
}
}
// Actually perform the query, if necessary
if (updateSet == true)
{
mWorkingQueryBox = convexBox;
mWorkingQueryBox.min -= Point3F(2 * l, 2 * l, 2 * l);
mWorkingQueryBox.max += Point3F(2 * l, 2 * l, 2 * l);
disableCollision();
if (mCollisionObject)
mCollisionObject->disableCollision();
mConvex.updateWorkingList(mWorkingQueryBox, mask);
if (mCollisionObject)
mCollisionObject->enableCollision();
enableCollision();
}
}
void Item::updateVelocity(const F32 dt)
{
// Acceleration due to gravity
mVelocity.z += (mGravity * mDataBlock->gravityMod) * dt;
F32 len;
if (mDataBlock->maxVelocity > 0 && (len = mVelocity.len()) > (mDataBlock->maxVelocity * 1.05))
{
Point3F excess = mVelocity * (1.0 - (mDataBlock->maxVelocity / len ));
excess *= 0.1;
mVelocity -= excess;
}
// Container buoyancy & drag
mVelocity.z -= mBuoyancy * (mGravity * mDataBlock->gravityMod * mGravityMod) * dt;
mVelocity -= mVelocity * mDrag * dt;
}
void Item::updatePos(const U32 /*mask*/, const F32 dt)
{
// Try and move
Point3F pos;
mObjToWorld.getColumn(3,&pos);
delta.posVec = pos;
bool contact = false;
bool nonStatic = false;
bool stickyNotify = false;
CollisionList collisionList;
F32 time = dt;
static Polyhedron sBoxPolyhedron;
static ExtrudedPolyList sExtrudedPolyList;
static EarlyOutPolyList sEarlyOutPolyList;
MatrixF collisionMatrix(true);
Point3F end = pos + mVelocity * time;
U32 mask = isServerObject() ? sServerCollisionMask : sClientCollisionMask;
// Part of our speed problem here is that we don't track contact surfaces, like we do
// with the player. In order to handle the most common and performance impacting
// instance of this problem, we'll use a ray cast to detect any contact surfaces below
// us. This won't be perfect, but it only needs to catch a few of these to make a
// big difference. We'll cast from the top center of the bounding box at the tick's
// beginning to the bottom center of the box at the end.
Point3F startCast((mObjBox.min.x + mObjBox.max.x) * 0.5,
(mObjBox.min.y + mObjBox.max.y) * 0.5,
mObjBox.max.z);
Point3F endCast((mObjBox.min.x + mObjBox.max.x) * 0.5,
(mObjBox.min.y + mObjBox.max.y) * 0.5,
mObjBox.min.z);
collisionMatrix.setColumn(3, pos);
collisionMatrix.mulP(startCast);
collisionMatrix.setColumn(3, end);
collisionMatrix.mulP(endCast);
RayInfo rinfo;
bool doToughCollision = true;
if (mCollisionObject)
mCollisionObject->disableCollision();
if (getContainer()->castRay(startCast, endCast, mask, &rinfo))
{
F32 bd = -mDot(mVelocity, rinfo.normal);
if (bd >= 0.0)
{
// Contact!
if (mDataBlock->sticky && rinfo.object->getType() & (InteriorObjectType|TerrainObjectType))
{
mVelocity.set(0, 0, 0);
mAtRest = true;
mAtRestCounter = 0;
stickyNotify = true;
mStickyCollisionPos = rinfo.point;
mStickyCollisionNormal = rinfo.normal;
doToughCollision = false;;
}
else
{
// Subtract out velocity into surface and friction
VectorF fv = mVelocity + rinfo.normal * bd;
F32 fvl = fv.len();
if (fvl)
{
F32 ff = bd * mDataBlock->friction;
if (ff < fvl)
{
fv *= ff / fvl;
fvl = ff;
}
}
bd *= 1 + mDataBlock->elasticity;
VectorF dv = rinfo.normal * (bd + 0.002);
mVelocity += dv;
mVelocity -= fv;
// Keep track of what we hit
contact = true;
U32 typeMask = rinfo.object->getTypeMask();
if (!(typeMask & StaticObjectType))
nonStatic = true;
if (isServerObject() && (typeMask & ShapeBaseObjectType))
{
ShapeBase* col = static_cast<ShapeBase*>(rinfo.object);
queueCollision(col,mVelocity - col->getVelocity());
}
}
}
}
if (mCollisionObject)
mCollisionObject->enableCollision();
if (doToughCollision)
{
U32 count;
for (count = 0; count < 3; count++)
{
// Build list from convex states here...
end = pos + mVelocity * time;
collisionMatrix.setColumn(3, end);
Box3F wBox = getObjBox();
collisionMatrix.mul(wBox);
Box3F testBox = wBox;
Point3F oldMin = testBox.min;
Point3F oldMax = testBox.max;
testBox.min.setMin(oldMin + (mVelocity * time));
testBox.max.setMin(oldMax + (mVelocity * time));
sEarlyOutPolyList.clear();
sEarlyOutPolyList.mNormal.set(0,0,0);
sEarlyOutPolyList.mPlaneList.setSize(6);
sEarlyOutPolyList.mPlaneList[0].set(wBox.min,VectorF(-1,0,0));
sEarlyOutPolyList.mPlaneList[1].set(wBox.max,VectorF(0,1,0));
sEarlyOutPolyList.mPlaneList[2].set(wBox.max,VectorF(1,0,0));
sEarlyOutPolyList.mPlaneList[3].set(wBox.min,VectorF(0,-1,0));
sEarlyOutPolyList.mPlaneList[4].set(wBox.min,VectorF(0,0,-1));
sEarlyOutPolyList.mPlaneList[5].set(wBox.max,VectorF(0,0,1));
CollisionWorkingList& eorList = mConvex.getWorkingList();
CollisionWorkingList* eopList = eorList.wLink.mNext;
while (eopList != &eorList)
{
if ((eopList->mConvex->getObject()->getType() & mask) != 0)
{
Box3F convexBox = eopList->mConvex->getBoundingBox();
if (testBox.isOverlapped(convexBox))
{
eopList->mConvex->getPolyList(&sEarlyOutPolyList);
if (sEarlyOutPolyList.isEmpty() == false)
break;
}
}
eopList = eopList->wLink.mNext;
}
if (sEarlyOutPolyList.isEmpty())
{
pos = end;
break;
}
collisionMatrix.setColumn(3, pos);
sBoxPolyhedron.buildBox(collisionMatrix, mObjBox);
// Build extruded polyList...
VectorF vector = end - pos;
sExtrudedPolyList.extrude(sBoxPolyhedron, vector);
sExtrudedPolyList.setVelocity(mVelocity);
sExtrudedPolyList.setCollisionList(&collisionList);
CollisionWorkingList& rList = mConvex.getWorkingList();
CollisionWorkingList* pList = rList.wLink.mNext;
while (pList != &rList)
{
if ((pList->mConvex->getObject()->getType() & mask) != 0)
{
Box3F convexBox = pList->mConvex->getBoundingBox();
if (testBox.isOverlapped(convexBox))
{
pList->mConvex->getPolyList(&sExtrudedPolyList);
}
}
pList = pList->wLink.mNext;
}
if (collisionList.t < 1.0)
{
// Set to collision point
F32 dt = time * collisionList.t;
pos += mVelocity * dt;
time -= dt;
// Pick the most resistant surface
F32 bd = 0;
Collision* collision = 0;
for (int c = 0; c < collisionList.count; c++)
{
Collision &cp = collisionList.collision[c];
F32 dot = -mDot(mVelocity,cp.normal);
if (dot > bd)
{
bd = dot;
collision = &cp;
}
}
if (collision && mDataBlock->sticky &&
collision->object->getType() & (InteriorObjectType|TerrainObjectType))
{
mVelocity.set(0, 0, 0);
mAtRest = true;
mAtRestCounter = 0;
stickyNotify = true;
mStickyCollisionPos = collision->point;
mStickyCollisionNormal = collision->normal;
break;
}
else
{
// Subtract out velocity into surface and friction
if (collision)
{
VectorF fv = mVelocity + collision->normal * bd;
F32 fvl = fv.len();
if (fvl)
{
F32 ff = bd * mDataBlock->friction;
if (ff < fvl)
{
fv *= ff / fvl;
fvl = ff;
}
}
bd *= 1 + mDataBlock->elasticity;
VectorF dv = collision->normal * (bd + 0.002);
mVelocity += dv;
mVelocity -= fv;
// Keep track of what we hit
contact = true;
U32 typeMask = collision->object->getTypeMask();
if (!(typeMask & StaticObjectType))
nonStatic = true;
if (isServerObject() && (typeMask & ShapeBaseObjectType))
{
ShapeBase* col = static_cast<ShapeBase*>(collision->object);
queueCollision(col,mVelocity - col->getVelocity());
}
}
}
}
else
{
pos = end;
break;
}
}
if (count == 3)
{
// Couldn't move...
mVelocity.set(0, 0, 0);
}
}
// If on the client, calculate delta for backstepping
if (isGhost())
{
delta.pos = pos;
delta.posVec -= pos;
delta.dt = 1;
}
// Update transform
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -