Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/modules/objects/SpaceBoundaries.cc @ 10917

Last change on this file since 10917 was 10916, checked in by landauf, 10 years ago

use actual types instead of 'auto'. only exception is for complicated template types, e.g. when iterating over a map

  • Property svn:eol-style set to native
File size: 10.8 KB
RevLine 
[8087]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 *      Maurus Kaufmann
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "SpaceBoundaries.h"
30
[8632]31#include <OgreBillboardSet.h>
32
33#include "core/CoreIncludes.h"
[9667]34#include "core/object/ObjectListIterator.h"
[8201]35#include "core/XMLPort.h"
[8632]36
37#include "graphics/Billboard.h"
38#include "infos/PlayerInfo.h"
39#include "worldentities/WorldEntity.h"
[8201]40#include "worldentities/pawns/Pawn.h"
[8087]41
42namespace orxonox
43{
[9667]44    RegisterClass(SpaceBoundaries);
[8087]45
[9667]46    SpaceBoundaries::SpaceBoundaries(Context* context) : StaticEntity(context)
[8087]47    {
[8614]48        RegisterObject(SpaceBoundaries);
49
[8201]50        this->setMaxDistance(3000);
[8614]51        this->setWarnDistance(this->getMaxDistance());
52        this->setShowDistance(this->getMaxDistance());
[8404]53        this->setReaction(0);
[8087]54    }
55    SpaceBoundaries::~SpaceBoundaries()
56    {
[8470]57        if (this->isInitialized())
58        {
59            this->pawnsIn_.clear();
[8767]60
[10916]61            for(BillboardAdministration& billboard : this->billboards_)
[8301]62            {
[10916]63                if( billboard.billy != nullptr)
[8470]64                {
[10916]65                    delete billboard.billy;
[8470]66                }
[8301]67            }
[8470]68            this->billboards_.clear();
[8301]69        }
[8087]70    }
[8767]71
[8281]72    void SpaceBoundaries::checkWhoIsIn()
73    {
74        pawnsIn_.clear();
[9667]75        for(ObjectList<Pawn>::iterator current = ObjectList<Pawn>::begin(); current != ObjectList<Pawn>::end(); ++current)
[8281]76        {
77            Pawn* currentPawn = *current;
[8614]78            if( this->reaction_ == 0 )
[8281]79            {
[8614]80                float distance = this->computeDistance(currentPawn);
81                if(distance <= this->maxDistance_)
82                {
83                    pawnsIn_.push_back(currentPawn);
84                }
85            } else if (this->reaction_ == 2) {
86                float distance = this->computeDistance(currentPawn);
87                if(distance >= this->maxDistance_)
88                {
89                    pawnsIn_.push_back(currentPawn);
90                }
91            } else {
[8281]92                pawnsIn_.push_back(currentPawn);
93            }
94        }
95    }
[8767]96
[8660]97    void SpaceBoundaries::positionBillboard(const Vector3& position, float alpha)
[8301]98    {
[8660]99        size_t current;
100        for (current = 0; current < this->billboards_.size(); ++current)
101            if (!this->billboards_[current].usedYet)
[8301]102                break;
[8660]103
104        if (current == this->billboards_.size())
[8301]105        {
[9667]106            Billboard* billboard = new Billboard(this->getContext());
[8660]107            billboard->setPosition(position);
[8694]108            billboard->setSyncMode(ObjectDirection::None);
[8660]109            this->setBillboardOptions(billboard);
110            BillboardAdministration ba = {true, billboard};
111            this->billboards_.push_back(ba);
[8301]112        }
[8660]113
114        this->billboards_[current].billy->setPosition(position);
115        this->billboards_[current].billy->setVisible(true);
116        this->billboards_[current].billy->setColour(ColourValue(1, 1, 1, alpha));
117        this->billboards_[current].usedYet = true;
118
[9941]119        Vector3 directionVector = (this->getWorldPosition() - position).normalisedCopy(); // vector from the position of the billboard to the center of the sphere
[8660]120        this->billboards_[current].billy->setCommonDirection(directionVector);
121
122        Vector3 upVector = Vector3(directionVector.z, directionVector.z, -(directionVector.x + directionVector.y)); // vector perpendicular to the direction vector
123        upVector.normalise();
124        this->billboards_[current].billy->setCommonUpVector(upVector);
[8301]125    }
[8767]126
[8301]127    void SpaceBoundaries::setBillboardOptions(Billboard *billy)
128    {
[10765]129        if(billy != nullptr)
[8301]130        {
[8614]131            billy->setMaterial("Grid");
132            billy->setBillboardType(Ogre::BBT_PERPENDICULAR_COMMON);
133            billy->setDefaultDimensions(150, 150);
[8301]134            billy->setVisible(true);
135        }
136    }
[8767]137
[8301]138    void SpaceBoundaries::removeAllBillboards()
139    {
[10916]140        for(BillboardAdministration& billboard : this->billboards_)
[8301]141        {
[10916]142            billboard.usedYet = false;
143            billboard.billy->setVisible(false);
[8301]144        }
145    }
[8767]146
[8110]147    void SpaceBoundaries::setMaxDistance(float r)
148    {
[8166]149        this->maxDistance_ = r;
[8110]150    }
151    float SpaceBoundaries::getMaxDistance()
152    {
[8166]153        return this->maxDistance_;
[8110]154    }
[8767]155
[8110]156    void SpaceBoundaries::setWarnDistance(float r)
157    {
[8166]158        this->warnDistance_ = r;
[8110]159    }
160    float SpaceBoundaries::getWarnDistance()
161    {
[8166]162        return this->warnDistance_;
[8110]163    }
[8767]164
[8244]165    void SpaceBoundaries::setShowDistance(float r)
166    {
167        this->showDistance_ = r;
168    }
169    float SpaceBoundaries::getShowDistance()
170    {
171        return this->showDistance_;
172    }
[8767]173
[8201]174    void SpaceBoundaries::setHealthDecrease(float amount)
175    {
176        this->healthDecrease_ = amount/1000;
177    }
178    float SpaceBoundaries::getHealthDecrease()
179    {
180        return this->healthDecrease_;
181    }
[8767]182
[8404]183    void SpaceBoundaries::setReaction(int mode)
184    {
185        this->reaction_ = mode;
186    }
187    int SpaceBoundaries::getReaction()
188    {
189        return this->reaction_;
190    }
[8087]191
192    void SpaceBoundaries::XMLPort(Element& xmlelement, XMLPort::Mode mode)
193    {
[8110]194        SUPER(SpaceBoundaries, XMLPort, xmlelement, mode);
[8087]195
[8110]196        XMLPortParam(SpaceBoundaries, "maxDistance", setMaxDistance, getMaxDistance, xmlelement, mode);
197        XMLPortParam(SpaceBoundaries, "warnDistance", setWarnDistance, getWarnDistance, xmlelement, mode);
[8614]198        XMLPortParam(SpaceBoundaries, "showDistance", setShowDistance, getShowDistance, xmlelement, mode);
[8201]199        XMLPortParam(SpaceBoundaries, "healthDecrease", setHealthDecrease, getHealthDecrease, xmlelement, mode);
[8404]200        XMLPortParam(SpaceBoundaries, "reactionMode", setReaction, getReaction, xmlelement, mode);
[8087]201    }
[8767]202
[8110]203    void SpaceBoundaries::tick(float dt)
204    {
[8404]205        this->checkWhoIsIn();
[8301]206        this->removeAllBillboards();
[8767]207
[8301]208        float distance;
209        bool humanItem;
[10916]210        for(Pawn* currentPawn : pawnsIn_)
[8110]211        {
[8404]212            if( currentPawn && currentPawn->getNode() ) 
[8110]213            {
[8404]214                distance = this->computeDistance(currentPawn);
215                humanItem = this->isHumanPlayer(currentPawn);
[8858]216//                orxout() << "Distance:" << distance << endl; // message for debugging
[8614]217                if(distance > this->warnDistance_ && distance < this->maxDistance_) // Display warning
[8164]218                {
[8404]219                    if(humanItem)
220                    {
[8614]221                        this->displayWarning("Attention! You are close to the boundary!");
[8404]222                    }
[8201]223                }
[8614]224                if(/* humanItem &&*/ abs(this->maxDistance_ - distance) < this->showDistance_ )
[8164]225                {
[8660]226                    this->displayBoundaries(currentPawn, 1.0f - fabs(this->maxDistance_ - distance) / this->showDistance_); // Show the boundary
[8164]227                }
[8404]228                if(distance > this->maxDistance_ && (this->reaction_ == 1) )
229                {
230                    if( humanItem )
231                    {
[8858]232//                        orxout() << "Health should be decreasing!" << endl;
[8404]233                        this->displayWarning("You are out of the area now!");
234                    }
235                    currentPawn->removeHealth( (distance - this->maxDistance_) * this->healthDecrease_);
236                }
[8614]237                if( (this->reaction_ == 0) && (distance + 100 > this->maxDistance_)) // Exception: A Pawn can't move more than 100 units per tick.
[8404]238                {
239                    this->conditionalBounceBack(currentPawn, distance, dt);
240                }
[8614]241                if( this->reaction_ == 2 && (distance - 100 < this->maxDistance_) )
242                {
243                    this->conditionalBounceBack(currentPawn, distance, dt);
244                }
[8110]245            }
246        }
247    }
[8767]248
[8110]249    float SpaceBoundaries::computeDistance(WorldEntity *item)
250    {
[10765]251        if(item != nullptr)
[8301]252        {
[9941]253            Vector3 itemPosition = item->getWorldPosition();
254            return (itemPosition.distance(this->getWorldPosition()));
[8301]255        } else {
256            return -1;
257        }
[8110]258    }
[8767]259
[8164]260    void SpaceBoundaries::displayWarning(const std::string warnText)
[8767]261    {
[8614]262        // TODO
[8164]263    }
[8767]264
[8660]265    void SpaceBoundaries::displayBoundaries(Pawn *item, float alpha)
[8244]266    {
[8767]267
[9941]268        Vector3 direction = item->getWorldPosition() - this->getWorldPosition();
[8244]269        direction.normalise();
[8767]270
[9941]271        Vector3 boundaryPosition = this->getWorldPosition() + direction * this->maxDistance_;
[8767]272
[8660]273        this->positionBillboard(boundaryPosition, alpha);
[8244]274    }
[8767]275
[8404]276    void SpaceBoundaries::conditionalBounceBack(Pawn *item, float currentDistance, float dt)
[8244]277    {
[9941]278        Vector3 normal = item->getWorldPosition() - this->getWorldPosition();
[8404]279        normal.normalise();
280        Vector3 velocity = item->getVelocity();
281        float normalSpeed = item->getVelocity().dotProduct(normal);
[8767]282
[8614]283        /* Check, whether the Pawn would leave the boundary in the next tick, if so send it back. */
284        if( this->reaction_ == 0 && currentDistance + normalSpeed * dt > this->maxDistance_ - 10 ) // -10: "security measure"
[8244]285        {
[8614]286            bounceBack(item, &normal, &velocity);
287        } else if (this->reaction_ == 2 && currentDistance - normalSpeed * dt < this->maxDistance_ + 10 ) // 10: "security measure"
288        {
289            normal = normal * (-1);
290            bounceBack(item, &normal, &velocity);
[8244]291        }
292    }
[8767]293
[8614]294    void SpaceBoundaries::bounceBack(Pawn *item, Vector3 *normal, Vector3 *velocity)
295    {
296        float dampingFactor = 0.5;
297        *velocity = velocity->reflect(*normal);
298        Vector3 acceleration = item->getAcceleration();
299        acceleration = acceleration.reflect(*normal);
[8767]300
[9941]301        item->lookAt( *velocity + this->getWorldPosition() );
[8767]302
[8614]303        item->setAcceleration(acceleration * dampingFactor);
304        item->setVelocity(*velocity * dampingFactor);
[8767]305
[9941]306        item->setPosition( item->getWorldPosition() - *normal * 10 ); // Set the position of the Pawn to be well inside the boundary.
[8614]307    }
[8767]308
[8164]309    bool SpaceBoundaries::isHumanPlayer(Pawn *item)
310    {
[10765]311        if(item != nullptr)
[8164]312        {
[8201]313            if(item->getPlayer())
314            {
315                return item->getPlayer()->isHumanPlayer();
316            }
[8164]317        }
[8201]318        return false;
[8164]319    }
[8767]320
[8087]321}
Note: See TracBrowser for help on using the repository browser.