Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10793 was 10793, checked in by gania, 9 years ago

added choose maneuver type functionality

File size: 16.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    //to be called in action
361    //PRE: relativeTargetPosition is desired position relative to the spaceship,
362    //angleRoll is the angle in degrees of Roll that should be applied by the end of the movement
363    //POST: target orientation and position are set, so that it can be used by MoveAndRoll()
364    void CommonController::moveToPoint(const Vector3& relativeTargetPosition, float angleRoll)
365    {
366        ControllableEntity* entity = this->getControllableEntity();
367        if (!entity)
368            return;
369        Quaternion orient = entity->getWorldOrientation();
370        Quaternion rotation = Quaternion(Degree(angleRoll), Vector3::UNIT_Z);
371
372        Vector3 target = orient * relativeTargetPosition + entity->getWorldPosition();
373        setTargetPosition(target);
374        orient = orient * rotation;
375        this->setTargetOrientation(orient);
376       
377    }
378    //to be called in tick
379    //PRE: MoveToPoint was called
380    //POST: spaceship changes its yaw and pitch to point towards targetPosition_,
381    //moves towards targetPosition_ by amount depending on dt and its speed,
382    //rolls by amount depending on the difference between angleRoll_ and angleRolled_, dt, and
383    //angular speed
384    //if position reached with a certain tolerance, and angleRolled_ = angleRoll_, returns false,
385    //otherwise returns true
386    //dt is normally around 0.02f, which makes it 1/0.02 = 50 frames/sec
387    bool CommonController::moveAndRoll(float dt)
388    {
389        float factor = 1;
390        if (!this->getControllableEntity())
391            return false;
392        if (this->rank_ == Rank::DIVISIONLEADER)
393            factor = 0.8;
394        if (this->rank_ == Rank::SECTIONLEADER)
395            factor = 0.9;
396        int tolerance = 60;
397       
398        ControllableEntity* entity = this->getControllableEntity();
399        if (!entity)
400            return true;
401        Vector2 coord = get2DViewCoordinates
402            (entity->getPosition(), 
403            entity->getOrientation() * WorldEntity::FRONT, 
404            entity->getOrientation() * WorldEntity::UP, 
405            targetPosition_);
406
407        float distance = (targetPosition_ - this->getControllableEntity()->getPosition()).length();
408
409        //rotates should be in range [-1,+1], clamp cuts off all that is not
410        float rotateX = clamp(coord.x * 10, -1.0f, 1.0f);
411        float rotateY = clamp(coord.y * 10, -1.0f, 1.0f);
412
413       
414        if (distance > tolerance)
415        {
416            //Yaw and Pitch are enough to start facing the target
417            this->getControllableEntity()->rotateYaw(-2.0f * ROTATEFACTOR * rotateX * dt);
418            this->getControllableEntity()->rotatePitch(2.0f * ROTATEFACTOR * rotateY * dt);
419           
420            //Roll
421            if (bHasTargetOrientation_)
422            {
423                copyTargetOrientation(dt);
424            }
425         
426            //Move
427            this->getControllableEntity()->moveFrontBack(1.2f * SPEED * factor * dt);
428            //if still moving, return false
429            return false;
430        }
431        else
432        {     
433           
434            //if finished, return true;
435            return true;
436        }
437    }
438
439    float CommonController::squaredDistanceToTarget() const
440    {
441        if ( !this->getControllableEntity() )
442            return 0;
443        if ( !this->target_ )
444            return ( this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) );
445        else
446            return ( this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) );
447    }
448   
449    bool CommonController::isLookingAtTarget(float angle) const
450    {
451        if (!this->getControllableEntity())
452            return false;
453
454        return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle);
455    }
456
457    bool CommonController::canFire()
458    {
459        float squaredDistance = squaredDistanceToTarget();
460        if ( this->bShooting_ && squaredDistance < 9000000 && squaredDistance > 10000 && this->isLookingAtTarget(math::pi /(0.0002f*squaredDistance)) )
461        {
462            return true;
463        }
464        else
465        {
466            return false;
467        }
468
469    }
470    void CommonController::doFire()
471    {
472        if (!this->target_ || !this->getControllableEntity())
473            return;
474        static const float hardcoded_projectile_speed = 750;
475
476        this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getWorldPosition(), hardcoded_projectile_speed, this->target_->getWorldPosition(), this->target_->getVelocity());
477        this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO);
478
479        Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
480
481        if (pawn)
482            //pawn->setAimPosition(this->getControllableEntity()->getWorldPosition() + 4000*(this->getControllableEntity()->getOrientation() * WorldEntity::FRONT));
483            pawn->setAimPosition(this->targetPosition_);
484   
485        this->getControllableEntity()->fire(0);
486    }
487   
488
489}
Note: See TracBrowser for help on using the repository browser.