Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/worldentities/pawns/SpaceShip.cc @ 12253

Last change on this file since 12253 was 12029, checked in by merholzl, 6 years ago

added space race improvements

  • Property svn:eol-style set to native
File size: 17.9 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 *      ...
26 *
27 */
28
29#include "SpaceShip.h"
30
31#include <BulletDynamics/Dynamics/btRigidBody.h>
32
33#include "core/CoreIncludes.h"
34#include "core/config/ConfigValueIncludes.h"
35#include "core/Template.h"
36#include "core/XMLPort.h"
37#include "tools/Shader.h"
38#include "util/Math.h"
39
40#include "graphics/Camera.h"
41#include "items/Engine.h"
42
43#include "CameraManager.h"
44#include "Scene.h"
45
46namespace orxonox
47{
48    RegisterClass(SpaceShip);
49
50    SpaceShip::SpaceShip(Context* context) : Pawn(context), boostBlur_(nullptr)
51    {
52        RegisterObject(SpaceShip);
53
54        this->bInvertYAxis_ = false;
55
56        this->steering_ = Vector3::ZERO;
57
58        this->rotationThrust_ =  10;
59        this->localAngularAcceleration_.setValue(0, 0, 0);
60
61        this->bBoost_ = false;
62        this->bBoostCooldown_ = false;
63        this->initialBoostPower_ = 10.0f;
64        this->boostPower_ = 10.0f;
65        this->boostPowerRate_ = 1.0f;
66        this->boostRate_ = 5.0f;
67        this->boostCooldownDuration_ = 10.0f;
68
69        this->shakeFrequency_ = 15.0f;
70        this->shakeAmplitude_ = 5.0f;
71        this->shakeDt_ = 0.0f;
72        this->cameraOriginalPosition_ = Vector3::UNIT_SCALE;
73        this->cameraOriginalOrientation_ = Quaternion::IDENTITY;
74
75        this->lift_ = 1.0f;
76        this->stallSpeed_ = 220.0f;
77
78        this->setDestroyWhenPlayerLeft(true);
79
80        // SpaceShip is always a physical object per default
81        // Be aware of this call: The collision type legality check will not reach derived classes!
82        this->setCollisionType(WorldEntity::CollisionType::Dynamic);
83        // Get notification about collisions
84        this->enableCollisionCallback();
85
86        this->setConfigValues();
87        this->registerVariables();
88
89    }
90
91    SpaceShip::~SpaceShip()
92    {
93        if (this->isInitialized())
94        {
95            this->removeAllEngines();
96
97            if (this->boostBlur_)
98                delete this->boostBlur_;
99        }
100    }
101
102    void SpaceShip::XMLPort(Element& xmlelement, XMLPort::Mode mode)
103    {
104        SUPER(SpaceShip, XMLPort, xmlelement, mode);
105
106        XMLPortParamVariable(SpaceShip, "rotationThrust", rotationThrust_, xmlelement, mode);
107        XMLPortParam(SpaceShip, "boostPower", setInitialBoostPower, getInitialBoostPower, xmlelement, mode);
108        XMLPortParam(SpaceShip, "boostPowerRate", setBoostPowerRate, getBoostPowerRate, xmlelement, mode);
109        XMLPortParam(SpaceShip, "boostRate", setBoostRate, getBoostRate, xmlelement, mode);
110        XMLPortParam(SpaceShip, "boostCooldownDuration", setBoostCooldownDuration, getBoostCooldownDuration, xmlelement, mode);
111        XMLPortParam(SpaceShip, "shakeFrequency", setShakeFrequency, getShakeFrequency, xmlelement, mode);
112        XMLPortParam(SpaceShip, "shakeAmplitude", setShakeAmplitude, getShakeAmplitude, xmlelement, mode);
113        XMLPortParamVariable(SpaceShip, "lift", lift_, xmlelement, mode);
114        XMLPortParamVariable(SpaceShip, "stallSpeed", stallSpeed_, xmlelement, mode);
115
116        XMLPortObject(SpaceShip, Engine, "engines", addEngine, getEngine, xmlelement, mode);
117
118       
119    }
120
121    void SpaceShip::registerVariables()
122    {
123        registerVariable(this->rotationThrust_, VariableDirection::ToClient);
124        registerVariable(this->boostPower_, VariableDirection::ToClient);
125        registerVariable(this->boostPowerRate_, VariableDirection::ToClient);
126        registerVariable(this->boostRate_, VariableDirection::ToClient);
127        registerVariable(this->boostCooldownDuration_, VariableDirection::ToClient);
128        registerVariable(this->shakeFrequency_, VariableDirection::ToClient);
129        registerVariable(this->shakeAmplitude_, VariableDirection::ToClient);
130        registerVariable(this->lift_, VariableDirection::ToClient);
131        registerVariable(this->stallSpeed_, VariableDirection::ToClient);
132    }
133
134    void SpaceShip::setConfigValues()
135    {
136        SetConfigValue(bInvertYAxis_, false).description("Set this to true for joystick-like mouse behaviour (mouse up = ship down).");
137
138        SetConfigValueExternal(bEnableMotionBlur_, "GraphicsSettings", "enableMotionBlur", true)
139            .description("Enable or disable the motion blur effect when moving very fast")
140            .callback(this, &SpaceShip::changedEnableMotionBlur);
141        SetConfigValueExternal(blurStrength_, "GraphicsSettings", "blurStrength", 3.0f)
142            .description("Defines the strength of the motion blur effect");
143    }
144
145    bool SpaceShip::isCollisionTypeLegal(WorldEntity::CollisionType type) const
146    {
147        if (type != WorldEntity::CollisionType::Dynamic)
148        {
149            orxout(internal_warning) << "Cannot tell a SpaceShip not to be dynamic! Ignoring." << endl;
150            assert(false); // Only in debug mode
151            return false;
152        }
153        else
154            return true;
155    }
156
157    void SpaceShip::tick(float dt)
158    {
159        SUPER(SpaceShip, tick, dt);
160
161        // Run the engines
162        for(Engine* engine : this->engineList_)
163            engine->run(dt);
164
165        if (this->hasLocalController() || true)
166        {
167            // If not in mouse look apply the angular movement to the ship.
168            if (!this->isInMouseLook())
169            {
170                this->localAngularAcceleration_ *= this->getLocalInertia() * this->rotationThrust_;
171                this->physicalBody_->applyTorque(physicalBody_->getWorldTransform().getBasis() * this->localAngularAcceleration_);
172            }
173            this->localAngularAcceleration_.setValue(0, 0, 0);
174
175            // If not in boost cooldown, the boost power is recharged up to the initial boost power.
176            if(!this->isBoostCoolingDown() && this->boostPower_ < this->initialBoostPower_)
177            {
178                this->boostPower_ += this->boostPowerRate_*dt;
179            }
180            // If boosting
181            if(this->isBoosting())
182            {
183                // Discount the used power
184                this->boostPower_ -= this->boostRate_*dt;
185                // If the power has been used up boosting is stopped and boost cooldown is initiated.
186                if(this->boostPower_ <= 0.0f)
187                {
188                    this->boost(false);
189                    this->bBoostCooldown_ = true;
190                    this->timer_.setTimer(this->boostCooldownDuration_, false, createExecutor(createFunctor(&SpaceShip::boostCooledDown, this)));
191                }
192
193                // Shake the camera because of the boosting.
194                this->shakeCamera(dt);
195            }
196
197            // Enable Blur depending on settings
198            if(this->bEnableMotionBlur_)
199            {
200                if (this->boostBlur_ == nullptr && this->hasLocalController() && this->hasHumanController())
201                {
202                    this->boostBlur_ = new Shader(this->getScene()->getSceneManager());
203                    this->boostBlur_->setCompositorName("Radial Blur");
204                }
205                if (this->boostBlur_)
206                {
207                    float blur = this->blurStrength_ * clamp(-this->getLocalVelocity().z/(this->getMaxSpeedFront()*this->getBoostFactor()), 0.0f, 1.0f);
208
209                    // Show and hide blur effect depending on state of booster
210                    if(this->isBoosting())
211                        this->boostBlur_->setVisible(blur > 0.0f);
212                    else
213                        this->boostBlur_->setVisible(false);
214
215                    this->boostBlur_->setParameter(0, 0, "sampleStrength", blur);
216                }
217            }
218        }
219
220        this->steering_ = Vector3::ZERO;
221    }
222
223    /**
224    @brief
225        Rotate in yaw direction.
226        Due to added lift, can also lead to an additional right-left motion.
227    @param value
228        A vector whose first component specifies the magnitude of the rotation. Positive means yaw left, negative means yaw right.
229    */
230    void SpaceShip::rotateYaw(const Vector2& value)
231    {
232        this->localAngularAcceleration_.setY(this->localAngularAcceleration_.y() + value.x);
233
234        Pawn::rotateYaw(value);
235
236        // This function call adds a lift to the ship when it is rotating to make it's movement more "realistic" and enhance the feeling.
237        if (this->getLocalVelocity().z < 0 && std::abs(this->getLocalVelocity().z) < stallSpeed_)
238            this->moveRightLeft(-lift_ / 5.0f * value * sqrt(std::abs(this->getLocalVelocity().z)));
239    }
240
241    /**
242    @brief
243        Rotate in pitch direction.
244        Due to added left, can also lead to an additional up-down motion.
245    @param value
246        A vector whose first component specifies the magnitude of the rotation. Positive means pitch up, negative means pitch down.
247    */
248    void SpaceShip::rotatePitch(const Vector2& value)
249    {
250        Vector2 pitch = value;
251        if(this->bInvertYAxis_)
252            pitch.x = -pitch.x;
253
254        this->localAngularAcceleration_.setX(this->localAngularAcceleration_.x() + pitch.x*0.8f);
255
256        Pawn::rotatePitch(pitch);
257
258        // This function call adds a lift to the ship when it is pitching to make it's movement more "realistic" and enhance the feeling.
259        if (this->getLocalVelocity().z < 0 && std::abs(this->getLocalVelocity().z) < stallSpeed_)
260            this->moveUpDown(lift_ / 5.0f * pitch * sqrt(std::abs(this->getLocalVelocity().z)));
261    }
262
263    /**
264    @brief
265        Rotate in roll direction.
266    @param value
267        A vector whose first component specifies the magnitude of the rotation. Positive means roll left, negative means roll right.
268    */
269    void SpaceShip::rotateRoll(const Vector2& value)
270    {
271        this->localAngularAcceleration_.setZ(this->localAngularAcceleration_.z() + value.x);
272
273        Pawn::rotateRoll(value);
274    }
275
276    void SpaceShip::fire()
277    {
278    }
279
280    /**
281    @brief
282        Starts or stops boosting.
283    @param bBoost
284        Whether to start or stop boosting.
285    */
286    void SpaceShip::boost(bool bBoost)
287    {
288        // Can only boost if not cooling down.
289        if(bBoost && !this->isBoostCoolingDown())
290        {
291            this->bBoost_ = true;
292            this->backupCamera();
293        }
294        // Stop boosting.
295        if(!bBoost)
296        {
297            this->bBoost_ = false;
298            this->resetCamera();
299        }
300    }
301
302    void SpaceShip::gainBoostPower(float gainedBoostPower)
303    {
304        this->boostPower_ += gainedBoostPower;
305       
306        if (this->boostPower_ > this->initialBoostPower_)
307        {
308            this->boostPower_ = this->initialBoostPower_;
309        }
310
311        // If the booster is in cooldown mode and we gained boost power, the abort the cooldown.
312        if (this->isBoostCoolingDown() && this->boostPower_ > 0.0f)
313        {
314            timer_.stopTimer();
315            this->boostCooledDown();
316        }
317    }
318
319    /**
320    @brief
321        Add an Engine to the SpaceShip.
322    @param engine
323        A pointer to the Engine to be added.
324    */
325    void SpaceShip::addEngine(orxonox::Engine* engine)
326    {
327        OrxAssert(engine != nullptr, "The engine cannot be nullptr.");
328        this->engineList_.push_back(engine);
329        engine->addToSpaceShip(this);
330    }
331
332    /**
333    @brief
334        Check whether the SpaceShip has a particular Engine.
335    @param search
336        A pointer to the Engine to be checked.
337    */
338    bool SpaceShip::hasEngine(Engine* search) const
339    {
340        for(Engine* engine : this->engineList_)
341        {
342            if(engine == search)
343                return true;
344        }
345        return false;
346    }
347
348    /**
349    @brief
350        Get the i-th Engine of the SpaceShip.
351    @return
352        Returns a pointer to the i-the Engine. nullptr if there is no Engine with that index.
353    */
354    Engine* SpaceShip::getEngine(unsigned int i)
355    {
356        if(this->engineList_.size() >= i)
357            return nullptr;
358        else
359            return this->engineList_[i];
360    }
361
362    /**
363    @brief
364        Looks for an attached Engine with a certain name.
365    @param name
366        The name of the engine to be returned.
367    @return
368        Pointer to the engine with the given name, or nullptr if not found.
369    */
370    Engine* SpaceShip::getEngineByName(const std::string& name)
371    {
372        for(Engine* engine : this->engineList_)
373            if(engine->getName() == name)
374                return engine;
375
376        orxout(internal_warning) << "Couldn't find Engine with name \"" << name << "\"." << endl;
377        return nullptr;
378    }
379
380    /**
381    @brief
382        Remove and destroy all Engines of the SpaceShip.
383    */
384    void SpaceShip::removeAllEngines()
385    {
386        while(this->engineList_.size())
387            this->engineList_.back()->destroy();
388    }
389
390    /**
391    @brief
392        Remove a particular Engine from the SpaceShip.
393    @param engine
394        A pointer to the Engine to be removed.
395    @note
396        Don't forget to reset the Engine's ship pointer after it was removed (or destroy the engine).
397    */
398    void SpaceShip::removeEngine(Engine* engine)
399    {
400        for(std::vector<Engine*>::iterator it = this->engineList_.begin(); it != this->engineList_.end(); ++it)
401        {
402            if(*it == engine)
403            {
404                this->engineList_.erase(it);
405                return;
406            }
407        }
408    }
409
410    /**
411    @brief
412        Add to the speed factor for all engines of the SpaceShip.
413    @param factor
414        The factor to be added.
415    */
416    void SpaceShip::addSpeedFactor(float factor)
417    {
418        for(Engine* engine : this->engineList_)
419            engine->addSpeedMultiply(factor);
420    }
421
422    /**
423    @brief
424        Add to the speed factor for all engines of the SpaceShip.
425    @param speed
426        The speed to be added.
427    */
428    void SpaceShip::addSpeed(float speed)
429    {
430        for(Engine* engine : this->engineList_)
431            engine->addSpeedAdd(speed);
432    }
433
434    /**
435    @brief
436        Get the mean speed factor over all engines of the SpaceShip.
437    @return
438        Returns the mean speed factor over all engines of the SpaceShip.
439    */
440    float SpaceShip::getSpeedFactor() const
441    {
442        float sum = 0;
443        unsigned int i = 0;
444        for(; i<this->engineList_.size(); i++)
445            sum += this->engineList_[i]->getSpeedMultiply();
446        return sum/float(i);
447    }
448
449    /**
450    @brief
451        Get the largest maximal forward speed over all engines of the SpaceShip.
452    @return
453        Returns the largest forward speed over all engines of the SpaceShip.
454    */
455    float SpaceShip::getMaxSpeedFront() const
456    {
457        float speed=0;
458        for(Engine* engine : this->engineList_)
459        {
460            if(engine->getMaxSpeedFront() > speed)
461                speed = engine->getMaxSpeedFront();
462        }
463        return speed;
464    }
465
466    /**
467    @brief
468        Get the mean boost factor over all engines of the SpaceShip.
469    @return
470        Returns the mean boost factor over all engines of the SpaceShip.
471    */
472    float SpaceShip::getBoostFactor() const
473    {
474        float sum = 0;
475        unsigned int i=0;
476        for(; i<this->engineList_.size(); i++)
477            sum += this->engineList_[i]->getBoostFactor();
478        return sum/float(i);
479    }
480
481    /**
482    @brief
483        Is called when the enableMotionBlur config value has changed.
484    */
485    void SpaceShip::changedEnableMotionBlur()
486    {
487        if (!this->bEnableMotionBlur_ && this->boostBlur_ != nullptr)
488        {
489            delete this->boostBlur_;
490            this->boostBlur_ = nullptr;
491        }
492    }
493
494    /**
495    @brief
496        Shake the camera for a given time interval.
497    @param dt
498        The time interval in seconds.
499    */
500    void SpaceShip::shakeCamera(float dt)
501    {
502        // Make sure the ship is only shaking if it's moving forward and above the maximal forward speed.
503        if (-this->getLocalVelocity().z > this->getMaxSpeedFront())
504        {
505            this->shakeDt_ += dt;
506
507            float frequency = this->shakeFrequency_ * (square(std::abs(this->getLocalVelocity().z)));
508
509            if (this->shakeDt_ >= 1.0f/frequency)
510                this->shakeDt_ -= 1.0f/frequency;
511
512            Degree angle = Degree(sin(this->shakeDt_ * math::twoPi * frequency) * this->shakeAmplitude_);
513
514            Camera* camera = this->getCamera();
515            //Shaking Camera effect
516            if (camera != nullptr)
517                camera->setOrientation(Vector3::UNIT_X, angle);
518
519        }
520        // If the camera is no shaking, reset it.
521        else
522            this->resetCamera();
523    }
524
525    /**
526    @brief
527        Save the original position and orientation of the camera.
528    */
529    void SpaceShip::backupCamera()
530    {
531        Camera* camera = CameraManager::getInstance().getActiveCamera();
532        if(camera != nullptr)
533        {
534            this->cameraOriginalPosition_ = camera->getPosition();
535            this->cameraOriginalOrientation_ = camera->getOrientation();
536        }
537    }
538
539    /**
540    @brief
541        Reset the camera to its original position.
542    */
543    void SpaceShip::resetCamera()
544    {
545        if(this->hasLocalController() && this->hasHumanController())
546        {
547            Camera *camera = this->getCamera();
548            if (camera == nullptr)
549            {
550                orxout(internal_warning) << "Failed to reset camera!" << endl;
551                return;
552            }
553            this->shakeDt_ = 0.0f;
554            camera->setPosition(this->cameraOriginalPosition_);
555            camera->setOrientation(this->cameraOriginalOrientation_);
556        }
557    }
558
559}
Note: See TracBrowser for help on using the repository browser.