Steering Behaviors – Arrival: Revisited
Bom… finalmente fiz o simulador para os steering behaviors, nos moldes do simulador do Buckland. Foi realmente ótimo, eu devia ter investido nisso mais cedo.
Em primeiro lugar, descobri um detalhe no algoritmo do Buckland que passa meio batido. O parâmetro “deceleration”, no algoritmo do Buckland , pode assumir os valores 1, 2 ou 3, é condicionado pelo “decelerationTweeker”, que tem valor 0.3f. Eu não entendia o resultado dessa conta maluca, e assumi que estava certa. Essa continha é usada na seguinte linha:
float speed = distance / (deceleration * decelerationTweeker);
Ocorre que ao rodar no simulador, ficou claríssimo que o algoritmo sempre se comportava como o Seek. Então, resolvi ir até o trabalho original do Reynolds, para ver o que estava errado. No algoritmo do Reynolds a formula é a seguinte:
float speed = distance / desiredBreakDistance;
Logo, isso aqui teria que ser verdadeiro:
desiredBreakDistance = deceleration * decelerationTweeker
Agora, esse valor varia de acordo com a escala do mundo. Meus triângulos tem aproximadamente 10 cm de comprimento e uma “desiredBreakDistance” de 0.3 não significa nada para eles. Então, decidi alterar o algoritmo e mantê-lo de acordo com o original. Definitivamente, vou ter que pensar numa forma de abstrair distâncias e tamanhos para a IA.
Ah sim. Também aproveitei e mudei o nome “Arrive” para “Arrival”, como está no documento original do Buckland. O algoritmo final ficou assim:
#include "SteerForce.h"
namespace behavior
{
template <typename Target>
class Arrival : public SteerForce
{
private:
const Vehicle& vehicle;
const Target& target;
const float decelerationDistance;
public:
Arrival(const Vehicle& _vehicle, const Target& _target,
float _deceleration)
: vehicle(_vehicle), target(_target),
decelerationDistance(_deceleration)
{};
virtual math::Vector2D calculate()
{
math::Vector2D targetPos(target.getX(), target.getY());
math::Vector2D path(targetPos - vehicle.getPosition());
double distance = path.getSize();
if (distance <= 0)
return math::Vector2D();
//Calculate the speed required to reach
float speed = distance / decelerationDistance;
//Make sure the speed does not exceed the maximum allowed speed
speed = std::min(speed, vehicle.getMaxSpeed());
//From here proceed just like Seek, except we don't need to
//normalize the path vector because we have already gone the
//trouble of calculating it's length: distance
math::Vector2D desiredVelocity = path * (speed / distance);
return (desiredVelocity - vehicle.getVelocity());
};
};
};
No mais, continuei os estudos de templates. Já foram mais de 120 páginas estudadas, basicamente revisando todo o assunto. Também vi alguns detalhes um pouco mais avançados, que geralmente “passam batidos” nas aulas de templates. Como por exemplo, como funciona a regra de dedução de argumentos, porque não se pode usar dedução com métodos virtuais, como o C++ encara a sobrecarga de funções quando templates estão envolvidas, etc.Hoje já dediquei pelo menos 6 horas para o projeto. Amanhã pretendo dedicar outras 6. E mais outras depois de amanhã. No final desse carnaval, quero ter pelo menos mais 2 behaviors implementados e testados. Depois posto os fontes por aqui, inclusive do simulador.
Após implementar os behaviors, volto a tentar integra-los no Batalha Estelar. E então parto para a implementação de máquinas de estados.
Por fim, também implementei a classe NullForce, que representa um SteeringBehavior nulo (padrão do Objeto Nulo). Ela é um Singleton (já que não tem mesmo estado) e facilita muito o design, já que as classes que eventualmente dependam de behaviors não precisam se preocupar em testar nulidade. Na prática, isso representa poder usar referências no lugar de ponteiros, o que é altamente desejável. Só a título de curiosidade, aqui está o código da classe:
namespace behavior
{
class NullForce : public SteerForce
{
private:
const static NullForce& instance;
NullForce();
NullForce(const NullForce&);
NullForce operator = (const NullForce&);
public:
static const NullForce& getInstance() { return instance; }
virtual math::Vector2D calculate() {return math::Vector2D(); }
};
}
Boa noite Vinícius,
Seus artigos estão realmente me ajudando a entender cada vez mais não só a implementação mas os conceitos por trás das técnicas, por isso lhe parabenizo e agradeço.
Espero ver sua implementação em breve.
[]’s
blastedgame
04 dUTC Fevereiro dUTC 2008 em 02:50:03