topical media & game development
lib-game-delta3d-sdk-examples-testAI-aicharacter.cpp / cpp
/* -*-c++-*-
* testAI - aicharacter (.h & .cpp) - Using 'The MIT License'
* Copyright (C) 2004-2006 MOVES Institute
*
* 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.
*
* Bradley Anderegg 06/29/2006
*/
include <aicharacter.h>
include <dtAI/astarconfig.h>
include <dtAI/waypoint.h>
include <dtUtil/matrixutil.h>
include <dtCore/isector.h>
include <osg/MatrixTransform>
include <algorithm>
include <cassert>
include <cmath>
A quick functor that will be used with for_each to render
all waypoints in the list to green
struct funcRenderGreen
{
template<class _WayIter>
void operator()(const _WayIter& pWaypoint) const
{
const dtAI::Waypoint* way = dynamic_cast<const dtAI::Waypoint*>(&*pWaypoint);
if(way != NULL)
{
way->SetRenderFlag(dtAI::Waypoint::RENDER_GREEN);
}
}
};
namespace dtAI
{
AICharacter::AICharacter(dtCore::Scene* pScene, const WaypointInterface* pWaypoint, const std::string& pFilename, unsigned pSpeed)
: mSpeed(pSpeed)
, mCharacter(new dtAnim::CharacterWrapper(pFilename))
, mCurrentWaypoint(pWaypoint)
, mWaypointPath()
, mAStar()
, mScene(pScene)
{
mCharacter->SetGroundClamp(pScene, 0.0f);
SetPosition(pWaypoint);
pScene->AddDrawable(mCharacter.get());
}
AICharacter::~AICharacter()
{
}
void AICharacter::SetPosition(const WaypointInterface* pWaypoint)
{
osg::Matrix mat;
mat(3,0) = pWaypoint->GetPosition()[0];
mat(3,1) = pWaypoint->GetPosition()[1];
mat(3,2) = pWaypoint->GetPosition()[2] + 3.5f;
mCharacter->GetMatrixNode()->setMatrix(mat);
}
bool AICharacter::FindPathAndGoToWaypoint(const WaypointInterface* pWaypoint)
{
// to use AStar, we call reset with the two points we want to path between
mAStar.Reset(mCurrentWaypoint, pWaypoint);
// a single call to find path should return PATH_FOUND if no constraints are given
// and if a path exists
PathFindResult pHasPath = mAStar.FindPath();
if (pHasPath != NO_PATH)
{
// copy the resulting path
mWaypointPath = mAStar.GetPath();
// loop through the path and turn everything to render green
for_each(mWaypointPath.begin(), mWaypointPath.end(), funcRenderGreen());
const dtAI::Waypoint* way = dynamic_cast<const dtAI::Waypoint*>(pWaypoint);
if(way != NULL)
{
// set the last waypoint to render red
way->SetRenderFlag(dtAI::Waypoint::RENDER_RED);
}
return true;
}
// we could not path to that point
return false;
}
const WaypointAStar::config_type& AICharacter::GetConfig() const
{
return mAStar.GetConfig();
}
void AICharacter::GoToWaypoint(float dt, const WaypointInterface* pWaypoint)
{
// simple... just rotate to the waypoint over time and set a
// positive velocity to go there
mCharacter->RotateToPoint(pWaypoint->GetPosition(), dt * 3.0f);
//osg::Vec3 pVector = pWaypoint->GetPosition() - GetPosition();
//pVector [2] = 0.0f;
//float dir = std::abs(osg::RadiansToDegrees(atan2(pVector[0], -pVector[1])) - mCharacter->GetRotation());
//while (dir >= 360.0f) dir -= 360.0f;
//std::cout << dir << std::endl;
//if (dir < 5.0f)
//{
mCharacter->SetSpeed(-float(mSpeed));
if (!mCharacter->IsAnimationPlaying("Walk"))
{
mCharacter->ClearAllAnimations(0.5f);
mCharacter->PlayAnimation("Walk");
}
//}
//else
//{
// mCharacter->SetVelocity(0.0f);
//}
}
osg::Vec3 AICharacter::GetPosition() const
{
osg::Matrix mat = mCharacter->GetMatrixNode()->getMatrix();
osg::Vec3 pos(mat(3, 0), mat(3, 1), mat(3, 2));
return pos;
}
osg::Vec3 AICharacter::GetForward() const
{
osg::Matrix mat = mCharacter->GetMatrixNode()->getMatrix();
osg::Vec3 forward(mat(1, 0), mat(1, 1), mat(1, 2));
return forward;
}
bool AICharacter::AmAtWaypoint(const WaypointInterface* pWaypoint)
{
// a simple distance comparison to determine if we are within
// range of a waypoint to be considered "at it"
osg::Vec3 pos = GetPosition();
osg::Vec3 wayPos = pWaypoint->GetPosition();
float distToX = std::abs(pos[0] - wayPos[0]);
float distToY = std::abs(pos[1] - wayPos[1]);
if (mWaypointPath.size() == 1)
{
return (distToX < 0.1f && distToY < 0.1f);
}
else
{
return (distToX < 1.0f && distToY < 1.0f);
}
}
void AICharacter::Update(float dt)
{
// if we have waypoints to goto
if (!mWaypointPath.empty())
{
// if we have gotten to the current waypoint
if (AmAtWaypoint(mWaypointPath.front()))
{
// set it as the current waypoint
// meaning the last valid waypoint we visited
mCurrentWaypoint = mWaypointPath.front();
// remove that waypoint from the list
mWaypointPath.pop_front();
const dtAI::Waypoint* way = dynamic_cast<const dtAI::Waypoint*>(mCurrentWaypoint);
// set its render flag to render blue again
if(way != NULL)
{
way->SetRenderFlag(dtAI::Waypoint::RENDER_BLUE);
}
}
// if we have another waypoint to goto, goto it
if (!mWaypointPath.empty())
{
ApplyStringPulling();
GoToWaypoint(dt, mWaypointPath.front());
}
// else stop walking
else
{
mCharacter->SetSpeed(0);
if (!mCharacter->IsAnimationPlaying("Idle"))
{
mCharacter->ClearAllAnimations(0.5f);
mCharacter->PlayAnimation("Idle");
}
}
}
mCharacter->Update(dt);
}
void AICharacter::ApplyStringPulling()
{
if (mWaypointPath.size() < 2) return;
dtCore::RefPtr<dtCore::Isector> pIsector = new dtCore::Isector(mScene.get());
do
{
pIsector->Reset();
//osg::Vec3 vec = mWaypointPath.front()->GetPosition() - GetPosition();
//vec.normalize();
pIsector->SetStartPosition(GetPosition());// + vec);
const WaypointInterface* pNextWaypoint = *(++(mWaypointPath.begin()));
pIsector->SetEndPosition(pNextWaypoint->GetPosition());// - vec);
// if there is a path between the two points
if (!pIsector->Update())
{
const dtAI::Waypoint* way = dynamic_cast<const dtAI::Waypoint*>(mWaypointPath.front());
if(way != NULL)
{
way->SetRenderFlag(Waypoint::RENDER_BLUE);
}
mWaypointPath.pop_front();
}
else break;
}
while (mWaypointPath.size() > 2);
}
} // namespace dtAI
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.