Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/AI_HS15/src/orxonox/controllers/CommonController.cc @ 10796

Last change on this file since 10796 was 10796, checked in by gania, 8 years ago

Sometimes there are too many rotations

File size: 23.7 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 *      Dominik Solenicki
26 *
27 */
28#include "controllers/CommonController.h"
29#include "core/XMLPort.h"
30
31#include "weaponsystem/WeaponMode.h"
32#include "weaponsystem/WeaponPack.h"
33#include "weaponsystem/Weapon.h"
34#include "weaponsystem/WeaponSlot.h"
35#include "weaponsystem/WeaponSlot.h"
36#include "worldentities/pawns/SpaceShip.h"
37
38#include "Scene.h"
39#include <OgreRay.h>
40#include <OgreSceneQuery.h>
41#include <OgreCamera.h>
42#include <OgreSceneManager.h>
43namespace orxonox
44{
45
46    RegisterClass(CommonController);
47    float SPEED = 0.7f/0.02f;
48    float ROTATEFACTOR = 0.3f/0.02f;
49
50    CommonController::CommonController(Context* context) : Controller(context)
51    {
52        this->bSetupWorked = false;
53
54        this->executingManeuver_ = false;
55        this->executingMoveToPoint_ = false;
56
57        this->maneuverType_ = ManeuverType::NONE;
58        RegisterObject(CommonController);
59    }
60
61
62    CommonController::~CommonController()
63    {
64    }
65
66    void CommonController::XMLPort(Element& xmlelement, XMLPort::Mode mode)
67    {
68        SUPER(CommonController, XMLPort, xmlelement, mode);
69        XMLPortParam(CommonController, "formationMode", setFormationModeXML, getFormationModeXML,  xmlelement, mode);
70
71    }
72    void CommonController::setFormationModeXML(std::string val)
73    {
74        const std::string valUpper = getUppercase(val);
75        FormationMode::Value value;
76        if (valUpper == "VEE")
77            value = FormationMode::VEE;
78        else if (valUpper == "WALL")
79            value = FormationMode::WALL;
80        else if (valUpper == "FINGER4")
81            value = FormationMode::FINGER4;
82        else if (valUpper == "DIAMOND")
83            value = FormationMode::DIAMOND;
84        else
85            ThrowException(ParseError, std::string("Attempting to set an unknown FormationMode: '") + val + "'.");
86        this->setFormationMode(value);
87       
88    }
89    std::string CommonController::getFormationModeXML()
90    {
91        switch (this->formationMode_)
92        {
93            case FormationMode::VEE:
94            {
95                return "VEE";
96                break;
97            }
98            case FormationMode::WALL:
99            {
100                return "WALL";
101                break;
102            }
103            case FormationMode::FINGER4:
104            {
105                return "FINGER4";
106                break;
107            }
108            case FormationMode::DIAMOND:
109            {
110                return "DIAMOND";
111                break;
112            }
113            default:
114                return "DIAMOND";
115                break;
116
117        }
118    }
119    void CommonController::chooseManeuverType()
120    {
121
122        if (this->target_ && this->bHasPositionOfTarget_ && this->getControllableEntity())
123        {
124            Vector3 diffVector = this->positionOfTarget_ - this->getControllableEntity()->getWorldPosition();
125            Vector3 myForwardVector = this->getControllableEntity()->getOrientation() * WorldEntity::FRONT;
126            float myDotProduct = diffVector.dotProduct(myForwardVector);
127
128            Vector3 opponentForwardVector = this->target_->getOrientation() * WorldEntity::FRONT;
129            float opponentDotProduct = diffVector.dotProduct(opponentForwardVector);           
130
131
132            switch ((myDotProduct > 0) - (myDotProduct < 0))
133            {
134                case 1:
135                {
136                    switch ((opponentDotProduct > 0) - (opponentDotProduct < 0))
137                    {
138                        case 1:
139                        {
140                            this->maneuverType_ = ManeuverType::OFFENSIVE;
141                            break;
142                        }
143                        case 0:
144                        {
145                            this->maneuverType_ = ManeuverType::OFFENSIVE;
146                            break;
147                        }
148                        case -1:
149                        {
150                            this->maneuverType_ = ManeuverType::NEUTRAL;
151                            break;
152                        }
153                    }
154                    break;
155                }
156                case 0:
157                {
158                    switch ((opponentDotProduct > 0) - (opponentDotProduct < 0))
159                    {
160                        case 1:
161                        {
162                            this->maneuverType_ = ManeuverType::OFFENSIVE;
163                            break;
164                        }
165                        case 0:
166                        {
167                            this->maneuverType_ = ManeuverType::NEUTRAL;
168                            break;
169                        }
170                        case -1:
171                        {
172                            this->maneuverType_ = ManeuverType::DEFENCIVE;
173                            break;
174                        }
175                    }
176
177                    break;
178                }
179                case -1:
180                {
181                    switch ((opponentDotProduct > 0) - (opponentDotProduct < 0))
182                    {
183                        case 1:
184                        {
185                            this->maneuverType_ = ManeuverType::NEUTRAL;
186                            break;
187                        }
188                        case 0:
189                        {
190                            this->maneuverType_ = ManeuverType::DEFENCIVE;
191                            break;
192                        }
193                        case -1:
194                        {
195                            this->maneuverType_ = ManeuverType::DEFENCIVE;
196                            break;
197                        }
198                    }
199                    break;
200                }
201            }
202        }
203        if (this->getControllableEntity() && !this->target_)
204        {
205            this->maneuverType_ = ManeuverType::NONE;
206        }
207        orxout (internal_error) << "ManeuverType = " << this->maneuverType_ << endl;
208    }
209    bool CommonController::setWingman (CommonController* wingman)
210    {
211        return false;
212    }
213   
214    bool CommonController::hasWingman()
215    {
216        return true;
217    }
218    void CommonController::setTarget(ControllableEntity* target)
219    {
220        this->target_ = target;
221        orxout (internal_error) << " TARGET SET " << endl;
222       
223        if (this->target_ )
224        {
225            this->setPositionOfTarget(target_->getWorldPosition());
226
227        }
228    }
229    bool CommonController::hasTarget()
230    {
231        if (this->target_)
232            return true;
233        return false;
234    }
235    void CommonController::setPositionOfTarget(const Vector3& target)
236    {
237        this->positionOfTarget_ = target;
238        this->bHasPositionOfTarget_ = true;
239    }
240    void CommonController::setOrientationOfTarget(const Quaternion& orient)
241    {
242        this->orientationOfTarget_=orient;
243        this->bHasOrientationOfTarget_=true;
244    }
245
246    void CommonController::setTargetPosition(const Vector3& target)
247    {
248        this->targetPosition_ = target;
249        this->bHasTargetPosition_ = true;
250    }
251
252    void CommonController::setTargetOrientation(const Quaternion& orient)
253    {
254        this->targetOrientation_=orient;
255        this->bHasTargetOrientation_=true;
256    }
257
258    void CommonController::setTargetOrientation(ControllableEntity* target)
259    {
260        if (target)
261            setTargetOrientation(target->getOrientation());
262    }
263
264    /*void CommonController::spin()
265    {
266        this->moveToTargetPosition();
267        this->getControllableEntity()->rotateRoll(8.0f);
268    }
269    void CommonController::turn180()
270    {
271        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->targetPosition_);
272
273        this->getControllableEntity()->rotateYaw(-2.0f * sgn(coord.x) * coord.x*coord.x);
274        this->getControllableEntity()->rotatePitch(2.0f * sgn(coord.y) * coord.y*coord.y);
275
276        this->getControllableEntity()->moveFrontBack(SPEED);
277    }*/
278
279
280
281    //copy the Roll orientation of given Quaternion.
282    void CommonController::copyOrientation(const Quaternion& orient, float dt)
283    {
284        //roll angle difference in radian
285        float diff=orient.getRoll(false).valueRadians()-(this->getControllableEntity()->getOrientation().getRoll(false).valueRadians());
286        while(diff>math::twoPi) diff-=math::twoPi;
287        while(diff<-math::twoPi) diff+=math::twoPi;
288        this->getControllableEntity()->rotateRoll(diff*ROTATEFACTOR * dt);
289    }
290    void CommonController::copyTargetOrientation(float dt)
291    {
292        if (bHasTargetOrientation_)
293        {   
294            copyOrientation(targetOrientation_, dt);
295        }
296    }
297
298
299
300
301    void CommonController::moveToTargetPosition(float dt)
302    {
303        this->moveToPosition(this->targetPosition_, dt);
304    }
305    void CommonController::moveToPosition(const Vector3& target, float dt)
306    {
307        float factor = 1;
308        if (!this->getControllableEntity())
309            return;
310        if (this->rank_ == Rank::DIVISIONLEADER)
311            factor = 0.8;
312        if (this->rank_ == Rank::SECTIONLEADER)
313            factor = 0.9;
314       
315        //100 is (so far) the smallest tolerance (empirically found) that can be reached,
316        //with smaller distance spaceships can't reach position and go circles around it instead
317        int tolerance = 60;
318
319        ControllableEntity* entity = this->getControllableEntity();
320        Vector2 coord = get2DViewCoordinates
321            (entity->getPosition(), 
322            entity->getOrientation() * WorldEntity::FRONT, 
323            entity->getOrientation() * WorldEntity::UP, 
324            target);
325
326        float distance = (target - this->getControllableEntity()->getPosition()).length();
327
328        //rotates should be in range [-1,+1], clamp cuts off all that is not
329        float rotateX = clamp(coord.x * 10, -1.0f, 1.0f);
330        float rotateY = clamp(coord.y * 10, -1.0f, 1.0f);
331
332       
333        if (distance > tolerance)
334        {
335            //Yaw and Pitch are enough to start facing the target
336            this->getControllableEntity()->rotateYaw(-2.0f * ROTATEFACTOR * rotateX * dt);
337            this->getControllableEntity()->rotatePitch(2.0f * ROTATEFACTOR * rotateY * dt);
338
339            //300 works, maybe less is better
340            if (distance < 400)
341            {
342                //Change roll when close. When Spaceship faces target, roll doesn't affect it's trajectory
343                //It's important that roll is not changed in the process of changing yaw and pitch
344                //Wingmen won't face same direction as Leaders, but when Leaders start moving
345                //Yaw and Pitch will adapt.
346                if (bHasTargetOrientation_)
347                {
348                    copyTargetOrientation(dt);
349                }
350            }
351
352            this->getControllableEntity()->moveFrontBack(1.2f*SPEED*factor * dt);
353        }
354        else
355        {     
356            bHasTargetPosition_ = false;
357            bHasTargetOrientation_ = false;
358        }
359    }
360    float CommonController::randomInRange(float a, float b)
361    {
362        float random = rnd(1.0f);
363        float diff = b - a;
364        float r = random * diff;
365        return a + r;
366    }
367    void CommonController::attack()
368    {
369        if ( !this->getControllableEntity() )
370            return;
371        if ( this->target_ )
372        {
373            this->positionOfTarget_ = getPredictedPosition( 
374                this->getControllableEntity()->getWorldPosition(), 
375                hardcoded_projectile_speed, 
376                this->target_->getWorldPosition(), 
377                this->target_->getVelocity() 
378                );
379            Vector3 diffVector = this->positionOfTarget_ - this->getControllableEntity()->getWorldPosition();
380            float diffLength = diffVector.length();
381            if (diffLength < 100)
382            {
383                Vector3* targetPosition;
384                targetPosition = new Vector3 ( 
385                    //randomInRange(200, 300),
386                    0,
387                    //randomInRange(-300, -200),
388                    0,
389                    randomInRange(-300, -400) 
390                    );
391                Quaternion rotationToTarget = (this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).getRotationTo(diffVector);
392                Vector3 target = rotationToTarget * (*targetPosition);
393                moveToPoint( 
394                    target, 
395                    randomInRange(45, 180) 
396                    );
397                executingMoveToPoint_ = true; 
398                return;
399            }
400            this->bShooting_ = true;
401            this->positionOfTarget_ = getPredictedPosition( 
402                this->getControllableEntity()->getWorldPosition(), 
403                hardcoded_projectile_speed, 
404                this->target_->getWorldPosition(), 
405                this->target_->getVelocity() 
406                );
407            this->targetPosition_ = positionOfTarget_;
408
409        }   
410        else
411        {
412            this->chooseManeuverType();
413        }
414    }
415    void CommonController::scissors()
416    {
417        if ( !this->getControllableEntity() )
418            return;
419        if ( this->target_ )
420        {
421            this->positionOfTarget_ = getPredictedPosition( 
422                this->getControllableEntity()->getWorldPosition(), 
423                hardcoded_projectile_speed, 
424                this->target_->getWorldPosition(), 
425                this->target_->getVelocity() 
426                );
427            Vector3 diffVector = this->positionOfTarget_ - this->getControllableEntity()->getWorldPosition();
428            float diffLength = diffVector.length();
429            Vector3 opponentForwardVector = this->target_->getOrientation() * WorldEntity::FRONT;
430            float opponentDotProduct = diffVector.dotProduct(opponentForwardVector);           
431           
432            int f = (int) rnd(100.0f);
433            f = (f % 2 == 0 ? 1 : -1);
434
435            if(!this->executingMoveToPoint_)
436            {
437                Vector3* targetPosition;
438                if ( diffLength < 100 )
439                {
440                    targetPosition = new Vector3 ( 
441                        //f * randomInRange(200, 300),
442                        0,
443                        //f * randomInRange(-300, -200),
444                        0,
445                        //randomInRange(-300, -400)
446                        0
447                        );
448                }
449                else
450                {
451                    if ( opponentDotProduct < 0 )
452                    {
453                        targetPosition = new Vector3 ( 
454                        //f * randomInRange(200, 300),
455                        0,
456                        //f * randomInRange(-300, -200),
457                        0,
458                        //randomInRange(-300, -400)
459                        -300
460                        );
461                    }
462                    else
463                    {
464                        targetPosition = new Vector3 ( 
465                        //f * randomInRange(200, 300),
466                        0,
467                        //f * randomInRange(-300, -200),
468                        0,
469                        //randomInRange(-300, -400)
470                        300
471                        );
472                    }
473                }
474                Quaternion rotationToTarget = (this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).getRotationTo(diffVector);
475                Vector3 target = rotationToTarget * (*targetPosition);
476                moveToPoint( 
477                    target, 
478                    randomInRange(45, 180) 
479                    );
480                executingMoveToPoint_ = true; 
481            }
482        }
483       
484        else
485        {
486            this->chooseManeuverType();
487        }
488    }
489    void CommonController::gunsD()
490    {
491        if ( !this->getControllableEntity() )
492            return;
493        if ( this->target_ )
494        {
495            this->positionOfTarget_ = getPredictedPosition( 
496                this->getControllableEntity()->getWorldPosition(), 
497                hardcoded_projectile_speed, 
498                this->target_->getWorldPosition(), 
499                this->target_->getVelocity() 
500                );
501            Vector3 diffVector = this->positionOfTarget_ - this->getControllableEntity()->getWorldPosition();
502            float diffLength = diffVector.length();
503            if(!this->executingMoveToPoint_)
504            {
505                Vector3* targetPosition;
506                if ( diffLength < 200 )
507                {
508                    targetPosition = new Vector3 ( 
509                        //f * randomInRange(200, 300),
510                        0,
511                        //f * randomInRange(-300, -200),
512                        0,
513                        //randomInRange(-300, -400)
514                        0
515                        );
516                }
517                else if ( diffLength < 500 )
518                {
519                    targetPosition = new Vector3 ( 
520                        //randomInRange(100, 200),
521                        0,
522                        //randomInRange(-200, -100),
523                        0,
524                        //randomInRange(-400, -600)
525                        500
526                        );
527                }
528                else
529                {
530                    targetPosition = new Vector3 ( 
531                        //randomInRange(200, 300),
532                        0,
533                        //randomInRange(-300, -200),
534                        0,
535                        //randomInRange(-400, -600)
536                        500
537                        );
538                }
539                Quaternion rotationToTarget = (this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).getRotationTo(diffVector);
540                Vector3 target = rotationToTarget * (*targetPosition);
541                moveToPoint( 
542                    target, 
543                    randomInRange(45, 180) 
544                    );
545                executingMoveToPoint_ = true; 
546            }
547        }
548        else
549        {
550            this->chooseManeuverType();
551        }
552    }
553    //to be called in action
554    //PRE: relativeTargetPosition is desired position relative to the spaceship,
555    //angleRoll is the angle in degrees of Roll that should be applied by the end of the movement
556    //POST: target orientation and position are set, so that it can be used by MoveAndRoll()
557    void CommonController::moveToPoint(const Vector3& relativeTargetPosition, float angleRoll)
558    {
559        ControllableEntity* entity = this->getControllableEntity();
560        if (!entity)
561            return;
562        Quaternion orient = entity->getWorldOrientation();
563        Quaternion rotation = Quaternion(Degree(angleRoll), Vector3::UNIT_Z);
564
565        Vector3 target = orient * relativeTargetPosition + entity->getWorldPosition();
566        setTargetPosition(target);
567        orient = orient * rotation;
568        this->setTargetOrientation(orient);
569       
570    }
571    //to be called in tick
572    //PRE: MoveToPoint was called
573    //POST: spaceship changes its yaw and pitch to point towards targetPosition_,
574    //moves towards targetPosition_ by amount depending on dt and its speed,
575    //rolls by amount depending on the difference between angleRoll_ and angleRolled_, dt, and
576    //angular speed
577    //if position reached with a certain tolerance, and angleRolled_ = angleRoll_, returns false,
578    //otherwise returns true
579    //dt is normally around 0.02f, which makes it 1/0.02 = 50 frames/sec
580    bool CommonController::moveAndRoll(float dt)
581    {
582        float factor = 1;
583        if (!this->getControllableEntity())
584            return false;
585        if (this->rank_ == Rank::DIVISIONLEADER)
586            factor = 0.8;
587        if (this->rank_ == Rank::SECTIONLEADER)
588            factor = 0.9;
589        int tolerance = 60;
590       
591        ControllableEntity* entity = this->getControllableEntity();
592        if (!entity)
593            return true;
594        Vector2 coord = get2DViewCoordinates
595            (entity->getPosition(), 
596            entity->getOrientation() * WorldEntity::FRONT, 
597            entity->getOrientation() * WorldEntity::UP, 
598            targetPosition_);
599
600        float distance = (targetPosition_ - this->getControllableEntity()->getPosition()).length();
601
602        //rotates should be in range [-1,+1], clamp cuts off all that is not
603        float rotateX = clamp(coord.x * 10, -1.0f, 1.0f);
604        float rotateY = clamp(coord.y * 10, -1.0f, 1.0f);
605
606       
607        if (distance > tolerance)
608        {
609            //Yaw and Pitch are enough to start facing the target
610            this->getControllableEntity()->rotateYaw(-2.0f * ROTATEFACTOR * rotateX * dt);
611            this->getControllableEntity()->rotatePitch(2.0f * ROTATEFACTOR * rotateY * dt);
612           
613            //Roll
614            if (bHasTargetOrientation_)
615            {
616                copyTargetOrientation(dt);
617            }
618         
619            //Move
620            this->getControllableEntity()->moveFrontBack(1.2f * SPEED * factor * dt);
621            //if still moving, return false
622            return false;
623        }
624        else
625        {     
626           
627            //if finished, return true;
628            return true;
629        }
630    }
631
632    float CommonController::squaredDistanceToTarget() const
633    {
634        if ( !this->getControllableEntity() )
635            return 0;
636        if ( !this->target_ )
637            return ( this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) );
638        else
639            return ( this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) );
640    }
641   
642    bool CommonController::isLookingAtTarget(float angle) const
643    {
644        if (!this->getControllableEntity())
645            return false;
646
647        return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle);
648    }
649
650    bool CommonController::canFire()
651    {
652        float squaredDistance = squaredDistanceToTarget();
653        if ( this->bShooting_ && squaredDistance < 9000000 && squaredDistance > 10000 && this->isLookingAtTarget(math::pi /(0.0002f*squaredDistance)) )
654        {
655            return true;
656        }
657        else
658        {
659            return false;
660        }
661
662    }
663    void CommonController::doFire()
664    {
665        if (!this->target_ || !this->getControllableEntity())
666            return;
667        static const float hardcoded_projectile_speed = 750;
668
669        this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getWorldPosition(), hardcoded_projectile_speed, this->target_->getWorldPosition(), this->target_->getVelocity());
670        this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO);
671
672        Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
673
674        if (pawn)
675            //pawn->setAimPosition(this->getControllableEntity()->getWorldPosition() + 4000*(this->getControllableEntity()->getOrientation() * WorldEntity::FRONT));
676            pawn->setAimPosition(this->targetPosition_);
677   
678        this->getControllableEntity()->fire(0);
679    }
680   
681
682}
Note: See TracBrowser for help on using the repository browser.