[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