Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/fps/src/orxonox/controllers/NewHumanController.cc @ 6876

Last change on this file since 6876 was 6866, checked in by freicy, 15 years ago

commit by cyrill

  • Property svn:eol-style set to native
File size: 22.6 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.08f;
77        arrowsSize_ = 0.4f;
78
79        damageOverlayTime_ = 0.6f;
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.5f, overlaySize_ * 2.5f));
104            centerOverlay_->setPosition(Vector2(0.5f - overlaySize_*2.5f/2.0f, 0.5f - overlaySize_*2.5f/2.0f));
105            centerOverlay_->hide();
106
107            if (showDamageOverlay_)
108            {
109                damageOverlayTop_ = new OrxonoxOverlay(this);
110                damageOverlayTop_->setBackgroundMaterial("Orxonox/DamageOverlayTop");
111                damageOverlayTop_->setSize(Vector2(overlaySize_ * 2.5f, overlaySize_ * 2.5f));
112                damageOverlayTop_->setPosition(Vector2(0.5f - overlaySize_*2.5f/2.0f, 0.5f - overlaySize_*2.5f/2.0f));
113                damageOverlayTop_->hide();
114
115                damageOverlayRight_ = new OrxonoxOverlay(this);
116                damageOverlayRight_->setBackgroundMaterial("Orxonox/DamageOverlayRight");
117                damageOverlayRight_->setSize(Vector2(overlaySize_ * 2.5f, overlaySize_ * 2.5f));
118                damageOverlayRight_->setPosition(Vector2(0.5f - overlaySize_*2.5f/2.0f, 0.5f - overlaySize_*2.5f/2.0f));
119                damageOverlayRight_->hide();
120
121                damageOverlayBottom_ = new OrxonoxOverlay(this);
122                damageOverlayBottom_->setBackgroundMaterial("Orxonox/DamageOverlayBottom");
123                damageOverlayBottom_->setSize(Vector2(overlaySize_ * 2.5f, overlaySize_ * 2.5f));
124                damageOverlayBottom_->setPosition(Vector2(0.5f - overlaySize_*2.5f/2.0f, 0.5f - overlaySize_*2.5f/2.0f));
125                damageOverlayBottom_->hide();
126
127                damageOverlayLeft_ = new OrxonoxOverlay(this);
128                damageOverlayLeft_->setBackgroundMaterial("Orxonox/DamageOverlayLeft");
129                damageOverlayLeft_->setSize(Vector2(overlaySize_ * 2.5f, overlaySize_ * 2.5f));
130                damageOverlayLeft_->setPosition(Vector2(0.5f - overlaySize_*2.5f/2.0f, 0.5f - overlaySize_*2.5f/2.0f));
131                damageOverlayLeft_->hide();
132            }
133
134            if (showArrows_)
135            {
136                arrowsOverlay1_ = new OrxonoxOverlay(this);
137                arrowsOverlay1_->setBackgroundMaterial("Orxonox/DirectionArrows1");
138                arrowsOverlay1_->setSize(Vector2(0.02727f, 0.36f * arrowsSize_));
139                arrowsOverlay1_->setPickPoint(Vector2(0.5f, 0.5f));
140                arrowsOverlay1_->setPosition(Vector2(0.5f, 0.5f));
141                arrowsOverlay1_->hide();
142
143                arrowsOverlay2_ = new OrxonoxOverlay(this);
144                arrowsOverlay2_->setBackgroundMaterial("Orxonox/DirectionArrows2");
145                arrowsOverlay2_->setSize(Vector2(0.02727f, 0.59f * arrowsSize_));
146                arrowsOverlay2_->setPickPoint(Vector2(0.5f, 0.5f));
147                arrowsOverlay2_->setPosition(Vector2(0.5f, 0.5f));
148                arrowsOverlay2_->hide();
149
150                arrowsOverlay3_ = new OrxonoxOverlay(this);
151                arrowsOverlay3_->setBackgroundMaterial("Orxonox/DirectionArrows3");
152                arrowsOverlay3_->setSize(Vector2(0.02727f, 0.77f * arrowsSize_));
153                arrowsOverlay3_->setPickPoint(Vector2(0.5f, 0.5f));
154                arrowsOverlay3_->setPosition(Vector2(0.5f, 0.5f));
155                arrowsOverlay3_->hide();
156
157                arrowsOverlay4_ = new OrxonoxOverlay(this);
158                arrowsOverlay4_->setBackgroundMaterial("Orxonox/DirectionArrows4");
159                arrowsOverlay4_->setSize(Vector2(0.02727f, arrowsSize_));
160                arrowsOverlay4_->setPickPoint(Vector2(0.5f, 0.5f));
161                arrowsOverlay4_->setPosition(Vector2(0.5f, 0.5f));
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")) || this->getControllableEntity()->isExactlyA(ClassByString("FpsPlayer"))))
213                        this->showOverlays();
214
215                    this->crossHairOverlay_->setPosition(Vector2(static_cast<float>(this->currentYaw_)/2*-1+.5f-overlaySize_/2, static_cast<float>(this->currentPitch_)/2*-1+.5f-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.3f;
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+.5f, static_cast<float>(this->currentPitch_)/2*-1+.5f);
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*>(Ogre::any_cast<OrxonoxClass*>(itr->movable->getUserAny()));
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        if (this->getControllableEntity() && !this->getControllableEntity()->isExactlyA(ClassByString("FpsPlayer")))
428            this->currentYaw_ = value.x;
429    }
430
431    void NewHumanController::pitch(const Vector2& value)
432    {
433        //SUPER(NewHumanController, pitch, value);
434        if (this->controlMode_ == 0 || (this->controllableEntity_ && this->controllableEntity_->isInMouseLook()))
435            HumanController::pitch(value);
436
437        if (this->getControllableEntity() && !this->getControllableEntity()->isExactlyA(ClassByString("FpsPlayer")))
438            this->currentPitch_ = value.x;
439    }
440
441    void NewHumanController::changeMode()
442    {
443        if (NewHumanController::localController_s)
444        {
445            if (NewHumanController::localController_s->controlMode_ == 0)
446            {
447                NewHumanController::localController_s->controlMode_ = 1;
448                NewHumanController::localController_s->hideArrows();
449            }
450            else
451                NewHumanController::localController_s->controlMode_ = 0;
452        }
453    }
454
455    void NewHumanController::changedControllableEntity()
456    {
457        this->controlMode_ = 0;
458        this->currentYaw_ = 0;
459        this->currentPitch_ = 0;
460        if (this->getControllableEntity() && (this->getControllableEntity()->isExactlyA(ClassByString("SpaceShip")) || this->getControllableEntity()->isExactlyA(ClassByString("Rocket"))))
461        {
462            this->showOverlays_ = true;
463            if (!this->controlPaused_)
464            {
465                this->showOverlays();
466                this->alignArrows();
467            }
468        }
469        else
470        {
471            this->showOverlays_ = false;
472            this->hideOverlays();
473        }
474    }
475
476    void NewHumanController::accelerate()
477    {
478        if (NewHumanController::localController_s)
479            NewHumanController::localController_s->acceleration_ = clamp(NewHumanController::localController_s->acceleration_ + 0.2f, 0.00f, 1.0f);
480    }
481
482    void NewHumanController::decelerate()
483    {
484        if (NewHumanController::localController_s)
485            NewHumanController::localController_s->acceleration_ = clamp(NewHumanController::localController_s->acceleration_ - 0.1f, 0.0f, 1.0f);
486    }
487
488    void NewHumanController::doResumeControl()
489    {
490        this->controlPaused_ = false;
491        if (this->showOverlays_)
492            this->showOverlays();
493    }
494
495    void NewHumanController::doPauseControl()
496    {
497        this->controlPaused_ = true;
498        this->hideOverlays();
499    }
500
501    void NewHumanController::alignArrows()
502    {
503        if (showArrows_)
504        {
505            hideArrows();
506
507            float distance = sqrt(pow(static_cast<float>(this->currentYaw_)/2*-1,2) + pow(static_cast<float>(this->currentPitch_)/2*-1,2));
508
509            if (distance > 0.04f && distance <= 0.59f * arrowsSize_ / 2.0f )
510            {
511                this->arrowsOverlay1_->setRotation(Degree(-90 + -1.0f * atan2(static_cast<float>(this->currentPitch_)/2*-1, static_cast<float>(this->currentYaw_)/2*-1) / (2.0f * Ogre::Math::PI) * 360.0f));
512                this->arrowsOverlay1_->show();
513            }
514            else if (distance > 0.59f * arrowsSize_ / 2.0f && distance <= 0.77f * arrowsSize_ / 2.0f )
515            {
516                this->arrowsOverlay2_->setRotation(Degree(-90 + -1.0f * atan2(static_cast<float>(this->currentPitch_)/2*-1, static_cast<float>(this->currentYaw_)/2*-1) / (2.0f * Ogre::Math::PI) * 360.0f));
517                this->arrowsOverlay2_->show();
518            }
519            else if (distance > 0.77f * arrowsSize_ / 2.0f && distance <= arrowsSize_ / 2.0f)
520            {
521                this->arrowsOverlay3_->setRotation(Degree(-90 + -1.0f * atan2(static_cast<float>(this->currentPitch_)/2*-1, static_cast<float>(this->currentYaw_)/2*-1) / (2.0f * Ogre::Math::PI) * 360.0f));
522                this->arrowsOverlay3_->show();
523            }
524            else if (distance > arrowsSize_ / 2.0f)
525            {
526                this->arrowsOverlay4_->setRotation(Degree(-90 + -1.0f * atan2(static_cast<float>(this->currentPitch_)/2*-1, static_cast<float>(this->currentYaw_)/2*-1) / (2.0f * Ogre::Math::PI) * 360.0f));
527                this->arrowsOverlay4_->show();
528            }
529        }
530    }
531
532    void NewHumanController::showOverlays()
533    {
534        if (!GameMode::showsGraphics())
535            return;
536        this->crossHairOverlay_->show();
537        this->centerOverlay_->show();
538
539        if (showArrows_)
540        {
541            this->arrowsOverlay1_->show();
542            this->arrowsOverlay2_->show();
543            this->arrowsOverlay3_->show();
544            this->arrowsOverlay4_->show();
545        }
546    }
547
548    void NewHumanController::hideOverlays()
549    {
550        if (!GameMode::showsGraphics())
551            return;
552        this->crossHairOverlay_->hide();
553        this->centerOverlay_->hide();
554
555        if (showDamageOverlay_)
556        {
557            this->damageOverlayTop_->hide();
558            this->damageOverlayRight_->hide();
559            this->damageOverlayBottom_->hide();
560            this->damageOverlayLeft_->hide();
561        }
562
563        this->hideArrows();
564    }
565
566    void NewHumanController::hideArrows()
567    {
568        if(!GameMode::showsGraphics())
569            return;
570        if (showArrows_)
571        {
572            this->arrowsOverlay1_->hide();
573            this->arrowsOverlay2_->hide();
574            this->arrowsOverlay3_->hide();
575            this->arrowsOverlay4_->hide();
576        }
577    }
578}
Note: See TracBrowser for help on using the repository browser.