1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #pragma once
24 
25 #include "../Navigation/CrowdManager.h"
26 #include "../Scene/Component.h"
27 
28 namespace Urho3D
29 {
30 
31 enum CrowdAgentRequestedTarget
32 {
33     CA_REQUESTEDTARGET_NONE = 0,
34     CA_REQUESTEDTARGET_POSITION,
35     CA_REQUESTEDTARGET_VELOCITY
36 };
37 
38 enum CrowdAgentTargetState
39 {
40     CA_TARGET_NONE = 0,
41     CA_TARGET_FAILED,
42     CA_TARGET_VALID,
43     CA_TARGET_REQUESTING,
44     CA_TARGET_WAITINGFORQUEUE,
45     CA_TARGET_WAITINGFORPATH,
46     CA_TARGET_VELOCITY
47 };
48 
49 enum CrowdAgentState
50 {
51     CA_STATE_INVALID = 0,   ///< The agent is not in a valid state.
52     CA_STATE_WALKING,       ///< The agent is traversing a normal navigation mesh polygon.
53     CA_STATE_OFFMESH        ///< The agent is traversing an off-mesh connection.
54 };
55 
56 enum NavigationQuality
57 {
58     NAVIGATIONQUALITY_LOW = 0,
59     NAVIGATIONQUALITY_MEDIUM = 1,
60     NAVIGATIONQUALITY_HIGH = 2
61 };
62 
63 enum NavigationPushiness
64 {
65     NAVIGATIONPUSHINESS_LOW = 0,
66     NAVIGATIONPUSHINESS_MEDIUM,
67     NAVIGATIONPUSHINESS_HIGH,
68     NAVIGATIONPUSHINESS_NONE
69 };
70 
71 /// Crowd agent component, requires a CrowdManager component in the scene. When not set explicitly, agent's radius and height are defaulted to navigation mesh's agent radius and height, respectively.
72 class URHO3D_API CrowdAgent : public Component
73 {
74     URHO3D_OBJECT(CrowdAgent, Component);
75 
76     friend class CrowdManager;
77     friend void CrowdAgentUpdateCallback(dtCrowdAgent* ag, float dt);
78 
79 public:
80     /// Construct.
81     CrowdAgent(Context* context);
82     /// Destruct.
83     virtual ~CrowdAgent();
84     /// Register object factory.
85     static void RegisterObject(Context* context);
86     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
87     virtual void ApplyAttributes();
88 
89     /// Handle enabled/disabled state change.
90     virtual void OnSetEnabled();
91     /// Draw debug geometry.
92     void DrawDebugGeometry(bool depthTest);
93     /// Draw debug feelers.
94     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
95 
96     /// Submit a new target position request for this agent.
97     void SetTargetPosition(const Vector3& position);
98     /// Submit a new target velocity request for this agent.
99     void SetTargetVelocity(const Vector3& velocity);
100     /// Reset any target request for the specified agent. Note that the agent will continue to move into the current direction; set a zero target velocity to actually stop.
101     void ResetTarget();
102     /// Update the node position. When set to false, the node position should be updated by other means (e.g. using Physics) in response to the E_CROWD_AGENT_REPOSITION event.
103     void SetUpdateNodePosition(bool unodepos);
104     /// Set the agent's max acceleration.
105     void SetMaxAccel(float maxAccel);
106     /// Set the agent's max velocity.
107     void SetMaxSpeed(float maxSpeed);
108     /// Set the agent's radius.
109     void SetRadius(float radius);
110     /// Set the agent's height.
111     void SetHeight(float height);
112     /// Set the agent's query filter type.
113     void SetQueryFilterType(unsigned queryFilterType);
114     /// Set the agent's obstacle avoidance type.
115     void SetObstacleAvoidanceType(unsigned obstacleAvoidanceType);
116     /// Set the agent's navigation quality.
117     void SetNavigationQuality(NavigationQuality val);
118     /// Set the agent's navigation pushiness.
119     void SetNavigationPushiness(NavigationPushiness val);
120 
121     /// Return the agent's position.
122     Vector3 GetPosition() const;
123     /// Return the agent's desired velocity.
124     Vector3 GetDesiredVelocity() const;
125     /// Return the agent's actual velocity.
126     Vector3 GetActualVelocity() const;
127 
128     /// Return the agent's requested target position.
GetTargetPosition()129     const Vector3& GetTargetPosition() const { return targetPosition_; }
130 
131     /// Return the agent's requested target velocity.
GetTargetVelocity()132     const Vector3& GetTargetVelocity() const { return targetVelocity_; }
133 
134     /// Return the agent's requested target type, if any.
GetRequestedTargetType()135     CrowdAgentRequestedTarget GetRequestedTargetType() const { return requestedTargetType_; }
136 
137     /// Return the agent's  state.
138     CrowdAgentState GetAgentState() const;
139     /// Return the agent's target state.
140     CrowdAgentTargetState GetTargetState() const;
141 
142     /// Return true when the node's position should be updated by the CrowdManager.
GetUpdateNodePosition()143     bool GetUpdateNodePosition() const { return updateNodePosition_; }
144 
145     /// Return the agent id.
GetAgentCrowdId()146     int GetAgentCrowdId() const { return agentCrowdId_; }
147 
148     /// Get the agent's max acceleration.
GetMaxAccel()149     float GetMaxAccel() const { return maxAccel_; }
150 
151     /// Get the agent's max velocity.
GetMaxSpeed()152     float GetMaxSpeed() const { return maxSpeed_; }
153 
154     /// Get the agent's radius.
GetRadius()155     float GetRadius() const { return radius_; }
156 
157     /// Get the agent's height.
GetHeight()158     float GetHeight() const { return height_; }
159 
160     /// Get the agent's query filter type.
GetQueryFilterType()161     unsigned GetQueryFilterType() const { return queryFilterType_; }
162 
163     /// Get the agent's obstacle avoidance type.
GetObstacleAvoidanceType()164     unsigned GetObstacleAvoidanceType() const { return obstacleAvoidanceType_; }
165 
166     /// Get the agent's navigation quality.
GetNavigationQuality()167     NavigationQuality GetNavigationQuality() const { return navQuality_; }
168 
169     /// Get the agent's navigation pushiness.
GetNavigationPushiness()170     NavigationPushiness GetNavigationPushiness() const { return navPushiness_; }
171 
172     /// Return true when the agent has a target.
HasRequestedTarget()173     bool HasRequestedTarget() const { return requestedTargetType_ != CA_REQUESTEDTARGET_NONE; }
174 
175     /// Return true when the agent has arrived at its target.
176     bool HasArrived() const;
177     /// Return true when the agent is in crowd (being managed by a crowd manager).
178     bool IsInCrowd() const;
179 
180 protected:
181     /// Handle crowd agent being updated. It is called by CrowdManager::Update() via callback.
182     virtual void OnCrowdUpdate(dtCrowdAgent* ag, float dt);
183     /// Handle node being assigned.
184     virtual void OnNodeSet(Node* node);
185     /// Handle node being assigned.
186     virtual void OnSceneSet(Scene* scene);
187     /// \todo Handle node transform being dirtied.
188     virtual void OnMarkedDirty(Node* node);
189     /// Get internal Detour crowd agent.
190     const dtCrowdAgent* GetDetourCrowdAgent() const;
191     /// Handle navigation mesh tile added.
192     void HandleNavigationTileAdded(StringHash eventType, VariantMap& eventData);
193 
194 private:
195     /// Update Detour crowd agent parameter.
196     void UpdateParameters(unsigned scope = M_MAX_UNSIGNED);
197     /// Add agent into crowd.
198     int AddAgentToCrowd(bool force = false);
199     /// Remove agent from crowd.
200     void RemoveAgentFromCrowd();
201     /// Crowd manager.
202     WeakPtr<CrowdManager> crowdManager_;
203     /// Crowd manager reference to this agent.
204     int agentCrowdId_;
205     /// Requested target position.
206     Vector3 targetPosition_;
207     /// Requested target velocity.
208     Vector3 targetVelocity_;
209     /// Requested target type.
210     CrowdAgentRequestedTarget requestedTargetType_;
211     /// Flag indicating the node's position should be updated by Detour crowd manager.
212     bool updateNodePosition_;
213     /// Agent's max acceleration.
214     float maxAccel_;
215     /// Agent's max Velocity.
216     float maxSpeed_;
217     /// Agent's radius, if 0 the navigation mesh's setting will be used.
218     float radius_;
219     /// Agent's height, if 0 the navigation mesh's setting will be used.
220     float height_;
221     /// Agent's query filter type, it is an index to the query filter buffer configured in Detour crowd manager.
222     unsigned queryFilterType_;
223     /// Agent's obstacle avoidance type, it is an index to the obstacle avoidance array configured in Detour crowd manager. It is ignored when agent's navigation quality is not set to "NAVIGATIONQUALITY_HIGH".
224     unsigned obstacleAvoidanceType_;
225     /// Agent's navigation quality. The higher the setting, the higher the CPU usage during crowd simulation.
226     NavigationQuality navQuality_;
227     /// Agent's navigation pushiness. The higher the setting, the stronger the agent pushes its colliding neighbours around.
228     NavigationPushiness navPushiness_;
229     /// Agent's previous position used to check for position changes.
230     Vector3 previousPosition_;
231     /// Agent's previous target state used to check for state changes.
232     CrowdAgentTargetState previousTargetState_;
233     /// Agent's previous agent state used to check for state changes.
234     CrowdAgentState previousAgentState_;
235     /// Internal flag to ignore transform changes because it came from us, used in OnCrowdAgentReposition().
236     bool ignoreTransformChanges_;
237 };
238 
239 }
240