Changed SplinePath so that it is more flexible its logic is now separate from the scene hierarchy. Control Points are set and removed explicitly with the ability to define the order. Controlled Node is explicitly set so that the Move function affects that Node's WorldPosition.

This commit is contained in:
Alex Parlett 2014-03-09 19:18:40 +00:00
Родитель 3bb95a7d5d
Коммит 751b4f1c97
5 изменённых файлов: 278 добавлений и 111 удалений

Просмотреть файл

@ -1220,11 +1220,11 @@ void InitVectorStructs()
};
vectorStructs.Push(VectorStruct("StaticModelGroup", "Instance Nodes", staticModelGroupInstanceVariables, 1));
Array<String> splineControlPointVariables = {
Array<String> splinePathInstanceVariables = {
"Control Point Count",
" Point"
" Node ID"
};
vectorStructs.Push(VectorStruct("Spline", "Control Points", splineControlPointVariables, 1));
vectorStructs.Push(VectorStruct("SplinePath", "Control Points", splinePathInstanceVariables, 1));
}
VectorStruct@ GetVectorStruct(Array<Serializable@>@ serializables, uint index)

Просмотреть файл

@ -2,17 +2,21 @@ $#include "SplinePath.h"
class SplinePath : public Component
{
void AddControlPoint(Node* point, unsigned index = M_MAX_UNSIGNED);
void RemoveControlPoint(Node* point);
void ClearControlPoints();
Vector3 GetPoint(float factor) const;
InterpolationMode GetInterpolationMode() const;
Vector3 GetPosition() const;
void SetInterpolationMode(InterpolationMode mode);
void SetPosition(float factor);
Vector3 GetPoint(float factor) const;
void Move(float timeStep);
void Reset();
bool IsFinished() const;
tolua_property__get_set float speed;
tolua_property__get_set Node* controlledNode;
};

Просмотреть файл

