Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/controllers/NewHumanController.cc @ 6445

Last change on this file since 6445 was 6417, checked in by rgrieder, 15 years ago

Merged presentation2 branch back to trunk.
Major new features:

  • Actual GUI with settings, etc.
  • Improved space ship steering (human interaction)
  • Rocket fire and more particle effects
  • Advanced sound framework
  • Property svn:eol-style set to native
File size: 22.2 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 *      Michael Wirth
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "NewHumanController.h"
30
31#include <cmath>
32#include <OgreRay.h>
33#include <OgreSceneQuery.h>
34#include <OgreCamera.h>
35#include <OgreSceneManager.h>
36#include <bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h>
37
38#include "core/CoreIncludes.h"
39#include "core/ConsoleCommand.h"
40#include "worldentities/ControllableEntity.h"
41#include "worldentities/pawns/Pawn.h"
42#include "infos/PlayerInfo.h"
43#include "overlays/OrxonoxOverlay.h"
44#include "graphics/Camera.h"
45#include "sound/SoundManager.h"
46#include "tools/BulletConversions.h"
47#include "Scene.h"
48
49namespace orxonox
50{
51    SetConsoleCommand(NewHumanController, changeMode, false).keybindMode(KeybindMode::OnPress);
52    SetConsoleCommand(NewHumanController, accelerate, false).keybindMode(KeybindMode::OnPress);
53    SetConsoleCommand(NewHumanController, decelerate, false).keybindMode(KeybindMode::OnPress);
54    SetConsoleCommand(NewHumanController, unfire,      true).keybindMode(KeybindMode::OnRelease);
55
56    CreateUnloadableFactory(NewHumanController);
57
58    NewHumanController* NewHumanController::localController_s = 0;
59
60    NewHumanController::NewHumanController(BaseObject* creator)
61        : HumanController(creator)
62        , crossHairOverlay_(NULL)
63        , centerOverlay_(NULL)
64        , damageOverlayTop_(NULL)
65        , damageOverlayRight_(NULL)
66        , damageOverlayBottom_(NULL)
67        , damageOverlayLeft_(NULL)
68        , damageOverlayTT_(0)
69        , arrowsOverlay1_(NULL)
70        , arrowsOverlay2_(NULL)
71        , arrowsOverlay3_(NULL)
72        , arrowsOverlay4_(NULL)
73    {
74        RegisterObject(NewHumanController);
75
76        overlaySize_ = 0.08;
77        arrowsSize_ = 0.4;
78
79        damageOverlayTime_ = 0.6;
80
81        controlMode_ = 0;
82        acceleration_ = 0;
83        accelerating_ = false;
84        firemode_ = -1;
85
86        showArrows_ = true;
87        showOverlays_ = false;
88        showDamageOverlay_ = true;
89
90        //currentPitch_ = 1;
91        //currentYaw_ = 1;
92
93        if (GameMode::showsGraphics())
94        {
95            crossHairOverlay_ = new OrxonoxOverlay(this);
96            crossHairOverlay_->setBackgroundMaterial("Orxonox/Crosshair3");
97            crossHairOverlay_->setSize(Vector2(overlaySize_, overlaySize_));
98            crossHairOverlay_->hide();
99            //crossHairOverlay_->setAspectCorrection(true); not working
100
101            centerOverlay_ = new OrxonoxOverlay(this);
102            centerOverlay_->setBackgroundMaterial("Orxonox/CenterOverlay");
103            centerOverlay_->setSize(Vector2(overlaySize_ * 2.5, overlaySize_ * 2.5));
104            centerOverlay_->setPosition(Vector2(0.5 - overlaySize_*2.5/2.0, 0.5 - overlaySize_*2.5/2.0));
105            centerOverlay_->hide();
106
107            if (showDamageOverlay_)
108            {
109                damageOverlayTop_ = new OrxonoxOverlay(this);
110                damageOverlayTop_->setBackgroundMaterial("Orxonox/DamageOverlayTop");
111                damageOverlayTop_->setSize(Vector2(overlaySize_ * 2.5, overlaySize_ * 2.5));
112                damageOverlayTop_->setPosition(Vector2(0.5 - overlaySize_*2.5/2.0, 0.5 - overlaySize_*2.5/2.0));
113                damageOverlayTop_->hide();
114
115                damageOverlayRight_ = new OrxonoxOverlay(this);
116                damageOverlayRight_->setBackgroundMaterial("Orxonox/DamageOverlayRight");
117                damageOverlayRight_->setSize(Vector2(overlaySize_ * 2.5, overlaySize_ * 2.5));
118                damageOverlayRight_->setPosition(Vector2(0.5 - overlaySize_*2.5/2.0, 0.5 - overlaySize_*2.5/2.0));
119                damageOverlayRight_->hide();
120
121                damageOverlayBottom_ = new OrxonoxOverlay(this);
122                damageOverlayBottom_->setBackgroundMaterial("Orxonox/DamageOverlayBottom");
123                damageOverlayBottom_->setSize(Vector2(overlaySize_ * 2.5, overlaySize_ * 2.5));
124                damageOverlayBottom_->setPosition(Vector2(0.5 - overlaySize_*2.5/2.0, 0.5 - overlaySize_*2.5/2.0));
125                damageOverlayBottom_->hide();
126
127                damageOverlayLeft_ = new OrxonoxOverlay(this);
128                damageOverlayLeft_->setBackgroundMaterial("Orxonox/DamageOverlayLeft");
129                damageOverlayLeft_->setSize(Vector2(overlaySize_ * 2.5, overlaySize_ * 2.5));
130                damageOverlayLeft_->setPosition(Vector2(0.5 - overlaySize_*2.5/2.0, 0.5 - overlaySize_*2.5/2.0));
131                damageOverlayLeft_->hide();
132            }
133
134            if (showArrows_)
135            {
136                arrowsOverlay1_ = new OrxonoxOverlay(this);
137                arrowsOverlay1_->setBackgroundMaterial("Orxonox/DirectionArrows1");
138                arrowsOverlay1_->setSize(Vector2(0.02727, 0.36 * arrowsSize_));
139                arrowsOverlay1_->setPickPoint(Vector2(0.5, 0.5));
140                arrowsOverlay1_->setPosition(Vector2(0.5, 0.5));
141                arrowsOverlay1_->hide();
142
143                arrowsOverlay2_ = new OrxonoxOverlay(this);
144                arrowsOverlay2_->setBackgroundMaterial("Orxonox/DirectionArrows2");
145                arrowsOverlay2_->setSize(Vector2(0.02727, 0.59 * arrowsSize_));
146                arrowsOverlay2_->setPickPoint(Vector2(0.5, 0.5));
147                arrowsOverlay2_->setPosition(Vector2(0.5, 0.5));
148                arrowsOverlay2_->hide();
149
150                arrowsOverlay3_ = new OrxonoxOverlay(this);
151                arrowsOverlay3_->setBackgroundMaterial("Orxonox/DirectionArrows3");
152                arrowsOverlay3_->setSize(Vector2(0.02727, 0.77 * arrowsSize_));
153                arrowsOverlay3_->setPickPoint(Vector2(0.5, 0.5));
154                arrowsOverlay3_->setPosition(Vector2(0.5, 0.5));
155                arrowsOverlay3_->hide();
156
157                arrowsOverlay4_ = new OrxonoxOverlay(this);
158                arrowsOverlay4_->setBackgroundMaterial("Orxonox/DirectionArrows4");
159                arrowsOverlay4_->setSize(Vector2(0.02727, arrowsSize_));
160                arrowsOverlay4_->setPickPoint(Vector2(0.5, 0.5));
161                arrowsOverlay4_->setPosition(Vector2(0.5, 0.5));
162                arrowsOverlay4_->hide();
163            }
164        }
165
166        // HACK: Define which objects are targetable when considering the creator of an orxonox::Model
167        this->targetMask_.exclude(ClassByString("BaseObject"));
168        this->targetMask_.include(ClassByString("WorldEntity"));
169        this->targetMask_.exclude(ClassByString("Projectile"));
170
171        NewHumanController::localController_s = this;
172
173        controlPaused_ = false;
174
175        //HumanController::localController_s->getControllableEntity()->getCamera()->setDrag(true);
176    }
177
178    NewHumanController::~NewHumanController()
179    {
180        if (this->isInitialized())
181        {
182            if (this->crossHairOverlay_)
183                this->crossHairOverlay_->destroy();
184            if (this->centerOverlay_)
185                this->centerOverlay_->destroy();
186
187            if (showArrows_)
188            {
189                if (this->arrowsOverlay1_)
190                    this->arrowsOverlay1_->destroy();
191                if (this->arrowsOverlay2_)
192                    this->arrowsOverlay2_->destroy();
193                if (this->arrowsOverlay3_)
194                    this->arrowsOverlay3_->destroy();
195                if (this->arrowsOverlay4_)
196                    this->arrowsOverlay4_->destroy();
197            }
198        }
199    }
200
201    void NewHumanController::tick(float dt)
202    {
203        if (GameMode::showsGraphics())
204        {
205
206            if (this->controllableEntity_ && !this->controllableEntity_->isInMouseLook())
207            {
208                this->updateTarget();
209
210                if (!controlPaused_ )
211                {
212                    if (this->getControllableEntity() && (this->getControllableEntity()->isExactlyA(ClassByString("SpaceShip")) || this->getControllableEntity()->isExactlyA(ClassByString("Rocket"))))
213                        this->showOverlays();
214
215                    this->crossHairOverlay_->setPosition(Vector2(static_cast<float>(this->currentYaw_)/2*-1+.5-overlaySize_/2, static_cast<float>(this->currentPitch_)/2*-1+.5-overlaySize_/2));
216
217                    if (this->controlMode_ == 0 || (this->controlMode_ == 1 && this->firemode_ == 1))
218                    {
219                        if (this->showOverlays_ && this->showArrows_)
220                            alignArrows();
221                    }
222                    else
223                        hideArrows();
224
225                    if (this->showDamageOverlay_ && (this->damageOverlayTT_ > 0 || this->damageOverlayTR_ > 0 || this->damageOverlayTB_ > 0 || this->damageOverlayTL_ > 0))
226                    {
227                        this->damageOverlayTT_ -= dt;
228                        this->damageOverlayTR_ -= dt;
229                        this->damageOverlayTB_ -= dt;
230                        this->damageOverlayTL_ -= dt;
231                        if (this->damageOverlayTT_ <= 0)
232                            this->damageOverlayTop_->hide();
233                        if (this->damageOverlayTR_ <= 0)
234                            this->damageOverlayRight_->hide();
235                        if (this->damageOverlayTB_ <= 0)
236                            this->damageOverlayBottom_->hide();
237                        if (this->damageOverlayTL_ <= 0)
238                            this->damageOverlayLeft_->hide();
239                    }
240                }
241            }
242            else
243                this->hideOverlays();
244
245            if (this->acceleration_ > 0)
246            {
247                if (this->accelerating_)
248                    HumanController::moveFrontBack(Vector2(1, 0));
249                else
250                    HumanController::moveFrontBack(Vector2(this->acceleration_, 0));
251                this->accelerating_ = false;
252                //HumanController::moveFrontBack(Vector2(clamp(this->acceleration_ + this->currentAcceleration_, 0.0f, 1.0f), 0));
253            }
254        }
255
256        // Reset pitch and yaw rates
257        // TODO: Reactivate this to fix the game pad problem with 0 input
258        //this->currentPitch_ = 0;
259        //this->currentYaw_ = 0;
260
261        HumanController::tick(dt);
262    }
263
264    void NewHumanController::doFire(unsigned int firemode)
265    {
266        if (!this->controllableEntity_)
267            return;
268
269        this->firemode_ = firemode;
270
271        if (firemode == 1 && this->controlMode_ == 1)
272        {
273            //unlocked steering, steer on right mouse click
274            HumanController::yaw(Vector2(this->currentYaw_, 0));
275            HumanController::pitch(Vector2(this->currentPitch_, 0));
276        }
277        else
278            HumanController::localController_s->getControllableEntity()->fire(firemode);
279
280    }
281
282    void NewHumanController::hit(Pawn* originator, btManifoldPoint& contactpoint, float damage)
283    {
284        if (this->showDamageOverlay_ && !this->controlPaused_ && this->controllableEntity_ && !this->controllableEntity_->isInMouseLook())
285        {
286            Vector3 posA;
287            if (originator)
288                posA = originator->getWorldPosition();
289            else
290                posA = multi_cast<Vector3>(contactpoint.getPositionWorldOnA());
291            //Vector3 posB = multi_cast<Vector3>(contactpoint.getPositionWorldOnB());
292            //posA and posB are almost identical
293
294            Vector3 relativeHit = this->getControllableEntity()->getWorldOrientation().UnitInverse() * (this->getControllableEntity()->getWorldPosition() - posA);
295
296            //back is z positive
297            //x is left positive
298            //y is down positive
299            relativeHit.normalise();
300
301            float threshold = 0.3;
302            if (relativeHit.x > threshold) // Left
303            {
304                this->damageOverlayLeft_->show();
305                this->damageOverlayTL_ = this->damageOverlayTime_;
306                //this->damageOverlayLeft_->setBackgroundAlpha(0.3);
307            }
308            if (relativeHit.x < -threshold) //Right
309            {
310                this->damageOverlayRight_->show();
311                this->damageOverlayTR_ = this->damageOverlayTime_;
312                //this->damageOverlayRight_->setBackgroundAlpha(0.3);
313            }
314            if (relativeHit.y > threshold) //Top
315            {
316                this->damageOverlayBottom_->show();
317                this->damageOverlayTB_ = this->damageOverlayTime_;
318                //this->damageOverlayTop_->setBackgroundAlpha(0.3);
319            }
320            if (relativeHit.y < -threshold) //Bottom
321            {
322                this->damageOverlayTop_->show();
323                this->damageOverlayTT_ = this->damageOverlayTime_;
324                //this->damageOverlayBottom_->setBackgroundAlpha(0.3);
325            }
326        }
327    }
328
329    void NewHumanController::unfire()
330    {
331        if (NewHumanController::localController_s)
332            NewHumanController::localController_s->doUnfire();
333    }
334
335    void NewHumanController::doUnfire()
336    {
337        this->firemode_ = -1;
338        hideArrows();
339    }
340
341    void NewHumanController::updateTarget()
342    {
343        Ogre::RaySceneQuery * rsq = HumanController::localController_s->getControllableEntity()->getScene()->getSceneManager()->createRayQuery(Ogre::Ray());
344
345        Ogre::Ray mouseRay = HumanController::localController_s->getControllableEntity()->getCamera()->getOgreCamera()->getCameraToViewportRay(static_cast<float>(this->currentYaw_)/2*-1+.5, static_cast<float>(this->currentPitch_)/2*-1+.5);
346
347        rsq->setRay(mouseRay);
348        rsq->setSortByDistance(true);
349
350        /*
351        Distance of objects:
352        ignore everything under 200 maybe even take 1000 as min distance to shoot at
353
354        shots are regularly traced and are entities!!!!!!!!! this is the biggest problem
355        they vanish only after a distance of 10'000
356        */
357
358
359        Ogre::RaySceneQueryResult& result = rsq->execute();
360        Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
361
362        Ogre::RaySceneQueryResult::iterator itr;
363        for (itr = result.begin(); itr != result.end(); ++itr)
364        {
365            if (itr->movable->isInScene() && itr->movable->getMovableType() == "Entity" && itr->distance > 500)
366            {
367                // Try to cast the user pointer
368                WorldEntity* wePtr = dynamic_cast<WorldEntity*>(itr->movable->getUserObject());
369                if (wePtr)
370                {
371                    // go through all parents of object and look whether they are sightable or not
372                    bool isSightable = false;
373                    WorldEntity* parent = wePtr->getParent();
374                    while (parent)
375                    {
376                        if (this->targetMask_.isExcluded(parent->getIdentifier()))
377                        {
378                            parent = parent->getParent();
379                            continue;
380                        }
381                        else
382                        {
383                            isSightable = true;
384                            break;
385                        }
386                    }
387                    if (!isSightable)
388                        continue;
389                }
390
391                if (this->getControllableEntity() && this->getControllableEntity()->getTarget() != wePtr)
392                    this->getControllableEntity()->setTarget(wePtr);
393
394                if (pawn)
395                    pawn->setAimPosition( mouseRay.getOrigin() + mouseRay.getDirection() * itr->distance );
396
397                //itr->movable->getParentSceneNode()->showBoundingBox(true);
398                //return mouseRay.getOrigin() + mouseRay.getDirection() * itr->distance; //or itr->movable->getParentSceneNode()->_getDerivedPosition()
399                return;
400            }
401        }
402
403        if (pawn)
404            pawn->setAimPosition( mouseRay.getOrigin() + mouseRay.getDirection() * 1200 );
405
406        if( this->getControllableEntity() && this->getControllableEntity()->getTarget() != 0 )
407            this->getControllableEntity()->setTarget( 0 );
408
409        //return this->controllableEntity_->getWorldPosition() + (this->controllableEntity_->getWorldOrientation() * Vector3::NEGATIVE_UNIT_Z * 2000);
410        //return this->controllableEntity_->getWorldPosition() + (this->controllableEntity_->getCamera()->getOgreCamera()->getOrientation() * Vector3::NEGATIVE_UNIT_Z);
411    }
412
413    void NewHumanController::frontback(const Vector2& value)
414    {
415        this->accelerating_ = true;
416
417        //if (this->acceleration_ == 0)
418        HumanController::frontback(value);
419    }
420
421    void NewHumanController::yaw(const Vector2& value)
422    {
423        //SUPER(NewHumanController, yaw, value);
424        if (this->controlMode_ == 0 || (this->controllableEntity_ && this->controllableEntity_->isInMouseLook()))
425            HumanController::yaw(value);
426
427        this->currentYaw_ = value.x;
428    }
429
430    void NewHumanController::pitch(const Vector2& value)
431    {
432        //SUPER(NewHumanController, pitch, value);
433        if (this->controlMode_ == 0 || (this->controllableEntity_ && this->controllableEntity_->isInMouseLook()))
434            HumanController::pitch(value);
435
436        this->currentPitch_ = value.x;
437    }
438
439    void NewHumanController::changeMode()
440    {
441        if (NewHumanController::localController_s)
442        {
443            if (NewHumanController::localController_s->controlMode_ == 0)
444            {
445                NewHumanController::localController_s->controlMode_ = 1;
446                NewHumanController::localController_s->hideArrows();
447            }
448            else
449                NewHumanController::localController_s->controlMode_ = 0;
450        }
451    }
452
453    void NewHumanController::changedControllableEntity()
454    {
455        this->controlMode_ = 0;
456        this->currentYaw_ = 0;
457        this->currentPitch_ = 0;
458        if (this->getControllableEntity() && (this->getControllableEntity()->isExactlyA(ClassByString("SpaceShip")) || this->getControllableEntity()->isExactlyA(ClassByString("Rocket"))))
459        {
460            this->showOverlays_ = true;
461            if (!this->controlPaused_)
462            {
463                this->showOverlays();
464                this->alignArrows();
465            }
466        }
467        else
468        {
469            this->showOverlays_ = false;
470            this->hideOverlays();
471        }
472    }
473
474    void NewHumanController::accelerate()
475    {
476        if (NewHumanController::localController_s)
477            NewHumanController::localController_s->acceleration_ = clamp(NewHumanController::localController_s->acceleration_ + 0.2f, 0.00f, 1.0f);
478    }
479
480    void NewHumanController::decelerate()
481    {
482        if (NewHumanController::localController_s)
483            NewHumanController::localController_s->acceleration_ = clamp(NewHumanController::localController_s->acceleration_ - 0.1f, 0.0f, 1.0f);
484    }
485
486    void NewHumanController::doResumeControl()
487    {
488        this->controlPaused_ = false;
489        if (this->showOverlays_)
490            this->showOverlays();
491    }
492
493    void NewHumanController::doPauseControl()
494    {
495        this->controlPaused_ = true;
496        this->hideOverlays();
497    }
498
499    void NewHumanController::alignArrows()
500    {
501        if (showArrows_)
502        {
503            hideArrows();
504
505            float distance = sqrt(pow(static_cast<float>(this->currentYaw_)/2*-1,2) + pow(static_cast<float>(this->currentPitch_)/2*-1,2));
506
507            if (distance > 0.04 && distance <= 0.59 * arrowsSize_ / 2.0 )
508            {
509                this->arrowsOverlay1_->setRotation(Degree(-90 + -1.0 * atan2(static_cast<float>(this->currentPitch_)/2*-1, static_cast<float>(this->currentYaw_)/2*-1) / (2.0f * Ogre::Math::PI) * 360.0f));
510                this->arrowsOverlay1_->show();
511            }
512            else if (distance > 0.59 * arrowsSize_ / 2.0 && distance <= 0.77 * arrowsSize_ / 2.0 )
513            {
514                this->arrowsOverlay2_->setRotation(Degree(-90 + -1.0 * atan2(static_cast<float>(this->currentPitch_)/2*-1, static_cast<float>(this->currentYaw_)/2*-1) / (2.0f * Ogre::Math::PI) * 360.0f));
515                this->arrowsOverlay2_->show();
516            }
517            else if (distance > 0.77 * arrowsSize_ / 2.0 && distance <= arrowsSize_ / 2.0)
518            {
519                this->arrowsOverlay3_->setRotation(Degree(-90 + -1.0 * atan2(static_cast<float>(this->currentPitch_)/2*-1, static_cast<float>(this->currentYaw_)/2*-1) / (2.0f * Ogre::Math::PI) * 360.0f));
520                this->arrowsOverlay3_->show();
521            }
522            else if (distance > arrowsSize_ / 2.0)
523            {
524                this->arrowsOverlay4_->setRotation(Degree(-90 + -1.0 * atan2(static_cast<float>(this->currentPitch_)/2*-1, static_cast<float>(this->currentYaw_)/2*-1) / (2.0f * Ogre::Math::PI) * 360.0f));
525                this->arrowsOverlay4_->show();
526            }
527        }
528    }
529
530    void NewHumanController::showOverlays()
531    {
532        if (!GameMode::showsGraphics())
533            return;
534        this->crossHairOverlay_->show();
535        this->centerOverlay_->show();
536
537        if (showArrows_)
538        {
539            this->arrowsOverlay1_->show();
540            this->arrowsOverlay2_->show();
541            this->arrowsOverlay3_->show();
542            this->arrowsOverlay4_->show();
543        }
544    }
545
546    void NewHumanController::hideOverlays()
547    {
548        if (!GameMode::showsGraphics())
549            return;
550        this->crossHairOverlay_->hide();
551        this->centerOverlay_->hide();
552
553        if (showDamageOverlay_)
554        {
555            this->damageOverlayTop_->hide();
556            this->damageOverlayRight_->hide();
557            this->damageOverlayBottom_->hide();
558            this->damageOverlayLeft_->hide();
559        }
560
561        this->hideArrows();
562    }
563
564    void NewHumanController::hideArrows()
565    {
566        if(!GameMode::showsGraphics())
567            return;
568        if (showArrows_)
569        {
570            this->arrowsOverlay1_->hide();
571            this->arrowsOverlay2_->hide();
572            this->arrowsOverlay3_->hide();
573            this->arrowsOverlay4_->hide();
574        }
575    }
576}
Note: See TracBrowser for help on using the repository browser.