newspeoplefor developersdocumentationdownloads

actorphysicsproperty.cc

Go to the documentation of this file.
00001 //------------------------------------------------------------------------------
00002 //  properties/actorphysicsproperty.cc
00003 //  (C) 2005 Radon Labs GmbH
00004 //------------------------------------------------------------------------------
00005 #include "properties/actorphysicsproperty.h"
00006 #include "foundation/factory.h"
00007 #include "attr/attributes.h"
00008 #include "physics/server.h"
00009 #include "physics/level.h"
00010 #include "managers/timemanager.h"
00011 #include "mathlib/polar.h"
00012 #include "graphics/server.h"
00013 #include "graphics/cameraentity.h"
00014 #include "managers/entitymanager.h"
00015 #include "navigation/server.h"
00016 #include "msg/movesetvelocity.h"
00017 
00018 namespace Properties
00019 {
00020 ImplementRtti(Properties::ActorPhysicsProperty, Properties::AbstractPhysicsProperty);
00021 ImplementFactory(Properties::ActorPhysicsProperty);
00022 
00023 using namespace Game;
00024 using namespace Message;
00025 using namespace Managers;
00026 
00027 //------------------------------------------------------------------------------
00030 ActorPhysicsProperty::ActorPhysicsProperty() :
00031     followTargetDist(4.0f),
00032     curGotoSegment(0),
00033     gotoTimeStamp(0.0),
00034     headingGain(-4.0f),
00035     positionGain(-25.0f)
00036 {
00037     // empty
00038 }
00039 
00040 //------------------------------------------------------------------------------
00043 ActorPhysicsProperty::~ActorPhysicsProperty()
00044 {
00045     // empty
00046 }
00047 
00048 //------------------------------------------------------------------------------
00051 void
00052 ActorPhysicsProperty::SetupDefaultAttributes()
00053 {
00054     AbstractPhysicsProperty::SetupDefaultAttributes();
00055     this->GetEntity()->SetVector3(Attr::VelocityVector, vector3(0.0f, 0.0f, 0.0f));
00056     this->GetEntity()->SetFloat(Attr::RelVelocity, 1.0f);
00057     this->GetEntity()->SetFloat(Attr::MaxVelocity, 2.5f);
00058     this->GetEntity()->SetBool(Attr::Following, false);
00059     this->GetEntity()->SetBool(Attr::Moving, false);
00060 }
00061 
00062 //------------------------------------------------------------------------------
00066 void
00067 ActorPhysicsProperty::EnablePhysics()
00068 {
00069     n_assert(!this->IsEnabled());
00070     
00071     // create a char physics entity
00072     this->charPhysicsEntity = Physics::CharEntity::Create();
00073     this->charPhysicsEntity->SetUserData(this->GetEntity()->GetUniqueId());
00074     if (this->GetEntity()->HasAttr(Attr::Physics))
00075     {
00076         this->charPhysicsEntity->SetCompositeName(this->GetEntity()->GetString(Attr::Physics));
00077     }
00078     this->charPhysicsEntity->SetTransform(this->GetEntity()->GetMatrix44(Attr::Transform));
00079 
00080     // attach physics entity to physics level
00081     Physics::Level* physicsLevel = Physics::Server::Instance()->GetLevel();
00082     n_assert(physicsLevel);
00083     physicsLevel->AttachEntity(this->charPhysicsEntity);
00084 
00085     // make sure we are standing still
00086     this->Stop();
00087 
00088     // initialize feedback loops for motion smoothing
00089     nTime time = TimeManager::Instance()->GetTime();
00090     const matrix44& entityMatrix = this->GetEntity()->GetMatrix44(Attr::Transform);
00091     this->smoothedPosition.Reset(time, 0.0001f, this->positionGain, entityMatrix.pos_component());
00092 
00093     polar2 headingAngle(entityMatrix.z_component());
00094     this->smoothedHeading.Reset(time, 0.0001f, this->headingGain, headingAngle.rho);
00095 
00096     // call parrent
00097     AbstractPhysicsProperty::EnablePhysics();
00098 }
00099 
00100 //------------------------------------------------------------------------------
00103 void
00104 ActorPhysicsProperty::DisablePhysics()
00105 {
00106     n_assert(this->IsEnabled());
00107     
00108     // stop
00109     this->Stop();
00110 
00111     // remove from level
00112     Physics::Level* physicsLevel = Physics::Server::Instance()->GetLevel();
00113     n_assert(physicsLevel);
00114     physicsLevel->RemoveEntity(this->charPhysicsEntity);
00115 
00116     // cleanup resource
00117     this->charPhysicsEntity = 0;
00118 
00119     // call parrent
00120     AbstractPhysicsProperty::DisablePhysics();
00121 }
00122 
00123 //------------------------------------------------------------------------------
00126 bool
00127 ActorPhysicsProperty::Accepts(Message::Msg* msg)
00128 {
00129     return msg->CheckId(MoveDirection::Id) ||
00130            msg->CheckId(MoveFollow::Id) ||
00131            msg->CheckId(MoveGoto::Id) ||
00132            msg->CheckId(MoveStop::Id) ||
00133            msg->CheckId(SetTransform::Id) ||
00134            msg->CheckId(MoveTurn::Id) ||
00135            msg->CheckId(MoveSetVelocity::Id) ||
00136            msg->CheckId(MoveRotate::Id) ||
00137            AbstractPhysicsProperty::Accepts(msg);
00138 }
00139 
00140 //------------------------------------------------------------------------------
00143 void 
00144 ActorPhysicsProperty::HandleMessage(Message::Msg* msg)
00145 {
00146     if (!this->IsEnabled())
00147     {
00148         // disabled, don't listen to messages
00149         AbstractPhysicsProperty::HandleMessage(msg);
00150     }
00151     else if (msg->CheckId(MoveDirection::Id))
00152     {
00153         this->HandleMoveDirection((MoveDirection*) msg);
00154     }
00155     else if (msg->CheckId(MoveFollow::Id))
00156     {
00157         this->HandleMoveFollow((MoveFollow*) msg);
00158     }
00159     else if (msg->CheckId(MoveGoto::Id))
00160     {
00161         this->HandleMoveGoto((MoveGoto*) msg);
00162     }
00163     else if (msg->CheckId(MoveStop::Id))
00164     {
00165         this->Stop();
00166     }
00167     else if (msg->CheckId(SetTransform::Id))
00168     {
00169         this->HandleSetTransform((SetTransform*) msg);
00170     }
00171     else if (msg->CheckId(MoveTurn::Id))
00172     {
00173         this->HandleMoveTurn((MoveTurn*) msg);
00174     }
00175     else if (msg->CheckId(MoveRotate::Id))
00176     {
00177         this->HandleMoveRotate((MoveRotate*) msg);
00178     }
00179     else if (msg->CheckId(MoveSetVelocity::Id))
00180     {
00181         this->GetEntity()->SetFloat(Attr::RelVelocity, ((MoveSetVelocity*)msg)->GetRelVelocity());
00182     }
00183     else
00184     {
00185         AbstractPhysicsProperty::HandleMessage(msg);
00186     }
00187 }
00188 
00189 //------------------------------------------------------------------------------
00195 void
00196 ActorPhysicsProperty::OnMoveBefore()
00197 {
00198     this->HandlePendingMessages();
00199     if (this->IsEnabled())
00200     {
00201         if (this->IsGotoActive())
00202         {
00203             this->ContinueGoto();
00204         }
00205         if (this->GetEntity()->GetBool(Attr::Following))
00206         {
00207             this->ContinueFollow();
00208         }
00209     }
00210 }
00211 
00212 //------------------------------------------------------------------------------
00217 void
00218 ActorPhysicsProperty::OnMoveAfter()
00219 {
00220     if (this->IsEnabled())
00221     {
00222         // get current physics entity transform and velocity
00223         matrix44 physicsEntityTransform = this->charPhysicsEntity->GetTransform();
00224         vector3 physicsEntityVelocity = this->charPhysicsEntity->GetVelocity();
00225 
00226         // feed the feedback loops
00227         polar2 headingAngles(-physicsEntityTransform.z_component());
00228         this->smoothedPosition.SetGoal(physicsEntityTransform.pos_component());
00229         this->smoothedHeading.SetGoal(headingAngles.rho);
00230 
00231         // evaluate the feedback loops
00232         nTime time = TimeManager::Instance()->GetTime();
00233         this->smoothedPosition.Update(time);
00234         this->smoothedHeading.Update(time);
00235 
00236         // construct the new entity matrix
00237         matrix44 entityMatrix;
00238         entityMatrix.rotate_y(this->smoothedHeading.GetState());
00239         entityMatrix.translate(this->smoothedPosition.GetState());
00240 
00241         // update game entity
00242         Ptr<Message::UpdateTransform> msg = Message::UpdateTransform::Create();
00243         msg->SetMatrix(entityMatrix);
00244         this->GetEntity()->SendSync(msg);
00245         this->GetEntity()->SetVector3(Attr::VelocityVector, physicsEntityVelocity);
00246     }
00247 }
00248 
00249 //------------------------------------------------------------------------------
00255 void
00256 ActorPhysicsProperty::SendStop()
00257 {
00258     Ptr<MoveStop> msg = MoveStop::Create();
00259     this->GetEntity()->SendSync(msg);
00260 }
00261 
00262 //------------------------------------------------------------------------------
00268 void
00269 ActorPhysicsProperty::Stop()
00270 {
00271     this->charPhysicsEntity->SetDesiredVelocity(vector3(0.0f, 0.0f, 0.0f));
00272     this->gotoPath = 0;
00273     this->GetEntity()->SetBool(Attr::Moving, false);
00274     this->GetEntity()->SetVector3(Attr::VelocityVector, vector3(0.0f, 0.0f, 0.0f));
00275 }
00276 
00277 //------------------------------------------------------------------------------
00281 void
00282 ActorPhysicsProperty::HandleMoveDirection(MoveDirection* msg)
00283 {
00284     n_assert(msg);
00285 
00286     vector3 dir = msg->GetDirection();
00287 
00288     // convert camera relative vector into absolute vector if necessary
00289     if (msg->GetCameraRelative())
00290     {
00291         Graphics::CameraEntity* camera = Graphics::Server::Instance()->GetCamera();
00292         n_assert(camera);
00293         matrix44 camTransform = camera->GetTransform();
00294         camTransform.pos_component().set(0.0f, 0.0f, 0.0f);
00295         dir = camTransform * dir;
00296     }
00297     dir.y = 0.0f;
00298     dir.norm();
00299 
00300     vector3 desiredVelocity = dir * this->GetEntity()->GetFloat(Attr::RelVelocity) * this->GetEntity()->GetFloat(Attr::MaxVelocity);
00301     this->charPhysicsEntity->SetDesiredVelocity(desiredVelocity);
00302     this->charPhysicsEntity->SetDesiredLookat(dir);
00303     this->GetEntity()->SetBool(Attr::Moving, true);
00304 }
00305 
00306 //------------------------------------------------------------------------------
00310 void
00311 ActorPhysicsProperty::HandleMoveTurn(MoveTurn* msg)
00312 {
00313     n_assert(msg);
00314 
00315     this->SendStop();
00316 
00317     vector3 dir = msg->GetDirection();
00318     if (msg->GetCameraRelative())
00319     {
00320         Graphics::CameraEntity* camera = Graphics::Server::Instance()->GetCamera();
00321         n_assert(camera);
00322         matrix44 camTransform = camera->GetTransform();
00323         camTransform.pos_component().set(0.0f, 0.0f, 0.0f);
00324         dir = camTransform * dir;
00325     }
00326     dir.y = 0.0f;
00327     dir.norm();
00328     this->charPhysicsEntity->SetDesiredLookat(dir);
00329 }
00330 
00331 //------------------------------------------------------------------------------
00335 void
00336 ActorPhysicsProperty::HandleMoveRotate(MoveRotate* msg)
00337 {
00338     n_assert(msg);
00339 
00340     float angle = msg->GetAngle();
00341     vector3 direction = this->charPhysicsEntity->GetDesiredLookat();
00342     direction.rotate(vector3(0.f, 1.f, 0.f), angle);
00343     this->charPhysicsEntity->SetDesiredLookat(direction);
00344 }
00345 
00346 //------------------------------------------------------------------------------
00350 void
00351 ActorPhysicsProperty::HandleMoveGoto(MoveGoto* msg)
00352 {
00353     n_assert(msg);
00354 
00355     // make a navigation path from current to target position
00356     const vector3& from = this->GetEntity()->GetMatrix44(Attr::Transform).pos_component();
00357     const vector3& to = msg->GetPosition();
00358     this->gotoPath = Navigation::Server::Instance()->MakePath(from, to);
00359     this->curGotoSegment = 0;
00360 
00361     this->gotoTimeStamp = TimeManager::Instance()->GetTime();
00362     this->GetEntity()->SetBool(Attr::Moving, true);
00363 }
00364 
00365 //------------------------------------------------------------------------------
00369 void
00370 ActorPhysicsProperty::HandleSetTransform(SetTransform* msg)
00371 {
00372     n_assert(msg);
00373     this->charPhysicsEntity->SetTransform(msg->GetMatrix());   
00374 }
00375 
00376 //------------------------------------------------------------------------------
00380 void
00381 ActorPhysicsProperty::HandleMoveFollow(MoveFollow* msg)
00382 {
00383     n_assert(msg);
00384     this->GetEntity()->SetInt(Attr::TargetEntityId, msg->GetTargetEntityId());
00385     Entity* targetEntity = EntityManager::Instance()->FindEntityById(this->GetEntity()->GetInt(Attr::TargetEntityId));
00386     if (targetEntity)
00387     {
00388         this->followTargetDist = msg->GetDistance();
00389         this->GetEntity()->SetBool(Attr::Following, true);
00390     }
00391 }
00392 
00393 //------------------------------------------------------------------------------
00397 void
00398 ActorPhysicsProperty::ContinueGoto()
00399 {
00400     n_assert(this->gotoPath.isvalid());
00401 
00402     const vector3 curPos = this->GetEntity()->GetMatrix44(Attr::Transform).pos_component();
00403     vector3 targetVec = this->gotoPath->GetPoints()[this->curGotoSegment] - curPos;
00404     targetVec.y = 0.0f; // ignore vertical dimension
00405     float dist = targetVec.len();
00406 
00407     // current segment position reached?
00408     if (dist < (this->charPhysicsEntity->GetRadius() * 1.1f))
00409     {
00410         // reached final target position?
00411         if (this->curGotoSegment == this->gotoPath->CountSegments())
00412         {
00413             this->SendStop();
00414         }
00415         else
00416         {
00417             // nope, advance to next path segment
00418             this->curGotoSegment++;
00419         }
00420     }
00421     else
00422     {
00423         // just continue to go towards current segment position
00424         Ptr<MoveDirection> msg = MoveDirection::Create();
00425         msg->SetDirection(targetVec);
00426         this->GetEntity()->SendSync(msg);
00427     }
00428 }
00429 
00430 //------------------------------------------------------------------------------
00434 void
00435 ActorPhysicsProperty::ContinueFollow()
00436 {
00437     n_assert(this->GetEntity()->GetBool(Attr::Following));
00438 
00439     Game::Entity* targetEntity = EntityManager::Instance()->FindEntityById(this->GetEntity()->GetInt(Attr::TargetEntityId));
00440     if (0 == targetEntity)
00441     {
00442         // our target entity has gone...
00443         this->SendStop();
00444         return;
00445     }
00446 
00447     // compute positions in world coordinates
00448     const vector3 targetPos = targetEntity->GetMatrix44(Attr::Transform).pos_component();
00449     const vector3 curPos = this->GetEntity()->GetMatrix44(Attr::Transform).pos_component();
00450     vector3 targetVec = targetPos - curPos;
00451     targetVec.y = 0.0f; // ignore vertical dimension
00452     float targetDist = targetVec.len();
00453 
00454     // if we are close enough to our target, stop, and always face our target
00455     if (targetDist < this->followTargetDist)
00456     {
00457         // stop and look at our target
00458         this->SendStop();
00459         this->charPhysicsEntity->SetDesiredLookat(targetVec);
00460     }
00461 
00462     // continue following target position if not stopped.
00463     if ((this->gotoTimeStamp + 1.0) < TimeManager::Instance()->GetTime())
00464     {
00465         // continue moving towards our target entity
00466         Ptr<MoveGoto> moveGoto = MoveGoto::Create();
00467         moveGoto->SetPosition(targetPos);
00468         this->HandleMoveGoto(moveGoto);
00469     }
00470 }
00471 
00472 //------------------------------------------------------------------------------
00475 Physics::Entity*
00476 ActorPhysicsProperty::GetPhysicsEntity() const
00477 {
00478     return this->charPhysicsEntity;
00479 }
00480 
00481 }; // namespace Properties

Copyright © 1999-2005 by the contributing authors. Ideas, requests, problems: Send feedback.