Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/release2012/src/modules/objects/SpaceBoundaries.cc @ 11573

Last change on this file since 11573 was 9371, checked in by jo, 12 years ago

The UnderAttack level was improved. The defender's spawnpoints have been rearranged such that they don't get stuck in the Transporter. In order to catch bots that are too far away from the transporter a spaceboundary damages spaceships that are too far away from the transporter. Therefore the spaceboundary's code has to be updated to enable it to be moved around.

  • Property svn:eol-style set to native
File size: 11.0 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"
[8110]34#include "core/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{
44    CreateFactory(SpaceBoundaries);
45
46    SpaceBoundaries::SpaceBoundaries(BaseObject* creator) : StaticEntity(creator)
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
[8660]61            for( std::vector<BillboardAdministration>::iterator current = this->billboards_.begin(); current != this->billboards_.end(); current++)
[8301]62            {
[8470]63                if( current->billy != NULL)
64                {
65                    delete current->billy;
66                }
[8301]67            }
[8470]68            this->billboards_.clear();
[8301]69        }
[8087]70    }
[8767]71
[8281]72    void SpaceBoundaries::checkWhoIsIn()
73    {
74        pawnsIn_.clear();
75        for(ObjectListIterator<Pawn> current = ObjectList<Pawn>::begin(); current != ObjectList<Pawn>::end(); ++current)
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        {
[8660]106            Billboard* billboard = new Billboard(this);
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
[9371]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    {
129        if(billy != NULL)
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    {
[8660]140        for( std::vector<BillboardAdministration>::iterator current = this->billboards_.begin(); current != this->billboards_.end(); current++ )
[8301]141        {
142            current->usedYet = false;
143            current->billy->setVisible(false);
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;
[8404]210        for( std::list<WeakPtr<Pawn> >::iterator current = pawnsIn_.begin(); current != pawnsIn_.end(); current++ )
[8110]211        {
[8404]212            Pawn* currentPawn = current->get();
213            if( currentPawn && currentPawn->getNode() ) 
[8110]214            {
[8404]215                distance = this->computeDistance(currentPawn);
216                humanItem = this->isHumanPlayer(currentPawn);
[8858]217//                orxout() << "Distance:" << distance << endl; // message for debugging
[8614]218                if(distance > this->warnDistance_ && distance < this->maxDistance_) // Display warning
[8164]219                {
[8404]220                    if(humanItem)
221                    {
[8614]222                        this->displayWarning("Attention! You are close to the boundary!");
[8404]223                    }
[8201]224                }
[8614]225                if(/* humanItem &&*/ abs(this->maxDistance_ - distance) < this->showDistance_ )
[8164]226                {
[8660]227                    this->displayBoundaries(currentPawn, 1.0f - fabs(this->maxDistance_ - distance) / this->showDistance_); // Show the boundary
[8164]228                }
[8404]229                if(distance > this->maxDistance_ && (this->reaction_ == 1) )
230                {
231                    if( humanItem )
232                    {
[8858]233//                        orxout() << "Health should be decreasing!" << endl;
[8404]234                        this->displayWarning("You are out of the area now!");
235                    }
236                    currentPawn->removeHealth( (distance - this->maxDistance_) * this->healthDecrease_);
237                }
[8614]238                if( (this->reaction_ == 0) && (distance + 100 > this->maxDistance_)) // Exception: A Pawn can't move more than 100 units per tick.
[8404]239                {
240                    this->conditionalBounceBack(currentPawn, distance, dt);
241                }
[8614]242                if( this->reaction_ == 2 && (distance - 100 < this->maxDistance_) )
243                {
244                    this->conditionalBounceBack(currentPawn, distance, dt);
245                }
[8110]246            }
247        }
248    }
[8767]249
[8110]250    float SpaceBoundaries::computeDistance(WorldEntity *item)
251    {
[8301]252        if(item != NULL)
253        {
[9371]254            Vector3 itemPosition = item->getWorldPosition();
255            return (itemPosition.distance(this->getWorldPosition()));
[8301]256        } else {
257            return -1;
258        }
[8110]259    }
[8767]260
[8164]261    void SpaceBoundaries::displayWarning(const std::string warnText)
[8767]262    {
[8614]263        // TODO
[8164]264    }
[8767]265
[8660]266    void SpaceBoundaries::displayBoundaries(Pawn *item, float alpha)
[8244]267    {
[8767]268
[9371]269        Vector3 direction = item->getWorldPosition() - this->getWorldPosition();
[8244]270        direction.normalise();
[8767]271
[9371]272        Vector3 boundaryPosition = this->getWorldPosition() + direction * this->maxDistance_;
[8767]273
[8660]274        this->positionBillboard(boundaryPosition, alpha);
[8244]275    }
[8767]276
[8404]277    void SpaceBoundaries::conditionalBounceBack(Pawn *item, float currentDistance, float dt)
[8244]278    {
[9371]279        Vector3 normal = item->getWorldPosition() - this->getWorldPosition();
[8404]280        normal.normalise();
281        Vector3 velocity = item->getVelocity();
282        float normalSpeed = item->getVelocity().dotProduct(normal);
[8767]283
[8614]284        /* Check, whether the Pawn would leave the boundary in the next tick, if so send it back. */
285        if( this->reaction_ == 0 && currentDistance + normalSpeed * dt > this->maxDistance_ - 10 ) // -10: "security measure"
[8244]286        {
[8614]287            bounceBack(item, &normal, &velocity);
288        } else if (this->reaction_ == 2 && currentDistance - normalSpeed * dt < this->maxDistance_ + 10 ) // 10: "security measure"
289        {
290            normal = normal * (-1);
291            bounceBack(item, &normal, &velocity);
[8244]292        }
293    }
[8767]294
[8614]295    void SpaceBoundaries::bounceBack(Pawn *item, Vector3 *normal, Vector3 *velocity)
296    {
297        float dampingFactor = 0.5;
298        *velocity = velocity->reflect(*normal);
299        Vector3 acceleration = item->getAcceleration();
300        acceleration = acceleration.reflect(*normal);
[8767]301
[9371]302        item->lookAt( *velocity + this->getWorldPosition() );
[8767]303
[8614]304        item->setAcceleration(acceleration * dampingFactor);
305        item->setVelocity(*velocity * dampingFactor);
[8767]306
[9371]307        item->setPosition( item->getWorldPosition() - *normal * 10 ); // Set the position of the Pawn to be well inside the boundary.
[8614]308    }
[8767]309
[8164]310    bool SpaceBoundaries::isHumanPlayer(Pawn *item)
311    {
312        if(item != NULL)
313        {
[8201]314            if(item->getPlayer())
315            {
316                return item->getPlayer()->isHumanPlayer();
317            }
[8164]318        }
[8201]319        return false;
[8164]320    }
[8767]321
[8087]322}
Note: See TracBrowser for help on using the repository browser.