Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6858 was 6850, checked in by solex, 15 years ago

master/slave interaction of bots now correct - getting closer to formation flight

  • Property svn:eol-style set to native
File size: 15.3 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
39namespace orxonox
40{
41    ArtificialController::ArtificialController(BaseObject* creator) : Controller(creator)
42    {
43        RegisterObject(ArtificialController);
44
45        this->target_ = 0;
46        this->myMaster_ = 0;
47        this->freedomCount_ = 0;
48        this->team_ = -1;
49        this->state_ = FREE;
50        this->bShooting_ = false;
51        this->bHasTargetPosition_ = false;
52        this->targetPosition_ = Vector3::ZERO;
53
54        this->target_.setCallback(createFunctor(&ArtificialController::targetDied, this));
55    }
56
57    ArtificialController::~ArtificialController()
58    {
59    }
60
61    void ArtificialController::XMLPort(Element& xmlelement, XMLPort::Mode mode)
62    {
63        SUPER(ArtificialController, XMLPort, xmlelement, mode);
64
65        XMLPortParam(ArtificialController, "team", setTeam, getTeam, xmlelement, mode).defaultValues(0);
66    }
67
68// gets called when Bot dies
69    void ArtificialController::changedControllableEntity()
70    {
71COUT(0) << "~changedControllableEntity 0" << std::endl;
72        if(!getControllableEntity()) 
73        {
74COUT(0) << "~changedControllableEntity 1" << std::endl;
75        if (this->state_ == SLAVE) unregisterSlave();
76COUT(0) << "~changedControllableEntity 2" << std::endl;
77         if (this->state_ == MASTER) setNewMasterWithinFormation();
78COUT(0) << "~changedControllableEntity 3" << std::endl;
79        this->slaves_.clear();
80COUT(0) << "~changedControllableEntity 4" << std::endl;
81        this->state_ = FREE;
82COUT(0) << "~changedControllableEntity 5" << std::endl;
83        }
84    }
85
86    void ArtificialController::moveToPosition(const Vector3& target)
87    {
88        if (!this->getControllableEntity())
89            return;
90
91        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target);
92        float distance = (target - this->getControllableEntity()->getPosition()).length();
93
94        if (this->target_ || distance > 10)
95        {
96            // Multiply with rotateFactor to make them a bit slower
97            float rotateFactor;
98            if(this->state_ == SLAVE) rotateFactor = 1.0f;
99            if(this->state_ == MASTER) rotateFactor = 0.4f;
100            else rotateFactor = 0.8f;
101
102            this->getControllableEntity()->rotateYaw(-1.0f * rotateFactor * sgn(coord.x) * coord.x*coord.x);
103            this->getControllableEntity()->rotatePitch(rotateFactor * sgn(coord.y) * coord.y*coord.y);
104
105
106
107        }
108
109        if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
110        {
111            if(this->state_ == SLAVE) this->getControllableEntity()->moveFrontBack(-0.8f);
112            else this->getControllableEntity()->moveFrontBack(-0.05f); // They don't brake with full power to give the player a chance
113        } else {
114            if(this->state_ == SLAVE) this->getControllableEntity()->moveFrontBack(2.5f);
115            if(this->state_ == MASTER) this->getControllableEntity()->moveFrontBack(0.4f);
116            else this->getControllableEntity()->moveFrontBack(0.8f);
117        }
118    }
119
120    void ArtificialController::moveToTargetPosition()
121    {
122        this->moveToPosition(this->targetPosition_);
123    }
124
125    int ArtificialController::getState()
126    {
127        return this->state_;
128    }
129
130    void ArtificialController::unregisterSlave() {
131        if(myMaster_)
132        {
133            myMaster_->slaves_.remove(this);
134COUT(0) << "~unregister slave" << std::endl;
135        }
136    }
137
138    void ArtificialController::searchNewMaster()
139    {
140
141        if (!this->getControllableEntity())
142            return;
143
144        this->targetPosition_ = this->getControllableEntity()->getPosition();
145        this->forgetTarget();
146
147        //go through all pawns
148        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
149        {
150
151            //same team?
152            if (!ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
153                continue;
154
155            //has it an ArtificialController and is it a master?
156            if (!it->getController())
157                continue;
158
159            ArtificialController *newMaster = static_cast<ArtificialController*>(it->getController());
160
161            if (!newMaster || newMaster->getState() != MASTER)
162                continue;
163
164            //is pawn oneself? && is pawn in range?
165            if (static_cast<ControllableEntity*>(*it) != this->getControllableEntity()) //&& it->getPosition().squaredDistance(this->getControllableEntity()->getPosition()) < 1000
166            {
167                if(newMaster->slaves_.size() > 6) continue;
168
169                //this->freeSlaves();
170
171                for(std::list<ArtificialController*>::iterator itSlave = this->slaves_.begin(); itSlave != this->slaves_.end(); itSlave++)
172                {
173                    (*itSlave)->myMaster_ = newMaster;
174                    newMaster->slaves_.push_back(*itSlave);
175                }
176                this->slaves_.clear();
177                this->state_ = SLAVE;
178
179                this->myMaster_ = newMaster;
180                newMaster->slaves_.push_back(this);
181
182                break;
183            }
184        }//for
185
186        //hasn't encountered any masters in range? -> become a master
187        if (state_!=SLAVE) state_ = MASTER; // keep in mind: what happens when two masters encounter eache other? -> has to be evaluated in the for loop within master mode in AIcontroller...
188COUT(0) << "~searcheNewMaster" << std::endl;
189    }
190
191    void ArtificialController::commandSlaves() {
192
193        for(std::list<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
194        {
195            (*it)->setTargetPosition(this->getControllableEntity()->getPosition());
196        }
197    }
198
199    // binds slaves to new Master within formation
200    void ArtificialController::setNewMasterWithinFormation()
201    {
202COUT(0) << "~setNewMasterWithinFormation 1" << std::endl;
203        if (this->slaves_.empty())
204            return;
205COUT(0) << "~setNewMasterWithinFormation 1b" << std::endl;
206
207        ArtificialController *newMaster = this->slaves_.back();
208COUT(0) << "~setNewMasterWithinFormation 2" << std::endl;
209        this->slaves_.pop_back();
210COUT(0) << "~setNewMasterWithinFormation 3" << std::endl;
211        if(!newMaster) return;
212COUT(0) << "~setNewMasterWithinFormation 4" << std::endl;
213        newMaster->state_ = MASTER;
214        newMaster->slaves_ = this->slaves_;
215        this->slaves_.clear();
216
217        this->state_ = SLAVE;
218        this->myMaster_ = newMaster;
219
220COUT(0) << "~setNewMasterWithinFormation 5" << std::endl;
221        for(std::list<ArtificialController*>::iterator it = newMaster->slaves_.begin(); it != newMaster->slaves_.end(); it++)
222        {
223COUT(0) << "~setNewMasterWithinFormation 6" << std::endl;
224            (*it)->myMaster_ = newMaster;
225        }
226COUT(0) << "~setNewMasterWithinFormation 7" << std::endl;
227
228    }
229
230    void ArtificialController::freeSlaves()
231    {
232        for(std::list<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
233        {
234            (*it)->state_ = FREE;
235        }
236        this->slaves_.clear();
237    }
238
239    void ArtificialController::forceFreeSlaves()
240    {
241        for(std::list<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
242        {
243            (*it)->state_ = FREE;
244            (*it)->forceFreedom();
245            (*it)->targetPosition_ = this->targetPosition_;
246            (*it)->bShooting_ = true;
247            (*it)->getControllableEntity()->fire(0);
248        }
249    }
250
251    void ArtificialController::loseMasterState()
252    {
253        this->freeSlaves();
254        this->state_ = FREE;
255    }
256
257    void ArtificialController::forceFreedom()
258    {
259        this->freedomCount_ = 5;
260    }
261
262    bool ArtificialController::forcedFree()
263    {
264        if(this->freedomCount_ > 0) 
265        {
266            this->freedomCount_--;
267            return true;
268        } else return false;
269    }
270
271    void ArtificialController::setTargetPosition(const Vector3& target)
272    {
273        this->targetPosition_ = target;
274        this->bHasTargetPosition_ = true;
275    }
276
277    void ArtificialController::searchRandomTargetPosition()
278    {
279        this->targetPosition_ = Vector3(rnd(-2000,2000), rnd(-2000,2000), rnd(-2000,2000));
280        this->bHasTargetPosition_ = true;
281    }
282
283    void ArtificialController::setTarget(Pawn* target)
284    {
285        this->target_ = target;
286
287        if (target)
288            this->targetPosition_ = target->getPosition();
289    }
290
291    void ArtificialController::searchNewTarget()
292    {
293        if (!this->getControllableEntity())
294            return;
295
296        this->targetPosition_ = this->getControllableEntity()->getPosition();
297        this->forgetTarget();
298
299        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
300        {
301            if (ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
302                continue;
303
304            if (static_cast<ControllableEntity*>(*it) != this->getControllableEntity())
305            {
306                float speed = this->getControllableEntity()->getVelocity().length();
307                Vector3 distanceCurrent = this->targetPosition_ - this->getControllableEntity()->getPosition();
308                Vector3 distanceNew = it->getPosition() - this->getControllableEntity()->getPosition();
309                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))
310                        < 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))
311                {
312                    this->target_ = (*it);
313                    this->targetPosition_ = it->getPosition();
314                }
315            }
316        }
317    }
318
319    void ArtificialController::forgetTarget()
320    {
321        this->target_ = 0;
322        this->bShooting_ = false;
323    }
324
325    void ArtificialController::aimAtTarget()
326    {
327        if (!this->target_ || !this->getControllableEntity())
328            return;
329
330        static const float hardcoded_projectile_speed = 1250;
331
332        this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getPosition(), hardcoded_projectile_speed, this->target_->getPosition(), this->target_->getVelocity());
333        this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO);
334
335        Pawn* pawn = dynamic_cast<Pawn*>(this->getControllableEntity());
336        if (pawn)
337            pawn->setAimPosition(this->targetPosition_);
338    }
339
340    bool ArtificialController::isCloseAtTarget(float distance) const
341    {
342        if (!this->getControllableEntity())
343            return false;
344
345        if (!this->target_)
346            return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) < distance*distance);
347        else
348            return (this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance);
349    }
350
351    bool ArtificialController::isLookingAtTarget(float angle) const
352    {
353        if (!this->getControllableEntity())
354            return false;
355
356        return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle);
357    }
358
359    void ArtificialController::abandonTarget(Pawn* target)
360    {
361        if (target == this->target_)
362            this->targetDied();
363    }
364
365    void ArtificialController::targetDied()
366    {
367        this->forgetTarget();
368        this->searchRandomTargetPosition();
369    }
370
371    bool ArtificialController::sameTeam(ControllableEntity* entity1, ControllableEntity* entity2, Gametype* gametype)
372    {
373        if (entity1 == entity2)
374            return true;
375
376        int team1 = -1;
377        int team2 = -1;
378
379        Controller* controller = 0;
380        if (entity1->getController())
381            controller = entity1->getController();
382        else
383            controller = entity1->getXMLController();
384        if (controller)
385        {
386            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
387            if (ac)
388                team1 = ac->getTeam();
389        }
390
391        if (entity1->getController())
392            controller = entity1->getController();
393        else
394            controller = entity1->getXMLController();
395        if (controller)
396        {
397            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
398            if (ac)
399                team2 = ac->getTeam();
400        }
401
402        TeamDeathmatch* tdm = orxonox_cast<TeamDeathmatch*>(gametype);
403        if (tdm)
404        {
405            if (entity1->getPlayer())
406                team1 = tdm->getTeam(entity1->getPlayer());
407
408            if (entity2->getPlayer())
409                team2 = tdm->getTeam(entity2->getPlayer());
410        }
411
412        TeamBaseMatchBase* base = 0;
413        base = orxonox_cast<TeamBaseMatchBase*>(entity1);
414        if (base)
415        {
416            switch (base->getState())
417            {
418                case BaseState::ControlTeam1:
419                    team1 = 0;
420                    break;
421                case BaseState::ControlTeam2:
422                    team1 = 1;
423                    break;
424                case BaseState::Uncontrolled:
425                default:
426                    team1 = -1;
427            }
428        }
429        base = orxonox_cast<TeamBaseMatchBase*>(entity2);
430        if (base)
431        {
432            switch (base->getState())
433            {
434                case BaseState::ControlTeam1:
435                    team2 = 0;
436                    break;
437                case BaseState::ControlTeam2:
438                    team2 = 1;
439                    break;
440                case BaseState::Uncontrolled:
441                default:
442                    team2 = -1;
443            }
444        }
445
446        return (team1 == team2 && team1 != -1);
447    }
448}
Note: See TracBrowser for help on using the repository browser.