Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11163 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
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/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    CreateFactory(SpaceBoundaries);
45
46    SpaceBoundaries::SpaceBoundaries(BaseObject* creator) : StaticEntity(creator)
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( std::vector<BillboardAdministration>::iterator current = this->billboards_.begin(); current != this->billboards_.end(); current++)
62            {
63                if( current->billy != NULL)
64                {
65                    delete current->billy;
66                }
67            }
68            this->billboards_.clear();
69        }
70    }
71
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;
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);
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 != NULL)
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( std::vector<BillboardAdministration>::iterator current = this->billboards_.begin(); current != this->billboards_.end(); current++ )
141        {
142            current->usedYet = false;
143            current->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( std::list<WeakPtr<Pawn> >::iterator current = pawnsIn_.begin(); current != pawnsIn_.end(); current++ )
211        {
212            Pawn* currentPawn = current->get();
213            if( currentPawn && currentPawn->getNode() ) 
214            {
215                distance = this->computeDistance(currentPawn);
216                humanItem = this->isHumanPlayer(currentPawn);
217//                orxout() << "Distance:" << distance << endl; // message for debugging
218                if(distance > this->warnDistance_ && distance < this->maxDistance_) // Display warning
219                {
220                    if(humanItem)
221                    {
222                        this->displayWarning("Attention! You are close to the boundary!");
223                    }
224                }
225                if(/* humanItem &&*/ abs(this->maxDistance_ - distance) < this->showDistance_ )
226                {
227                    this->displayBoundaries(currentPawn, 1.0f - fabs(this->maxDistance_ - distance) / this->showDistance_); // Show the boundary
228                }
229                if(distance > this->maxDistance_ && (this->reaction_ == 1) )
230                {
231                    if( humanItem )
232                    {
233//                        orxout() << "Health should be decreasing!" << endl;
234                        this->displayWarning("You are out of the area now!");
235                    }
236                    currentPawn->removeHealth( (distance - this->maxDistance_) * this->healthDecrease_);
237                }
238                if( (this->reaction_ == 0) && (distance + 100 > this->maxDistance_)) // Exception: A Pawn can't move more than 100 units per tick.
239                {
240                    this->conditionalBounceBack(currentPawn, distance, dt);
241                }
242                if( this->reaction_ == 2 && (distance - 100 < this->maxDistance_) )
243                {
244                    this->conditionalBounceBack(currentPawn, distance, dt);
245                }
246            }
247        }
248    }
249
250    float SpaceBoundaries::computeDistance(WorldEntity *item)
251    {
252        if(item != NULL)
253        {
254            Vector3 itemPosition = item->getWorldPosition();
255            return (itemPosition.distance(this->getWorldPosition()));
256        } else {
257            return -1;
258        }
259    }
260
261    void SpaceBoundaries::displayWarning(const std::string warnText)
262    {
263        // TODO
264    }
265
266    void SpaceBoundaries::displayBoundaries(Pawn *item, float alpha)
267    {
268
269        Vector3 direction = item->getWorldPosition() - this->getWorldPosition();
270        direction.normalise();
271
272        Vector3 boundaryPosition = this->getWorldPosition() + direction * this->maxDistance_;
273
274        this->positionBillboard(boundaryPosition, alpha);
275    }
276
277    void SpaceBoundaries::conditionalBounceBack(Pawn *item, float currentDistance, float dt)
278    {
279        Vector3 normal = item->getWorldPosition() - this->getWorldPosition();
280        normal.normalise();
281        Vector3 velocity = item->getVelocity();
282        float normalSpeed = item->getVelocity().dotProduct(normal);
283
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"
286        {
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);
292        }
293    }
294
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);
301
302        item->lookAt( *velocity + this->getWorldPosition() );
303
304        item->setAcceleration(acceleration * dampingFactor);
305        item->setVelocity(*velocity * dampingFactor);
306
307        item->setPosition( item->getWorldPosition() - *normal * 10 ); // Set the position of the Pawn to be well inside the boundary.
308    }
309
310    bool SpaceBoundaries::isHumanPlayer(Pawn *item)
311    {
312        if(item != NULL)
313        {
314            if(item->getPlayer())
315            {
316                return item->getPlayer()->isHumanPlayer();
317            }
318        }
319        return false;
320    }
321
322}
Note: See TracBrowser for help on using the repository browser.