Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ai/src/orxonox/controllers/ArtificialController.cc @ 6888

Last change on this file since 6888 was 6888, checked in by solex, 14 years ago

formation flight: new formations

  • Property svn:eol-style set to native
File size: 17.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "ArtificialController.h"
30
31#include "core/CoreIncludes.h"
32#include "core/XMLPort.h"
33#include "worldentities/ControllableEntity.h"
34#include "worldentities/pawns/Pawn.h"
35#include "worldentities/pawns/TeamBaseMatchBase.h"
36#include "gametypes/TeamDeathmatch.h"
37#include "controllers/WaypointPatrolController.h"
38#include "util/Math.h"
39
40namespace orxonox
41{
42
43    static const unsigned int MAX_FORMATION_SIZE = 6;
44    static const int FREEDOM_COUNT = 4; //seconds the slaves in a formation will be set free when master attacks an enemy
45    static const float SPEED_MASTER = 0.6f;
46    static const float ROTATEFACTOR_MASTER = 0.2f;
47    static const float SPEED_FREE = 0.8f;
48    static const float ROTATEFACTOR_FREE = 0.8f;
49
50    ArtificialController::ArtificialController(BaseObject* creator) : Controller(creator)
51    {
52        RegisterObject(ArtificialController);
53
54        this->target_ = 0;
55        this->myMaster_ = 0;
56        this->freedomCount_ = 0;
57        this->team_ = -1;
58        this->state_ = FREE;
59        this->bShooting_ = false;
60        this->bHasTargetPosition_ = false;
61        this->targetPosition_ = Vector3::ZERO;
62
63        this->target_.setCallback(createFunctor(&ArtificialController::targetDied, this));
64    }
65
66    ArtificialController::~ArtificialController()
67    {
68    }
69
70    void ArtificialController::XMLPort(Element& xmlelement, XMLPort::Mode mode)
71    {
72        SUPER(ArtificialController, XMLPort, xmlelement, mode);
73
74        XMLPortParam(ArtificialController, "team", setTeam, getTeam, xmlelement, mode).defaultValues(0);
75    }
76
77// gets called when Bot dies
78    void ArtificialController::changedControllableEntity()
79    {
80        if(!getControllableEntity()) 
81        {
82        if (this->state_ == SLAVE) unregisterSlave();
83         if (this->state_ == MASTER) setNewMasterWithinFormation();
84        this->slaves_.clear();
85        this->state_ = FREE;
86
87        }
88    }
89
90    void ArtificialController::moveToPosition(const Vector3& target)
91    {
92        if (!this->getControllableEntity())
93            return;
94
95        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target);
96        float distance = (target - this->getControllableEntity()->getPosition()).length();
97
98
99        if(this->state_ == FREE)
100        {
101            if (this->target_ || distance > 10)
102            {
103                // Multiply with 0.8 to make them a bit slower
104                this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_FREE * sgn(coord.x) * coord.x*coord.x);
105                this->getControllableEntity()->rotatePitch(ROTATEFACTOR_FREE * sgn(coord.y) * coord.y*coord.y);
106            }
107
108            if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
109            {
110              this->getControllableEntity()->moveFrontBack(-0.05f); // They don't brake with full power to give the player a chance
111            } else this->getControllableEntity()->moveFrontBack(SPEED_FREE);
112        }
113
114
115
116        if(this->state_ == MASTER)
117        {
118            if (this->target_ || distance > 10)
119            {
120                this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_MASTER * sgn(coord.x) * coord.x*coord.x);
121                this->getControllableEntity()->rotatePitch(ROTATEFACTOR_MASTER * sgn(coord.y) * coord.y*coord.y);
122
123            }
124
125            if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
126            {
127                this->getControllableEntity()->moveFrontBack(-0.05f);
128            } else this->getControllableEntity()->moveFrontBack(SPEED_MASTER);
129        }
130
131
132
133        if(this->state_ == SLAVE)
134        {
135//             if (this->target_ || distance > 10)
136//             {
137                float rotateFactor;
138                if(this->state_ == SLAVE) rotateFactor = 1.0f;
139
140
141                this->getControllableEntity()->rotateYaw(-1.0f * rotateFactor * sgn(coord.x) * coord.x*coord.x);
142                this->getControllableEntity()->rotatePitch(rotateFactor * sgn(coord.y) * coord.y*coord.y);
143
144
145
146//             }
147
148            if (this->target_ && distance < 500 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
149            {
150                if (this->target_ && distance < 60)
151                {
152                    this->getControllableEntity()->setVelocity(0.8f*this->target_->getVelocity());
153                } else this->getControllableEntity()->moveFrontBack(-1.0f*exp(distance/100.0));
154
155            } else {
156                this->getControllableEntity()->moveFrontBack(1.0f + distance/500.0f);
157            }
158        }
159    }
160
161    void ArtificialController::moveToTargetPosition()
162    {
163        this->moveToPosition(this->targetPosition_);
164    }
165
166    int ArtificialController::getState()
167    {
168        return this->state_;
169    }
170
171    void ArtificialController::unregisterSlave() {
172        if(myMaster_)
173        {
174            std::vector<ArtificialController*>::iterator it = std::find(myMaster_->slaves_.begin(), myMaster_->slaves_.end(), this);
175            if( it != myMaster_->slaves_.end() )
176                myMaster_->slaves_.erase(it);
177//COUT(0) << "~unregister slave" << std::endl;
178        }
179    }
180
181    void ArtificialController::searchNewMaster()
182    {
183
184        if (!this->getControllableEntity())
185            return;
186
187        this->targetPosition_ = this->getControllableEntity()->getPosition();
188        this->forgetTarget();
189
190        //go through all pawns
191        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
192        {
193
194            //same team?
195            if (!ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
196                continue;
197
198            //has it an ArtificialController and is it a master?
199            if (!it->getController())
200                continue;
201
202            ArtificialController *newMaster = static_cast<ArtificialController*>(it->getController());
203
204            if (!newMaster || newMaster->getState() != MASTER)
205                continue;
206
207            float distance = (it->getPosition() - this->getControllableEntity()->getPosition()).length();
208
209            //is pawn oneself? && is pawn in range?
210            if (static_cast<ControllableEntity*>(*it) != this->getControllableEntity() && distance < 5000) 
211            {
212                if(newMaster->slaves_.size() > MAX_FORMATION_SIZE) continue;
213
214                for(std::vector<ArtificialController*>::iterator itSlave = this->slaves_.begin(); itSlave != this->slaves_.end(); itSlave++)
215                {
216                    (*itSlave)->myMaster_ = newMaster;
217                    newMaster->slaves_.push_back(*itSlave);
218                }
219                this->slaves_.clear();
220                this->state_ = SLAVE;
221
222                this->myMaster_ = newMaster;
223                newMaster->slaves_.push_back(this);
224
225                break;
226            }
227        }//for
228
229        //hasn't encountered any masters in range? -> become a master
230        if (state_!=SLAVE) state_ = MASTER;//master encounters master? ->done
231    }
232
233    void ArtificialController::commandSlaves() {
234
235        Quaternion orient = this->getControllableEntity()->getOrientation();
236        Vector3 dest = this->getControllableEntity()->getPosition();
237
238        // 1 slave: follow
239        if (this->slaves_.size() == 1)
240        {
241            dest += 4*orient*WorldEntity::BACK;
242            this->slaves_.front()->setTargetPosition(dest);
243        }
244
245        // 2 slaves: triangle
246         if (this->slaves_.size() == 2) 
247        {
248            dest += 10*orient*WorldEntity::BACK;
249            this->slaves_[0]->setTargetPosition(dest + 10*orient*WorldEntity::LEFT);
250            this->slaves_[1]->setTargetPosition(dest + 10*orient*WorldEntity::RIGHT);
251        }
252
253        if (this->slaves_.size() > MAX_FORMATION_SIZE)
254        {
255            for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
256            {
257                (*it)->setTargetPosition(this->getControllableEntity()->getPosition());
258            }
259        }
260    }
261
262    // binds slaves to new Master within formation
263    void ArtificialController::setNewMasterWithinFormation()
264    {
265
266        if (this->slaves_.empty())
267            return;
268
269        ArtificialController *newMaster = this->slaves_.back();
270        this->slaves_.pop_back();
271
272        if(!newMaster) return;
273        newMaster->state_ = MASTER;
274        newMaster->slaves_ = this->slaves_;
275
276        this->slaves_.clear();
277        this->state_ = SLAVE;
278        this->myMaster_ = newMaster;
279
280        for(std::vector<ArtificialController*>::iterator it = newMaster->slaves_.begin(); it != newMaster->slaves_.end(); it++)
281        {
282            (*it)->myMaster_ = newMaster;
283        }
284
285    }
286
287    void ArtificialController::freeSlaves()
288    {
289        for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
290        {
291            (*it)->state_ = FREE;
292        }
293        this->slaves_.clear();
294    }
295
296    void ArtificialController::forceFreeSlaves()
297    {
298        for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
299        {
300            (*it)->state_ = FREE;
301            (*it)->forceFreedom();
302            (*it)->targetPosition_ = this->targetPosition_;
303            (*it)->bShooting_ = true;
304            (*it)->getControllableEntity()->fire(0);// fire once for fun
305        }
306    }
307
308    void ArtificialController::loseMasterState()
309    {
310        this->freeSlaves();
311        this->state_ = FREE;
312    }
313
314    void ArtificialController::forceFreedom()
315    {
316        this->freedomCount_ = FREEDOM_COUNT;
317    }
318
319    bool ArtificialController::forcedFree()
320    {
321        if(this->freedomCount_ > 0) 
322        {
323            this->freedomCount_--;
324            return true;
325        } else return false;
326    }
327
328    void ArtificialController::setTargetPosition(const Vector3& target)
329    {
330        this->targetPosition_ = target;
331        this->bHasTargetPosition_ = true;
332    }
333
334    void ArtificialController::searchRandomTargetPosition()
335    {
336        this->targetPosition_ = Vector3(rnd(-2000,2000), rnd(-2000,2000), rnd(-2000,2000));
337        this->bHasTargetPosition_ = true;
338    }
339
340    void ArtificialController::setTarget(Pawn* target)
341    {
342        this->target_ = target;
343
344        if (target)
345            this->targetPosition_ = target->getPosition();
346    }
347
348    void ArtificialController::searchNewTarget()
349    {
350        if (!this->getControllableEntity())
351            return;
352
353        this->targetPosition_ = this->getControllableEntity()->getPosition();
354        this->forgetTarget();
355
356        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
357        {
358            if (ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
359                continue;
360
361            if (static_cast<ControllableEntity*>(*it) != this->getControllableEntity())
362            {
363                float speed = this->getControllableEntity()->getVelocity().length();
364                Vector3 distanceCurrent = this->targetPosition_ - this->getControllableEntity()->getPosition();
365                Vector3 distanceNew = it->getPosition() - this->getControllableEntity()->getPosition();
366                if (!this->target_ || it->getPosition().squaredDistance(this->getControllableEntity()->getPosition()) * (1.5f + acos((this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).dotProduct(distanceNew) / speed / distanceNew.length()) / (2 * Ogre::Math::PI))
367                        < this->targetPosition_.squaredDistance(this->getControllableEntity()->getPosition()) * (1.5f + acos((this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).dotProduct(distanceCurrent) / speed / distanceCurrent.length()) / (2 * Ogre::Math::PI)) + rnd(-250, 250))
368                {
369                    this->target_ = (*it);
370                    this->targetPosition_ = it->getPosition();
371                }
372            }
373        }
374    }
375
376    void ArtificialController::forgetTarget()
377    {
378        this->target_ = 0;
379        this->bShooting_ = false;
380    }
381
382    void ArtificialController::aimAtTarget()
383    {
384        if (!this->target_ || !this->getControllableEntity())
385            return;
386
387        static const float hardcoded_projectile_speed = 1250;
388
389        this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getPosition(), hardcoded_projectile_speed, this->target_->getPosition(), this->target_->getVelocity());
390        this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO);
391
392        Pawn* pawn = dynamic_cast<Pawn*>(this->getControllableEntity());
393        if (pawn)
394            pawn->setAimPosition(this->targetPosition_);
395    }
396
397    bool ArtificialController::isCloseAtTarget(float distance) const
398    {
399        if (!this->getControllableEntity())
400            return false;
401
402        if (!this->target_)
403            return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) < distance*distance);
404        else
405            return (this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance);
406    }
407
408    bool ArtificialController::isLookingAtTarget(float angle) const
409    {
410        if (!this->getControllableEntity())
411            return false;
412
413        return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle);
414    }
415
416    void ArtificialController::abandonTarget(Pawn* target)
417    {
418        if (target == this->target_)
419            this->targetDied();
420    }
421
422    void ArtificialController::targetDied()
423    {
424        this->forgetTarget();
425        this->searchRandomTargetPosition();
426    }
427
428    bool ArtificialController::sameTeam(ControllableEntity* entity1, ControllableEntity* entity2, Gametype* gametype)
429    {
430        if (entity1 == entity2)
431            return true;
432
433        int team1 = -1;
434        int team2 = -1;
435
436        Controller* controller = 0;
437        if (entity1->getController())
438            controller = entity1->getController();
439        else
440            controller = entity1->getXMLController();
441        if (controller)
442        {
443            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
444            if (ac)
445                team1 = ac->getTeam();
446        }
447
448        if (entity1->getController())
449            controller = entity1->getController();
450        else
451            controller = entity1->getXMLController();
452        if (controller)
453        {
454            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
455            if (ac)
456                team2 = ac->getTeam();
457        }
458
459        TeamDeathmatch* tdm = orxonox_cast<TeamDeathmatch*>(gametype);
460        if (tdm)
461        {
462            if (entity1->getPlayer())
463                team1 = tdm->getTeam(entity1->getPlayer());
464
465            if (entity2->getPlayer())
466                team2 = tdm->getTeam(entity2->getPlayer());
467        }
468
469        TeamBaseMatchBase* base = 0;
470        base = orxonox_cast<TeamBaseMatchBase*>(entity1);
471        if (base)
472        {
473            switch (base->getState())
474            {
475                case BaseState::ControlTeam1:
476                    team1 = 0;
477                    break;
478                case BaseState::ControlTeam2:
479                    team1 = 1;
480                    break;
481                case BaseState::Uncontrolled:
482                default:
483                    team1 = -1;
484            }
485        }
486        base = orxonox_cast<TeamBaseMatchBase*>(entity2);
487        if (base)
488        {
489            switch (base->getState())
490            {
491                case BaseState::ControlTeam1:
492                    team2 = 0;
493                    break;
494                case BaseState::ControlTeam2:
495                    team2 = 1;
496                    break;
497                case BaseState::Uncontrolled:
498                default:
499                    team2 = -1;
500            }
501        }
502
503        return (team1 == team2 && team1 != -1);
504    }
505}
Note: See TracBrowser for help on using the repository browser.