Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/campaignHS15/src/orxonox/controllers/FightingController.cc @ 10906

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

tried to fix fighting whn fps is low

File size: 16.2 KB
RevLine 
[10871]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:
[10885]23 *      Gani Aliguzhinov
[10871]24 *   Co-authors:
[10885]25 *      Fabian 'x3n' Landau, Dominik Solenicki
[10871]26 *
27 */
28#include "controllers/FightingController.h"
29#include "core/XMLPort.h"
[10875]30#include "util/Math.h"
[10871]31
32
[10885]33#include "worldentities/pawns/SpaceShip.h"
34
35#include "weaponsystem/WeaponMode.h"
36#include "weaponsystem/WeaponPack.h"
37#include "weaponsystem/Weapon.h"
38#include "weaponsystem/WeaponSlot.h"
[10903]39#include "weaponsystem/WeaponSystem.h"
40#include "weaponsystem/Munition.h"
41
[10871]42namespace orxonox
43{
44
45    RegisterClass (FightingController);
46   
47    FightingController::FightingController( Context* context ): FlyingController( context )
48    {
[10886]49        this->attackRange_ = 2500;
[10871]50        this->stopLookingAtTarget();
[10885]51        this->bSetupWorked = false;
52        this->timeout_ = 0;
[10871]53        RegisterObject( FightingController );
54    }
55    FightingController::~FightingController() 
56    {
57       
58    }
59    void FightingController::XMLPort( Element& xmlelement, XMLPort::Mode mode )
60    {
61        SUPER( FightingController, XMLPort, xmlelement, mode );
62    }
63    void FightingController::lookAtTarget(float dt)
64    {
65        ControllableEntity* entity = this->getControllableEntity();
66        if ( !entity )
67            return;
68        Vector2 coord = get2DViewCoordinates
69            ( entity->getPosition() , 
70            entity->getOrientation()  * WorldEntity::FRONT, 
71            entity->getOrientation()  * WorldEntity::UP, 
72            positionOfTarget_ );
73
74        //rotates should be in range [-1,+1], clamp cuts off all that is not
75        float rotateX = -clamp( coord.x * 10, -1.0f, 1.0f );
76        float rotateY = clamp( coord.y * 10, -1.0f, 1.0f ); 
77   
78        //Yaw and Pitch are enough to start facing the target
79        this->getControllableEntity() ->rotateYaw( ROTATEFACTOR * rotateX * dt );
80        this->getControllableEntity() ->rotatePitch( ROTATEFACTOR * rotateY * dt );
81    }
82    void FightingController::stopLookingAtTarget()
83    {
84        this->bLookAtTarget_ = false;
85    }
86    void FightingController::startLookingAtTarget()
87    {
88        this->bLookAtTarget_ = true;
89    }
[10885]90    bool FightingController::hasTarget() const
[10871]91    {
92        if ( this->target_ )
93            return true;
94        return false;
95    }
96
97    void FightingController::setTarget( ControllableEntity* target )
98    {
99        this->target_ = target;       
100        if ( this->target_ )
101        {
102            this->setPositionOfTarget( target_->getWorldPosition() );
103        }
104    }
105    void FightingController::setPositionOfTarget( const Vector3& target )
106    {
107        this->positionOfTarget_ = target;
108        this->bHasPositionOfTarget_ = true;
109    }
110    void FightingController::setOrientationOfTarget( const Quaternion& orient )
111    {
112        this->orientationOfTarget_=orient;
113        this->bHasOrientationOfTarget_=true;
114    }
115   
116    void FightingController::maneuver() 
117    {
[10885]118        if ( !this->target_ || !this->getControllableEntity())
119            return;
[10871]120
[10906]121
[10871]122        Vector3 thisPosition = this->getControllableEntity()->getWorldPosition();
[10885]123        this->setPositionOfTarget(this->target_->getWorldPosition());
124        //this->setOrientationOfTarget(this->target_->getOrientation());
[10871]125        Vector3 diffVector = this->positionOfTarget_ - thisPosition;
126        float diffLength = diffVector.length();
127        Vector3 diffUnit = diffVector/diffLength;
[10906]128        bool bTargetIsLookingAtThis = CommonController::isLooking (this->target_, this->getControllableEntity(), math::pi/10.0f)
[10886]129            || this->deltaHp < 0;
130
[10871]131        //too far? well, come closer then
[10883]132        if (diffLength > this->attackRange_)
[10871]133        {
[10886]134            this->spread_ = 400;
135            this->formationMode_ = FormationMode::DIAMOND;
[10883]136            this->bKeepFormation_ = true;
137           
[10886]138            this->setTargetPosition(this->positionOfTarget_ - diffUnit * 100.0f);
[10871]139        }
[10906]140        else
141        {
142            this->bKeepFormation_ = false;
143            // if (this->actionCounter_ % 3 == 0)
144            if (maneuverCounter_ <= 1.2)
145            {
146                // orxout(internal_error) << "attacking" << endl;
147                this->setTargetPosition(this->positionOfTarget_ - diffUnit * 50.0f);   
148                return;
149            }
150            else if (bTargetIsLookingAtThis || diffLength < 700.0f)
151            {
152                // orxout(internal_error) << "dodging" << endl;
153                if (!this->bStartedDodging_)
154                {
155                    this->bStartedDodging_ = true;
156                    dodge(thisPosition, diffLength, diffUnit);       
157                }
158            }
159            else
160            {
161                if (diffLength < 1000)
162                {
163                // orxout(internal_error) << "looking" << endl;                   
164                    this->stopMoving();
165                    this->startLookingAtTarget();
166
167                }
168                else
169                {
170                // orxout(internal_error) << "closing up" << endl;                   
171                    this->setTargetPosition(this->positionOfTarget_ - diffUnit * 300.0f);
172                }
173            }
174        }
175        /*//too close? How do u expect to dodge anything? Just attack!
[10903]176        else if (diffLength < 1000)
[10871]177        {   
[10883]178            this->bKeepFormation_ = false;
179
[10871]180            //at this point, just look and shoot
[10906]181            if (diffLength < 1000)
[10871]182            {
183                this->stopMoving();
184                this->startLookingAtTarget();
[10906]185
[10871]186            }
187            else
188            {
[10903]189                this->setTargetPosition(this->positionOfTarget_ - diffUnit * 300.0f);
[10871]190            }
191        }
192        //Good distance? Check if target looks at us. It doesn't? Go hunt!
[10885]193        else if (!bTargetIsLookingAtThis)
[10871]194        {
[10883]195            this->bKeepFormation_ = false;
[10906]196            this->setTargetPosition(this->positionOfTarget_ - diffUnit * 900.0f);
[10871]197        }
198        //That's unfortunate, he is looking and probably shooting... try to dodge what we can... 
199        else
200        {   
[10883]201            this->bKeepFormation_ = false;
[10871]202            if (maneuverCounter_ == 0)
203            {
[10906]204                this->setTargetPosition(this->positionOfTarget_ - diffUnit * 900.0f);   
[10871]205                return;
206            }
[10903]207            if (this->actionCounter_ % 3 == 0)
[10906]208                dodge(thisPosition, diffLength, diffUnit);
209        }*/
[10871]210    }
[10888]211    void FightingController::dodgeTowards (Vector3& position)
212    {
213        Vector3 thisPosition = this->getControllableEntity()->getPosition();
214        Vector3 diff = (position - thisPosition);
215        float diffLength = diff.length();
216        Vector3 diffUnit = diff/diffLength;
217        float factor = 300.0f;
218        if (diffLength < 300)
219        {
220            this->setTargetPosition(position);
221            return;   
222        }
223        else if (diffLength < 600)
224            factor = 400.0f;
225        else if (diffLength < 1000)
226            factor = 700.0f;
227        else
228            factor = 1000.0f;
229        float x = CommonController::randomInRange (400, 800) * (CommonController::randomInRange(0,1) <= 0.5 ? 1 : -1);
230        float y = CommonController::randomInRange (400, 800) * (CommonController::randomInRange(0,1) <= 0.5 ? 1 : -1);
231        float z = diffUnit.z == 0 ? 0 : (1/diffUnit.z) * (-x * diffUnit.x - y * diffUnit.y);
232        this->setTargetPosition(thisPosition + Vector3(x,y,z) + diffUnit * factor);
233        // orxout(internal_error) << "Dodging towards " << Vector3(x,y,z)  << endl;
234        this->boostControl();
235    }
[10906]236    void FightingController::dodge(const Vector3& thisPosition, float diffLength, Vector3& diffUnit)
[10871]237    {
[10885]238        //d.x*x + d.y*y + d.z*z == 0
239        //z = 1/d.z * (-d.y*y - d.x * x)
[10906]240        float x = CommonController::randomInRange (300, 800) * (CommonController::randomInRange(0,1) <= 0.5 ? 1 : -1);
241        float y = CommonController::randomInRange (300, 800) * (CommonController::randomInRange(0,1) <= 0.5 ? 1 : -1);
[10888]242        float z = diffUnit.z == 0 ? 0 : (1/diffUnit.z) * (-x * diffUnit.x - y * diffUnit.y);
[10906]243        if (diffLength < 150.0f)
244        {
245            this->setTargetPosition(this->positionOfTarget_ + Vector3(z,x,y));
246        }
247        else
248        {
249        this->setTargetPosition(thisPosition + Vector3(x,y,z) + (this->deltaHp < 0 ? -diffUnit * 450.0f : 
250            (diffLength < 700.0f ? -diffUnit*700.0f : diffUnit * 50.0f)));
251
252        }
[10885]253        this->boostControl();
[10871]254
255    }
256    bool FightingController::canFire() 
257    {
258        //no target? why fire?
[10885]259        if (!this->target_)
[10871]260            return false;
[10885]261        Vector3 newPositionOfTarget = getPredictedPosition(this->getControllableEntity()->getWorldPosition(), 
262                                                           hardcoded_projectile_speed, this->target_->getWorldPosition(), 
263                                                           this->target_->getVelocity());
[10891]264        //Vector3.isNaN() is what I used on my machine and it worked...
265        if (!(std::isnan(newPositionOfTarget.x) || std::isnan(newPositionOfTarget.y) || std::isnan(newPositionOfTarget.z)))
[10871]266        {
[10885]267            this->setPositionOfTarget(newPositionOfTarget);
[10871]268        }
[10886]269
[10906]270        return squaredDistanceToTarget() < this->attackRange_*this->attackRange_ && this->isLookingAtTarget(math::pi / 10.0f);
[10871]271    }
272
[10885]273
[10871]274    float FightingController::squaredDistanceToTarget()  const
275    {
[10885]276        if (!this->getControllableEntity())
[10871]277            return 0;
[10885]278        if (!this->target_ || !this->getControllableEntity())
279            return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_));
[10871]280        else
[10885]281            return (this->getControllableEntity()->getPosition().squaredDistance(this->positionOfTarget_));
[10871]282    }
[10885]283    bool FightingController::isLookingAtTarget( float angle ) const
[10871]284    {
285        if ( !this->getControllableEntity()  || !this->target_ )
286            return false;
[10877]287        return CommonController::isLooking(this->getControllableEntity(), this->getTarget(), angle);
[10871]288    }
[10885]289    void FightingController::setClosestTarget()
[10871]290    {
291        this->setTarget (static_cast<ControllableEntity*>( closestTarget() ) ); 
292    }
293   
[10885]294    Pawn* FightingController::closestTarget() const
[10871]295    {
296        if (!this->getControllableEntity())
297            return 0;
298
299        Pawn* closestTarget = 0;
300        float minDistance =  std::numeric_limits<float>::infinity();
301        Gametype* gt = this->getGametype();
302        for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
303        {
304            if ( CommonController::sameTeam (this->getControllableEntity(), static_cast<ControllableEntity*>(*itP), gt) )
305                continue;
306
307            float distance = CommonController::distance (*itP, this->getControllableEntity());
308            if (distance < minDistance)
309            {
310                closestTarget = *itP;
311                minDistance = distance;
312            }
313        }
314        if (closestTarget)
315        {
316           return closestTarget;
317        } 
318        return 0; 
319    }
[10885]320    //I checked it out, rockets DO NOT cause any problems! this->getControllableEntity() is always a SpaceShip
321    void FightingController::doFire()
322    {
323        if (!this->bSetupWorked)
324        {
325            this->setupWeapons();
326        }
327        if (!this->target_ || !this->getControllableEntity())
328        {
329            return;
330        }
[10886]331
[10885]332        Pawn* pawn = orxonox_cast<Pawn*> (this->getControllableEntity());
333        if (pawn)
334            pawn->setAimPosition (this->positionOfTarget_);
[10886]335        // if (pawn->getHealth() < 100)
336        //     orxout(internal_error) << "not full, hp = " << pawn->getHealth() << endl;
[10885]337        int firemode;
338        float distance = CommonController::distance (this->getControllableEntity(), this->target_);
339
340        // firemode = distance < 1500 ? (distance > 800 && distance < 1200 ?
341        //                             (this->rocketsLeft_ > 0 && !this->bFiredRocket_ ? getFiremode("RocketFire") : getFiremode ("HsW01"))
342        //                                                      : getFiremode("HsW01")) :
343        //                                                      (distance < 2500 ? getFiremode("LightningGun") : getFiremode("HsW01"));
[10886]344        if (distance < 1500)
[10885]345        {
[10886]346            if (this->rocketsLeft_ > 0 && !this->bFiredRocket_)
[10885]347            {
[10886]348                firemode = getFiremode ("RocketFire");
[10885]349            }
350            else
351            {
[10886]352                if (distance > 800)
353                    firemode = getFiremode ("HsW01");
354                else
[10885]355                    firemode = getFiremode ("LightningGun");
356            }
357
358        } 
[10886]359        // else if (distance < 1000)
360        // {
361        //     if (this->rocketsLeft_ > 0 && !this->bFiredRocket_)
362        //     {
363        //         firemode = getFiremode ("RocketFire");
364        //     }
365        //     else
366        //     {
367        //         firemode = getFiremode ("HsW01");
368        //     }
369        // }
370        else if (distance < 2000)
[10885]371        {
[10886]372            firemode = getFiremode ("HsW01");
[10885]373        }
[10886]374        else
[10885]375        {
376            firemode = getFiremode ("LightningGun");
377        }
378        if (firemode < 0)
379        {
[10886]380            //assuming there is always some weapon with index 0
381            firemode = 0;
[10885]382        }
383        if (firemode == getFiremode("RocketFire"))
384        {
[10886]385            this->timeout_ = 0.5f;
[10885]386            this->rocketsLeft_--;
387            this->bFiredRocket_ = true;
388        }
389        if (firemode == getFiremode("SimpleRocketFire"))
390        {
391            this->rocketsLeft_--;
392        }
393             
394        this->getControllableEntity()->fire(firemode);
395       
396    }
397    void FightingController::setupWeapons() //TODO: Make this function generic!! (at the moment is is based on conventions)
398    {
399        this->bSetupWorked = false;
400        if(this->getControllableEntity())
401        {
402            Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
403            if(pawn && pawn->isA(Class(SpaceShip))) //fix for First Person Mode: check for SpaceShip
404            {
405                this->weaponModes_.clear(); // reset previous weapon information
406                WeaponSlot* wSlot = 0;
407                for(int l=0; (wSlot = pawn->getWeaponSlot(l)) ; l++)
408                {
409                    WeaponMode* wMode = 0;
410                    for(int i=0; (wMode = wSlot->getWeapon()->getWeaponmode(i)) ; i++)
411                    {
412                        std::string wName = wMode->getIdentifier()->getName();
[10903]413                        // SubclassIdentifier<Munition> munition =  ClassByString(wName);
[10885]414                        if (wName == "RocketFire")
415                            this->rocketsLeft_ = 10;
[10903]416                            // this->rocketsLeft_ = orxonox_cast<Pawn*>(this->getControllableEntity())->getWeaponSystem()->getMunition(&munition)->getNumMunitionInCurrentMagazine(wMode);
[10885]417                        if(this->getFiremode(wName) == -1) //only add a weapon, if it is "new"
418                            weaponModes_[wName] = wMode->getMode();
419                    }
420                }
421                if(weaponModes_.size())//at least one weapon detected
422                    this->bSetupWorked = true;
423            }//pawn->weaponSystem_->getMunition(SubclassIdentifier< Munition > *identifier)->getNumMunition (WeaponMode *user);
424        }
[10903]425
426        //orxout (internal_error) << this->rocketsLeft_ << " rockets left" << endl;
[10885]427    }
428
429    int FightingController::getFiremode(std::string name)
430    {
431        for (std::map< std::string, int >::iterator it = this->weaponModes_.begin(); it != this->weaponModes_.end(); ++it)
432        {
433            if (it->first == name)
434                return it->second;
435        }
436        return -1;
437    }
[10871]438}
Note: See TracBrowser for help on using the repository browser.