1cfd74d65d832137e20e193c960802afba73b5d38sm/*
23c1e67e433728684b5f228c5d4f3e5b1457bb271sm * Copyright (C) 2010 The Android Open Source Project
3cfd74d65d832137e20e193c960802afba73b5d38sm *
4cfd74d65d832137e20e193c960802afba73b5d38sm * Licensed under the Apache License, Version 2.0 (the "License");
5cfd74d65d832137e20e193c960802afba73b5d38sm * you may not use this file except in compliance with the License.
6cfd74d65d832137e20e193c960802afba73b5d38sm * You may obtain a copy of the License at
7cfd74d65d832137e20e193c960802afba73b5d38sm *
8cfd74d65d832137e20e193c960802afba73b5d38sm *      http://www.apache.org/licenses/LICENSE-2.0
9cfd74d65d832137e20e193c960802afba73b5d38sm *
10cfd74d65d832137e20e193c960802afba73b5d38sm * Unless required by applicable law or agreed to in writing, software
11cfd74d65d832137e20e193c960802afba73b5d38sm * distributed under the License is distributed on an "AS IS" BASIS,
12cfd74d65d832137e20e193c960802afba73b5d38sm * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cfd74d65d832137e20e193c960802afba73b5d38sm * See the License for the specific language governing permissions and
14cfd74d65d832137e20e193c960802afba73b5d38sm * limitations under the License.
15cfd74d65d832137e20e193c960802afba73b5d38sm */
16cfd74d65d832137e20e193c960802afba73b5d38sm
17cfd74d65d832137e20e193c960802afba73b5d38smpackage com.replica.replicaisland;
18cfd74d65d832137e20e193c960802afba73b5d38sm
19cfd74d65d832137e20e193c960802afba73b5d38sm
20cfd74d65d832137e20e193c960802afba73b5d38smpublic class OrbitalMagnetComponent extends GameComponent {
21cfd74d65d832137e20e193c960802afba73b5d38sm	private final static float DEFAULT_STRENGTH = 15.0f;
22cfd74d65d832137e20e193c960802afba73b5d38sm
23cfd74d65d832137e20e193c960802afba73b5d38sm	private float mStrength;
24cfd74d65d832137e20e193c960802afba73b5d38sm	private Vector2 mCenter;
25cfd74d65d832137e20e193c960802afba73b5d38sm	private Vector2 mDelta;
26cfd74d65d832137e20e193c960802afba73b5d38sm	private Vector2 mRim;
27cfd74d65d832137e20e193c960802afba73b5d38sm	private Vector2 mVelocity;
28cfd74d65d832137e20e193c960802afba73b5d38sm	private float mMagnetRadius;
29cfd74d65d832137e20e193c960802afba73b5d38sm	private float mAreaRadius;
30cfd74d65d832137e20e193c960802afba73b5d38sm
31cfd74d65d832137e20e193c960802afba73b5d38sm	public OrbitalMagnetComponent() {
32cfd74d65d832137e20e193c960802afba73b5d38sm        super();
33cfd74d65d832137e20e193c960802afba73b5d38sm        mCenter = new Vector2();
34cfd74d65d832137e20e193c960802afba73b5d38sm        mDelta = new Vector2();
35cfd74d65d832137e20e193c960802afba73b5d38sm        mRim = new Vector2();
36cfd74d65d832137e20e193c960802afba73b5d38sm        mVelocity = new Vector2();
37cfd74d65d832137e20e193c960802afba73b5d38sm        reset();
38cfd74d65d832137e20e193c960802afba73b5d38sm        setPhase(ComponentPhases.COLLISION_DETECTION.ordinal());
39cfd74d65d832137e20e193c960802afba73b5d38sm    }
40cfd74d65d832137e20e193c960802afba73b5d38sm
41cfd74d65d832137e20e193c960802afba73b5d38sm    @Override
42cfd74d65d832137e20e193c960802afba73b5d38sm    public void reset() {
43cfd74d65d832137e20e193c960802afba73b5d38sm    	mCenter.zero();
44cfd74d65d832137e20e193c960802afba73b5d38sm    	mDelta.zero();
45cfd74d65d832137e20e193c960802afba73b5d38sm    	mRim.zero();
46cfd74d65d832137e20e193c960802afba73b5d38sm    	mVelocity.zero();
47cfd74d65d832137e20e193c960802afba73b5d38sm    	mStrength = DEFAULT_STRENGTH;
48cfd74d65d832137e20e193c960802afba73b5d38sm    	mAreaRadius = 0.0f;
49cfd74d65d832137e20e193c960802afba73b5d38sm    	mMagnetRadius = 0.0f;
50cfd74d65d832137e20e193c960802afba73b5d38sm    }
51cfd74d65d832137e20e193c960802afba73b5d38sm
52cfd74d65d832137e20e193c960802afba73b5d38sm    @Override
53cfd74d65d832137e20e193c960802afba73b5d38sm    public void update(float timeDelta, BaseObject parent) {
54cfd74d65d832137e20e193c960802afba73b5d38sm        GameObjectManager manager = sSystemRegistry.gameObjectManager;
55cfd74d65d832137e20e193c960802afba73b5d38sm        if (manager != null) {
56cfd74d65d832137e20e193c960802afba73b5d38sm        	GameObject player = manager.getPlayer();
57cfd74d65d832137e20e193c960802afba73b5d38sm        	if (player != null) {
58cfd74d65d832137e20e193c960802afba73b5d38sm        		GameObject parentObject =  (GameObject)parent;
59cfd74d65d832137e20e193c960802afba73b5d38sm        		applyMagnetism(player,
60cfd74d65d832137e20e193c960802afba73b5d38sm        				parentObject.getCenteredPositionX(),
61cfd74d65d832137e20e193c960802afba73b5d38sm        				parentObject.getCenteredPositionY(),
62cfd74d65d832137e20e193c960802afba73b5d38sm        				timeDelta);
63cfd74d65d832137e20e193c960802afba73b5d38sm        	}
64cfd74d65d832137e20e193c960802afba73b5d38sm        }
65cfd74d65d832137e20e193c960802afba73b5d38sm    }
66cfd74d65d832137e20e193c960802afba73b5d38sm
67cfd74d65d832137e20e193c960802afba73b5d38sm    private void applyMagnetism(GameObject target, float centerX, float centerY, float timeDelta) {
68cfd74d65d832137e20e193c960802afba73b5d38sm    	mCenter.set(centerX, centerY);
69cfd74d65d832137e20e193c960802afba73b5d38sm    	final float targetX = target.getCenteredPositionX();
70cfd74d65d832137e20e193c960802afba73b5d38sm    	final float targetY = target.getCenteredPositionY();
71cfd74d65d832137e20e193c960802afba73b5d38sm    	mDelta.set(targetX, targetY);
72cfd74d65d832137e20e193c960802afba73b5d38sm    	mDelta.subtract(mCenter);
73cfd74d65d832137e20e193c960802afba73b5d38sm
74cfd74d65d832137e20e193c960802afba73b5d38sm    	final float distanceFromCenter2 = mDelta.length2();
75cfd74d65d832137e20e193c960802afba73b5d38sm    	final float area2 = mAreaRadius * mAreaRadius;
76cfd74d65d832137e20e193c960802afba73b5d38sm    	if (distanceFromCenter2 < area2) {
77cfd74d65d832137e20e193c960802afba73b5d38sm    		mRim.set(mDelta);
78cfd74d65d832137e20e193c960802afba73b5d38sm    		mRim.normalize();
79cfd74d65d832137e20e193c960802afba73b5d38sm    		mRim.multiply(mMagnetRadius);
80cfd74d65d832137e20e193c960802afba73b5d38sm    		mRim.add(mCenter);
81cfd74d65d832137e20e193c960802afba73b5d38sm    		// rim is now the closest point on the magnet circle
82cfd74d65d832137e20e193c960802afba73b5d38sm
83cfd74d65d832137e20e193c960802afba73b5d38sm    		// remove gravity
84cfd74d65d832137e20e193c960802afba73b5d38sm    		final Vector2 targetVelocity = target.getVelocity();
85cfd74d65d832137e20e193c960802afba73b5d38sm    		GravityComponent gravity = target.findByClass(GravityComponent.class);
86cfd74d65d832137e20e193c960802afba73b5d38sm            final Vector2 gravityVector = gravity.getGravity();
87cfd74d65d832137e20e193c960802afba73b5d38sm            mVelocity.set(gravityVector);
88cfd74d65d832137e20e193c960802afba73b5d38sm            mVelocity.multiply(timeDelta);
89cfd74d65d832137e20e193c960802afba73b5d38sm            targetVelocity.subtract(mVelocity);
90cfd74d65d832137e20e193c960802afba73b5d38sm
91cfd74d65d832137e20e193c960802afba73b5d38sm    		mDelta.add(targetVelocity);
92cfd74d65d832137e20e193c960802afba73b5d38sm    		mDelta.normalize();
93cfd74d65d832137e20e193c960802afba73b5d38sm    		mDelta.multiply(mMagnetRadius);
94cfd74d65d832137e20e193c960802afba73b5d38sm    		mDelta.add(mCenter);
95cfd74d65d832137e20e193c960802afba73b5d38sm
96cfd74d65d832137e20e193c960802afba73b5d38sm    		// mDelta is now the next point on the magnet circle in the direction of
97cfd74d65d832137e20e193c960802afba73b5d38sm    		// movement.
98cfd74d65d832137e20e193c960802afba73b5d38sm
99cfd74d65d832137e20e193c960802afba73b5d38sm    		mDelta.subtract(mRim);
100cfd74d65d832137e20e193c960802afba73b5d38sm    		mDelta.normalize();
101cfd74d65d832137e20e193c960802afba73b5d38sm    		// Now mDelta is the tangent to the magnet circle, pointing in the direction
102cfd74d65d832137e20e193c960802afba73b5d38sm    		// of movement.
103cfd74d65d832137e20e193c960802afba73b5d38sm
104cfd74d65d832137e20e193c960802afba73b5d38sm    		mVelocity.set(mDelta);
105cfd74d65d832137e20e193c960802afba73b5d38sm    		mVelocity.normalize();
106cfd74d65d832137e20e193c960802afba73b5d38sm
107cfd74d65d832137e20e193c960802afba73b5d38sm    		// mVelocity is now the direction to push the player
108cfd74d65d832137e20e193c960802afba73b5d38sm
109cfd74d65d832137e20e193c960802afba73b5d38sm			mVelocity.multiply(mStrength);
110cfd74d65d832137e20e193c960802afba73b5d38sm			float weight = 1.0f;
111cfd74d65d832137e20e193c960802afba73b5d38sm			if (distanceFromCenter2 > mMagnetRadius * mMagnetRadius) {
112cfd74d65d832137e20e193c960802afba73b5d38sm				float distance = (float)Math.sqrt(distanceFromCenter2);
113cfd74d65d832137e20e193c960802afba73b5d38sm				weight = (distance - mMagnetRadius) / (mAreaRadius - mMagnetRadius);
114cfd74d65d832137e20e193c960802afba73b5d38sm				weight = 1.0f - weight;
115cfd74d65d832137e20e193c960802afba73b5d38sm				mVelocity.multiply(weight);
116cfd74d65d832137e20e193c960802afba73b5d38sm			}
117cfd74d65d832137e20e193c960802afba73b5d38sm			final float speed = targetVelocity.length();
118cfd74d65d832137e20e193c960802afba73b5d38sm			targetVelocity.add(mVelocity);
119cfd74d65d832137e20e193c960802afba73b5d38sm			if (targetVelocity.length2() > (speed * speed)) {
120cfd74d65d832137e20e193c960802afba73b5d38sm				targetVelocity.normalize();
121cfd74d65d832137e20e193c960802afba73b5d38sm				targetVelocity.multiply(speed);
122cfd74d65d832137e20e193c960802afba73b5d38sm			}
123cfd74d65d832137e20e193c960802afba73b5d38sm
124cfd74d65d832137e20e193c960802afba73b5d38sm    	}
125cfd74d65d832137e20e193c960802afba73b5d38sm
126cfd74d65d832137e20e193c960802afba73b5d38sm    }
127cfd74d65d832137e20e193c960802afba73b5d38sm
128cfd74d65d832137e20e193c960802afba73b5d38sm    public void setup(float areaRadius, float orbitRadius) {
129cfd74d65d832137e20e193c960802afba73b5d38sm    	mAreaRadius = areaRadius;
130cfd74d65d832137e20e193c960802afba73b5d38sm    	mMagnetRadius = orbitRadius;
131cfd74d65d832137e20e193c960802afba73b5d38sm    }
132cfd74d65d832137e20e193c960802afba73b5d38sm}
133