mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 04:34:48 +00:00
620 lines
18 KiB
C++
620 lines
18 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "platform/platform.h"
|
|
#include "T3D/components/collision/collisionTrigger.h"
|
|
|
|
#include "scene/sceneRenderState.h"
|
|
#include "console/consoleTypes.h"
|
|
#include "console/engineAPI.h"
|
|
#include "collision/boxConvex.h"
|
|
|
|
#include "core/stream/bitStream.h"
|
|
#include "math/mathIO.h"
|
|
#include "gfx/gfxTransformSaver.h"
|
|
#include "renderInstance/renderPassManager.h"
|
|
#include "gfx/gfxDrawUtil.h"
|
|
#include "T3D/physics/physicsPlugin.h"
|
|
#include "T3D/physics/physicsBody.h"
|
|
#include "T3D/physics/physicsCollision.h"
|
|
|
|
|
|
bool CollisionTrigger::smRenderCollisionTriggers = false;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
//--------------------------------------------------------------------------
|
|
|
|
IMPLEMENT_CO_NETOBJECT_V1(CollisionTrigger);
|
|
|
|
ConsoleDocClass(CollisionTrigger,
|
|
"@brief A CollisionTrigger is a volume of space that initiates script callbacks "
|
|
"when objects pass through the CollisionTrigger.\n\n"
|
|
|
|
"CollisionTriggerData provides the callbacks for the CollisionTrigger when an object enters, stays inside "
|
|
"or leaves the CollisionTrigger's volume.\n\n"
|
|
|
|
"@see CollisionTriggerData\n"
|
|
"@ingroup gameObjects\n"
|
|
);
|
|
|
|
IMPLEMENT_CALLBACK(CollisionTrigger, onAdd, void, (U32 objectId), (objectId),
|
|
"@brief Called when the CollisionTrigger is being created.\n\n"
|
|
"@param objectId the object id of the CollisionTrigger being created\n");
|
|
|
|
IMPLEMENT_CALLBACK(CollisionTrigger, onRemove, void, (U32 objectId), (objectId),
|
|
"@brief Called just before the CollisionTrigger is deleted.\n\n"
|
|
"@param objectId the object id of the CollisionTrigger being deleted\n");
|
|
|
|
CollisionTrigger::CollisionTrigger()
|
|
{
|
|
// Don't ghost by default.
|
|
mNetFlags.set(Ghostable | ScopeAlways);
|
|
|
|
mTypeMask |= TriggerObjectType;
|
|
|
|
mObjScale.set(1, 1, 1);
|
|
mObjToWorld.identity();
|
|
mWorldToObj.identity();
|
|
|
|
mLastThink = 0;
|
|
mCurrTick = 0;
|
|
|
|
mConvexList = new Convex;
|
|
|
|
mPhysicsRep = NULL;
|
|
}
|
|
|
|
CollisionTrigger::~CollisionTrigger()
|
|
{
|
|
delete mConvexList;
|
|
mConvexList = NULL;
|
|
SAFE_DELETE(mPhysicsRep);
|
|
}
|
|
|
|
bool CollisionTrigger::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
|
|
{
|
|
// Collide against bounding box
|
|
F32 st, et, fst = 0, fet = 1;
|
|
F32 *bmin = &mObjBox.minExtents.x;
|
|
F32 *bmax = &mObjBox.maxExtents.x;
|
|
F32 const *si = &start.x;
|
|
F32 const *ei = &end.x;
|
|
|
|
for (S32 i = 0; i < 3; i++)
|
|
{
|
|
if (*si < *ei)
|
|
{
|
|
if (*si > *bmax || *ei < *bmin)
|
|
return false;
|
|
F32 di = *ei - *si;
|
|
st = (*si < *bmin) ? (*bmin - *si) / di : 0;
|
|
et = (*ei > *bmax) ? (*bmax - *si) / di : 1;
|
|
}
|
|
else
|
|
{
|
|
if (*ei > *bmax || *si < *bmin)
|
|
return false;
|
|
F32 di = *ei - *si;
|
|
st = (*si > *bmax) ? (*bmax - *si) / di : 0;
|
|
et = (*ei < *bmin) ? (*bmin - *si) / di : 1;
|
|
}
|
|
if (st > fst) fst = st;
|
|
if (et < fet) fet = et;
|
|
if (fet < fst)
|
|
return false;
|
|
bmin++; bmax++;
|
|
si++; ei++;
|
|
}
|
|
|
|
info->normal = start - end;
|
|
info->normal.normalizeSafe();
|
|
getTransform().mulV(info->normal);
|
|
|
|
info->t = fst;
|
|
info->object = this;
|
|
info->point.interpolate(start, end, fst);
|
|
info->material = 0;
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CollisionTrigger::consoleInit()
|
|
{
|
|
Con::addVariable("$CollisionTrigger::renderCollisionTriggers", TypeBool, &smRenderCollisionTriggers,
|
|
"@brief Forces all CollisionTrigger's to render.\n\n"
|
|
"Used by the Tools and debug render modes.\n"
|
|
"@ingroup gameObjects");
|
|
}
|
|
|
|
void CollisionTrigger::initPersistFields()
|
|
{
|
|
addField("polyhedron", TypeTriggerPolyhedron, Offset(mCollisionTriggerPolyhedron, CollisionTrigger),
|
|
"@brief Defines a non-rectangular area for the CollisionTrigger.\n\n"
|
|
"Rather than the standard rectangular bounds, this optional parameter defines a quadrilateral "
|
|
"CollisionTrigger area. The quadrilateral is defined as a corner point followed by three vectors "
|
|
"representing the edges extending from the corner.\n");
|
|
|
|
addProtectedField("enterCommand", TypeCommand, Offset(mEnterCommand, CollisionTrigger), &setEnterCmd, &defaultProtectedGetFn,
|
|
"The command to execute when an object enters this CollisionTrigger. Object id stored in %%obj. Maximum 1023 characters.");
|
|
addProtectedField("leaveCommand", TypeCommand, Offset(mLeaveCommand, CollisionTrigger), &setLeaveCmd, &defaultProtectedGetFn,
|
|
"The command to execute when an object leaves this CollisionTrigger. Object id stored in %%obj. Maximum 1023 characters.");
|
|
addProtectedField("tickCommand", TypeCommand, Offset(mTickCommand, CollisionTrigger), &setTickCmd, &defaultProtectedGetFn,
|
|
"The command to execute while an object is inside this CollisionTrigger. Maximum 1023 characters.");
|
|
|
|
Parent::initPersistFields();
|
|
}
|
|
|
|
bool CollisionTrigger::setEnterCmd(void *object, const char *index, const char *data)
|
|
{
|
|
static_cast<CollisionTrigger*>(object)->setMaskBits(EnterCmdMask);
|
|
return true; // to update the actual field
|
|
}
|
|
|
|
bool CollisionTrigger::setLeaveCmd(void *object, const char *index, const char *data)
|
|
{
|
|
static_cast<CollisionTrigger*>(object)->setMaskBits(LeaveCmdMask);
|
|
return true; // to update the actual field
|
|
}
|
|
|
|
bool CollisionTrigger::setTickCmd(void *object, const char *index, const char *data)
|
|
{
|
|
static_cast<CollisionTrigger*>(object)->setMaskBits(TickCmdMask);
|
|
return true; // to update the actual field
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
bool CollisionTrigger::onAdd()
|
|
{
|
|
if (!Parent::onAdd())
|
|
return false;
|
|
|
|
onAdd_callback(getId());
|
|
|
|
Polyhedron temp = mCollisionTriggerPolyhedron;
|
|
setTriggerPolyhedron(temp);
|
|
|
|
addToScene();
|
|
|
|
if (isServerObject())
|
|
scriptOnAdd();
|
|
|
|
return true;
|
|
}
|
|
|
|
void CollisionTrigger::onRemove()
|
|
{
|
|
onRemove_callback(getId());
|
|
|
|
mConvexList->nukeList();
|
|
|
|
removeFromScene();
|
|
Parent::onRemove();
|
|
}
|
|
|
|
bool CollisionTrigger::onNewDataBlock(GameBaseData *dptr, bool reload)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void CollisionTrigger::onDeleteNotify(SimObject *obj)
|
|
{
|
|
GameBase* pScene = dynamic_cast<GameBase*>(obj);
|
|
|
|
if (pScene != NULL)
|
|
{
|
|
for (U32 i = 0; i < mObjects.size(); i++)
|
|
{
|
|
if (pScene == mObjects[i])
|
|
{
|
|
mObjects.erase(i);
|
|
//onLeaveCollisionTrigger_callback(this, pScene);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Parent::onDeleteNotify(obj);
|
|
}
|
|
|
|
void CollisionTrigger::inspectPostApply()
|
|
{
|
|
setTriggerPolyhedron(mCollisionTriggerPolyhedron);
|
|
setMaskBits(PolyMask);
|
|
Parent::inspectPostApply();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
void CollisionTrigger::buildConvex(const Box3F& box, Convex* convex)
|
|
{
|
|
// These should really come out of a pool
|
|
mConvexList->collectGarbage();
|
|
|
|
Box3F realBox = box;
|
|
mWorldToObj.mul(realBox);
|
|
realBox.minExtents.convolveInverse(mObjScale);
|
|
realBox.maxExtents.convolveInverse(mObjScale);
|
|
|
|
if (realBox.isOverlapped(getObjBox()) == 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;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void CollisionTrigger::setTransform(const MatrixF & mat)
|
|
{
|
|
Parent::setTransform(mat);
|
|
|
|
if (mPhysicsRep)
|
|
mPhysicsRep->setTransform(mat);
|
|
|
|
if (isServerObject()) {
|
|
MatrixF base(true);
|
|
base.scale(Point3F(1.0 / mObjScale.x,
|
|
1.0 / mObjScale.y,
|
|
1.0 / mObjScale.z));
|
|
base.mul(mWorldToObj);
|
|
mClippedList.setBaseTransform(base);
|
|
|
|
setMaskBits(TransformMask | ScaleMask);
|
|
}
|
|
}
|
|
|
|
void CollisionTrigger::prepRenderImage(SceneRenderState *state)
|
|
{
|
|
// only render if selected or render flag is set
|
|
if (!smRenderCollisionTriggers && !isSelected())
|
|
return;
|
|
|
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
|
ri->renderDelegate.bind(this, &CollisionTrigger::renderObject);
|
|
ri->type = RenderPassManager::RIT_Editor;
|
|
ri->translucentSort = true;
|
|
ri->defaultKey = 1;
|
|
state->getRenderPass()->addInst(ri);
|
|
}
|
|
|
|
void CollisionTrigger::renderObject(ObjectRenderInst *ri,
|
|
SceneRenderState *state,
|
|
BaseMatInstance *overrideMat)
|
|
{
|
|
if (overrideMat)
|
|
return;
|
|
|
|
GFXStateBlockDesc desc;
|
|
desc.setZReadWrite(true, false);
|
|
desc.setBlend(true);
|
|
|
|
// CollisionTrigger polyhedrons are set up with outward facing normals and CCW ordering
|
|
// so can't enable backface culling.
|
|
desc.setCullMode(GFXCullNone);
|
|
|
|
GFXTransformSaver saver;
|
|
|
|
MatrixF mat = getRenderTransform();
|
|
mat.scale(getScale());
|
|
|
|
GFX->multWorld(mat);
|
|
|
|
GFXDrawUtil *drawer = GFX->getDrawUtil();
|
|
|
|
drawer->drawPolyhedron(desc, mCollisionTriggerPolyhedron, ColorI(255, 192, 0, 45));
|
|
|
|
// Render wireframe.
|
|
|
|
desc.setFillModeWireframe();
|
|
drawer->drawPolyhedron(desc, mCollisionTriggerPolyhedron, ColorI::BLACK);
|
|
}
|
|
|
|
void CollisionTrigger::setTriggerPolyhedron(const Polyhedron& rPolyhedron)
|
|
{
|
|
mCollisionTriggerPolyhedron = rPolyhedron;
|
|
|
|
if (mCollisionTriggerPolyhedron.mPointList.size() != 0) {
|
|
mObjBox.minExtents.set(1e10, 1e10, 1e10);
|
|
mObjBox.maxExtents.set(-1e10, -1e10, -1e10);
|
|
for (U32 i = 0; i < mCollisionTriggerPolyhedron.mPointList.size(); i++) {
|
|
mObjBox.minExtents.setMin(mCollisionTriggerPolyhedron.mPointList[i]);
|
|
mObjBox.maxExtents.setMax(mCollisionTriggerPolyhedron.mPointList[i]);
|
|
}
|
|
}
|
|
else {
|
|
mObjBox.minExtents.set(-0.5, -0.5, -0.5);
|
|
mObjBox.maxExtents.set(0.5, 0.5, 0.5);
|
|
}
|
|
|
|
MatrixF xform = getTransform();
|
|
setTransform(xform);
|
|
|
|
mClippedList.clear();
|
|
mClippedList.mPlaneList = mCollisionTriggerPolyhedron.mPlaneList;
|
|
// for (U32 i = 0; i < mClippedList.mPlaneList.size(); i++)
|
|
// mClippedList.mPlaneList[i].neg();
|
|
|
|
MatrixF base(true);
|
|
base.scale(Point3F(1.0 / mObjScale.x,
|
|
1.0 / mObjScale.y,
|
|
1.0 / mObjScale.z));
|
|
base.mul(mWorldToObj);
|
|
|
|
mClippedList.setBaseTransform(base);
|
|
|
|
SAFE_DELETE(mPhysicsRep);
|
|
|
|
if (PHYSICSMGR)
|
|
{
|
|
PhysicsCollision *colShape = PHYSICSMGR->createCollision();
|
|
|
|
MatrixF colMat(true);
|
|
colMat.displace(Point3F(0, 0, mObjBox.getExtents().z * 0.5f * mObjScale.z));
|
|
|
|
colShape->addBox(mObjBox.getExtents() * 0.5f * mObjScale, colMat);
|
|
//MatrixF colMat( true );
|
|
//colMat.scale( mObjScale );
|
|
//colShape->addConvex( mCollisionTriggerPolyhedron.pointList.address(), mCollisionTriggerPolyhedron.pointList.size(), colMat );
|
|
|
|
PhysicsWorld *world = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
|
|
mPhysicsRep = PHYSICSMGR->createBody();
|
|
mPhysicsRep->init(colShape, 0, PhysicsBody::BF_TRIGGER | PhysicsBody::BF_KINEMATIC, this, world);
|
|
mPhysicsRep->setTransform(getTransform());
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
bool CollisionTrigger::testObject(GameBase* enter)
|
|
{
|
|
if (mCollisionTriggerPolyhedron.mPointList.size() == 0)
|
|
return false;
|
|
|
|
mClippedList.clear();
|
|
|
|
SphereF sphere;
|
|
sphere.center = (mWorldBox.minExtents + mWorldBox.maxExtents) * 0.5;
|
|
VectorF bv = mWorldBox.maxExtents - sphere.center;
|
|
sphere.radius = bv.len();
|
|
|
|
enter->buildPolyList(PLC_Collision, &mClippedList, mWorldBox, sphere);
|
|
return mClippedList.isEmpty() == false;
|
|
}
|
|
|
|
|
|
void CollisionTrigger::potentialEnterObject(GameBase* enter)
|
|
{
|
|
for (U32 i = 0; i < mObjects.size(); i++) {
|
|
if (mObjects[i] == enter)
|
|
return;
|
|
}
|
|
|
|
if (testObject(enter) == true) {
|
|
mObjects.push_back(enter);
|
|
deleteNotify(enter);
|
|
|
|
if (!mEnterCommand.isEmpty())
|
|
{
|
|
String command = String("%obj = ") + enter->getIdString() + ";" + mEnterCommand;
|
|
Con::evaluate(command.c_str());
|
|
}
|
|
|
|
//onEnterCollisionTrigger_callback(this, enter);
|
|
}
|
|
}
|
|
|
|
|
|
void CollisionTrigger::processTick(const Move* move)
|
|
{
|
|
Parent::processTick(move);
|
|
|
|
//
|
|
if (mObjects.size() == 0)
|
|
return;
|
|
|
|
if (mLastThink + 100 < mCurrTick)
|
|
{
|
|
mCurrTick = 0;
|
|
mLastThink = 0;
|
|
|
|
for (S32 i = S32(mObjects.size() - 1); i >= 0; i--)
|
|
{
|
|
if (testObject(mObjects[i]) == false)
|
|
{
|
|
GameBase* remove = mObjects[i];
|
|
mObjects.erase(i);
|
|
clearNotify(remove);
|
|
|
|
if (!mLeaveCommand.isEmpty())
|
|
{
|
|
String command = String("%obj = ") + remove->getIdString() + ";" + mLeaveCommand;
|
|
Con::evaluate(command.c_str());
|
|
}
|
|
|
|
//onLeaveCollisionTrigger_callback(this, remove);
|
|
}
|
|
}
|
|
|
|
if (!mTickCommand.isEmpty())
|
|
Con::evaluate(mTickCommand.c_str());
|
|
|
|
//if (mObjects.size() != 0)
|
|
// onTickCollisionTrigger_callback(this);
|
|
}
|
|
else
|
|
{
|
|
mCurrTick += TickMs;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
U32 CollisionTrigger::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
|
{
|
|
U32 i;
|
|
U32 retMask = Parent::packUpdate(con, mask, stream);
|
|
|
|
if (stream->writeFlag(mask & TransformMask))
|
|
{
|
|
stream->writeAffineTransform(mObjToWorld);
|
|
}
|
|
|
|
// Write the polyhedron
|
|
if (stream->writeFlag(mask & PolyMask))
|
|
{
|
|
stream->write(mCollisionTriggerPolyhedron.mPointList.size());
|
|
for (i = 0; i < mCollisionTriggerPolyhedron.mPointList.size(); i++)
|
|
mathWrite(*stream, mCollisionTriggerPolyhedron.mPointList[i]);
|
|
|
|
stream->write(mCollisionTriggerPolyhedron.mPlaneList.size());
|
|
for (i = 0; i < mCollisionTriggerPolyhedron.mPlaneList.size(); i++)
|
|
mathWrite(*stream, mCollisionTriggerPolyhedron.mPlaneList[i]);
|
|
|
|
stream->write(mCollisionTriggerPolyhedron.mEdgeList.size());
|
|
for (i = 0; i < mCollisionTriggerPolyhedron.mEdgeList.size(); i++) {
|
|
const Polyhedron::Edge& rEdge = mCollisionTriggerPolyhedron.mEdgeList[i];
|
|
|
|
stream->write(rEdge.face[0]);
|
|
stream->write(rEdge.face[1]);
|
|
stream->write(rEdge.vertex[0]);
|
|
stream->write(rEdge.vertex[1]);
|
|
}
|
|
}
|
|
|
|
if (stream->writeFlag(mask & EnterCmdMask))
|
|
stream->writeLongString(CMD_SIZE - 1, mEnterCommand.c_str());
|
|
if (stream->writeFlag(mask & LeaveCmdMask))
|
|
stream->writeLongString(CMD_SIZE - 1, mLeaveCommand.c_str());
|
|
if (stream->writeFlag(mask & TickCmdMask))
|
|
stream->writeLongString(CMD_SIZE - 1, mTickCommand.c_str());
|
|
|
|
return retMask;
|
|
}
|
|
|
|
void CollisionTrigger::unpackUpdate(NetConnection* con, BitStream* stream)
|
|
{
|
|
Parent::unpackUpdate(con, stream);
|
|
|
|
U32 i, size;
|
|
|
|
// Transform
|
|
if (stream->readFlag())
|
|
{
|
|
MatrixF temp;
|
|
stream->readAffineTransform(&temp);
|
|
setTransform(temp);
|
|
}
|
|
|
|
// Read the polyhedron
|
|
if (stream->readFlag())
|
|
{
|
|
Polyhedron tempPH;
|
|
stream->read(&size);
|
|
tempPH.mPointList.setSize(size);
|
|
for (i = 0; i < tempPH.mPointList.size(); i++)
|
|
mathRead(*stream, &tempPH.mPointList[i]);
|
|
|
|
stream->read(&size);
|
|
tempPH.mPlaneList.setSize(size);
|
|
for (i = 0; i < tempPH.mPlaneList.size(); i++)
|
|
mathRead(*stream, &tempPH.mPlaneList[i]);
|
|
|
|
stream->read(&size);
|
|
tempPH.mEdgeList.setSize(size);
|
|
for (i = 0; i < tempPH.mEdgeList.size(); i++) {
|
|
Polyhedron::Edge& rEdge = tempPH.mEdgeList[i];
|
|
|
|
stream->read(&rEdge.face[0]);
|
|
stream->read(&rEdge.face[1]);
|
|
stream->read(&rEdge.vertex[0]);
|
|
stream->read(&rEdge.vertex[1]);
|
|
}
|
|
setTriggerPolyhedron(tempPH);
|
|
}
|
|
|
|
if (stream->readFlag())
|
|
{
|
|
char buf[CMD_SIZE];
|
|
stream->readLongString(CMD_SIZE - 1, buf);
|
|
mEnterCommand = buf;
|
|
}
|
|
if (stream->readFlag())
|
|
{
|
|
char buf[CMD_SIZE];
|
|
stream->readLongString(CMD_SIZE - 1, buf);
|
|
mLeaveCommand = buf;
|
|
}
|
|
if (stream->readFlag())
|
|
{
|
|
char buf[CMD_SIZE];
|
|
stream->readLongString(CMD_SIZE - 1, buf);
|
|
mTickCommand = buf;
|
|
}
|
|
}
|
|
|
|
//ConsoleMethod( CollisionTrigger, getNumObjects, S32, 2, 2, "")
|
|
DefineEngineMethod(CollisionTrigger, getNumObjects, S32, (), ,
|
|
"@brief Get the number of objects that are within the CollisionTrigger's bounds.\n\n"
|
|
"@see getObject()\n")
|
|
{
|
|
return object->getNumCollisionTriggeringObjects();
|
|
}
|
|
|
|
//ConsoleMethod( CollisionTrigger, getObject, S32, 3, 3, "(int idx)")
|
|
DefineEngineMethod(CollisionTrigger, getObject, S32, (S32 index), ,
|
|
"@brief Retrieve the requested object that is within the CollisionTrigger's bounds.\n\n"
|
|
"@param index Index of the object to get (range is 0 to getNumObjects()-1)\n"
|
|
"@returns The SimObjectID of the object, or -1 if the requested index is invalid.\n"
|
|
"@see getNumObjects()\n")
|
|
{
|
|
if (index >= object->getNumCollisionTriggeringObjects() || index < 0)
|
|
return -1;
|
|
else
|
|
return object->getObject(U32(index))->getId();
|
|
}
|