Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentationFS14/src/orxonox/worldentities/pawns/SpaceShip.cc @ 10214

Last change on this file since 10214 was 10214, checked in by landauf, 9 years ago

fixed segfault. after removing the engine from the ship, we need to destroy it. otherwise the engine remains in the object lists and will be destroyed at the end of the game - but at this point the ship may not exist anymore, leading to a crash.

  • Property svn:eol-style set to native
File size: 17.5 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_(NULL)
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_ = 5.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::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    void SpaceShip::registerVariables()
120    {
121        registerVariable(this->rotationThrust_, VariableDirection::ToClient);
122        registerVariable(this->boostPower_, VariableDirection::ToClient);
123        registerVariable(this->boostPowerRate_, VariableDirection::ToClient);
124        registerVariable(this->boostRate_, VariableDirection::ToClient);
125        registerVariable(this->boostCooldownDuration_, VariableDirection::ToClient);
126        registerVariable(this->shakeFrequency_, VariableDirection::ToClient);
127        registerVariable(this->shakeAmplitude_, VariableDirection::ToClient);
128        registerVariable(this->lift_, VariableDirection::ToClient);
129        registerVariable(this->stallSpeed_, VariableDirection::ToClient);
130    }
131
132    void SpaceShip::setConfigValues()
133    {
134        SetConfigValue(bInvertYAxis_, false).description("Set this to true for joystick-like mouse behaviour (mouse up = ship down).");
135
136        SetConfigValueExternal(bEnableMotionBlur_, "GraphicsSettings", "enableMotionBlur", true)
137            .description("Enable or disable the motion blur effect when moving very fast")
138            .callback(this, &SpaceShip::changedEnableMotionBlur);
139        SetConfigValueExternal(blurStrength_, "GraphicsSettings", "blurStrength", 3.0f)
140            .description("Defines the strength of the motion blur effect");
141    }
142
143    bool SpaceShip::isCollisionTypeLegal(WorldEntity::CollisionType type) const
144    {
145        if (type != WorldEntity::Dynamic)
146        {
147            orxout(internal_warning) << "Cannot tell a SpaceShip not to be dynamic! Ignoring." << endl;
148            assert(false); // Only in debug mode
149            return false;
150        }
151        else
152            return true;
153    }
154
155    void SpaceShip::tick(float dt)
156    {
157        SUPER(SpaceShip, tick, dt);
158
159        // Run the engines
160        for(std::vector<Engine*>::iterator it = this->engineList_.begin(); it != this->engineList_.end(); it++)
161            (*it)->run(dt);
162
163        if (this->hasLocalController())
164        {
165            // If not in mouse look apply the angular movement to the ship.
166            if (!this->isInMouseLook())
167            {
168                this->localAngularAcceleration_ *= this->getLocalInertia() * this->rotationThrust_;
169                this->physicalBody_->applyTorque(physicalBody_->getWorldTransform().getBasis() * this->localAngularAcceleration_);
170            }
171            this->localAngularAcceleration_.setValue(0, 0, 0);
172
173            // If not in boost cooldown, the boost power is recharged up to the initial boost power.
174            if(!this->isBoostCoolingDown() && this->boostPower_ < this->initialBoostPower_)
175            {
176                this->boostPower_ += this->boostPowerRate_*dt;
177            }
178            // If boosting
179            if(this->isBoosting())
180            {
181                // Discount the used power
182                this->boostPower_ -= this->boostRate_*dt;
183                // If the power has been used up boosting is stopped and boost cooldown is initiated.
184                if(this->boostPower_ <= 0.0f)
185                {
186                    this->boost(false);
187                    this->bBoostCooldown_ = true;
188                    this->timer_.setTimer(this->boostCooldownDuration_, false, createExecutor(createFunctor(&SpaceShip::boostCooledDown, this)));
189                }
190
191                // Shake the camera because of the boosting.
192                this->shakeCamera(dt);
193            }
194
195            // Enable Blur depending on settings
196            if(this->bEnableMotionBlur_)
197            {
198                if (this->boostBlur_ == NULL && this->hasLocalController() && this->hasHumanController())
199                {
200                    this->boostBlur_ = new Shader(this->getScene()->getSceneManager());
201                    this->boostBlur_->setCompositorName("Radial Blur");
202                }
203                if (this->boostBlur_)
204                {
205                    float blur = this->blurStrength_ * clamp(-this->getLocalVelocity().z/(this->getMaxSpeedFront()*this->getBoostFactor()), 0.0f, 1.0f);
206
207                    // Show and hide blur effect depending on state of booster
208                    if(this->isBoosting())
209                        this->boostBlur_->setVisible(blur > 0.0f);
210                    else
211                        this->boostBlur_->setVisible(false);
212
213                    this->boostBlur_->setParameter(0, 0, "sampleStrength", blur);
214                }
215            }
216        }
217
218        this->steering_ = Vector3::ZERO;
219    }
220
221    /**
222    @brief
223        Rotate in yaw direction.
224        Due to added lift, can also lead to an additional right-left motion.
225    @param value
226        A vector whose first component specifies the magnitude of the rotation. Positive means yaw left, negative means yaw right.
227    */
228    void SpaceShip::rotateYaw(const Vector2& value)
229    {
230        this->localAngularAcceleration_.setY(this->localAngularAcceleration_.y() + value.x);
231
232        Pawn::rotateYaw(value);
233
234        // This function call adds a lift to the ship when it is rotating to make it's movement more "realistic" and enhance the feeling.
235        if (this->getLocalVelocity().z < 0 && abs(this->getLocalVelocity().z) < stallSpeed_)
236            this->moveRightLeft(-lift_ / 5.0f * value * sqrt(abs(this->getLocalVelocity().z)));
237    }
238
239    /**
240    @brief
241        Rotate in pitch direction.
242        Due to added left, can also lead to an additional up-down motion.
243    @param value
244        A vector whose first component specifies the magnitude of the rotation. Positive means pitch up, negative means pitch down.
245    */
246    void SpaceShip::rotatePitch(const Vector2& value)
247    {
248        Vector2 pitch = value;
249        if(this->bInvertYAxis_)
250            pitch.x = -pitch.x;
251
252        this->localAngularAcceleration_.setX(this->localAngularAcceleration_.x() + pitch.x*0.8f);
253
254        Pawn::rotatePitch(pitch);
255
256        // This function call adds a lift to the ship when it is pitching to make it's movement more "realistic" and enhance the feeling.
257        if (this->getLocalVelocity().z < 0 && abs(this->getLocalVelocity().z) < stallSpeed_)
258            this->moveUpDown(lift_ / 5.0f * pitch * sqrt(abs(this->getLocalVelocity().z)));
259    }
260
261    /**
262    @brief
263        Rotate in roll direction.
264    @param value
265        A vector whose first component specifies the magnitude of the rotation. Positive means roll left, negative means roll right.
266    */
267    void SpaceShip::rotateRoll(const Vector2& value)
268    {
269        this->localAngularAcceleration_.setZ(this->localAngularAcceleration_.z() + value.x);
270
271        Pawn::rotateRoll(value);
272    }
273
274    void SpaceShip::fire()
275    {
276    }
277
278    /**
279    @brief
280        Starts or stops boosting.
281    @param bBoost
282        Whether to start or stop boosting.
283    */
284    void SpaceShip::boost(bool bBoost)
285    {
286        // Can only boost if not cooling down.
287        if(bBoost && !this->isBoostCoolingDown())
288        {
289            this->bBoost_ = true;
290            this->backupCamera();
291        }
292        // Stop boosting.
293        if(!bBoost)
294        {
295            this->bBoost_ = false;
296            this->resetCamera();
297        }
298    }
299    /**
300    @brief
301        Add an Engine to the SpaceShip.
302    @param engine
303        A pointer to the Engine to be added.
304    */
305    void SpaceShip::addEngine(orxonox::Engine* engine)
306    {
307        OrxAssert(engine != NULL, "The engine cannot be NULL.");
308        this->engineList_.push_back(engine);
309        engine->addToSpaceShip(this);
310    }
311
312    /**
313    @brief
314        Check whether the SpaceShip has a particular Engine.
315    @param engine
316        A pointer to the Engine to be checked.
317    */
318    bool SpaceShip::hasEngine(Engine* engine) const
319    {
320        for(unsigned int i = 0; i < this->engineList_.size(); i++)
321        {
322            if(this->engineList_[i] == engine)
323                return true;
324        }
325        return false;
326    }
327
328    /**
329    @brief
330        Get the i-th Engine of the SpaceShip.
331    @return
332        Returns a pointer to the i-the Engine. NULL if there is no Engine with that index.
333    */
334    Engine* SpaceShip::getEngine(unsigned int i)
335    {
336        if(this->engineList_.size() >= i)
337            return NULL;
338        else
339            return this->engineList_[i];
340    }
341
342    /**
343    @brief
344        Looks for an attached Engine with a certain name.
345    @param name
346        The name of the engine to be returned.
347    @return
348        Pointer to the engine with the given name, or NULL if not found.
349    */
350    Engine* SpaceShip::getEngineByName(const std::string& name)
351    {
352        for(size_t i = 0; i < this->engineList_.size(); ++i)
353            if(this->engineList_[i]->getName() == name)
354                return this->engineList_[i];
355
356        orxout(internal_warning) << "Couldn't find Engine with name \"" << name << "\"." << endl;
357        return NULL;
358    }
359
360    /**
361    @brief
362        Remove and destroy all Engines of the SpaceShip.
363    */
364    void SpaceShip::removeAllEngines()
365    {
366        while(this->engineList_.size())
367            this->engineList_.back()->destroy();
368    }
369
370    /**
371    @brief
372        Remove a particular Engine from the SpaceShip.
373    @param engine
374        A pointer to the Engine to be removed.
375    @note
376        Don't forget to reset the Engine's ship pointer after it was removed (or destroy the engine).
377    */
378    void SpaceShip::removeEngine(Engine* engine)
379    {
380        for(std::vector<Engine*>::iterator it = this->engineList_.begin(); it != this->engineList_.end(); ++it)
381        {
382            if(*it == engine)
383            {
384                this->engineList_.erase(it);
385                return;
386            }
387        }
388    }
389
390    /**
391    @brief
392        Add to the speed factor for all engines of the SpaceShip.
393    @param factor
394        The factor to be added.
395    */
396    void SpaceShip::addSpeedFactor(float factor)
397    {
398        for(unsigned int i=0; i<this->engineList_.size(); i++)
399            this->engineList_[i]->addSpeedMultiply(factor);
400    }
401
402    /**
403    @brief
404        Add to the speed factor for all engines of the SpaceShip.
405    @param speed
406        The speed to be added.
407    */
408    void SpaceShip::addSpeed(float speed)
409    {
410        for(unsigned int i=0; i<this->engineList_.size(); i++)
411            this->engineList_[i]->addSpeedAdd(speed);
412    }
413
414    /**
415    @brief
416        Get the mean speed factor over all engines of the SpaceShip.
417    @return
418        Returns the mean speed factor over all engines of the SpaceShip.
419    */
420    float SpaceShip::getSpeedFactor() const
421    {
422        float sum = 0;
423        unsigned int i = 0;
424        for(; i<this->engineList_.size(); i++)
425            sum += this->engineList_[i]->getSpeedMultiply();
426        return sum/float(i);
427    }
428
429    /**
430    @brief
431        Get the largest maximal forward speed over all engines of the SpaceShip.
432    @return
433        Returns the largest forward speed over all engines of the SpaceShip.
434    */
435    float SpaceShip::getMaxSpeedFront() const
436    {
437        float speed=0;
438        for(unsigned int i=0; i<this->engineList_.size(); i++)
439        {
440            if(this->engineList_[i]->getMaxSpeedFront() > speed)
441                speed = this->engineList_[i]->getMaxSpeedFront();
442        }
443        return speed;
444    }
445
446    /**
447    @brief
448        Get the mean boost factor over all engines of the SpaceShip.
449    @return
450        Returns the mean boost factor over all engines of the SpaceShip.
451    */
452    float SpaceShip::getBoostFactor() const
453    {
454        float sum = 0;
455        unsigned int i=0;
456        for(; i<this->engineList_.size(); i++)
457            sum += this->engineList_[i]->getBoostFactor();
458        return sum/float(i);
459    }
460
461    /**
462    @brief
463        Is called when the enableMotionBlur config value has changed.
464    */
465    void SpaceShip::changedEnableMotionBlur()
466    {
467        if (!this->bEnableMotionBlur_ && this->boostBlur_ != NULL)
468        {
469            delete this->boostBlur_;
470            this->boostBlur_ = NULL;
471        }
472    }
473
474    /**
475    @brief
476        Shake the camera for a given time interval.
477    @param dt
478        The time interval in seconds.
479    */
480    void SpaceShip::shakeCamera(float dt)
481    {
482        // Make sure the ship is only shaking if it's moving forward and above the maximal forward speed.
483        if (-this->getLocalVelocity().z > this->getMaxSpeedFront())
484        {
485            this->shakeDt_ += dt;
486
487            float frequency = this->shakeFrequency_ * (square(abs(this->getLocalVelocity().z)));
488
489            if (this->shakeDt_ >= 1.0f/frequency)
490                this->shakeDt_ -= 1.0f/frequency;
491
492            Degree angle = Degree(sin(this->shakeDt_ * math::twoPi * frequency) * this->shakeAmplitude_);
493
494            Camera* camera = this->getCamera();
495            //Shaking Camera effect
496            if (camera != 0)
497                camera->setOrientation(Vector3::UNIT_X, angle);
498
499        }
500        // If the camera is no shaking, reset it.
501        else
502            this->resetCamera();
503    }
504
505    /**
506    @brief
507        Save the original position and orientation of the camera.
508    */
509    void SpaceShip::backupCamera()
510    {
511        Camera* camera = CameraManager::getInstance().getActiveCamera();
512        if(camera != NULL)
513        {
514            this->cameraOriginalPosition_ = camera->getPosition();
515            this->cameraOriginalOrientation_ = camera->getOrientation();
516        }
517    }
518
519    /**
520    @brief
521        Reset the camera to its original position.
522    */
523    void SpaceShip::resetCamera()
524    {
525        if(this->hasLocalController() && this->hasHumanController())
526        {
527            Camera *camera = this->getCamera();
528            if (camera == 0)
529            {
530                orxout(internal_warning) << "Failed to reset camera!" << endl;
531                return;
532            }
533            this->shakeDt_ = 0.0f;
534            camera->setPosition(this->cameraOriginalPosition_);
535            camera->setOrientation(this->cameraOriginalOrientation_);
536        }
537    }
538
539}
Note: See TracBrowser for help on using the repository browser.