@ -22,11 +22,8 @@
#include "Precompiled.h"
#include "Context.h"
#include "ForEach.h"
#include "Log.h"
#include "Node.h"
#include "Scene.h"
#include "SceneEvents.h"
#include "SplinePath.h"
namespace Urho3D
@ -41,36 +38,70 @@ SplinePath::SplinePath(Context* context) :
elapsedTime_(0.f),
length_(0.f),
traveled_(0.f),
spline_(BEZIER_CURVE)
spline_(BEZIER_CURVE),
controlledIdAttr_(0),
controlledNode_(NULL),
dirty_(false)
{
SubscribeToEvent(E_SCENEPOSTUPDATE, HANDLER(SplinePath, PointsUpdated));
}
SplinePath::~SplinePath()
{
UnsubscribeFromAllEvents();
UpdateNodeIds();
}
void SplinePath::RegisterObject(Context* context)
{
context->RegisterFactory<SplinePath>(LOGIC_CATEGORY);
ATTRIBUTE(SplinePath, VAR_FLOAT, "Speed", speed_, 1.f, AM_FILE);
ENUM_ACCESSOR_ATTRIBUTE(SplinePath, "Interpolation Mode", GetInterpolationMode, SetInterpolationMode, InterpolationMode, interpolationModeNames, BEZIER_CURVE, AM_FILE);
ATTRIBUTE(SplinePath, VAR_FLOAT, "Speed", speed_, 1.f, AM_FILE);
ATTRIBUTE(SplinePath, VAR_FLOAT, "Traveled", traveled_, 0.f, AM_FILE | AM_NOEDIT);
ATTRIBUTE(SplinePath, VAR_FLOAT, "Elapsed Time", elapsedTime_, 0.f, AM_FILE | AM_NOEDIT);
ACCESSOR_ATTRIBUTE(SplinePath, VAR_INT, "Controlled", GetControlledIdAttr, SetControlledIdAttr, unsigned, 0, AM_FILE | AM_NODEID);
REF_ACCESSOR_ATTRIBUTE(SplinePath, VAR_VARIANTVECTOR, "Control Points", GetControlPointIdsAttr, SetControlPointIdsAttr, VariantVector, Variant::emptyVariantVector, AM_FILE | AM_NODEIDVECTOR);
}
void SplinePath::ApplyAttributes()
{
SubscribeToEvent(node_->GetScene(), E_NODEADDED, HANDLER(SplinePath, PointAdded));
SubscribeToEvent(node_->GetScene(), E_NODEREMOVED, HANDLER(SplinePath, PointRemoved));
if (!dirty_)
return;
for (Vector<SharedPtr<Node> >::ConstIterator i = node_->GetChildren().Begin(); i != node_->GetChildren().End(); ++i)
(*i)->AddListener(this);
// Remove all old instance nodes before searching for new. Can not call RemoveAllInstances() as that would modify
// the ID list on its own
for (unsigned i = 0; i < controlPoints_.Size(); ++i)
{
Node* node = controlPoints_[i];
if (node)
node->RemoveListener(this);
}
controlPoints_.Clear();
spline_.Clear();
Scene* scene = GetScene();
if (scene)
{
// The first index stores the number of IDs redundantly. This is for editing
for (unsigned i = 1; i < controlPointIdsAttr_.Size(); ++i)
{
Node* node = scene->GetNode(controlPointIdsAttr_[i].GetUInt());
if (node)
{
WeakPtr<Node> controlPoint(node);
node->AddListener(this);
controlPoints_.Push(controlPoint);
spline_.AddKnot(node->GetWorldPosition());
}
}
Node* node = scene->GetNode(controlledIdAttr_);
if (node)
{
WeakPtr<Node> controlled(node);
controlledNode_ = controlled;
}
}
UpdatePoints();
CalculateLength();
dirty_ = false;
}
void SplinePath::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
@ -88,15 +119,78 @@ void SplinePath::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
}
}
for (Vector<SharedPtr<Node> >::ConstIterator i = node_->GetChildren().Begin(); i != node_->GetChildren().End(); ++i)
for (Vector<WeakPtr<Node> >::ConstIterator i = controlPoints_.Begin(); i != controlPoints_.End(); ++i)
debug->AddNode(*i);
if (controlledNode_)
debug->AddNode(controlledNode_);
}
}
void SplinePath::AddControlPoint(Node* point, unsigned index)
{
if (!point)
return;
WeakPtr<Node> controlPoint(point);
point->AddListener(this);
controlPoints_.Insert(index, controlPoint);
spline_.AddKnot(point->GetWorldPosition(), index);
UpdateNodeIds();
CalculateLength();
}
void SplinePath::RemoveControlPoint(Node* point)
{
if (!point)
return;
WeakPtr<Node> controlPoint(point);
point->RemoveListener(this);
for (unsigned i = 0; i < controlPoints_.Size(); ++i)
{
if (controlPoints_[i] == controlPoint)
{
controlPoints_.Erase(i);
spline_.RemoveKnot(i);
break;
}
}
UpdateNodeIds();
CalculateLength();
}
void SplinePath::ClearControlPoints()
{
for (unsigned i = 0; i < controlPoints_.Size(); ++i)
{
Node* node = controlPoints_[i];
if (node)
node->RemoveListener(this);
}
controlPoints_.Clear();
spline_.Clear();
UpdateNodeIds();
CalculateLength();
}
void SplinePath::SetControlledNode(Node* controlled)
{
if (controlled)
controlledNode_ = WeakPtr<Node>(controlled);
}
void SplinePath::SetInterpolationMode(InterpolationMode interpolationMode)
{
spline_.SetInterpolationMode(interpolationMode);
dirty_ = true;
CalculateLength();
}
void SplinePath::SetPosition(float factor)
@ -111,11 +205,6 @@ void SplinePath::SetPosition(float factor)
traveled_ = t;
}
Vector3 SplinePath::GetPosition() const
{
return GetPoint(traveled_);
}
Vector3 SplinePath::GetPoint(float factor) const
{
return spline_.GetPoint(factor).GetVector3();
@ -123,7 +212,7 @@ Vector3 SplinePath::GetPoint(float factor) const
void SplinePath::Move(float timeStep)
{
if (traveled_ >= 1.0f || length_ <= 0.0f)
if (traveled_ >= 1.0f || length_ <= 0.0f || controlledNode_.Null())
return;
elapsedTime_ += timeStep;
@ -132,7 +221,7 @@ void SplinePath::Move(float timeStep)
float distanceCovered = elapsedTime_ * speed_;
traveled_ = distanceCovered / length_;
node_->SetPosition(GetPoint(traveled_));
controlledNode_->SetWorldPosition(GetPoint(traveled_));
}
void SplinePath::Reset()
@ -141,16 +230,103 @@ void SplinePath::Reset()
elapsedTime_ = 0.f;
}
void SplinePath::OnMarkedDirty(Node* node)
void SplinePath::SetControlPointIdsAttr(const VariantVector& value)
{
if (node)
// Just remember the node IDs. They need to go through the SceneResolver, and we actually find the nodes during
// ApplyAttributes()
if (value.Size())
{
controlPointIdsAttr_.Clear();
unsigned index = 0;
unsigned numInstances = value[index++].GetUInt();
// Prevent crash on entering negative value in the editor
if (numInstances > M_MAX_INT)
numInstances = 0;
controlPointIdsAttr_.Push(numInstances);
while (numInstances--)
{
// If vector contains less IDs than should, fill the rest with zeros
if (index < value.Size())
controlPointIdsAttr_.Push(value[index++].GetUInt());
else
controlPointIdsAttr_.Push(0);
}
dirty_ = true;
}
else
{
controlPointIdsAttr_.Clear();
controlPointIdsAttr_.Push(0);
dirty_ = true;
}
}
void SplinePath::OnNodeSetEnabled(Node* node)
void SplinePath::SetControlledIdAttr(unsigned value)
{
if (node)
dirty_ = true;
if (value > 0 && value < M_MAX_UNSIGNED)
controlledIdAttr_ = value;
dirty_ = true;
}
void SplinePath::OnMarkedDirty(Node* point)
{
if (!point)
return;
WeakPtr<Node> controlPoint(point);
for (unsigned i = 0; i < controlPoints_.Size(); ++i)
{
if (controlPoints_[i] == controlPoint)
{
spline_.SetKnot(point->GetWorldPosition(), i);
break;
}
}
CalculateLength();
}
void SplinePath::OnNodeSetEnabled(Node* point)
{
if (!point)
return;
WeakPtr<Node> controlPoint(point);
for (unsigned i = 0; i < controlPoints_.Size(); ++i)
{
if (controlPoints_[i] == controlPoint)
{
if (point->IsEnabled())
spline_.AddKnot(point->GetWorldPosition(), i);
else
spline_.RemoveKnot(i);
break;
}
}
CalculateLength();
}
void SplinePath::UpdateNodeIds()
{
unsigned numInstances = controlPoints_.Size();
controlPointIdsAttr_.Clear();
controlPointIdsAttr_.Push(numInstances);
for (unsigned i = 0; i < numInstances; ++i)
{
Node* node = controlPoints_[i];
controlPointIdsAttr_.Push(node ? node->GetID() : 0);
}
}
void SplinePath::CalculateLength()
@ -169,50 +345,4 @@ void SplinePath::CalculateLength()
}
}
void SplinePath::PointAdded(StringHash eventType, VariantMap& eventData)
{
using namespace NodeAdded;
Node* parent = static_cast<Node*>(eventData[P_PARENT].GetPtr());
Node* child = static_cast<Node*>(eventData[P_NODE].GetPtr());
if (child != NULL && parent != NULL && parent == node_)
{
child->AddListener(this);
dirty_ = true;
}
}
void SplinePath::PointRemoved(StringHash eventType, VariantMap& eventData)
{
using namespace NodeRemoved;
Node* parent = static_cast<Node*>(eventData[P_PARENT].GetPtr());
if (parent != NULL && parent == node_)
dirty_ = true;
}
void SplinePath::PointsUpdated(StringHash eventType, VariantMap& eventData)
{
if (dirty_)
{
UpdatePoints();
CalculateLength();
dirty_ = false;
}
}
void SplinePath::UpdatePoints()
{
spline_.Clear();
for (Vector<SharedPtr<Node> >::ConstIterator i = node_->GetChildren().Begin(); i != node_->GetChildren().End(); ++i)
{
if ((*i)->IsEnabled())
spline_.AddKnot((*i)->GetWorldPosition());
}
}
}

