MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gravitywell.cpp
1 // © Copyright 2010 - 2014 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _gravitywell_cpp
41 #define _gravitywell_cpp
42 
43 #include "gravitywell.h"
44 
45 #include "Physics/rigidproxy.h"
46 #include "Physics/ghostproxy.h"
47 #include "Physics/physicsmanager.h"
48 
49 #include "entresol.h"
50 #include "serialization.h"
51 #include "exception.h"
52 #include "stringtool.h"
53 
54 namespace Mezzanine
55 {
57  AreaEffect(TheWorld),
58  AttenAmount(0),
59  Strength(0),
60  AttenStyle(Mezzanine::Att_None),
61  AllowWorldGrav(true)
62  { }
63 
64  GravityWell::GravityWell(const String& Name, World* TheWorld) :
65  AreaEffect(Name,TheWorld),
66  AttenAmount(0),
67  Strength(0),
68  AttenStyle(Mezzanine::Att_None),
69  AllowWorldGrav(true)
70  { }
71 
72  GravityWell::GravityWell(const XML::Node& SelfRoot, World* TheWorld) :
73  AreaEffect(TheWorld),
74  AttenAmount(0),
75  Strength(0),
76  AttenStyle(Mezzanine::Att_None),
77  AllowWorldGrav(true)
78  { this->ProtoDeSerialize(SelfRoot); }
79 
81  { }
82 
83  ///////////////////////////////////////////////////////////////////////////////
84  // Utility
85 
86  Mezzanine::WorldObjectType GravityWell::GetType() const
87  { return Mezzanine::WO_AreaEffectGravityWell; }
88 
90  {
91  /// @todo This currently will apply this fields force uniformly to all rigid proxies contained in a WorldObject.
92  /// Instead this should perhaps apply only to the ones in the field, or perhaps apply force based on the proxy position
93  /// rather than the WorldObject position to get more interesting results.
94  /// @todo Update to allow the application of force to soft proxies.
95 
96  if( 0 == this->Strength )
97  return;
98 
99  if( !this->AllowWorldGrav && !this->AddedObjects.empty() )
100  {
101  for( ObjectIterator AddedIt = this->AddedObjects.begin() ; AddedIt != this->AddedObjects.end() ; ++AddedIt )
102  {
103  ProxyContainer RigidProxies;
104  (*AddedIt)->GetProxies(Mezzanine::PT_Physics_RigidProxy,RigidProxies);
105  for( ProxyIterator ProxIt = RigidProxies.begin() ; ProxIt != RigidProxies.end() ; ++ProxIt )
106  {
107  Physics::RigidProxy* RigProx = static_cast<Physics::RigidProxy*>( *ProxIt );
108  RigProx->SetGravity( Vector3(0,0,0) );
109  }
110  }
111  }
112 
113  if( !this->OverlappingObjects.empty() ) {
114  const Vector3 SelfLoc = this->Ghost->GetLocation();
115  Vector3 ObjectLoc, Direction;
116  Real Distance = 0,AppliedStrength = 0;
117 
118  for( ObjectIterator ObjIt = this->OverlappingObjects.begin() ; ObjIt != this->OverlappingObjects.end() ; ObjIt++ )
119  {
120  ProxyContainer RigidProxies;
121  (*ObjIt)->GetProxies(Mezzanine::PT_Physics_RigidProxy,RigidProxies);
122  if( RigidProxies.empty() )
123  continue;
124 
125  Distance = ObjectLoc.Distance(SelfLoc);
126  Direction = (SelfLoc - ObjectLoc) / Distance;
127  switch(this->AttenStyle)
128  {
130  AppliedStrength = Strength - (AttenAmount * Distance);
131  break;
133  AppliedStrength = Strength - (AttenAmount * (Distance * Distance));
134  break;
135  default:
136  AppliedStrength = Strength;
137  break;
138  }
139 
140  //Apply the Force
141  for( ProxyIterator ProxIt = RigidProxies.begin() ; ProxIt != RigidProxies.end() ; ++ProxIt )
142  {
143  Physics::RigidProxy* RigProx = static_cast<Physics::RigidProxy*>( *ProxIt );
144 
145  Real Mass = RigProx->GetMass();
146  if( 0 > AppliedStrength ) {
147  AppliedStrength = 0;
148  }
149 
150  RigProx->ApplyForce( Direction * (AppliedStrength * Mass ) );
151  }
152  }
153  }
154 
155  if( !this->AllowWorldGrav && !this->RemovedObjects.empty() )
156  {
158  for( ObjectIterator RemovedIt = this->RemovedObjects.begin() ; RemovedIt != this->RemovedObjects.end() ; ++RemovedIt )
159  {
160  ProxyContainer RigidProxies;
161  (*RemovedIt)->GetProxies(Mezzanine::PT_Physics_RigidProxy,RigidProxies);
162  for( ProxyIterator ProxIt = RigidProxies.begin() ; ProxIt != RigidProxies.end() ; ++ProxIt )
163  {
164  Physics::RigidProxy* RigProx = static_cast<Physics::RigidProxy*>( *ProxIt );
165  RigProx->SetGravity( WorldGravity );
166  }
167  }
168  }
169  }
170 
171  ///////////////////////////////////////////////////////////////////////////////
172  // GravityWell Properties
173 
174  void GravityWell::SetFieldStrength(const Real FieldStrength)
175  { this->Strength = FieldStrength; }
176 
178  { return this->Strength; }
179 
180  void GravityWell::SetAllowWorldGravity(Boolean WorldGravity)
181  { this->AllowWorldGrav = WorldGravity; }
182 
184  { return this->AllowWorldGrav; }
185 
187  {
188  this->AttenAmount = Amount;
189  this->AttenStyle = Style;
190  }
191 
193  { this->AttenStyle = Style; }
194 
196  { return this->AttenStyle; }
197 
199  { this->AttenAmount = Amount; }
200 
202  { return this->AttenAmount; }
203 
204  ///////////////////////////////////////////////////////////////////////////////
205  // Serialization
206 
208  {
209  this->AreaEffect::ProtoSerializeProperties(SelfRoot);
210 
211  XML::Node PropertiesNode = SelfRoot.AppendChild( GravityWell::GetSerializableName() + "Properties" );
212 
213  if( PropertiesNode.AppendAttribute("Version").SetValue("1") &&
214  PropertiesNode.AppendAttribute("AttenAmount").SetValue( this->GetAttenuationAmount() ) &&
215  PropertiesNode.AppendAttribute("AttenStyle").SetValue( this->GetAttenuationStyle() ) &&
216  PropertiesNode.AppendAttribute("Strength").SetValue( this->GetFieldStrength() ) &&
217  PropertiesNode.AppendAttribute("AllowWorldGravity").SetValue( this->GetAllowWorldGravity() ? "true" : "false" ) )
218  {
219  return;
220  }else{
221  SerializeError("Create XML Attribute Values",GravityWell::GetSerializableName() + "Properties",true);
222  }
223  }
224 
226  {
228 
229  XML::Attribute CurrAttrib;
230  XML::Node PropertiesNode = SelfRoot.GetChild( GravityWell::GetSerializableName() + "Properties" );
231 
232  if( !PropertiesNode.Empty() ) {
233  if(PropertiesNode.GetAttribute("Version").AsInt() == 1) {
234  CurrAttrib = PropertiesNode.GetAttribute("AttenAmount");
235  if( !CurrAttrib.Empty() )
236  this->SetAttenuationAmount( CurrAttrib.AsReal() );
237 
238  CurrAttrib = PropertiesNode.GetAttribute("AttenStyle");
239  if( !CurrAttrib.Empty() )
240  this->SetAttenuationStyle( static_cast<Mezzanine::AttenuationStyle>( CurrAttrib.AsWhole() ) );
241 
242  CurrAttrib = PropertiesNode.GetAttribute("Strength");
243  if( !CurrAttrib.Empty() )
244  this->SetFieldStrength( CurrAttrib.AsReal() );
245 
246  CurrAttrib = PropertiesNode.GetAttribute("AllowWorldGravity");
247  if( !CurrAttrib.Empty() )
249  }else{
250  MEZZ_EXCEPTION(Exception::INVALID_VERSION_EXCEPTION,"Incompatible XML Version for " + (GravityWell::GetSerializableName() + "Properties" ) + ": Not Version 1.");
251  }
252  }else{
253  MEZZ_EXCEPTION(Exception::II_IDENTITY_NOT_FOUND_EXCEPTION,GravityWell::GetSerializableName() + "Properties" + " was not found in the provided XML node, which was expected.");
254  }
255  }
256 
259 
261  { return "GravityWell"; }
262 
263  ///////////////////////////////////////////////////////////////////////////////
264  // GravityWellFactory Methods
265 
267  { }
268 
270  { }
271 
274 
276  { return new GravityWell(Name,TheWorld); }
277 
279  { return static_cast<GravityWell*>( this->CreateAreaEffect(XMLNode,TheWorld) ); }
280 
282  { return new GravityWell(Name,TheWorld); }
283 
285  { return new GravityWell(XMLNode,TheWorld); }
286 
288  { delete ToBeDestroyed; }
289 }//Mezzanine
290 
291 #endif