Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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