Просмотреть файл

@ -24,6 +24,11 @@
#include "Component.h"
#include "DebugRenderer.h"
#include "MathDefs.h"
#include "Node.h"
#include "Ptr.h"
#include "Variant.h"
#include "Vector.h"
#include "Vector3.h"
#include "Spline.h"
@ -36,70 +41,93 @@ class URHO3D_API SplinePath : public Component
OBJECT(SplinePath)
public:
/// Construct an Empty Spline.
/// Construct an Empty SplinePath.
SplinePath(Context* context);
/// Destructor.
virtual ~SplinePath();
virtual ~SplinePath() {};
/// Register object factory.
static void RegisterObject(Context* context);
/// Apply Attributes to the Node.
/// Apply Attributes to the SplinePath.
virtual void ApplyAttributes();
/// Draw the Debug Geometry.
virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
/// Add a Node to the SplinePath as a Control Point.
void AddControlPoint(Node* point, unsigned index = M_MAX_UNSIGNED);
/// Remove a Node Control Point from the SplinePath.
void RemoveControlPoint(Node* point);
/// Clear the Control Points from the SplinePath.
void ClearControlPoints();
/// Set the Interpolation Mode.
void SetInterpolationMode(InterpolationMode interpolationMode);
/// Set the movement Speed.
void SetSpeed(float speed) { speed_ = speed; }
/// Set the parent node's position on the Spline.
/// Set the controlled Node's position on the SplinePath.
void SetPosition(float factor);
/// Set the Node to be moved along the SplinePath.
void SetControlledNode(Node* controlled);
/// Get the Interpolation Mode.
InterpolationMode GetInterpolationMode() const { return spline_.GetInterpolationMode(); }
/// Get the movement Speed.
float GetSpeed() const { return speed_; }
/// Get the parent node's last position on the spline.
Vector3 GetPosition() const;
/// Get the parent Node's last position on the spline.
Vector3 GetPosition() const { return GetPoint(traveled_); }
/// Get the controlled Node.
Node* GetControlledNode() const { return controlledNode_; }
/// Get a point on the spline from 0.f to 1.f where 0 is the start and 1 is the end.
/// Get a point on the SplinePath from 0.f to 1.f where 0 is the start and 1 is the end.
Vector3 GetPoint(float factor) const;
/// Move the parent node to the next position along the Spline based off the Speed value.
/// Move the controlled Node to the next position along the SplinePath based off the Speed value.
void Move(float timeStep);
/// Reset movement along the path.
void Reset();
/// Returns whether the movement along the Spline complete.
/// Returns whether the movement along the SplinePath is complete.
bool IsFinished() const { return traveled_ >= 1.0f; }
/// Set Control Point Node IDs attribute.
void SetControlPointIdsAttr(const VariantVector& value);
/// Return Control Point Node IDs attribute.
const VariantVector& GetControlPointIdsAttr() const { return controlPointIdsAttr_; }
/// Set Controlled Node ID attribute.
void SetControlledIdAttr(unsigned value);
/// Get Controlled Node ID attribute.
unsigned GetControlledIdAttr() const { return controlledIdAttr_; }
protected:
virtual void OnMarkedDirty(Node* node);
virtual void OnNodeSetEnabled(Node* node);
/// Listener to manage Control Point movement.
virtual void OnMarkedDirty(Node* point);
/// Listener to manage Control Point enabling.
virtual void OnNodeSetEnabled(Node* point);
private:
/// Calculate the length of the Spline. Used for movement calculations.
/// Update the Node IDs of the Control Points.
void UpdateNodeIds();
/// Calculate the length of the SplinePath. Used for movement calculations.
void CalculateLength();
/// Handle Points Changed.
void PointAdded(StringHash eventType, VariantMap& eventData);
/// Handle Points Changed.
void PointRemoved(StringHash eventType, VariantMap& eventData);
/// Handle Points Changed.
void PointsUpdated(StringHash eventType, VariantMap& eventData);
/// Update the Point Set
void UpdatePoints();
/// The Control Points of the Spline.
Spline spline_;
/// The Speed of movement along the Spline.
float speed_;
/// Amount of time that has elapsed while moving.
float elapsedTime_;
/// The fraction of the Spline covered.
/// The fraction of the SplinePath covered.
float traveled_;
/// The length of the Spline.
/// The length of the SplinePath.
float length_;
/// Whether the Spline has changed.
/// Whether the Control Point IDs are dirty.
bool dirty_;
/// Node to be moved along the SplinePath.
WeakPtr<Node> controlledNode_;
/// Control Points for the SplinePath.
Vector<WeakPtr<Node> > controlPoints_;
/// Control Point ID's for the SplinePath.
mutable VariantVector controlPointIdsAttr_;
/// Controlled ID for the SplinePath.
mutable unsigned controlledIdAttr_;
};
}

