[Orxonox-commit 185] r2860 - trunk/src/orxonox/objects/controllers
landauf at orxonox.net
landauf at orxonox.net
Fri Mar 27 19:11:31 CET 2009
Author: landauf
Date: 2009-03-27 18:11:30 +0000 (Fri, 27 Mar 2009)
New Revision: 2860
Modified:
trunk/src/orxonox/objects/controllers/PongAI.cc
trunk/src/orxonox/objects/controllers/PongAI.h
Log:
Improved PongAI - it tries to predict the position of the ball (but does some random mistakes, depending on the AI's strength) and moves to this position (with a reaction delay, also depending on the strength). Additionally fixed some inaccuracies caused by the hysteresis avoidance system.
Modified: trunk/src/orxonox/objects/controllers/PongAI.cc
===================================================================
--- trunk/src/orxonox/objects/controllers/PongAI.cc 2009-03-27 15:04:24 UTC (rev 2859)
+++ trunk/src/orxonox/objects/controllers/PongAI.cc 2009-03-27 18:11:30 UTC (rev 2860)
@@ -33,23 +33,40 @@
#include "core/ConfigValueIncludes.h"
#include "objects/worldentities/ControllableEntity.h"
#include "objects/worldentities/PongBall.h"
+#include "tools/Timer.h"
namespace orxonox
{
CreateUnloadableFactory(PongAI);
+ const static float MAX_REACTION_TIME = 0.4;
+
PongAI::PongAI(BaseObject* creator) : Controller(creator)
{
RegisterObject(PongAI);
this->ball_ = 0;
+ this->ballDirection_ = Vector2::ZERO;
+ this->ballEndPosition_ = 0;
this->randomOffset_ = 0;
this->relHysteresisOffset_ = 0.02;
this->strength_ = 0.5;
+ this->movement_ = 0;
this->setConfigValues();
+
+// this->randomOffsetTimer_.setTimer(MAX_REACTION_TIME * (1 - this->strength_), false, this, createExecutor(createFunctor(&PongAI::calculateRandomOffset)));
+// this->ballEndPositionTimer_.setTimer(MAX_REACTION_TIME * (1 - this->strength_), false, this, createExecutor(createFunctor(&PongAI::calculateBallEndPosition)));
+// this->randomOffsetTimer_.stopTimer();
+// this->ballEndPositionTimer_.stopTimer();
}
+ PongAI::~PongAI()
+ {
+ for (std::list<std::pair<Timer<PongAI>*, char> >::iterator it = this->reactionTimers_.begin(); it != this->reactionTimers_.end(); ++it)
+ delete (*it).first;
+ }
+
void PongAI::setConfigValues()
{
SetConfigValue(strength_, 0.5).description("A value from 0 to 1 where 0 is weak and 1 is strong.");
@@ -60,39 +77,67 @@
if (!this->ball_ || !this->getControllableEntity())
return;
- ControllableEntity* bat = this->getControllableEntity();
-
- Vector3 mypos = bat->getPosition();
+ Vector3 mypos = this->getControllableEntity()->getPosition();
Vector3 ballpos = this->ball_->getPosition();
Vector3 ballvel = this->ball_->getVelocity();
float hysteresisOffset = this->relHysteresisOffset_ * this->ball_->getFieldDimension().y;
+ char move = 0;
+
// Check in which direction the ball is flying
if ((mypos.x > 0 && ballvel.x < 0) || (mypos.x < 0 && ballvel.x > 0))
{
// Ball is flying away
- this->calculateRandomOffset();
+ this->ballDirection_.x = -1;
+ this->ballDirection_.y = 0;
if (mypos.z > hysteresisOffset)
- bat->moveFrontBack(1);
+ move = 1;
else if (mypos.z < -hysteresisOffset)
- bat->moveFrontBack(-1);
+ move = -1;
}
else if (ballvel.x == 0)
{
// Ball is standing still
- this->calculateRandomOffset();
+ this->ballDirection_.x = 0;
+ this->ballDirection_.y = 0;
}
else
{
// Ball is approaching
- float desiredZValue = ballpos.z + this->randomOffset_;
+ if (this->ballDirection_.x != 1)
+ {
+ this->ballDirection_.x = 1;
+ this->ballDirection_.y = sgn(ballvel.z);
+ this->ballEndPosition_ = 0;
+ this->randomOffset_ = 0;
- if (mypos.z > desiredZValue + hysteresisOffset)
- bat->moveFrontBack(1);
- else if (mypos.z < desiredZValue - hysteresisOffset)
- bat->moveFrontBack(-1);
+ this->calculateRandomOffset();
+ this->calculateBallEndPosition();
+ //this->randomOffsetTimer_.setInterval(MAX_REACTION_TIME * (1 - this->strength_));
+ //this->ballEndPositionTimer_.setInterval(MAX_REACTION_TIME * (1 - this->strength_));
+ //this->randomOffsetTimer_.startTimer();
+ //this->ballEndPositionTimer_.startTimer();
+ }
+
+ if (this->ballDirection_.y != sgn(ballvel.z))
+ {
+ this->ballDirection_.y = sgn(ballvel.z);
+
+ this->calculateBallEndPosition();
+ //this->ballEndPositionTimer_.startTimer();
+ }
+
+ float desiredZValue = /*((1 - this->strength_) * ballpos.z) + */(/*this->strength_ * */this->ballEndPosition_) + this->randomOffset_;
+
+ if (mypos.z > desiredZValue + hysteresisOffset * (this->randomOffset_ < 0))
+ move = 1;
+ else if (mypos.z < desiredZValue - hysteresisOffset * (this->randomOffset_ > 0))
+ move = -1;
}
+
+ this->move(move);
+ this->getControllableEntity()->moveFrontBack(this->movement_);
}
void PongAI::calculateRandomOffset()
@@ -107,7 +152,7 @@
// exp < 1 -> position is more likely a large number
// The position shouln't be larger than 0.5 (50% of the bat-length from the middle is the end)
- position *= 0.45;
+ position *= 0.48;
// Both sides are equally probable
position *= sgn(rnd(-1,1));
@@ -115,4 +160,66 @@
// Calculate the offset in world units
this->randomOffset_ = position * this->ball_->getBatLength() * this->ball_->getFieldDimension().y;
}
+
+ void PongAI::calculateBallEndPosition()
+ {
+ Vector3 position = this->ball_->getPosition();
+ Vector3 velocity = this->ball_->getVelocity();
+ Vector2 dimension = this->ball_->getFieldDimension();
+
+ // calculate end-height: current height + slope * distance
+ this->ballEndPosition_ = position.z + velocity.z / velocity.x * (-position.x + dimension.x / 2 * sgn(velocity.x));
+
+ // Calculate bounces
+ for (float limit = 0.35; limit < this->strength_ || this->strength_ > 0.99; limit += 0.4)
+ {
+ if (this->ballEndPosition_ > dimension.y / 2)
+ {
+ this->ballEndPosition_ = dimension.y - this->ballEndPosition_ + (rnd(-1, 1) * dimension.y * (1 - this->strength_));
+ continue;
+ }
+ if (this->ballEndPosition_ < -dimension.y / 2)
+ {
+ this->ballEndPosition_ = -dimension.y - this->ballEndPosition_ + (rnd(-1, 1) * dimension.y * (1 - this->strength_));
+ continue;
+ }
+ break;
+ }
+ }
+
+ void PongAI::move(char direction)
+ {
+ // The current direction is either what we're doing right now (movement_) or what is last in the queue
+ char currentDirection = this->movement_;
+ if (this->reactionTimers_.size() > 0)
+ currentDirection = this->reactionTimers_.back().second;
+
+ // Only add changes of direction
+ if (direction == currentDirection)
+ return;
+
+ // Calculate delay, but only to change direction or start moving (stop works without delay)
+ if (direction != 0)
+ {
+ float delay = MAX_REACTION_TIME * (1 - this->strength_);
+
+ // Add a new Timer
+ Timer<PongAI>* timer = new Timer<PongAI>(delay, false, this, createExecutor(createFunctor(&PongAI::delayedMove)));
+ this->reactionTimers_.push_back(std::pair<Timer<PongAI>*, char>(timer, direction));
+ }
+ else
+ {
+ this->movement_ = 0;
+ }
+ }
+
+ void PongAI::delayedMove()
+ {
+ this->movement_ = this->reactionTimers_.front().second;
+
+ Timer<PongAI>* timer = this->reactionTimers_.front().first;
+ delete timer;
+
+ this->reactionTimers_.pop_front();
+ }
}
Modified: trunk/src/orxonox/objects/controllers/PongAI.h
===================================================================
--- trunk/src/orxonox/objects/controllers/PongAI.h 2009-03-27 15:04:24 UTC (rev 2859)
+++ trunk/src/orxonox/objects/controllers/PongAI.h 2009-03-27 18:11:30 UTC (rev 2860)
@@ -31,8 +31,11 @@
#include "OrxonoxPrereqs.h"
+#include <list>
+
#include "Controller.h"
#include "objects/Tickable.h"
+#include "util/Math.h"
namespace orxonox
{
@@ -40,7 +43,7 @@
{
public:
PongAI(BaseObject* creator);
- virtual ~PongAI() {}
+ virtual ~PongAI();
void setConfigValues();
@@ -51,11 +54,21 @@
protected:
void calculateRandomOffset();
+ void calculateBallEndPosition();
+ void move(char direction);
+ void delayedMove();
PongBall* ball_;
+ Vector2 ballDirection_;
+ float ballEndPosition_;
float randomOffset_;
float relHysteresisOffset_;
float strength_;
+
+// Timer<PongAI> randomOffsetTimer_;
+// Timer<PongAI> ballEndPositionTimer_;
+ std::list<std::pair<Timer<PongAI>*, char> > reactionTimers_;
+ char movement_;
};
}
More information about the Orxonox-commit
mailing list