Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ai2/src/modules/objects/SpaceBoundaries.cc @ 8770

Last change on this file since 8770 was 8706, checked in by dafrick, 13 years ago

Merging presentation branch back into trunk.
There are many new features and also a lot of other changes and bugfixes, if you want to know, digg through the svn log.
Not everything is yet working as it should, but it should be fairly stable. If you habe any bug reports, just send me an email.

  • Property svn:eol-style set to native
File size: 11.1 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->getPosition() - 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                COUT(5) << "Distance:" << distance << std::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                        COUT(5) << "Health should be decreasing!" << std::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->getPosition();
255            return (itemPosition.distance(this->getPosition()));
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->getPosition() - this->getPosition();
270        direction.normalise();
271       
272        Vector3 boundaryPosition = this->getPosition() + 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->getPosition() - this->getPosition();
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->getPosition() );
303       
304        item->setAcceleration(acceleration * dampingFactor);
305        item->setVelocity(*velocity * dampingFactor);
306       
307        item->setPosition( item->getPosition() - *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.