Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

some comments added

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