• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.replica.replicaisland;
18 
19 /**
20  * Component that adds physics to its parent game object.  This component implements force
21  * calculation based on mass, impulses, friction, and collisions.
22  */
23 public class PhysicsComponent extends GameComponent {
24 
25     private float mMass;
26     private float mBounciness; // 1.0 = super bouncy, 0.0 = zero bounce
27     private float mInertia;
28     private float mStaticFrictionCoeffecient;
29     private float mDynamicFrictionCoeffecient;
30 
31     private static final float DEFAULT_MASS = 1.0f;
32     private static final float DEFAULT_BOUNCINESS = 0.1f;
33     private static final float DEFAULT_INERTIA = 0.01f;
34     private static final float DEFAULT_STATIC_FRICTION_COEFFECIENT = 0.05f;
35     private static final float DEFAULT_DYNAMIC_FRICTION_COEFFECIENT = 0.02f;
36 
PhysicsComponent()37     PhysicsComponent() {
38         super();
39         reset();
40         setPhase(ComponentPhases.POST_PHYSICS.ordinal());
41     }
42 
43     @Override
reset()44     public void reset() {
45         // TODO: no reason to call accessors here locally.
46         setMass(DEFAULT_MASS);
47         setBounciness(DEFAULT_BOUNCINESS);
48         setInertia(DEFAULT_INERTIA);
49         setStaticFrictionCoeffecient(DEFAULT_STATIC_FRICTION_COEFFECIENT);
50         setDynamicFrictionCoeffecient(DEFAULT_DYNAMIC_FRICTION_COEFFECIENT);
51     }
52 
53     @Override
update(float timeDelta, BaseObject parent)54     public void update(float timeDelta, BaseObject parent) {
55         GameObject parentObject = (GameObject) parent;
56 
57         // we look to user data so that other code can provide impulses
58         Vector2 impulseVector = parentObject.getImpulse();
59 
60         final Vector2 currentVelocity = parentObject.getVelocity();
61 
62         final Vector2 surfaceNormal = parentObject.getBackgroundCollisionNormal();
63         if (surfaceNormal.length2() > 0.0f) {
64             resolveCollision(currentVelocity, impulseVector, surfaceNormal, impulseVector);
65         }
66 
67         VectorPool vectorPool = sSystemRegistry.vectorPool;
68 
69         // if our speed is below inertia, we need to overcome inertia before we can move.
70 
71         boolean physicsCausesMovement = true;
72 
73         final float inertiaSquared = getInertia() * getInertia();
74 
75         Vector2 newVelocity = vectorPool.allocate(currentVelocity);
76         newVelocity.add(impulseVector);
77 
78         if (newVelocity.length2() < inertiaSquared) {
79             physicsCausesMovement = false;
80         }
81 
82         final boolean touchingFloor = parentObject.touchingGround();
83 
84         GravityComponent gravity = parentObject.findByClass(GravityComponent.class);
85 
86         if (touchingFloor && currentVelocity.y <= 0.0f && Math.abs(newVelocity.x) > 0.0f
87                         && gravity != null) {
88             final Vector2 gravityVector = gravity.getGravity();
89 
90             // if we were moving last frame, we'll use dynamic friction. Else
91             // static.
92             float frictionCoeffecient = Math.abs(currentVelocity.x) > 0.0f ?
93                         getDynamicFrictionCoeffecient() : getStaticFrictionCoeffecient();
94             frictionCoeffecient *= timeDelta;
95 
96             // Friction = cofN, where cof = friction coefficient and N = force
97             // perpendicular to the ground.
98             final float maxFriction = Math.abs(gravityVector.y) * getMass()
99                     * frictionCoeffecient;
100 
101             if (maxFriction > Math.abs(newVelocity.x)) {
102                 newVelocity.x = (0.0f);
103             } else {
104                 newVelocity.x = (newVelocity.x
105                         - (maxFriction * Utils.sign(newVelocity.x)));
106             }
107         }
108 
109         if (Math.abs(newVelocity.x) < 0.01f) {
110             newVelocity.x = (0.0f);
111         }
112 
113         if (Math.abs(newVelocity.y) < 0.01f) {
114             newVelocity.y = (0.0f);
115         }
116 
117         // physics-based movements means constant acceleration, always. set the target to the
118         // velocity.
119         if (physicsCausesMovement) {
120             parentObject.setVelocity(newVelocity);
121             parentObject.setTargetVelocity(newVelocity);
122             parentObject.setAcceleration(Vector2.ZERO);
123             parentObject.setImpulse(Vector2.ZERO);
124         }
125 
126         vectorPool.release(newVelocity);
127     }
128 
resolveCollision(Vector2 velocity, Vector2 impulse, Vector2 opposingNormal, Vector2 outputImpulse)129     protected void resolveCollision(Vector2 velocity, Vector2 impulse, Vector2 opposingNormal,
130                     Vector2 outputImpulse) {
131         VectorPool vectorPool = sSystemRegistry.vectorPool;
132 
133         outputImpulse.set(impulse);
134 
135         Vector2 collisionNormal = vectorPool.allocate(opposingNormal);
136 
137         collisionNormal.normalize();
138 
139         Vector2 relativeVelocity = vectorPool.allocate(velocity);
140         relativeVelocity.add(impulse);
141 
142         final float dotRelativeAndNormal = relativeVelocity.dot(collisionNormal);
143 
144         // make sure the motion of the entity requires resolution
145         if (dotRelativeAndNormal < 0.0f) {
146             final float coefficientOfRestitution = getBounciness(); // 0 = perfectly inelastic,
147                                                                     // 1 = perfectly elastic
148 
149             // calculate an impulse to apply to the entity
150             float j = (-(1 + coefficientOfRestitution) * dotRelativeAndNormal);
151 
152             j /= ((collisionNormal.dot(collisionNormal)) * (1 / getMass()));
153 
154             Vector2 entity1Adjust = vectorPool.allocate(collisionNormal);
155 
156             entity1Adjust.set(collisionNormal);
157             entity1Adjust.multiply(j);
158             entity1Adjust.divide(getMass());
159             entity1Adjust.add(impulse);
160             outputImpulse.set(entity1Adjust);
161             vectorPool.release(entity1Adjust);
162 
163         }
164 
165         vectorPool.release(collisionNormal);
166         vectorPool.release(relativeVelocity);
167     }
168 
resolveCollision(Vector2 velocity, Vector2 impulse, Vector2 opposingNormal, float otherMass, Vector2 otherVelocity, Vector2 otherImpulse, float otherBounciness, Vector2 outputImpulse)169     protected void resolveCollision(Vector2 velocity, Vector2 impulse, Vector2 opposingNormal,
170                     float otherMass, Vector2 otherVelocity, Vector2 otherImpulse,
171                     float otherBounciness, Vector2 outputImpulse) {
172         VectorPool vectorPool = sSystemRegistry.vectorPool;
173 
174         Vector2 collisionNormal = vectorPool.allocate(opposingNormal);
175         collisionNormal.normalize();
176 
177         Vector2 entity1Velocity = vectorPool.allocate(velocity);
178         entity1Velocity.add(impulse);
179 
180         Vector2 entity2Velocity = vectorPool.allocate(otherVelocity);
181         entity2Velocity.add(otherImpulse);
182 
183         Vector2 relativeVelocity = vectorPool.allocate(entity1Velocity);
184         relativeVelocity.subtract(entity2Velocity);
185 
186         final float dotRelativeAndNormal = relativeVelocity.dot(collisionNormal);
187 
188         // make sure the entities' motion requires resolution
189         if (dotRelativeAndNormal < 0.0f) {
190             final float bounciness = Math.min(getBounciness() + otherBounciness, 1.0f);
191             final float coefficientOfRestitution = bounciness;  // 0 = perfectly inelastic,
192                                                                 // 1 = perfectly elastic
193 
194             // calculate an impulse to apply to both entities
195             float j = (-(1 + coefficientOfRestitution) * dotRelativeAndNormal);
196 
197             j /= ((collisionNormal.dot(collisionNormal)) * (1 / getMass() + 1 / otherMass));
198 
199             Vector2 entity1Adjust = vectorPool.allocate(collisionNormal);
200             entity1Adjust.multiply(j);
201             entity1Adjust.divide(getMass());
202             entity1Adjust.add(impulse);
203 
204             outputImpulse.set(entity1Adjust);
205 
206             // TODO: Deal impulses both ways.
207             /*
208              * Vector3 entity2Adjust = (collisionNormal j);
209              * entity2Adjust[0] /= otherMass;
210              * entity2Adjust[1] /= otherMass;
211              * entity2Adjust[2] /= otherMass;
212              *
213              * const Vector3 newEntity2Impulse = otherImpulse + entity2Adjust;
214              */
215 
216             vectorPool.release(entity1Adjust);
217         }
218 
219         vectorPool.release(collisionNormal);
220         vectorPool.release(entity1Velocity);
221         vectorPool.release(entity2Velocity);
222         vectorPool.release(relativeVelocity);
223     }
224 
getMass()225     public float getMass() {
226         return mMass;
227     }
228 
setMass(float mass)229     public void setMass(float mass) {
230         mMass = mass;
231     }
232 
getBounciness()233     public float getBounciness() {
234         return mBounciness;
235     }
236 
setBounciness(float bounciness)237     public void setBounciness(float bounciness) {
238         mBounciness = bounciness;
239     }
240 
getInertia()241     public float getInertia() {
242         return mInertia;
243     }
244 
setInertia(float inertia)245     public void setInertia(float inertia) {
246         mInertia = inertia;
247     }
248 
getStaticFrictionCoeffecient()249     public float getStaticFrictionCoeffecient() {
250         return mStaticFrictionCoeffecient;
251     }
252 
setStaticFrictionCoeffecient(float staticFrictionCoeffecient)253     public void setStaticFrictionCoeffecient(float staticFrictionCoeffecient) {
254         mStaticFrictionCoeffecient = staticFrictionCoeffecient;
255     }
256 
getDynamicFrictionCoeffecient()257     public float getDynamicFrictionCoeffecient() {
258         return mDynamicFrictionCoeffecient;
259     }
260 
setDynamicFrictionCoeffecient(float dynamicFrictionCoeffecient)261     public void setDynamicFrictionCoeffecient(float dynamicFrictionCoeffecient) {
262         mDynamicFrictionCoeffecient = dynamicFrictionCoeffecient;
263     }
264 
265 }
266