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