📄 item.cc
字号:
MatrixF mat = mObjToWorld;
mat.setColumn(3,pos);
Parent::setTransform(mat);
enableCollision();
if (mCollisionObject)
mCollisionObject->enableCollision();
updateContainer();
//
if (contact)
{
// Check for rest condition
if (!nonStatic && mVelocity.len() < sAtRestVelocity)
{
mVelocity.x = mVelocity.y = mVelocity.z = 0;
mAtRest = true;
mAtRestCounter = 0;
}
// Only update the client if we hit a non-static shape or
// if this is our final rest pos.
if (nonStatic || mAtRest)
setMaskBits(PositionMask);
}
// Collision callbacks. These need to be processed whether we hit
// anything or not.
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
if (!isGhost())
#endif
{
SimObjectPtr<Item> safePtr(this);
if (stickyNotify)
{
notifyCollision();
if(bool(safePtr))
Con::executef(mDataBlock, 2, "onStickyCollision", scriptThis());
}
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
else
notifyCollision();
#endif
// water
if(bool(safePtr))
{
if(!mInLiquid && mWaterCoverage != 0.0f)
{
Con::executef(mDataBlock,4,"onEnterLiquid",scriptThis(), Con::getFloatArg(mWaterCoverage), Con::getIntArg(mLiquidType));
mInLiquid = true;
}
else if(mInLiquid && mWaterCoverage == 0.0f)
{
Con::executef(mDataBlock,3,"onLeaveLiquid",scriptThis(), Con::getIntArg(mLiquidType));
mInLiquid = false;
}
}
}
}
//----------------------------------------------------------------------------
static MatrixF IMat(1);
bool Item::buildPolyList(AbstractPolyList* polyList, const Box3F&, const SphereF&)
{
// Collision with the item is always against the item's object
// space bounding box axis aligned in world space.
Point3F pos;
mObjToWorld.getColumn(3,&pos);
IMat.setColumn(3,pos);
polyList->setTransform(&IMat, mObjScale);
polyList->setObject(this);
polyList->addBox(mObjBox);
return true;
}
//----------------------------------------------------------------------------
U32 Item::packUpdate(NetConnection *connection, U32 mask, BitStream *stream)
{
U32 retMask = Parent::packUpdate(connection,mask,stream);
if (stream->writeFlag(mask & InitialUpdateMask))
{
stream->writeFlag(mRotate);
stream->writeFlag(mStatic);
stream->writeFlag(mCollidable);
if (stream->writeFlag(getScale() != Point3F(1, 1, 1)))
mathWrite(*stream, getScale());
}
if (mask & ThrowSrcMask && mCollisionObject)
{
S32 gIndex = connection->getGhostIndex(mCollisionObject);
if (stream->writeFlag(gIndex != -1))
stream->writeInt(gIndex,GhostConnection::GhostIdBitSize);
}
else
stream->writeFlag(false);
if (stream->writeFlag(mask & RotationMask && !mRotate))
{
// Assumes rotation is about the Z axis
AngAxisF aa(mObjToWorld);
stream->writeFlag(aa.axis.z < 0);
stream->write(aa.angle);
}
if (stream->writeFlag(mask & PositionMask))
{
Point3F pos;
mObjToWorld.getColumn(3,&pos);
mathWrite(*stream, pos);
if (!stream->writeFlag(mAtRest))
mathWrite(*stream, mVelocity);
stream->writeFlag(!(mask & NoWarpMask));
}
return retMask;
}
void Item::unpackUpdate(NetConnection *connection, BitStream *stream)
{
Parent::unpackUpdate(connection,stream);
if (stream->readFlag())
{
mRotate = stream->readFlag();
mStatic = stream->readFlag();
mCollidable = stream->readFlag();
if (stream->readFlag())
mathRead(*stream, &mObjScale);
else
mObjScale.set(1, 1, 1);
}
if (stream->readFlag())
{
S32 gIndex = stream->readInt(GhostConnection::GhostIdBitSize);
setCollisionTimeout(static_cast<ShapeBase*>(connection->resolveGhost(gIndex)));
}
MatrixF mat = mObjToWorld;
if (stream->readFlag())
{
// Assumes rotation is about the Z axis
AngAxisF aa;
aa.axis.set(0,0,stream->readFlag()? -1: 1);
stream->read(&aa.angle);
aa.setMatrix(&mat);
Point3F pos;
mObjToWorld.getColumn(3,&pos);
mat.setColumn(3,pos);
}
if (stream->readFlag())
{
Point3F pos;
mathRead(*stream, &pos);
F32 speed = mVelocity.len();
if ((mAtRest = stream->readFlag()) == true)
mVelocity.set(0,0,0);
else
mathRead(*stream, &mVelocity);
if (stream->readFlag() && isProperlyAdded())
{
// Determine number of ticks to warp based on the average
// of the client and server velocities.
delta.warpOffset = pos - delta.pos;
F32 as = (speed + mVelocity.len()) * 0.5 * TickSec;
F32 dt = (as > 0.00001f) ? delta.warpOffset.len() / as: sMaxWarpTicks;
delta.warpTicks = (S32)((dt > sMinWarpTicks)? getMax(mFloor(dt + 0.5), 1.0f): 0.0f);
if (delta.warpTicks)
{
// Setup the warp to start on the next tick, only the
// object's position is warped.
if (delta.warpTicks > sMaxWarpTicks)
delta.warpTicks = sMaxWarpTicks;
delta.warpOffset /= delta.warpTicks;
}
else
{
// Going to skip the warp, server and client are real close.
// Adjust the frame interpolation to move smoothly to the
// new position within the current tick.
Point3F cp = delta.pos + delta.posVec * delta.dt;
VectorF vec = delta.pos - cp;
F32 vl = vec.len();
if (vl)
{
F32 s = delta.posVec.len() / vl;
delta.posVec = (cp - pos) * s;
}
delta.pos = pos;
mat.setColumn(3,pos);
}
}
else
{
// Set the item to the server position
delta.warpTicks = 0;
delta.posVec.set(0,0,0);
delta.pos = pos;
delta.dt = 0;
mat.setColumn(3,pos);
}
}
Parent::setTransform(mat);
}
ConsoleMethod(Item, isStatic, bool, 2, 2, "()"
"Is the object static (ie, non-movable)?")
{
return object->isStatic();
}
ConsoleMethod(Item, isRotating, bool, 2, 2, "()"
"Is the object still rotating?")
{
return object->isRotating();
}
ConsoleMethod(Item, setCollisionTimeout, bool, 3, 3, "(ShapeBase obj)"
"Temporarily disable collisions against obj.")
{
ShapeBase* source;
if (Sim::findObject(dAtoi(argv[2]),source))
{
object->setCollisionTimeout(source);
return true;
}
return false;
}
ConsoleMethod( Item, getLastStickyPos, const char *, 2, 2, "()"
"Get the position on the surface on which the object is stuck.")
{
char* ret = Con::getReturnBuffer(256);
if (object->isServerObject())
dSprintf(ret, 255, "%g %g %g",
object->mStickyCollisionPos.x,
object->mStickyCollisionPos.y,
object->mStickyCollisionPos.z);
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
else
dStrcpy(ret, "0 0 0");
#endif
return ret;
}
ConsoleMethod( Item, getLastStickyNormal, const char *, 2, 2, "()"
"Get the normal of the surface on which the object is stuck.")
{
char* ret = Con::getReturnBuffer(256);
if (object->isServerObject())
dSprintf(ret, 255, "%g %g %g",
object->mStickyCollisionNormal.x,
object->mStickyCollisionNormal.y,
object->mStickyCollisionNormal.z);
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
else
dStrcpy(ret, "0 0 0");
#endif
return ret;
}
//----------------------------------------------------------------------------
void Item::initPersistFields()
{
Parent::initPersistFields();
addGroup("Misc");
addDepricatedField("collideable");
addField("collidable", TypeBool, Offset(mCollidable, Item));
addField("static", TypeBool, Offset(mStatic, Item));
addField("rotate", TypeBool, Offset(mRotate, Item));
endGroup("Misc");
}
void Item::consoleInit()
{
Con::addVariable("Item::minWarpTicks",TypeF32,&sMinWarpTicks);
Con::addVariable("Item::maxWarpTicks",TypeS32,&sMaxWarpTicks);
}
//----------------------------------------------------------------------------
bool Item::prepRenderImage(SceneState* state,
const U32 stateKey,
const U32 startZone,
const bool modifyBaseState)
{
// Items do NOT render if destroyed
if (getDamageState() == Destroyed)
return false;
return Parent::prepRenderImage(state, stateKey, startZone, modifyBaseState);
}
void Item::renderImage(SceneState* state, SceneRenderImage* image)
{
// Client side rotation
if (mRotate)
{
F32 t = Sim::getCurrentTime() * F32(1)/1000;
F32 r = (t / sRotationSpeed) * M_2PI;
Point3F pos;
mRenderObjToWorld.getColumn(3,&pos);
MatrixF mat = mRenderObjToWorld;
mat.set(Point3F(0,0,r));
mat.setColumn(3,pos);
Parent::setRenderTransform(mat);
}
Parent::renderImage(state, image);
if (mShadow)
{
mShadow->setMoving(!mAtRest);
mShadow->setAnimating(!mAtRest && !mRotate);
}
}
void Item::buildConvex(const Box3F& box, Convex* convex)
{
if (mShapeInstance == NULL)
return;
// These should really come out of a pool
mConvexList->collectGarbage();
if (box.isOverlapped(getWorldBox()) == false)
return;
// Just return a box convex for the entire shape...
Convex* cc = 0;
CollisionWorkingList& wl = convex->getWorkingList();
for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext)
{
if (itr->mConvex->getType() == BoxConvexType &&
itr->mConvex->getObject() == this)
{
cc = itr->mConvex;
break;
}
}
if (cc)
return;
// Create a new convex.
BoxConvex* cp = new BoxConvex;
mConvexList->registerObject(cp);
convex->addToWorkingList(cp);
cp->init(this);
mObjBox.getCenter(&cp->mCenter);
cp->mSize.x = mObjBox.len_x() / 2.0f;
cp->mSize.y = mObjBox.len_y() / 2.0f;
cp->mSize.z = mObjBox.len_z() / 2.0f;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -