Angel 3.2
A 2D Game Prototyping Engine
PhysicsActor.cpp
1 
2 // Copyright (C) 2008-2013, Shane Liesegang
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of the copyright holder nor the names of any
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "stdafx.h"
31 #include "../Actors/PhysicsActor.h"
32 
33 #include "../Infrastructure/World.h"
34 #include "../Infrastructure/Log.h"
35 #include "../Util/MathUtil.h"
36 
37 #include <Box2D/Box2D.h>
38 
39 
40 #define POST_PHYSICS_INIT_WARNING "WARNING: %s had no effect; don't change an actor after its physics have been initialized."
41 #define PRE_PHYSICS_INIT_WARNING "WARNING: %s had no effect; this actor's physics were not initialized."
42 
44 _physBody(NULL),
45 _density(1.f),
46 _friction(0.3f),
47 _restitution(0.0f),
48 _shapeType(SHAPETYPE_BOX),
49 _isSensor(false),
50 _groupIndex(0),
51 _fixedRotation(false)
52 {
53 }
54 
56 {
57  if( _physBody != NULL )
58  {
59  _physBody->SetUserData(NULL);
60  theWorld.GetPhysicsWorld().DestroyBody(_physBody);
61  }
62 }
63 
64 void PhysicsActor::SetDensity(float density)
65 {
66  if (_physBody == NULL)
67  _density = density;
68  else
69  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetDensity()");
70 }
71 
72 void PhysicsActor::SetFriction(float friction)
73 {
74  if (_physBody == NULL)
75  _friction = friction;
76  else
77  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetFriction()");
78 }
79 
80 void PhysicsActor::SetRestitution(float restitution)
81 {
82  if (_physBody == NULL)
83  _restitution = restitution;
84  else
85  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetRestitution()");
86 }
87 
89 {
90  if (_physBody == NULL)
91  _shapeType = shapeType;
92  else
93  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetShapeType()");
94 }
95 
96 void PhysicsActor::SetIsSensor(bool isSensor)
97 {
98  if (_physBody == NULL)
99  _isSensor = isSensor;
100  else
101  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetIsSensor()");
102 }
103 
104 void PhysicsActor::SetGroupIndex(int groupIndex)
105 {
106  if (_physBody == NULL)
107  _groupIndex = groupIndex;
108  else
109  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetGroupIndex()");
110 }
111 
112 void PhysicsActor::SetFixedRotation(bool fixedRotation)
113 {
114  if (_physBody == NULL)
115  _fixedRotation = fixedRotation;
116  else
117  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetFixedRotation()");
118 }
119 
120 
122 {
123  if (!theWorld.IsPhysicsSetUp())
124  {
125  sysLog.Log("ERROR: World physics must be initialized before Actor's.");
126  return;
127  }
128 
129  b2CircleShape circle;
130  b2PolygonShape box;
131  b2Shape* shape = NULL;
132  if (_shapeType == SHAPETYPE_BOX)
133  {
134  // The extents is just a vector of the box's half widths.
135  // Box2D is tuned for meters, kilograms, and seconds. (Unless you've changed its units. [You probably shouldn't.])
136  box.SetAsBox(0.5f*_size.X, 0.5f*_size.Y);
137  shape = &box;
138  }
139  else if (_shapeType == SHAPETYPE_CIRCLE)
140  {
141  circle.m_radius = 0.5f*_size.X;
142  shape = &circle;
143  }
144  else
145  {
146  sysLog.Log("ERROR: Invalid shape type given.");
147  return;
148  }
149 
150  b2FixtureDef fixtureDef;
151  fixtureDef.shape = shape;
152  fixtureDef.density = _density;
153  fixtureDef.friction = _friction;
154  fixtureDef.restitution = _restitution;
155 
156  fixtureDef.filter.groupIndex = _groupIndex;
157  fixtureDef.isSensor = _isSensor;
158 
159  InitShape( shape );
160 
161  b2BodyDef bd;
162  bd.userData = this;
163  bd.position.Set(_position.X, _position.Y);
164  bd.angle = MathUtil::ToRadians(_rotation);
165  bd.fixedRotation = _fixedRotation;
166  if (MathUtil::FuzzyEquals(_density, 0.0f))
167  {
168  bd.type = b2_staticBody;
169  }
170  else
171  {
172  bd.type = b2_dynamicBody;
173  }
174 
175  _physBody = theWorld.GetPhysicsWorld().CreateBody(&bd);
176  _physBody->CreateFixture(&fixtureDef);
177  _physBody->SetUserData(this);
179 }
180 
181 void PhysicsActor::ApplyForce(const Vector2& force, const Vector2& point)
182 {
183  if (_physBody != NULL)
184  _physBody->ApplyForce(b2Vec2(force.X, force.Y), b2Vec2(point.X + _position.X, point.Y + _position.Y));
185  else
186  sysLog.Printf(PRE_PHYSICS_INIT_WARNING, "ApplyForce()");
187 }
188 
189 void PhysicsActor::ApplyLocalForce(const Vector2& force, const Vector2& point)
190 {
191  if (_physBody != NULL)
192  _physBody->ApplyForce(_physBody->GetWorldVector(b2Vec2(force.X, force.Y)), b2Vec2(point.X + _position.X, point.Y + _position.Y));
193  else
194  sysLog.Printf(PRE_PHYSICS_INIT_WARNING, "ApplyLocalForce()");
195 }
196 
197 void PhysicsActor::ApplyTorque(float torque)
198 {
199  if (_physBody != NULL)
200  _physBody->ApplyTorque(torque);
201  else
202  sysLog.Printf(PRE_PHYSICS_INIT_WARNING, "ApplyTorque()");
203 }
204 
205 void PhysicsActor::ApplyLinearImpulse(const Vector2& impulse, const Vector2& point)
206 {
207  if (_physBody != NULL)
208  _physBody->ApplyLinearImpulse(b2Vec2(impulse.X, impulse.Y), b2Vec2(point.X + _position.X, point.Y + _position.Y));
209  else
210  sysLog.Printf(PRE_PHYSICS_INIT_WARNING, "ApplyLinearImpulse()");
211 }
212 
214 {
215  if (_physBody != NULL)
216  _physBody->ApplyAngularImpulse(impulse);
217  else
218  sysLog.Printf(PRE_PHYSICS_INIT_WARNING, "ApplyAngularImpulse()");
219 }
220 
221 void PhysicsActor::SetSize(float x, float y)
222 {
223  if (_physBody == NULL)
224  Actor::SetSize(x, y);
225  else
226  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetSize()");
227 }
228 
229 void PhysicsActor::SetDrawSize(float x, float y)
230 {
231  Actor::SetSize(x,y);
232 }
233 
234 void PhysicsActor::SetPosition(float x, float y)
235 {
236  if (_physBody == NULL)
237  Actor::SetPosition(x, y);
238  else
239  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetPosition()");
240 }
241 
243 {
244  if (_physBody == NULL)
245  Actor::SetPosition(pos);
246  else
247  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetPosition()");
248 }
249 
250 void PhysicsActor::SetRotation(float rotation)
251 {
252  if (_physBody == NULL)
253  Actor::SetRotation(rotation);
254  else
255  sysLog.Printf(POST_PHYSICS_INIT_WARNING, "SetRotation()");
256 }
257 
258 void PhysicsActor::_syncPosRot(float x, float y, float rotation)
259 {
260  _position.X = x;
261  _position.Y = y;
262  _rotation = rotation;
263  while (_rotation > 180.f)
264  _rotation -= 360.f;
265  while (_rotation < -180.f)
266  _rotation += 360.f;
267 }
268