InputGameInterface.java revision 9d4cc2572d37983607df38b0f4216ed76ac51814
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
17package com.replica.replicaisland;
18
19import android.view.KeyEvent;
20
21public class InputGameInterface extends BaseObject {
22	private static final float ORIENTATION_DEAD_ZONE_MIN = 0.03f;
23	private static final float ORIENTATION_DEAD_ZONE_MAX = 0.1f;
24	private static final float ORIENTATION_DEAD_ZONE_SCALE = 0.75f;
25
26	private final static float ROLL_TIMEOUT = 0.1f;
27	private final static float ROLL_RESET_DELAY = 0.075f;
28
29    // Raw trackball input is filtered by this value. Increasing it will
30    // make the control more twitchy, while decreasing it will make the control more precise.
31    private final static float ROLL_FILTER = 0.4f;
32    private final static float ROLL_DECAY = 8.0f;
33
34    private final static float KEY_FILTER = 0.25f;
35
36	private InputButton mJumpButton = new InputButton();
37	private InputButton mAttackButton = new InputButton();
38	private InputXY mDirectionalPad = new InputXY();
39	private InputXY mTilt = new InputXY();
40
41	private int mLeftKeyCode = KeyEvent.KEYCODE_DPAD_LEFT;
42	private int mRightKeyCode = KeyEvent.KEYCODE_DPAD_RIGHT;
43	private int mJumpKeyCode = KeyEvent.KEYCODE_SPACE;
44	private int mAttackKeyCode = KeyEvent.KEYCODE_SHIFT_LEFT;
45
46	private float mOrientationDeadZoneMin = ORIENTATION_DEAD_ZONE_MIN;
47	private float mOrientationDeadZoneMax = ORIENTATION_DEAD_ZONE_MAX;
48	private float mOrientationDeadZoneScale = ORIENTATION_DEAD_ZONE_SCALE;
49	private float mOrientationSensitivity = 1.0f;
50	private float mOrientationSensitivityFactor = 1.0f;
51	private float mMovementSensitivity = 1.0f;
52
53
54	private boolean mUseClickButtonForAttack = true;
55	private boolean mUseOrientationForMovement = false;
56
57	private float mLastRollTime;
58
59	public InputGameInterface() {
60		super();
61		reset();
62	}
63
64	@Override
65	public void reset() {
66		mJumpButton.release();
67		mAttackButton.release();
68		mDirectionalPad.release();
69		mTilt.release();
70	}
71
72
73
74	@Override
75    public void update(float timeDelta, BaseObject parent) {
76		InputSystem input = sSystemRegistry.inputSystem;
77		final InputButton[] keys = input.getKeyboard().getKeys();
78		final InputXY orientation = input.getOrientationSensor();
79
80		// tilt is easy
81		mTilt.clone(orientation);
82
83		// update movement inputs
84		if (mUseOrientationForMovement) {
85			mDirectionalPad.clone(orientation);
86			mDirectionalPad.setMagnitude(
87					filterOrientationForMovement(orientation.getX()),
88					filterOrientationForMovement(orientation.getY()));
89		} else {
90			// keys or trackball
91			final InputXY trackball = input.getTrackball();
92			final InputButton left = keys[mLeftKeyCode];
93			final InputButton right = keys[mRightKeyCode];
94			final float leftPressedTime = left.getLastPressedTime();
95			final float rightPressedTime = right.getLastPressedTime();
96
97			final float gameTime = sSystemRegistry.timeSystem.getGameTime();
98
99			if (trackball.getLastPressedTime() > Math.max(leftPressedTime, rightPressedTime)) {
100				// The trackball never goes "up", so force it to turn off if it wasn't triggered in the last frame.
101				// What follows is a bunch of code to filter trackball events into something like a dpad event.
102				// The goals here are:
103				// 	- For roll events that occur in quick succession to accumulate.
104				//	- For roll events that occur with more time between them, lessen the impact of older events
105				//	- In the absence of roll events, fade the roll out over time.
106				if (gameTime - trackball.getLastPressedTime() < ROLL_TIMEOUT) {
107					float newX;
108					float newY;
109					final float delay = Math.max(ROLL_RESET_DELAY, timeDelta);
110					if (gameTime - mLastRollTime <= delay) {
111						newX = mDirectionalPad.getX() + (trackball.getX() * ROLL_FILTER * mMovementSensitivity);
112						newY = mDirectionalPad.getY() + (trackball.getY() * ROLL_FILTER * mMovementSensitivity);
113					} else {
114						float oldX = mDirectionalPad.getX() != 0.0f ? mDirectionalPad.getX() / 2.0f : 0.0f;
115						float oldY = mDirectionalPad.getX() != 0.0f ? mDirectionalPad.getX() / 2.0f : 0.0f;
116						newX = oldX + (trackball.getX() * ROLL_FILTER * mMovementSensitivity);
117						newY = oldY + (trackball.getX() * ROLL_FILTER * mMovementSensitivity);
118					}
119
120					mDirectionalPad.press(gameTime, newX, newY);
121					mLastRollTime = gameTime;
122					trackball.release();
123				} else {
124					float x = mDirectionalPad.getX();
125					float y = mDirectionalPad.getY();
126					if (x != 0.0f) {
127						int sign = Utils.sign(x);
128						x = x - (sign * ROLL_DECAY * timeDelta);
129						if (Utils.sign(x) != sign) {
130							x = 0.0f;
131						}
132					}
133
134					if (y != 0.0f) {
135						int sign = Utils.sign(y);
136						y = y - (sign * ROLL_DECAY * timeDelta);
137						if (Utils.sign(x) != sign) {
138							y = 0.0f;
139						}
140					}
141
142
143					if (x == 0 && y == 0) {
144						mDirectionalPad.release();
145					} else {
146						mDirectionalPad.setMagnitude(x, y);
147					}
148				}
149
150			} else {
151				float xMagnitude = 0.0f;
152				float yMagnitude = 0.0f;
153				float pressTime = 0.0f;
154				// left and right are mutually exclusive
155				if (leftPressedTime > rightPressedTime) {
156					xMagnitude = -left.getMagnitude() * KEY_FILTER * mMovementSensitivity;
157					pressTime = leftPressedTime;
158				} else {
159					xMagnitude = right.getMagnitude() * KEY_FILTER * mMovementSensitivity;
160					pressTime = rightPressedTime;
161				}
162
163				if (xMagnitude != 0.0f) {
164					mDirectionalPad.press(pressTime, xMagnitude, yMagnitude);
165				} else {
166					mDirectionalPad.release();
167				}
168			}
169		}
170
171		// update other buttons
172		final InputButton jumpKey = keys[mJumpKeyCode];
173		final InputXY touch = input.getTouchScreen();
174
175		if (jumpKey.getPressed()) {
176			mJumpButton.press(jumpKey.getLastPressedTime(), jumpKey.getMagnitude());
177		} else if (touch.getPressed() && getTouchedWithinRegion(
178							touch.getX(),
179							touch.getY(),
180	                        ButtonConstants.FLY_BUTTON_REGION_X,
181	                        ButtonConstants.FLY_BUTTON_REGION_Y,
182	                        ButtonConstants.FLY_BUTTON_REGION_WIDTH,
183	                        ButtonConstants.FLY_BUTTON_REGION_HEIGHT)) {
184			if (!mJumpButton.getPressed()) {
185				mJumpButton.press(touch.getLastPressedTime(), 1.0f);
186			}
187		} else {
188			mJumpButton.release();
189		}
190
191		final InputButton attackKey = keys[mAttackKeyCode];
192		final InputButton clickButton = keys[KeyEvent.KEYCODE_DPAD_CENTER]; // special case
193
194		if (mUseClickButtonForAttack && clickButton.getPressed()) {
195			mAttackButton.press(clickButton.getLastPressedTime(), clickButton.getMagnitude());
196		} else if (attackKey.getPressed()) {
197			mAttackButton.press(attackKey.getLastPressedTime(), attackKey.getMagnitude());
198		} else if (touch.getPressed() && getTouchedWithinRegion(
199							touch.getX(),
200							touch.getY(),
201	                        ButtonConstants.STOMP_BUTTON_REGION_X,
202	                        ButtonConstants.STOMP_BUTTON_REGION_Y,
203	                        ButtonConstants.STOMP_BUTTON_REGION_WIDTH,
204	                        ButtonConstants.STOMP_BUTTON_REGION_HEIGHT)) {
205			// Since touch events come in constantly, we only want to press the attack button
206			// here if it's not already down.  That makes it act like the other buttons (down once then up).
207			if (!mAttackButton.getPressed()) {
208				mAttackButton.press(touch.getLastPressedTime(), 1.0f);
209			}
210		} else {
211			mAttackButton.release();
212		}
213	}
214
215
216	private float filterOrientationForMovement(float magnitude) {
217		float scaledMagnitude = magnitude * mOrientationSensitivityFactor;
218
219		return deadZoneFilter(scaledMagnitude, mOrientationDeadZoneMin, mOrientationDeadZoneMax, mOrientationDeadZoneScale);
220	}
221
222	private float deadZoneFilter(float magnitude, float min, float max, float scale) {
223		float smoothedMagnatude = magnitude;
224    	if (Math.abs(magnitude) < min) {
225    		smoothedMagnatude = 0.0f;	// dead zone
226    	} else if (Math.abs(magnitude) < max) {
227    		smoothedMagnatude *= scale;
228    	}
229
230    	return smoothedMagnatude;
231	}
232
233	private final boolean getTouchedWithinRegion(float x, float y, float regionX, float regionY, float regionWidth, float regionHeight) {
234		 return (x >= regionX &&
235				 y >= regionY &&
236				 x <= regionX + regionWidth &&
237				 y <= regionY + regionHeight);
238	}
239
240	public final InputXY getDirectionalPad() {
241		return mDirectionalPad;
242	}
243
244	public final InputXY getTilt() {
245		return mTilt;
246	}
247
248	public final InputButton getJumpButton() {
249		return mJumpButton;
250	}
251
252	public final InputButton getAttackButton() {
253		return mAttackButton;
254	}
255
256	public void setKeys(int left, int right, int jump, int attack) {
257		mLeftKeyCode = left;
258		mRightKeyCode = right;
259		mJumpKeyCode = jump;
260		mAttackKeyCode = attack;
261	}
262
263	public void setUseClickForAttack(boolean click) {
264		mUseClickButtonForAttack = click;
265	}
266
267	public void setUseOrientationForMovement(boolean orientation) {
268		mUseOrientationForMovement = orientation;
269	}
270
271	public void setOrientationMovementSensitivity(float sensitivity) {
272		mOrientationSensitivity = sensitivity;
273		mOrientationSensitivityFactor = 2.9f * sensitivity + 0.1f;
274	}
275
276	public void setMovementSensitivity(float sensitivity) {
277		mMovementSensitivity  = sensitivity;
278	}
279
280}
281