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
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        this->bSetupWorked = false;
54
55       
56        this->executingMoveToPoint_ = false;
57        this->action_ = Action::FLY;
58        this->stopLookingAtTarget();
59       
60        RegisterObject( CommonController );
61    }
62
63
64    CommonController::~CommonController() 
65    {
66        //orxout(internal_error) << "I died, my Rank is " << rank_ << endl;
67    }
68
69    void CommonController::XMLPort( Element& xmlelement, XMLPort::Mode mode )
70    {
71        SUPER( CommonController, XMLPort, xmlelement, mode );
72        XMLPortParam( CommonController, "formationMode", setFormationModeXML, getFormationModeXML,  xmlelement, mode );
73
74    }
75    void CommonController::setFormationModeXML( std::string val )
76    {
77        const std::string valUpper = getUppercase( val );
78        FormationMode::Value value;
79       
80        if ( valUpper == "WALL" )
81            value = FormationMode::WALL;
82        else if ( valUpper == "FINGER4" )
83            value = FormationMode::FINGER4;
84        else if ( valUpper == "DIAMOND" )
85            value = FormationMode::DIAMOND;
86        else
87            ThrowException( ParseError, std::string( "Attempting to set an unknown FormationMode: '" )+ val + "'." );
88        this->setFormationMode( value );
89       
90    }
91    std::string CommonController::getFormationModeXML() 
92    {
93        switch ( this->formationMode_ )
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;
113
114        }
115    }
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    }
158    void CommonController::maneuver() 
159    {
160        counter++;
161
162        if (counter > 5)
163            counter = 0;
164        if ( this->target_ && this->getControllableEntity())
165        {
166            Vector3 thisPosition = this->getControllableEntity()->getWorldPosition();
167            //Quaternion thisOrientation = this->getControllableEntity()->getOrientation();
168
169            this->setPositionOfTarget( getPredictedPosition( 
170                thisPosition, 
171                hardcoded_projectile_speed, 
172                this->target_->getWorldPosition() , 
173                this->target_->getVelocity() 
174                )  );
175            this->setOrientationOfTarget( this->target_->getOrientation() );
176
177
178            Vector3 diffVector = this->positionOfTarget_ - thisPosition;
179            float diffLength = diffVector.length();
180            Vector3 diffUnit = diffVector/diffLength;
181
182
183
184            //bool bThisIsLookingAtTarget = this->isLooking ( getControllableEntity(), this->target_, math::pi/4 );
185            bool bTargetIsLookingAtThis = this->isLooking ( this->target_, getControllableEntity(), math::pi/5.0f );
186           
187
188
189            //too far? well, come closer then
190            if ( diffLength > 3000 )
191            {
192                if (diffLength < 6000)
193                {
194
195                }
196                else
197                {
198                }
199                this->setTargetPosition( this->positionOfTarget_ );
200            }
201            //too close? How do u expect to dodge anything? Just attack!
202            else if ( diffLength < 500 )
203            {   
204                //at this point, just look and shoot
205                if ( diffLength < 250 )
206                {
207                    this->stopMoving();
208                    this->startLookingAtTarget();
209                }
210                else
211                {
212                    this->setTargetPosition( this->positionOfTarget_ );
213                }
214            }
215            //Good distance? Check if target looks at us. It doesn't? Go hunt!
216            else if ( !bTargetIsLookingAtThis )
217            {
218                this->setTargetPosition( this->positionOfTarget_ );
219              /*  if (counter == 0)
220                {
221                    this->setTargetPosition( this->positionOfTarget_ );   
222                    return;
223                }
224                else
225                {
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)
234                {
235                    this->setTargetPosition( this->positionOfTarget_ );   
236                    return;
237                }
238                dodge( thisPosition, diffUnit );
239               
240            }
241        }
242       
243        //orxout ( internal_error ) << "ManeuverType = " << this->maneuverType_ << endl;
244    }
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   
328    bool CommonController::setWingman ( CommonController* wingman )
329    {
330        return false;
331    }
332   
333    bool CommonController::hasWingman() 
334    {
335        return true;
336    }
337    void CommonController::setTarget( ControllableEntity* target )
338    {
339        this->target_ = target;
340        //orxout ( internal_error ) << " TARGET SET " << endl;
341       
342        if ( this->target_ )
343        {
344            this->setPositionOfTarget( target_->getWorldPosition() );
345
346        }
347    }
348    bool CommonController::hasTarget() 
349    {
350        if ( this->target_ )
351            return true;
352        return false;
353    }
354    void CommonController::setPositionOfTarget( const Vector3& target )
355    {
356        this->positionOfTarget_ = target;
357        this->bHasPositionOfTarget_ = true;
358    }
359    void CommonController::setOrientationOfTarget( const Quaternion& orient )
360    {
361        this->orientationOfTarget_=orient;
362        this->bHasOrientationOfTarget_=true;
363    }
364
365    void CommonController::setTargetPosition( const Vector3& target )
366    {
367        this->targetPosition_ = target;
368        this->bHasTargetPosition_ = true;
369    }
370
371    void CommonController::setTargetOrientation( const Quaternion& orient )
372    {
373        this->targetOrientation_=orient;
374        this->bHasTargetOrientation_=true;
375    }
376
377    void CommonController::setTargetOrientation( ControllableEntity* target )
378    {
379        if ( target )
380            setTargetOrientation( target->getOrientation() );
381    }
382
383
384
385    //copy the Roll orientation of given Quaternion.
386    void CommonController::copyOrientation( const Quaternion& orient, float dt )
387    {
388        //roll angle difference in radian
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 );
393    }
394    void CommonController::copyTargetOrientation( float dt )
395    {
396        if ( bHasTargetOrientation_ )
397        {   
398            copyOrientation( targetOrientation_, dt );
399        }
400    }
401
402
403
404
405    void CommonController::moveToTargetPosition( float dt )
406    {
407        this->moveToPosition( this->targetPosition_, dt );
408    }
409    void CommonController::moveToPosition( const Vector3& target, float dt )
410    {
411     
412       
413        //100 is ( so far )the smallest tolerance ( empirically found )that can be reached,
414        //with smaller distance spaceships can't reach position and go circles around it instead
415        int tolerance = 65;
416
417        ControllableEntity* entity = this->getControllableEntity();
418        Vector2 coord = get2DViewCoordinates
419            ( entity->getPosition() , 
420            entity->getOrientation()  * WorldEntity::FRONT, 
421            entity->getOrientation()  * WorldEntity::UP, 
422            target );
423
424        float distance = ( target - this->getControllableEntity() ->getPosition() ).length();
425
426        //rotates should be in range [-1,+1], clamp cuts off all that is not
427        float rotateX = -clamp( coord.x * 10, -1.0f, 1.0f );
428        float rotateY = clamp( coord.y * 10, -1.0f, 1.0f );
429
430       
431        if ( distance > tolerance )
432        {
433            //Yaw and Pitch are enough to start facing the target
434            this->getControllableEntity() ->rotateYaw( ROTATEFACTOR * rotateX * dt );
435            this->getControllableEntity() ->rotatePitch( ROTATEFACTOR * rotateY * dt );
436
437            //300 works, maybe less is better
438            if ( distance < 400 )
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.
444                if ( bHasTargetOrientation_ )
445                {
446                    copyTargetOrientation( dt );
447                }
448            }
449
450            this->getControllableEntity() ->moveFrontBack( SPEED * dt );
451        }
452        else
453        {     
454            bHasTargetPosition_ = false;
455            bHasTargetOrientation_ = false;
456        }
457    }
458    float CommonController::randomInRange( float a, float b )
459    {
460        float random = rnd( 1.0f );
461        float diff = b - a;
462        float r = random * diff;
463        return a + r;
464    }
465   
466
467    //to be called in action
468    //PRE: relativeTargetPosition is desired position relative to the spaceship,
469    //angleRoll is the angle in degrees of Roll that should be applied by the end of the movement
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 )
472    {
473        ControllableEntity* entity = this->getControllableEntity();
474        if ( !entity )
475            return;
476        Quaternion orient = entity->getWorldOrientation();
477        Quaternion rotation = Quaternion( Degree( angleRoll ), Vector3::UNIT_Z );
478
479        Vector3 target = orient * relativeTargetPosition + entity->getWorldPosition();
480        setTargetPosition( target );
481        orient = orient * rotation;
482        this->setTargetOrientation( orient );
483       
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
493    //dt is normally around 0.02f, which makes it 1/0.02 = 50 frames/sec
494    bool CommonController::moveAndRoll( float dt )
495    {
496        float factor = 1;
497        if ( !this->getControllableEntity() )
498            return false;
499        if ( this->rank_ == Rank::DIVISIONLEADER )
500            factor = 0.8;
501        if ( this->rank_ == Rank::SECTIONLEADER )
502            factor = 0.9;
503        int tolerance = 60;
504       
505        ControllableEntity* entity = this->getControllableEntity();
506        if ( !entity )
507            return true;
508        Vector2 coord = get2DViewCoordinates
509            ( entity->getPosition() , 
510            entity->getOrientation()  * WorldEntity::FRONT, 
511            entity->getOrientation()  * WorldEntity::UP, 
512            targetPosition_ );
513
514        float distance = ( targetPosition_ - this->getControllableEntity() ->getPosition() ).length();
515
516        //rotates should be in range [-1,+1], clamp cuts off all that is not
517        float rotateX = clamp( coord.x * 10, -1.0f, 1.0f );
518        float rotateY = clamp( coord.y * 10, -1.0f, 1.0f );
519
520       
521        if ( distance > tolerance )
522        {
523            //Yaw and Pitch are enough to start facing the target
524            this->getControllableEntity() ->rotateYaw( -2.0f * ROTATEFACTOR * rotateX * dt );
525            this->getControllableEntity() ->rotatePitch( 2.0f * ROTATEFACTOR * rotateY * dt );
526           
527            //Roll
528            if ( bHasTargetOrientation_ )
529            {
530                copyTargetOrientation( dt );
531            }
532         
533            //Move
534            this->getControllableEntity() ->moveFrontBack( 1.2f * SPEED * factor * dt );
535            //if still moving, return false
536            return false;
537        }
538        else
539        {     
540           
541            //if finished, return true;
542            return true;
543        }
544    }
545
546    float CommonController::squaredDistanceToTarget()  const
547    {
548        if ( !this->getControllableEntity()  )
549            return 0;
550        if ( !this->target_ || !this->getControllableEntity() )
551            return ( this->getControllableEntity() ->getPosition() .squaredDistance( this->targetPosition_ ) );
552        else
553            return ( this->getControllableEntity() ->getPosition() .squaredDistance( this->positionOfTarget_ ) );
554    }
555   
556    bool CommonController::isLookingAtTarget( float angle )const
557    {
558        if ( !this->getControllableEntity()  || !this->target_ )
559            return false;
560
561        return ( getAngle( this->getControllableEntity() ->getPosition() , 
562            this->getControllableEntity() ->getOrientation()  * WorldEntity::FRONT, this->positionOfTarget_ ) < angle );
563    }
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    }
572
573    bool CommonController::canFire() 
574    {
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
587        float squaredDistance = squaredDistanceToTarget();
588
589        if ( squaredDistance < 9000000.0f && this->isLookingAtTarget( math::pi / 10.0f)) {
590            return true;
591        }
592        else
593        {
594            return false;
595        }
596
597    }
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    }
610    void CommonController::doFire() 
611    {
612        if ( !this->target_ || !this->getControllableEntity() )
613        {
614            return;
615        }
616     
617
618       
619        Pawn* pawn = orxonox_cast<Pawn*>( this->getControllableEntity() );
620
621        if ( pawn )
622            //pawn->setAimPosition( this->getControllableEntity() ->getWorldPosition()  + 4000*( this->getControllableEntity() ->getOrientation()  * WorldEntity::FRONT ));
623            pawn->setAimPosition( this->positionOfTarget_ );
624   
625        this->getControllableEntity() ->fire( 0 );
626    }
627   
628
629}
Note: See TracBrowser for help on using the repository browser.