Просмотреть файл

@ -93,13 +93,18 @@ static void RegisterSpline(asIScriptEngine* engine)
static void RegisterSplinePath(asIScriptEngine* engine)
{
RegisterComponent<SplinePath>(engine, "SplinePath");
engine->RegisterObjectMethod("SplinePath", "void set_interpolationMode(InterpolationMode)", asMETHOD(SplinePath, SetInterpolationMode), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "InterpolationMode get_interpolationMode() const", asMETHOD(SplinePath, GetInterpolationMode), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void set_speed(float)", asMETHOD(SplinePath, SetSpeed), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "float get_speed() const", asMETHOD(SplinePath, GetSpeed), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void set_position(float)", asMETHOD(SplinePath, SetPosition), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "Vector3 get_position() const", asMETHOD(SplinePath, GetPosition), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void AddControlPoint(Node@+ point, uint index = M_MAX_UNSIGNED)", asMETHOD(SplinePath, AddControlPoint), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void RemoveControlPoint(Node@+ point)", asMETHOD(SplinePath, RemoveControlPoint), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void ClearControlPoints()", asMETHOD(SplinePath, ClearControlPoints), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "Vector3 GetPoint(float) const", asMETHOD(SplinePath, GetPoint), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void set_interpolationMode(InterpolationMode)", asMETHOD(SplinePath, SetInterpolationMode), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void set_speed(float)", asMETHOD(SplinePath, SetSpeed), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void set_position(float)", asMETHOD(SplinePath, SetPosition), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void set_controlledNode(Node@+)", asMETHOD(SplinePath, GetControlledNode), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "InterpolationMode get_interpolationMode() const", asMETHOD(SplinePath, GetInterpolationMode), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "float get_speed() const", asMETHOD(SplinePath, GetSpeed), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "Vector3 get_position() const", asMETHOD(SplinePath, GetPosition), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "Node@ get_controlledNode() const", asMETHOD(SplinePath, GetControlledNode), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void Move(float)", asMETHOD(SplinePath, Move), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "void Reset()", asMETHOD(SplinePath, Reset), asCALL_THISCALL);
engine->RegisterObjectMethod("SplinePath", "bool get_isFinished() const", asMETHOD(SplinePath, IsFinished), asCALL_THISCALL);