mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-11 14:44:36 +00:00
Updates to various components, added a few new ones.
This commit is contained in:
parent
e0627973fb
commit
dac8d6e1fd
52 changed files with 4566 additions and 1799 deletions
149
Engine/source/T3D/components/game/controlObjectComponent.cpp
Normal file
149
Engine/source/T3D/components/game/controlObjectComponent.cpp
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "T3D/components/game/controlObjectComponent.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Constructor/Destructor
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ControlObjectComponent::ControlObjectComponent() : Component(),
|
||||
mOwnerConnection(nullptr),
|
||||
mOwnerConnectionId(0)
|
||||
{
|
||||
mFriendlyName = "Control Object";
|
||||
mComponentType = "Game";
|
||||
|
||||
mDescription = getDescriptionText("Allows owner entity to be controlled by a client.");
|
||||
}
|
||||
|
||||
ControlObjectComponent::~ControlObjectComponent()
|
||||
{
|
||||
}
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(ControlObjectComponent);
|
||||
|
||||
bool ControlObjectComponent::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControlObjectComponent::onRemove()
|
||||
{
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior
|
||||
void ControlObjectComponent::onComponentAdd()
|
||||
{
|
||||
Parent::onComponentAdd();
|
||||
|
||||
if (mOwnerConnection && mOwnerConnection->getControlObject() == nullptr)
|
||||
{
|
||||
mOwnerConnection->setControlObject(mOwner);
|
||||
mOwnerConnectionId = mOwnerConnection->getId();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlObjectComponent::onComponentRemove()
|
||||
{
|
||||
Parent::onComponentRemove();
|
||||
|
||||
if (mOwnerConnection)
|
||||
{
|
||||
mOwnerConnection->setControlObject(nullptr);
|
||||
mOwnerConnectionId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ControlObjectComponent::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("clientOwner", TypeS32, Offset(mOwnerConnectionId, ControlObjectComponent), "Client connection ID");
|
||||
}
|
||||
|
||||
void ControlObjectComponent::setConnectionControlObject(GameConnection* conn)
|
||||
{
|
||||
if (conn)
|
||||
{
|
||||
if (conn->getControlObject() == nullptr)
|
||||
{
|
||||
conn->setControlObject(mOwner);
|
||||
mOwnerConnectionId = conn->getId();
|
||||
}
|
||||
else
|
||||
{
|
||||
//Inform the old control object it's no longer in control?
|
||||
conn->setControlObject(mOwner);
|
||||
mOwnerConnectionId = conn->getId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ControlObjectComponent::onClientConnect(GameConnection* conn)
|
||||
{
|
||||
if (conn && conn->getControlObject() == nullptr)
|
||||
{
|
||||
conn->setControlObject(mOwner);
|
||||
mOwnerConnectionId = conn->getId();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlObjectComponent::onClientDisconnect(GameConnection* conn)
|
||||
{
|
||||
if (conn && conn->getControlObject() == mOwner)
|
||||
{
|
||||
conn->setControlObject(nullptr);
|
||||
mOwnerConnectionId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DefineEngineMethod(ControlObjectComponent, onClientConnect, void, (GameConnection* conn), (nullAsType<GameConnection*>()),
|
||||
"Triggers a signal call to all components for a certain function.")
|
||||
{
|
||||
if (conn == nullptr)
|
||||
return;
|
||||
|
||||
object->onClientConnect(conn);
|
||||
}
|
||||
|
||||
DefineEngineMethod(ControlObjectComponent, onClientDisconnect, void, (GameConnection* conn), (nullAsType<GameConnection*>()),
|
||||
"Triggers a signal call to all components for a certain function.")
|
||||
{
|
||||
if (conn == nullptr)
|
||||
return;
|
||||
|
||||
object->onClientDisconnect(conn);
|
||||
}
|
||||
|
||||
DefineEngineMethod(ControlObjectComponent, setConnectionControlObject, void, (GameConnection* conn), (nullAsType<GameConnection*>()),
|
||||
"Triggers a signal call to all components for a certain function.")
|
||||
{
|
||||
if (conn == nullptr)
|
||||
return;
|
||||
|
||||
object->setConnectionControlObject(conn);
|
||||
}
|
||||
30
Engine/source/T3D/components/game/controlObjectComponent.h
Normal file
30
Engine/source/T3D/components/game/controlObjectComponent.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "T3D/components/component.h"
|
||||
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
|
||||
class ControlObjectComponent : public Component
|
||||
{
|
||||
typedef Component Parent;
|
||||
|
||||
GameConnection* mOwnerConnection;
|
||||
S32 mOwnerConnectionId;
|
||||
|
||||
public:
|
||||
ControlObjectComponent();
|
||||
~ControlObjectComponent();
|
||||
|
||||
DECLARE_CONOBJECT(ControlObjectComponent);
|
||||
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
static void initPersistFields();
|
||||
|
||||
virtual void onComponentAdd();
|
||||
virtual void onComponentRemove();
|
||||
|
||||
void onClientConnect(GameConnection* conn);
|
||||
void onClientDisconnect(GameConnection* conn);
|
||||
void setConnectionControlObject(GameConnection* conn);
|
||||
};
|
||||
359
Engine/source/T3D/components/game/followPathComponent.cpp
Normal file
359
Engine/source/T3D/components/game/followPathComponent.cpp
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
#include "T3D/components/game/followPathComponent.h"
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(FollowPathComponent);
|
||||
|
||||
IMPLEMENT_CALLBACK(FollowPathComponent, onNode, void, (S32 node), (node),
|
||||
"A script callback that indicates the path camera has arrived at a specific node in its path. Server side only.\n"
|
||||
"@param Node Unique ID assigned to this node.\n");
|
||||
|
||||
FollowPathComponent::FollowPathComponent()
|
||||
{
|
||||
delta.time = 0;
|
||||
delta.timeVec = 0;
|
||||
|
||||
//mDataBlock = 0;
|
||||
mState = Forward;
|
||||
mNodeBase = 0;
|
||||
mNodeCount = 0;
|
||||
mPosition = 0;
|
||||
mTarget = 0;
|
||||
mTargetSet = false;
|
||||
}
|
||||
|
||||
FollowPathComponent::~FollowPathComponent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool FollowPathComponent::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
/*// Initialize from the current transform.
|
||||
if (!mNodeCount)
|
||||
{
|
||||
QuatF rot(getTransform());
|
||||
Point3F pos = getPosition();
|
||||
mSpline.removeAll();
|
||||
mSpline.push_back(new CameraSpline::Knot(pos, rot, 1,
|
||||
CameraSpline::Knot::NORMAL, CameraSpline::Knot::SPLINE));
|
||||
mNodeCount = 1;
|
||||
}
|
||||
|
||||
//
|
||||
mObjBox.maxExtents = mObjScale;
|
||||
mObjBox.minExtents = mObjScale;
|
||||
mObjBox.minExtents.neg();
|
||||
resetWorldBox();*/
|
||||
|
||||
return true;
|
||||
}
|
||||
void FollowPathComponent::onRemove()
|
||||
{
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void FollowPathComponent::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void FollowPathComponent::componentAddedToOwner(Component *comp)
|
||||
{
|
||||
Parent::componentAddedToOwner(comp);
|
||||
}
|
||||
|
||||
void FollowPathComponent::componentRemovedFromOwner(Component *comp)
|
||||
{
|
||||
Parent::componentRemovedFromOwner(comp);
|
||||
}
|
||||
|
||||
void FollowPathComponent::processTick()
|
||||
{
|
||||
Parent::processTick();
|
||||
|
||||
// Move to new time
|
||||
advancePosition(TickMs);
|
||||
|
||||
// Set new position
|
||||
MatrixF mat;
|
||||
interpolateMat(mPosition, &mat);
|
||||
mOwner->setTransform(mat);
|
||||
|
||||
mOwner->updateContainer();
|
||||
}
|
||||
|
||||
void FollowPathComponent::interpolateTick(F32 dt)
|
||||
{
|
||||
Parent::interpolateTick(dt);
|
||||
|
||||
MatrixF mat;
|
||||
interpolateMat(delta.time + (delta.timeVec * dt), &mat);
|
||||
mOwner->setRenderTransform(mat);
|
||||
}
|
||||
|
||||
void FollowPathComponent::interpolateMat(F32 pos, MatrixF* mat)
|
||||
{
|
||||
/*CameraSpline::Knot knot;
|
||||
mSpline.value(pos - mNodeBase, &knot);
|
||||
knot.mRotation.setMatrix(mat);
|
||||
mat->setPosition(knot.mPosition);*/
|
||||
}
|
||||
|
||||
void FollowPathComponent::advanceTime(F32 dt)
|
||||
{
|
||||
Parent::advanceTime(dt);
|
||||
}
|
||||
|
||||
void FollowPathComponent::advancePosition(S32 ms)
|
||||
{
|
||||
/*delta.timeVec = mPosition;
|
||||
|
||||
// Advance according to current speed
|
||||
if (mState == Forward) {
|
||||
mPosition = mSpline.advanceTime(mPosition - mNodeBase, ms);
|
||||
if (mPosition > F32(mNodeCount - 1))
|
||||
mPosition = F32(mNodeCount - 1);
|
||||
mPosition += (F32)mNodeBase;
|
||||
if (mTargetSet && mPosition >= mTarget) {
|
||||
mTargetSet = false;
|
||||
mPosition = mTarget;
|
||||
mState = Stop;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (mState == Backward) {
|
||||
mPosition = mSpline.advanceTime(mPosition - mNodeBase, -ms);
|
||||
if (mPosition < 0)
|
||||
mPosition = 0;
|
||||
mPosition += mNodeBase;
|
||||
if (mTargetSet && mPosition <= mTarget) {
|
||||
mTargetSet = false;
|
||||
mPosition = mTarget;
|
||||
mState = Stop;
|
||||
}
|
||||
}
|
||||
|
||||
// Script callbacks
|
||||
if (int(mPosition) != int(delta.timeVec))
|
||||
onNode(int(mPosition));
|
||||
|
||||
// Set frame interpolation
|
||||
delta.time = mPosition;
|
||||
delta.timeVec -= mPosition;*/
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/*void FollowPathComponent::getCameraTransform(F32* pos, MatrixF* mat)
|
||||
{
|
||||
// Overide the ShapeBase method to skip all the first/third person support.
|
||||
getRenderEyeTransform(mat);
|
||||
|
||||
// Apply Camera FX.
|
||||
mat->mul(gCamFXMgr.getTrans());
|
||||
}*/
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void FollowPathComponent::setPosition(F32 pos)
|
||||
{
|
||||
mPosition = mClampF(pos, (F32)mNodeBase, (F32)(mNodeBase + mNodeCount - 1));
|
||||
MatrixF mat;
|
||||
interpolateMat(mPosition, &mat);
|
||||
mOwner->setTransform(mat);
|
||||
setMaskBits(PositionMask);
|
||||
}
|
||||
|
||||
void FollowPathComponent::setTarget(F32 pos)
|
||||
{
|
||||
mTarget = pos;
|
||||
mTargetSet = true;
|
||||
if (mTarget > mPosition)
|
||||
mState = Forward;
|
||||
else
|
||||
if (mTarget < mPosition)
|
||||
mState = Backward;
|
||||
else {
|
||||
mTargetSet = false;
|
||||
mState = Stop;
|
||||
}
|
||||
setMaskBits(TargetMask | StateMask);
|
||||
}
|
||||
|
||||
void FollowPathComponent::setState(State s)
|
||||
{
|
||||
mState = s;
|
||||
setMaskBits(StateMask);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FollowPathComponent::reset(F32 speed)
|
||||
{
|
||||
/*CameraSpline::Knot *knot = new CameraSpline::Knot;
|
||||
mSpline.value(mPosition - mNodeBase, knot);
|
||||
if (speed)
|
||||
knot->mSpeed = speed;
|
||||
mSpline.removeAll();
|
||||
mSpline.push_back(knot);
|
||||
|
||||
mNodeBase = 0;
|
||||
mNodeCount = 1;
|
||||
mPosition = 0;
|
||||
mTargetSet = false;
|
||||
mState = Forward;
|
||||
setMaskBits(StateMask | PositionMask | WindowMask | TargetMask);*/
|
||||
}
|
||||
|
||||
/*void FollowPathComponent::pushBack(CameraSpline::Knot *knot)
|
||||
{
|
||||
// Make room at the end
|
||||
if (mNodeCount == NodeWindow) {
|
||||
delete mSpline.remove(mSpline.getKnot(0));
|
||||
mNodeBase++;
|
||||
}
|
||||
else
|
||||
mNodeCount++;
|
||||
|
||||
// Fill in the new node
|
||||
mSpline.push_back(knot);
|
||||
setMaskBits(WindowMask);
|
||||
|
||||
// Make sure the position doesn't fall off
|
||||
if (mPosition < mNodeBase) {
|
||||
mPosition = (F32)mNodeBase;
|
||||
setMaskBits(PositionMask);
|
||||
}
|
||||
}
|
||||
|
||||
void FollowPathComponent::pushFront(CameraSpline::Knot *knot)
|
||||
{
|
||||
// Make room at the front
|
||||
if (mNodeCount == NodeWindow)
|
||||
delete mSpline.remove(mSpline.getKnot(mNodeCount));
|
||||
else
|
||||
mNodeCount++;
|
||||
mNodeBase--;
|
||||
|
||||
// Fill in the new node
|
||||
mSpline.push_front(knot);
|
||||
setMaskBits(WindowMask);
|
||||
|
||||
// Make sure the position doesn't fall off
|
||||
if (mPosition > F32(mNodeBase + (NodeWindow - 1)))
|
||||
{
|
||||
mPosition = F32(mNodeBase + (NodeWindow - 1));
|
||||
setMaskBits(PositionMask);
|
||||
}
|
||||
}*/
|
||||
|
||||
void FollowPathComponent::popFront()
|
||||
{
|
||||
/*if (mNodeCount < 2)
|
||||
return;
|
||||
|
||||
// Remove the first node. Node base and position are unaffected.
|
||||
mNodeCount--;
|
||||
delete mSpline.remove(mSpline.getKnot(0));
|
||||
|
||||
if (mPosition > 0)
|
||||
mPosition--;*/
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void FollowPathComponent::onNode(S32 node)
|
||||
{
|
||||
//if (!isGhost())
|
||||
// onNode_callback(node);
|
||||
|
||||
}
|
||||
|
||||
/*U32 FollowPathComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||
{
|
||||
Parent::packUpdate(con, mask, stream);
|
||||
|
||||
if (stream->writeFlag(mask & StateMask))
|
||||
stream->writeInt(mState, StateBits);
|
||||
|
||||
if (stream->writeFlag(mask & PositionMask))
|
||||
stream->write(mPosition);
|
||||
|
||||
if (stream->writeFlag(mask & TargetMask))
|
||||
if (stream->writeFlag(mTargetSet))
|
||||
stream->write(mTarget);
|
||||
|
||||
if (stream->writeFlag(mask & WindowMask)) {
|
||||
stream->write(mNodeBase);
|
||||
stream->write(mNodeCount);
|
||||
for (S32 i = 0; i < mNodeCount; i++) {
|
||||
CameraSpline::Knot *knot = mSpline.getKnot(i);
|
||||
mathWrite(*stream, knot->mPosition);
|
||||
mathWrite(*stream, knot->mRotation);
|
||||
stream->write(knot->mSpeed);
|
||||
stream->writeInt(knot->mType, CameraSpline::Knot::NUM_TYPE_BITS);
|
||||
stream->writeInt(knot->mPath, CameraSpline::Knot::NUM_PATH_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
// The rest of the data is part of the control object packet update.
|
||||
// If we're controlled by this client, we don't need to send it.
|
||||
if (stream->writeFlag(getControllingClient() == con && !(mask & InitialUpdateMask)))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FollowPathComponent::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||
{
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
// StateMask
|
||||
if (stream->readFlag())
|
||||
mState = stream->readInt(StateBits);
|
||||
|
||||
// PositionMask
|
||||
if (stream->readFlag())
|
||||
{
|
||||
stream->read(&mPosition);
|
||||
delta.time = mPosition;
|
||||
delta.timeVec = 0;
|
||||
}
|
||||
|
||||
// TargetMask
|
||||
if (stream->readFlag())
|
||||
{
|
||||
mTargetSet = stream->readFlag();
|
||||
if (mTargetSet)
|
||||
stream->read(&mTarget);
|
||||
}
|
||||
|
||||
// WindowMask
|
||||
if (stream->readFlag())
|
||||
{
|
||||
mSpline.removeAll();
|
||||
stream->read(&mNodeBase);
|
||||
stream->read(&mNodeCount);
|
||||
for (S32 i = 0; i < mNodeCount; i++)
|
||||
{
|
||||
CameraSpline::Knot *knot = new CameraSpline::Knot();
|
||||
mathRead(*stream, &knot->mPosition);
|
||||
mathRead(*stream, &knot->mRotation);
|
||||
stream->read(&knot->mSpeed);
|
||||
knot->mType = (CameraSpline::Knot::Type)stream->readInt(CameraSpline::Knot::NUM_TYPE_BITS);
|
||||
knot->mPath = (CameraSpline::Knot::Path)stream->readInt(CameraSpline::Knot::NUM_PATH_BITS);
|
||||
mSpline.push_back(knot);
|
||||
}
|
||||
}
|
||||
|
||||
// Controlled by the client?
|
||||
if (stream->readFlag())
|
||||
return;
|
||||
|
||||
}*/
|
||||
82
Engine/source/T3D/components/game/followPathComponent.h
Normal file
82
Engine/source/T3D/components/game/followPathComponent.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include "T3D/components/component.h"
|
||||
|
||||
class FollowPathComponent : public Component
|
||||
{
|
||||
typedef Component Parent;
|
||||
|
||||
enum State {
|
||||
Forward,
|
||||
Backward,
|
||||
Stop,
|
||||
StateBits = 3
|
||||
};
|
||||
|
||||
enum MaskBits {
|
||||
WindowMask = Parent::NextFreeMask,
|
||||
PositionMask = Parent::NextFreeMask + 1,
|
||||
TargetMask = Parent::NextFreeMask + 2,
|
||||
StateMask = Parent::NextFreeMask + 3,
|
||||
NextFreeMask = Parent::NextFreeMask << 1
|
||||
};
|
||||
|
||||
struct StateDelta {
|
||||
F32 time;
|
||||
F32 timeVec;
|
||||
};
|
||||
StateDelta delta;
|
||||
|
||||
enum Constants {
|
||||
NodeWindow = 128 // Maximum number of active nodes
|
||||
};
|
||||
|
||||
//
|
||||
//PathCameraData* mDataBlock;
|
||||
//CameraSpline mSpline;
|
||||
S32 mNodeBase;
|
||||
S32 mNodeCount;
|
||||
F32 mPosition;
|
||||
S32 mState;
|
||||
F32 mTarget;
|
||||
bool mTargetSet;
|
||||
|
||||
void interpolateMat(F32 pos, MatrixF* mat);
|
||||
void advancePosition(S32 ms);
|
||||
|
||||
public:
|
||||
DECLARE_CONOBJECT(FollowPathComponent);
|
||||
|
||||
FollowPathComponent();
|
||||
~FollowPathComponent();
|
||||
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
static void initPersistFields();
|
||||
|
||||
//This is called when a different component is added to our owner entity
|
||||
virtual void componentAddedToOwner(Component *comp);
|
||||
//This is called when a different component is removed from our owner entity
|
||||
virtual void componentRemovedFromOwner(Component *comp);
|
||||
|
||||
virtual void processTick();
|
||||
virtual void interpolateTick(F32 dt);
|
||||
virtual void advanceTime(F32 dt);
|
||||
|
||||
//
|
||||
//void onEditorEnable();
|
||||
//void onEditorDisable();
|
||||
|
||||
void onNode(S32 node);
|
||||
|
||||
void reset(F32 speed = 1);
|
||||
//void pushFront(CameraSpline::Knot *knot);
|
||||
//void pushBack(CameraSpline::Knot *knot);
|
||||
void popFront();
|
||||
|
||||
void setPosition(F32 pos);
|
||||
void setTarget(F32 pos);
|
||||
void setState(State s);
|
||||
|
||||
DECLARE_CALLBACK(void, onNode, (S32 node));
|
||||
};
|
||||
171
Engine/source/T3D/components/game/interactComponent.cpp
Normal file
171
Engine/source/T3D/components/game/interactComponent.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "T3D/components/game/interactComponent.h"
|
||||
#include "scene/sceneContainer.h"
|
||||
#include "T3D/components/game/interactableComponent.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Constructor/Destructor
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
InteractComponent::InteractComponent() : Component(),
|
||||
mUseRaycastInteract(true),
|
||||
mUseRenderedRaycast(false),
|
||||
mUseRadiusInteract(true),
|
||||
mInteractRadius(1.5),
|
||||
mInteractRayDist(1.5),
|
||||
mUseNaturalReach(false)
|
||||
{
|
||||
mFriendlyName = "Interact";
|
||||
mComponentType = "Game";
|
||||
|
||||
mDescription = getDescriptionText("Allows owner entity interact.");
|
||||
}
|
||||
|
||||
InteractComponent::~InteractComponent()
|
||||
{
|
||||
}
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(InteractComponent);
|
||||
|
||||
bool InteractComponent::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InteractComponent::onRemove()
|
||||
{
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior
|
||||
void InteractComponent::onComponentAdd()
|
||||
{
|
||||
Parent::onComponentAdd();
|
||||
}
|
||||
|
||||
void InteractComponent::onComponentRemove()
|
||||
{
|
||||
Parent::onComponentRemove();
|
||||
}
|
||||
|
||||
void InteractComponent::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void InteractComponent::processTick()
|
||||
{
|
||||
if (isClientObject())
|
||||
return; //this shouldn't happen
|
||||
|
||||
//First, if we're doing rays, try that as if we get a hit, we can always assume that's the "correct" option
|
||||
if (mUseRaycastInteract)
|
||||
{
|
||||
mOwner->disableCollision();
|
||||
|
||||
Point3F start = mOwner->getPosition();
|
||||
Point3F end = mOwner->getTransform().getForwardVector() * mInteractRayDist + start;
|
||||
|
||||
RayInfo rinfo;
|
||||
S32 ret = 0;
|
||||
|
||||
if (mUseRenderedRaycast)
|
||||
{
|
||||
rinfo.generateTexCoord = true;
|
||||
if (gServerContainer.castRayRendered(mOwner->getPosition(), end, EntityObjectType, &rinfo) == true)
|
||||
ret = rinfo.object->getId();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gServerContainer.castRay(mOwner->getPosition(), end, EntityObjectType, &rinfo) == true)
|
||||
ret = rinfo.object->getId();
|
||||
}
|
||||
|
||||
mOwner->enableCollision();
|
||||
|
||||
Entity* hitEntity = static_cast<Entity*>(rinfo.object);
|
||||
|
||||
if (hitEntity)
|
||||
{
|
||||
//call on that badboy!
|
||||
InteractableComponent* iComp = hitEntity->getComponent<InteractableComponent>();
|
||||
|
||||
if (iComp)
|
||||
{
|
||||
iComp->interact(this, rinfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If not using rays or no hit, then do the radius search if we have it
|
||||
if (mUseRadiusInteract)
|
||||
{
|
||||
gServerContainer.initRadiusSearch(mOwner->getPosition(), mInteractRadius, EntityObjectType);
|
||||
|
||||
F32 lastBestDist = 9999;
|
||||
F32 lastBestWeight = 0;
|
||||
Entity* bestFitEntity = nullptr;
|
||||
|
||||
Entity* e = static_cast<Entity*>(gServerContainer.containerSearchNextObject());
|
||||
|
||||
while (e != nullptr)
|
||||
{
|
||||
InteractableComponent* iComp = e->getComponent<InteractableComponent>();
|
||||
|
||||
if (iComp != nullptr)
|
||||
{
|
||||
F32 weight = iComp->getWeight();
|
||||
VectorF distVec = e->getPosition() - mOwner->getPosition();
|
||||
F32 dist = distVec.len();
|
||||
|
||||
//If the weight is better, always pick it
|
||||
if (weight > lastBestWeight)
|
||||
{
|
||||
lastBestDist = dist;
|
||||
lastBestWeight = weight;
|
||||
bestFitEntity = e;
|
||||
}
|
||||
//Otherwise, if the weight is matched and the distance is closer, pick that
|
||||
else if (weight >= lastBestWeight && lastBestDist < dist)
|
||||
{
|
||||
lastBestWeight = weight;
|
||||
bestFitEntity = e;
|
||||
}
|
||||
}
|
||||
|
||||
e = static_cast<Entity*>(gServerContainer.containerSearchNextObject()); //loop 'round
|
||||
}
|
||||
|
||||
if (bestFitEntity)
|
||||
{
|
||||
//call on that badboy!
|
||||
InteractableComponent* iComp = bestFitEntity->getComponent<InteractableComponent>();
|
||||
|
||||
iComp->interact(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Engine/source/T3D/components/game/interactComponent.h
Normal file
34
Engine/source/T3D/components/game/interactComponent.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "T3D/components/component.h"
|
||||
|
||||
|
||||
class InteractComponent : public Component
|
||||
{
|
||||
typedef Component Parent;
|
||||
|
||||
bool mUseRaycastInteract;
|
||||
bool mUseRenderedRaycast;
|
||||
bool mUseRadiusInteract;
|
||||
|
||||
F32 mInteractRadius;
|
||||
F32 mInteractRayDist;
|
||||
|
||||
//Adjusts the length of the ray based on the idea of further reach if you look down because of crouching
|
||||
bool mUseNaturalReach;
|
||||
|
||||
public:
|
||||
InteractComponent();
|
||||
~InteractComponent();
|
||||
|
||||
DECLARE_CONOBJECT(InteractComponent);
|
||||
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
static void initPersistFields();
|
||||
|
||||
virtual void onComponentAdd();
|
||||
virtual void onComponentRemove();
|
||||
|
||||
virtual void processTick();
|
||||
};
|
||||
94
Engine/source/T3D/components/game/interactableComponent.cpp
Normal file
94
Engine/source/T3D/components/game/interactableComponent.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "T3D/components/game/InteractableComponent.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Constructor/Destructor
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
InteractableComponent::InteractableComponent() : Component(),
|
||||
mInteractableWeight(1)
|
||||
{
|
||||
mFriendlyName = "Interactable";
|
||||
mComponentType = "Game";
|
||||
|
||||
mDescription = getDescriptionText("Allows owner entity to be interacted with.");
|
||||
}
|
||||
|
||||
InteractableComponent::~InteractableComponent()
|
||||
{
|
||||
}
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(InteractableComponent);
|
||||
|
||||
bool InteractableComponent::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InteractableComponent::onRemove()
|
||||
{
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior
|
||||
void InteractableComponent::onComponentAdd()
|
||||
{
|
||||
Parent::onComponentAdd();
|
||||
}
|
||||
|
||||
void InteractableComponent::onComponentRemove()
|
||||
{
|
||||
Parent::onComponentRemove();
|
||||
}
|
||||
|
||||
void InteractableComponent::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("interactableWeight", TypeF32, Offset(mInteractableWeight, InteractableComponent), "Controls importance values when using radius mode for interaction");
|
||||
}
|
||||
|
||||
void InteractableComponent::interact(InteractComponent* interactor)
|
||||
{
|
||||
if (interactor != nullptr)
|
||||
{
|
||||
mOwner->notifyComponents("onInteract", interactor->getIdString());
|
||||
|
||||
if(isMethod("onInteract"))
|
||||
Con::executef(this, "onInteract", interactor);
|
||||
}
|
||||
}
|
||||
|
||||
void InteractableComponent::interact(InteractComponent* interactor, RayInfo rayInfo)
|
||||
{
|
||||
if (interactor != nullptr)
|
||||
{
|
||||
mOwner->notifyComponents("onInteract", interactor->getIdString());
|
||||
|
||||
if (isMethod("onInteract"))
|
||||
Con::executef(this, "onInteract", interactor);
|
||||
}
|
||||
}
|
||||
30
Engine/source/T3D/components/game/interactableComponent.h
Normal file
30
Engine/source/T3D/components/game/interactableComponent.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "T3D/components/component.h"
|
||||
#include "T3D/components/game/interactComponent.h"
|
||||
|
||||
class InteractableComponent : public Component
|
||||
{
|
||||
typedef Component Parent;
|
||||
|
||||
//Controls importance values when using radius mode for interaction
|
||||
F32 mInteractableWeight;
|
||||
|
||||
public:
|
||||
InteractableComponent();
|
||||
~InteractableComponent();
|
||||
|
||||
DECLARE_CONOBJECT(InteractableComponent);
|
||||
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
static void initPersistFields();
|
||||
|
||||
virtual void onComponentAdd();
|
||||
virtual void onComponentRemove();
|
||||
|
||||
void interact(InteractComponent* interactor);
|
||||
void interact(InteractComponent* interactor, RayInfo rayInfo);
|
||||
|
||||
F32 getWeight() { return mInteractableWeight; }
|
||||
};
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
#include "console/engineAPI.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
#include "T3D/components/coreInterfaces.h"
|
||||
//#include "T3D/components/coreInterfaces.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "collision/concretePolyList.h"
|
||||
#include "collision/clippedPolyList.h"
|
||||
|
|
@ -94,21 +94,21 @@ void TriggerComponent::onComponentAdd()
|
|||
{
|
||||
Parent::onComponentAdd();
|
||||
|
||||
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
|
||||
CollisionComponent *colComp = mOwner->getComponent<CollisionComponent>();
|
||||
|
||||
if(colInt)
|
||||
if(colComp)
|
||||
{
|
||||
colInt->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
|
||||
colComp->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
|
||||
}
|
||||
}
|
||||
|
||||
void TriggerComponent::onComponentRemove()
|
||||
{
|
||||
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
|
||||
CollisionComponent *colComp = mOwner->getComponent<CollisionComponent>();
|
||||
|
||||
if(colInt)
|
||||
if(colComp)
|
||||
{
|
||||
colInt->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
|
||||
colComp->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
|
||||
}
|
||||
|
||||
Parent::onComponentRemove();
|
||||
|
|
@ -119,11 +119,11 @@ void TriggerComponent::componentAddedToOwner(Component *comp)
|
|||
if (comp->getId() == getId())
|
||||
return;
|
||||
|
||||
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
|
||||
CollisionComponent *colComp = mOwner->getComponent<CollisionComponent>();
|
||||
|
||||
if (colInt)
|
||||
if (colComp)
|
||||
{
|
||||
colInt->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
|
||||
colComp->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,11 +132,11 @@ void TriggerComponent::componentRemovedFromOwner(Component *comp)
|
|||
if (comp->getId() == getId()) //?????????
|
||||
return;
|
||||
|
||||
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
|
||||
CollisionComponent *colComp = mOwner->getComponent<CollisionComponent>();
|
||||
|
||||
if (colInt)
|
||||
if (colComp)
|
||||
{
|
||||
colInt->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
|
||||
colComp->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -217,19 +217,19 @@ bool TriggerComponent::testObject(SceneObject* enter)
|
|||
return false;
|
||||
|
||||
//check if the entity has a collision shape
|
||||
CollisionInterface *cI = enterEntity->getComponent<CollisionInterface>();
|
||||
if (cI)
|
||||
CollisionComponent *colComp = enterEntity->getComponent<CollisionComponent>();
|
||||
if (colComp)
|
||||
{
|
||||
cI->buildPolyList(PLC_Collision, &mClippedList, mOwner->getWorldBox(), sphere);
|
||||
colComp->buildPolyList(PLC_Collision, &mClippedList, mOwner->getWorldBox(), sphere);
|
||||
|
||||
if (!mClippedList.isEmpty())
|
||||
{
|
||||
//well, it's clipped with, or inside, our bounds
|
||||
//now to test the clipped list against our own collision mesh
|
||||
CollisionInterface *myCI = mOwner->getComponent<CollisionInterface>();
|
||||
CollisionComponent *myColComp = mOwner->getComponent<CollisionComponent>();
|
||||
|
||||
//wait, how would we NOT have this?
|
||||
if (myCI)
|
||||
if (myColComp)
|
||||
{
|
||||
//anywho, build our list and then we'll check intersections
|
||||
ClippedPolyList myList;
|
||||
|
|
@ -238,7 +238,7 @@ bool TriggerComponent::testObject(SceneObject* enter)
|
|||
myList.setTransform(&ownerTransform, mOwner->getScale());
|
||||
myList.setObject(mOwner);
|
||||
|
||||
myCI->buildPolyList(PLC_Collision, &myList, enterBox, sphere);
|
||||
myColComp->buildPolyList(PLC_Collision, &myList, enterBox, sphere);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -354,4 +354,4 @@ DefineEngineMethod( TriggerComponent, visualizeFrustums, void,
|
|||
"@return true if successful, false if failed (objB is not valid)" )
|
||||
{
|
||||
object->visualizeFrustums(renderTime);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
#include "T3D/entity.h"
|
||||
#endif
|
||||
|
||||
#ifndef _COLLISION_INTERFACES_H_
|
||||
#include "T3D/components/collision/collisionInterfaces.h"
|
||||
#ifndef COLLISION_COMPONENT_H
|
||||
#include "T3D/components/collision/collisionComponent.h"
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue