Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Mar 27, 2009, 7:11:30 PM (16 years ago)
Author:
landauf
Message:

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.

Location:
code/trunk/src/orxonox/objects/controllers
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk/src/orxonox/objects/controllers/PongAI.cc

    r2857 r2860  
    3434#include "objects/worldentities/ControllableEntity.h"
    3535#include "objects/worldentities/PongBall.h"
     36#include "tools/Timer.h"
    3637
    3738namespace orxonox
     
    3940    CreateUnloadableFactory(PongAI);
    4041
     42    const static float MAX_REACTION_TIME = 0.4;
     43
    4144    PongAI::PongAI(BaseObject* creator) : Controller(creator)
    4245    {
     
    4447
    4548        this->ball_ = 0;
     49        this->ballDirection_ = Vector2::ZERO;
     50        this->ballEndPosition_ = 0;
    4651        this->randomOffset_ = 0;
    4752        this->relHysteresisOffset_ = 0.02;
    4853        this->strength_ = 0.5;
     54        this->movement_ = 0;
    4955
    5056        this->setConfigValues();
     57
     58//        this->randomOffsetTimer_.setTimer(MAX_REACTION_TIME * (1 - this->strength_), false, this, createExecutor(createFunctor(&PongAI::calculateRandomOffset)));
     59//        this->ballEndPositionTimer_.setTimer(MAX_REACTION_TIME * (1 - this->strength_), false, this, createExecutor(createFunctor(&PongAI::calculateBallEndPosition)));
     60//        this->randomOffsetTimer_.stopTimer();
     61//        this->ballEndPositionTimer_.stopTimer();
     62    }
     63
     64    PongAI::~PongAI()
     65    {
     66        for (std::list<std::pair<Timer<PongAI>*, char> >::iterator it = this->reactionTimers_.begin(); it != this->reactionTimers_.end(); ++it)
     67            delete (*it).first;
    5168    }
    5269
     
    6178            return;
    6279
    63         ControllableEntity* bat = this->getControllableEntity();
    64 
    65         Vector3 mypos = bat->getPosition();
     80        Vector3 mypos = this->getControllableEntity()->getPosition();
    6681        Vector3 ballpos = this->ball_->getPosition();
    6782        Vector3 ballvel = this->ball_->getVelocity();
    6883        float hysteresisOffset = this->relHysteresisOffset_ * this->ball_->getFieldDimension().y;
    6984
     85        char move = 0;
     86
    7087        // Check in which direction the ball is flying
    7188        if ((mypos.x > 0 && ballvel.x < 0) || (mypos.x < 0 && ballvel.x > 0))
    7289        {
    7390            // Ball is flying away
    74             this->calculateRandomOffset();
     91            this->ballDirection_.x = -1;
     92            this->ballDirection_.y = 0;
    7593
    7694            if (mypos.z > hysteresisOffset)
    77                 bat->moveFrontBack(1);
     95                move = 1;
    7896            else if (mypos.z < -hysteresisOffset)
    79                 bat->moveFrontBack(-1);
     97                move = -1;
    8098        }
    8199        else if (ballvel.x == 0)
    82100        {
    83101            // Ball is standing still
    84             this->calculateRandomOffset();
     102            this->ballDirection_.x = 0;
     103            this->ballDirection_.y = 0;
    85104        }
    86105        else
    87106        {
    88107            // Ball is approaching
    89             float desiredZValue = ballpos.z + this->randomOffset_;
    90 
    91             if (mypos.z > desiredZValue + hysteresisOffset)
    92                 bat->moveFrontBack(1);
    93             else if (mypos.z < desiredZValue - hysteresisOffset)
    94                 bat->moveFrontBack(-1);
    95         }
     108            if (this->ballDirection_.x != 1)
     109            {
     110                this->ballDirection_.x = 1;
     111                this->ballDirection_.y = sgn(ballvel.z);
     112                this->ballEndPosition_ = 0;
     113                this->randomOffset_ = 0;
     114
     115                this->calculateRandomOffset();
     116                this->calculateBallEndPosition();
     117                //this->randomOffsetTimer_.setInterval(MAX_REACTION_TIME * (1 - this->strength_));
     118                //this->ballEndPositionTimer_.setInterval(MAX_REACTION_TIME * (1 - this->strength_));
     119                //this->randomOffsetTimer_.startTimer();
     120                //this->ballEndPositionTimer_.startTimer();
     121            }
     122
     123            if (this->ballDirection_.y != sgn(ballvel.z))
     124            {
     125                this->ballDirection_.y = sgn(ballvel.z);
     126
     127                this->calculateBallEndPosition();
     128                //this->ballEndPositionTimer_.startTimer();
     129            }
     130
     131            float desiredZValue = /*((1 - this->strength_) * ballpos.z) + */(/*this->strength_ * */this->ballEndPosition_) + this->randomOffset_;
     132
     133            if (mypos.z > desiredZValue + hysteresisOffset * (this->randomOffset_ < 0))
     134                move = 1;
     135            else if (mypos.z < desiredZValue - hysteresisOffset * (this->randomOffset_ > 0))
     136                move = -1;
     137        }
     138
     139        this->move(move);
     140        this->getControllableEntity()->moveFrontBack(this->movement_);
    96141    }
    97142
     
    108153
    109154        // The position shouln't be larger than 0.5 (50% of the bat-length from the middle is the end)
    110         position *= 0.45;
     155        position *= 0.48;
    111156
    112157        // Both sides are equally probable
     
    116161        this->randomOffset_ = position * this->ball_->getBatLength() * this->ball_->getFieldDimension().y;
    117162    }
     163
     164    void PongAI::calculateBallEndPosition()
     165    {
     166        Vector3 position = this->ball_->getPosition();
     167        Vector3 velocity = this->ball_->getVelocity();
     168        Vector2 dimension = this->ball_->getFieldDimension();
     169
     170        // calculate end-height: current height + slope * distance
     171        this->ballEndPosition_ = position.z + velocity.z / velocity.x * (-position.x + dimension.x / 2 * sgn(velocity.x));
     172
     173        // Calculate bounces
     174        for (float limit = 0.35; limit < this->strength_ || this->strength_ > 0.99; limit += 0.4)
     175        {
     176            if (this->ballEndPosition_ > dimension.y / 2)
     177            {
     178                this->ballEndPosition_ = dimension.y - this->ballEndPosition_ + (rnd(-1, 1) * dimension.y * (1 - this->strength_));
     179                continue;
     180            }
     181            if (this->ballEndPosition_ < -dimension.y / 2)
     182            {
     183                this->ballEndPosition_ = -dimension.y - this->ballEndPosition_ + (rnd(-1, 1) * dimension.y * (1 - this->strength_));
     184                continue;
     185            }
     186            break;
     187        }
     188    }
     189
     190    void PongAI::move(char direction)
     191    {
     192        // The current direction is either what we're doing right now (movement_) or what is last in the queue
     193        char currentDirection = this->movement_;
     194        if (this->reactionTimers_.size() > 0)
     195            currentDirection = this->reactionTimers_.back().second;
     196
     197        // Only add changes of direction
     198        if (direction == currentDirection)
     199            return;
     200
     201        // Calculate delay, but only to change direction or start moving (stop works without delay)
     202        if (direction != 0)
     203        {
     204            float delay = MAX_REACTION_TIME * (1 - this->strength_);
     205
     206            // Add a new Timer
     207            Timer<PongAI>* timer = new Timer<PongAI>(delay, false, this, createExecutor(createFunctor(&PongAI::delayedMove)));
     208            this->reactionTimers_.push_back(std::pair<Timer<PongAI>*, char>(timer, direction));
     209        }
     210        else
     211        {
     212            this->movement_ = 0;
     213        }
     214    }
     215
     216    void PongAI::delayedMove()
     217    {
     218        this->movement_ = this->reactionTimers_.front().second;
     219
     220        Timer<PongAI>* timer = this->reactionTimers_.front().first;
     221        delete timer;
     222
     223        this->reactionTimers_.pop_front();
     224    }
    118225}
  • code/trunk/src/orxonox/objects/controllers/PongAI.h

    r2857 r2860  
    3232#include "OrxonoxPrereqs.h"
    3333
     34#include <list>
     35
    3436#include "Controller.h"
    3537#include "objects/Tickable.h"
     38#include "util/Math.h"
    3639
    3740namespace orxonox
     
    4144        public:
    4245            PongAI(BaseObject* creator);
    43             virtual ~PongAI() {}
     46            virtual ~PongAI();
    4447
    4548            void setConfigValues();
     
    5255        protected:
    5356            void calculateRandomOffset();
     57            void calculateBallEndPosition();
     58            void move(char direction);
     59            void delayedMove();
    5460
    5561            PongBall* ball_;
     62            Vector2 ballDirection_;
     63            float ballEndPosition_;
    5664            float randomOffset_;
    5765            float relHysteresisOffset_;
    5866            float strength_;
     67
     68//            Timer<PongAI> randomOffsetTimer_;
     69//            Timer<PongAI> ballEndPositionTimer_;
     70            std::list<std::pair<Timer<PongAI>*, char> > reactionTimers_;
     71            char movement_;
    5972    };
    6073}
Note: See TracChangeset for help on using the changeset viewer.