Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/spacestationentry/src/modules/objects/ForceField.cc @ 10181

Last change on this file since 10181 was 9857, checked in by agermann, 11 years ago

Docking funktioniert nun mit einem eingebauten Trigger ueber undocking XMLPort. Jedoch immer noch mit cmdUndock(). Forcefield wurde um eine homogenes Kraftfeld erweitert, dass Kugelfoermig und mit einer bestimmten Richtung gemacht werden kann.

  • Property svn:eol-style set to native
File size: 11.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 *      Aurelian Jaggi
24 *   Co-authors:
25 *      Kevin Young
26 *
27 */
28
29/**
30    @file ForceField.cc
31    @brief Implementation of the ForceField class.
32*/
33
34#include "ForceField.h"
35
36#include "core/CoreIncludes.h"
37#include "core/XMLPort.h"
38#include "worldentities/MobileEntity.h"
39
40namespace orxonox
41{
42    RegisterClass(ForceField);
43
44    /*static*/ const std::string ForceField::modeTube_s = "tube";
45    /*static*/ const std::string ForceField::modeSphere_s = "sphere";
46    /*static*/ const std::string ForceField::modeInvertedSphere_s = "invertedSphere";
47
48    /*static*/ const std::string ForceField::modeHomogen_s = "homogen";
49
50    /*static*/ const std::string ForceField::modeNewtonianGravity_s = "newtonianGravity";
51    /*static*/ const float ForceField::gravConstant_ = 6.673e-11;
52    /*static*/ const float ForceField::attenFactor_ = 1;
53
54
55    /**
56    @brief
57        Constructor. Registers the object and initializes some values.
58    */
59    ForceField::ForceField(Context* context) : StaticEntity(context)
60    {
61        RegisterObject(ForceField);
62
63        //Standard Values
64        this->setDirection(Vector3::ZERO);
65        this->setVelocity(100);
66        this->setDiameter(500);
67        this->setMassDiameter(0);   //! We allow point-masses
68        this->setLength(2000);
69        this->mode_ = forceFieldMode::tube;
70       
71        this->registerVariables();
72    }
73
74    /**
75    @brief
76        Destructor.
77    */
78    ForceField::~ForceField()
79    {
80    }
81
82    /**
83    @brief
84        Creates a ForceField object through XML.
85    */
86    void ForceField::XMLPort(Element& xmlelement, XMLPort::Mode mode)
87    {
88        SUPER(ForceField, XMLPort, xmlelement, mode);
89
90        XMLPortParam(ForceField, "velocity", setVelocity, getVelocity, xmlelement, mode).defaultValues(100);
91        XMLPortParam(ForceField, "diameter", setDiameter, getDiameter, xmlelement, mode).defaultValues(500);
92        XMLPortParam(ForceField, "massDiameter", setMassDiameter, getMassDiameter, xmlelement, mode).defaultValues(0);
93        XMLPortParam(ForceField, "length", setLength  , getLength  , xmlelement, mode).defaultValues(2000);
94        XMLPortParam(ForceField, "mode", setMode, getMode, xmlelement, mode);
95        XMLPortParam(ForceField, "forcedirection", setForceDirection, getForceDirection, xmlelement, mode).defaultValues(Vector3(0,-400,0));
96    }
97   
98    void ForceField::registerVariables()
99    {
100        registerVariable(this->velocity_, VariableDirection::ToClient);
101        registerVariable(this->radius_, VariableDirection::ToClient);
102        registerVariable(this->massRadius_, VariableDirection::ToClient);
103        registerVariable(this->halfLength_, VariableDirection::ToClient);
104        registerVariable(this->mode_, VariableDirection::ToClient);
105    }
106
107
108    /**
109    @brief
110        A method that is called every tick.
111        Implements the behavior of the ForceField.
112    @param dt
113        The amount of time that elapsed since the last tick.
114    */
115    void ForceField::tick(float dt)
116    {
117        if(this->mode_ == forceFieldMode::tube)
118        {
119            // Iterate over all objects that could possibly be affected by the ForceField.
120            for (ObjectList<MobileEntity>::iterator it = ObjectList<MobileEntity>::begin(); it != ObjectList<MobileEntity>::end(); ++it)
121            {
122                // The direction of the orientation of the force field.
123                Vector3 direction = this->getOrientation() * WorldEntity::FRONT;
124                direction.normalise();
125
126                // Vector from the center of the force field to the object its acting on.
127                Vector3 distanceVector = it->getWorldPosition() - (this->getWorldPosition() + (this->halfLength_ * direction));
128
129                // The object is outside a ball around the center with radius length/2 of the ForceField.
130                if(distanceVector.length() > this->halfLength_)
131                    continue;
132
133                // The distance of the object form the orientation vector. (Or rather the smallest distance from the orientation vector)
134                float distanceFromDirectionVector = ((it->getWorldPosition() - this->getWorldPosition()).crossProduct(direction)).length();
135
136                // If the object in a tube of radius 'radius' around the direction of orientation.
137                if(distanceFromDirectionVector >= this->radius_)
138                    continue;
139
140                // Apply a force to the object in the direction of the orientation.
141                // The force is highest when the object is directly on the direction vector, with a linear decrease, finally reaching zero, when distanceFromDirectionVector = radius.
142                it->applyCentralForce((this->radius_ - distanceFromDirectionVector)/this->radius_ * this->velocity_ * direction);
143            }
144        }
145        else if(this->mode_ == forceFieldMode::sphere)
146        {
147            // Iterate over all objects that could possibly be affected by the ForceField.
148            for (ObjectList<MobileEntity>::iterator it = ObjectList<MobileEntity>::begin(); it != ObjectList<MobileEntity>::end(); ++it)
149            {
150                Vector3 distanceVector = it->getWorldPosition() - this->getWorldPosition();
151                float distance = distanceVector.length();
152                // If the object is within 'radius' distance.
153                if (distance < this->radius_)
154                {
155                    distanceVector.normalise();
156                    // Apply a force proportional to the velocity, with highest force at the origin of the sphere, linear decreasing until reaching a distance of 'radius' from the origin, where the force reaches zero.
157                    it->applyCentralForce((this->radius_ - distance)/this->radius_ * this->velocity_ * distanceVector);
158                }
159            }
160        }
161        else if(this->mode_ == forceFieldMode::invertedSphere)
162        {
163            // Iterate over all objects that could possibly be affected by the ForceField.
164            for (ObjectList<MobileEntity>::iterator it = ObjectList<MobileEntity>::begin(); it != ObjectList<MobileEntity>::end(); ++it)
165            {
166                Vector3 distanceVector = this->getWorldPosition() - it->getWorldPosition();
167                float distance = distanceVector.length();
168                // If the object is within 'radius' distance and no more than 'length' away from the boundary of the sphere.
169                float range = this->radius_ - this->halfLength_*2;
170                if (distance < this->radius_ && distance > range)
171                {
172                    distanceVector.normalise();
173                    // Apply a force proportional to the velocity, with highest force at the boundary of the sphere, linear decreasing until reaching a distance of 'radius-length' from the origin, where the force reaches zero.
174                    it->applyCentralForce((distance-range)/range * this->velocity_ * distanceVector);
175                }
176            }
177        }
178        else if(this->mode_ == forceFieldMode::newtonianGravity)
179        {
180            // Iterate over all objects that could possibly be affected by the ForceField.
181            for (ObjectList<MobileEntity>::iterator it = ObjectList<MobileEntity>::begin(); it != ObjectList<MobileEntity>::end(); ++it)
182            {
183                Vector3 distanceVector = it->getWorldPosition() - this->getWorldPosition();
184                float distance = distanceVector.length();
185                // If the object is within 'radius' distance and especially further away than massRadius_
186                if (distance < this->radius_ && distance > this->massRadius_)
187                {
188                    distanceVector.normalise();
189                    /* Apply a central force that follows the newtownian law of gravity, ie.:
190                     * F = G * (M*m) / D^2,
191                     * while M is the mass of the stellar body and m is the mass of the affected object.
192                     * D is the distance from the center of mass of both bodies
193                     * and it should be noted that massRadius_ denotes the radius of the stellar body,
194                     * at which point the force vanishes (you can use this to dictate the size of the body).
195                     * attenFactor_ weakens the field by a constant factor. The -1 is needed for an attractive force.
196                     */
197                   
198                    // Note: this so called force is actually an acceleration!
199                    it->applyCentralForce((-1) * (ForceField::attenFactor_ * ForceField::gravConstant_ * this->getMass()) / (distance * distance) * distanceVector);
200                }
201            }
202        }
203        else if(this->mode_ == forceFieldMode::homogen)
204        {
205                // Iterate over all objects that could possibly be affected by the ForceField.
206                for (ObjectList<MobileEntity>::iterator it = ObjectList<MobileEntity>::begin(); it != ObjectList<MobileEntity>::end(); ++it)
207                {
208                        Vector3 distanceVector = it->getWorldPosition() - this->getWorldPosition();
209                    float distance = distanceVector.length();
210                    if (distance < this->radius_ && distance > this->massRadius_)
211                    {
212                        // Add a Acceleration in forceDirection_.
213                        // Vector3(0,0,0) is the direction, where the force should work.
214                        it->addAcceleration(forceDirection_ , Vector3(0,0,0));
215                    }
216                }
217        }
218    }
219
220    /**
221    @brief
222        Set the mode of the ForceField.
223    @param mode
224        The mode as a string.
225    */
226    void ForceField::setMode(const std::string& mode)
227    {
228        if(mode == ForceField::modeTube_s)
229            this->mode_ = forceFieldMode::tube;
230        else if(mode == ForceField::modeSphere_s)
231            this->mode_ = forceFieldMode::sphere;
232        else if(mode == ForceField::modeInvertedSphere_s)
233            this->mode_ = forceFieldMode::invertedSphere;
234        else if(mode == ForceField::modeNewtonianGravity_s)
235            this->mode_ = forceFieldMode::newtonianGravity;
236
237        else if(mode == ForceField::modeHomogen_s)
238            this->mode_ = forceFieldMode::homogen;
239
240        else
241        {
242            orxout(internal_warning) << "Wrong mode '" << mode << "' in ForceField. Setting to 'tube'." << endl;
243            this->mode_ = forceFieldMode::tube;
244        }
245    }
246
247    /**
248    @brief
249        Get the mode of the ForceField.
250    @return
251        Returns the mode of the ForceField as a string.
252    */
253    const std::string& ForceField::getMode(void)
254    {
255        switch(this->mode_)
256        {
257            case forceFieldMode::tube:
258                return ForceField::modeTube_s;
259            case forceFieldMode::sphere:
260                return ForceField::modeSphere_s;
261            case forceFieldMode::invertedSphere:
262                return ForceField::modeInvertedSphere_s;
263            case forceFieldMode::newtonianGravity:
264                return ForceField::modeNewtonianGravity_s;
265
266            case forceFieldMode::homogen:
267                return ForceField::modeHomogen_s;
268
269            default:
270                return ForceField::modeTube_s;
271        }
272    }
273
274}
Note: See TracBrowser for help on using the repository browser.