// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/> // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. #ifndef NL_TRACK_H #define NL_TRACK_H #include "nel/misc/types_nl.h" #include "nel/misc/smart_ptr.h" #include "nel/misc/vector.h" #include "nel/misc/vectord.h" #include "nel/misc/entity_id.h" #include "nel/misc/sheet_id.h" #include "nel/pacs/u_move_container.h" #include "nel/pacs/u_move_primitive.h" #include "nel/georges/u_form.h" #include "nel/georges/u_form_elm.h" /** * The base class for moving entity * \author Benjamin Legros * \author Nevrax France * \date 2002 */ class CTrackBase { public: /// State type enum TTrackState { Idle = 0, // not controlled yet MovingTowardsTarget, // first step of motion, moving towards target TargetLocked, // close to target, locked TargetLost, // target moved away, can't reach it any longer TargetUnreachable // can't reach target, too far or too many obstacles on the way }; /// Get Id virtual const NLMISC::CEntityId &getId() const = 0; /// Get SheetId virtual const NLMISC::CSheetId &getSheetId() const = 0; /// Has Id ? virtual bool hasId() const = 0; /// Get track Position virtual void getPosition(NLMISC::CVectorD &pos, float &heading) const = 0; /// Has Position ? virtual bool hasPosition() const = 0; /// Set user data virtual void setUserData(void *data) = 0; /// Get user data virtual void *getUserData() = 0; /// Get Track state virtual TTrackState getTrackState() const = 0; }; /** * A track that represents a moving point * \author Benjamin Legros * \author Nevrax France * \date 2002 */ class CTrack : public CTrackBase, public NLMISC::CRefCount { public: /** * The sheet type read by Georges */ class CSheet { public: CSheet(): WalkSpeed(1.3f), RunSpeed(6.0f), Radius(0.5f), Height(2.0f), Length(1.0), Width(1.0) {} /// The Walk speed of the entity float WalkSpeed; /// The Run speed of the entity float RunSpeed; /// The Pacs radius of the entity float Radius; /// The Height radius of the entity float Height; /// The Animation length of the entity float Length; /// The Width length of the entity float Width; void readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId) { // the form was found so read the true values from George form->getRootNode ().getValueByName (WalkSpeed, "Basics.MovementSpeeds.WalkSpeed"); form->getRootNode ().getValueByName (RunSpeed, "Basics.MovementSpeeds.RunSpeed"); form->getRootNode ().getValueByName (Radius, "Collision.CollisionRadius"); form->getRootNode ().getValueByName (Height, "Collision.Height"); form->getRootNode ().getValueByName (Width, "Collision.Width"); form->getRootNode ().getValueByName (Length, "Collision.Length"); } void serial (NLMISC::IStream &s) { s.serial (WalkSpeed, RunSpeed); s.serial (Radius, Height); s.serial (Length, Width); } static uint getVersion () { return 1; } /// The default sheet static CSheet DefaultSheet; }; public: /// Constructor CTrack() : _OwnControl(NULL), _MoveContainer(NULL), _MovePrimitive(NULL), _Id(NLMISC::CEntityId::Unknown), _SheetId(NLMISC::CSheetId::Unknown), _Sheet(NULL), _Followed(NULL), _HasPosition(false), _HasId(false), _IdRequested(false), _PositionUpdatesRequested(false), _IsStatic(false), _ForceRelease(false), _ReceiveVision(false), _UserData(NULL), _State(Idle), _SmoothedTargetDistanceDelta(3.0), _LastTargetDistance(-1.0) { } /// Destructor ~CTrack(); /// Init track void setId(const NLMISC::CEntityId &id, const NLMISC::CSheetId &sheet); /// Get Id const NLMISC::CEntityId &getId() const { return _Id; } /// Get SheetId const NLMISC::CSheetId &getSheetId() const { return _SheetId; } /// Get SheetId const CSheet *getSheet() const { return _Sheet; } /// Has Id ? bool hasId() const { return _HasId; } /// Update track position void setPosition(const NLMISC::CVectorD &pos, float heading) { // don't allow more than one position to be set when control is owned if (_HasPosition && _OwnControl) return; _Position = pos; _Heading = heading; _HasPosition = true; } /// Get track Position void getPosition(NLMISC::CVectorD &pos, float &heading) const { if (_HasPosition) { pos = _Position; heading = _Heading; } else { nlwarning("ReynoldsLib:CTrack:getPosition(): Track %s position not yet set", _Id.toString().c_str()); } } /// Set Static state void setStatic(bool isstatic = true) { _IsStatic = isstatic; } /// Has Control Owned ? bool hasControlOwned() const { return _OwnControl; } /// Has Position ? bool hasPosition() const { return _HasPosition; } /// Invalid position void invalidPosition() { _HasPosition = false; } /// Is static ? bool isStatic() const { return _IsStatic; } /// Follow void follow(CTrack *followed); /// Leave void leave(); /// Update void update(double dt); /// Update vision void updateVision(const std::vector<NLMISC::CEntityId> &in, const std::vector<NLMISC::CEntityId> &out); /// Update vision void updateVision(const std::vector<NLMISC::CEntityId> &vision); /// Force release void forceRelease() { _ForceRelease = true; } /// Get current state TTrackState getTrackState() const { return _State; } /// Set user data void setUserData(void *data) { _UserData = data; } /// Get user data void *getUserData() { return _UserData; } /// Get contact distance double rawDistance(const CTrack *other, NLMISC::CVectorD &distance) const { distance = other->_Position - _Position; distance.z = 0.0; return distance.norm(); } /// Get contact distance double contactDistance(const CTrack *other, NLMISC::CVectorD &distance, double &rawdistance) const { rawdistance = rawDistance(other, distance); return contactDistanceWithRawDistance(other, distance, rawdistance); } /// Get contact distance double contactDistanceWithRawDistance(const CTrack *other, NLMISC::CVectorD &distance, double &rawdistance) const { double theta = atan2(distance.y, distance.x); double theta1 = _Heading - theta; double theta2 = other->_Heading - theta + 3.1415926535; float l1 = _Sheet->Length, w1 = _Sheet->Width; float l2 = other->_Sheet->Length, w2 = other->_Sheet->Width; double r1 = 0.5 * sqrt( l1*l1 + (w1*w1-l1*l1)*NLMISC::sqr(sin(theta1)) ); double r2 = 0.5 * sqrt( l2*l2 + (w2*w2-l2*l2)*NLMISC::sqr(sin(theta2)) ); return rawdistance - r1 - r2; } protected: /// Own Control void acquireControl(); /// Release Control void releaseControl(); /// Acquire vision void acquireVision(); /// Release vision void releaseVision(); /// Create Move primitive void createMovePrimitive(); /// Delete Move primitive void deleteMovePrimitive(); /// Check has position (ask for it if necessary) bool isValid() { if (!hasId()) return false; if (!hasPosition()) { if (!hasControlOwned() && !_PositionUpdatesRequested) requestPositionUpdates(); return false; } return true; } /// Request Id void requestId(); /// Request Position void requestPositionUpdates(); protected: /// @name Track Id //@{ /// Has Id bool _HasId; /// Id Requested bool _IdRequested; /// Entity Id NLMISC::CEntityId _Id; /// Sheet Id NLMISC::CSheetId _SheetId; /// Sheet const CSheet *_Sheet; /// Is static bool _IsStatic; //@} /// @name Track Position Control //@{ /// Own control bool _OwnControl; /// Has Position bool _HasPosition; /// Id Requested bool _PositionUpdatesRequested; /// Position NLMISC::CVectorD _Position; /// Heading float _Heading; /// Followed track NLMISC::CSmartPtr<CTrack> _Followed; //@} /// @name Track PACS //@{ /// Move Container NLPACS::UMoveContainer *_MoveContainer; /// Move Primitive NLPACS::UMovePrimitive *_MovePrimitive; //@} /// @name Misc //@{ /// Force release bool _ForceRelease; /// Vision container typedef std::map<NLMISC::CEntityId, NLMISC::CSmartPtr<CTrack> > TVision; /// Vision TVision _Vision; /// Receive vision bool _ReceiveVision; /// User data void *_UserData; /// Track state TTrackState _State; /// Last move cycle uint32 _LastMoveCycle; /// Last target distance double _LastTargetDistance; /// Smoothed target distance double _SmoothedTargetDistanceDelta; //@} public: /// @name Target attraction control //@{ /// Required target spacing static double TargetSpacing; /// Target attraction strength static double TargetAttraction; /// Target attraction amplification static double TargetAmp; //@} /// @name Obstacle repulsion control //@{ /// Fast obstacle exclusion distance static double ObstacleExcludeDistance; /// Required obstacle spacing static double ObstacleSpacing; /// Obstacle repulsion strength static double ObstacleRepulsion; /// Obstacle repulsion amplification static double ObstacleAmp; //@} /// @name Track motion control //@{ /// Minimum motion distance static double MinimumMotion; /// Lock distance threshold static double LockThreshold; /// Lose distance threshold static double LoseThreshold; /// Stabilise cycle static uint32 StabiliseCycle; //@} }; #endif // NL_TRACK_H /* End of track.h */