Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

minor bugfixes and code style improvement

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