1*5eae8ebbSCole Faust /* 2*5eae8ebbSCole Faust * Copyright (C) 2010 The Android Open Source Project 3*5eae8ebbSCole Faust * 4*5eae8ebbSCole Faust * Licensed under the Apache License, Version 2.0 (the "License"); 5*5eae8ebbSCole Faust * you may not use this file except in compliance with the License. 6*5eae8ebbSCole Faust * You may obtain a copy of the License at 7*5eae8ebbSCole Faust * 8*5eae8ebbSCole Faust * http://www.apache.org/licenses/LICENSE-2.0 9*5eae8ebbSCole Faust * 10*5eae8ebbSCole Faust * Unless required by applicable law or agreed to in writing, software 11*5eae8ebbSCole Faust * distributed under the License is distributed on an "AS IS" BASIS, 12*5eae8ebbSCole Faust * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*5eae8ebbSCole Faust * See the License for the specific language governing permissions and 14*5eae8ebbSCole Faust * limitations under the License. 15*5eae8ebbSCole Faust */ 16*5eae8ebbSCole Faust 17*5eae8ebbSCole Faust package com.replica.replicaisland; 18*5eae8ebbSCole Faust 19*5eae8ebbSCole Faust import android.view.KeyEvent; 20*5eae8ebbSCole Faust 21*5eae8ebbSCole Faust public class InputGameInterface extends BaseObject { 22*5eae8ebbSCole Faust private static final float ORIENTATION_DEAD_ZONE_MIN = 0.03f; 23*5eae8ebbSCole Faust private static final float ORIENTATION_DEAD_ZONE_MAX = 0.1f; 24*5eae8ebbSCole Faust private static final float ORIENTATION_DEAD_ZONE_SCALE = 0.75f; 25*5eae8ebbSCole Faust 26*5eae8ebbSCole Faust private final static float ROLL_TIMEOUT = 0.1f; 27*5eae8ebbSCole Faust private final static float ROLL_RESET_DELAY = 0.075f; 28*5eae8ebbSCole Faust 29*5eae8ebbSCole Faust // Raw trackball input is filtered by this value. Increasing it will 30*5eae8ebbSCole Faust // make the control more twitchy, while decreasing it will make the control more precise. 31*5eae8ebbSCole Faust private final static float ROLL_FILTER = 0.4f; 32*5eae8ebbSCole Faust private final static float ROLL_DECAY = 8.0f; 33*5eae8ebbSCole Faust 34*5eae8ebbSCole Faust private final static float KEY_FILTER = 0.25f; 35*5eae8ebbSCole Faust private final static float SLIDER_FILTER = 0.25f; 36*5eae8ebbSCole Faust 37*5eae8ebbSCole Faust 38*5eae8ebbSCole Faust private InputButton mJumpButton = new InputButton(); 39*5eae8ebbSCole Faust private InputButton mAttackButton = new InputButton(); 40*5eae8ebbSCole Faust private InputXY mDirectionalPad = new InputXY(); 41*5eae8ebbSCole Faust private InputXY mTilt = new InputXY(); 42*5eae8ebbSCole Faust 43*5eae8ebbSCole Faust private int mLeftKeyCode = KeyEvent.KEYCODE_DPAD_LEFT; 44*5eae8ebbSCole Faust private int mRightKeyCode = KeyEvent.KEYCODE_DPAD_RIGHT; 45*5eae8ebbSCole Faust private int mJumpKeyCode = KeyEvent.KEYCODE_SPACE; 46*5eae8ebbSCole Faust private int mAttackKeyCode = KeyEvent.KEYCODE_SHIFT_LEFT; 47*5eae8ebbSCole Faust 48*5eae8ebbSCole Faust private float mOrientationDeadZoneMin = ORIENTATION_DEAD_ZONE_MIN; 49*5eae8ebbSCole Faust private float mOrientationDeadZoneMax = ORIENTATION_DEAD_ZONE_MAX; 50*5eae8ebbSCole Faust private float mOrientationDeadZoneScale = ORIENTATION_DEAD_ZONE_SCALE; 51*5eae8ebbSCole Faust private float mOrientationSensitivity = 1.0f; 52*5eae8ebbSCole Faust private float mOrientationSensitivityFactor = 1.0f; 53*5eae8ebbSCole Faust private float mMovementSensitivity = 1.0f; 54*5eae8ebbSCole Faust 55*5eae8ebbSCole Faust private boolean mUseClickButtonForAttack = true; 56*5eae8ebbSCole Faust private boolean mUseOrientationForMovement = false; 57*5eae8ebbSCole Faust private boolean mUseOnScreenControls = false; 58*5eae8ebbSCole Faust 59*5eae8ebbSCole Faust private float mLastRollTime; 60*5eae8ebbSCole Faust InputGameInterface()61*5eae8ebbSCole Faust public InputGameInterface() { 62*5eae8ebbSCole Faust super(); 63*5eae8ebbSCole Faust reset(); 64*5eae8ebbSCole Faust } 65*5eae8ebbSCole Faust 66*5eae8ebbSCole Faust @Override reset()67*5eae8ebbSCole Faust public void reset() { 68*5eae8ebbSCole Faust mJumpButton.release(); 69*5eae8ebbSCole Faust mAttackButton.release(); 70*5eae8ebbSCole Faust mDirectionalPad.release(); 71*5eae8ebbSCole Faust mTilt.release(); 72*5eae8ebbSCole Faust } 73*5eae8ebbSCole Faust 74*5eae8ebbSCole Faust 75*5eae8ebbSCole Faust 76*5eae8ebbSCole Faust @Override update(float timeDelta, BaseObject parent)77*5eae8ebbSCole Faust public void update(float timeDelta, BaseObject parent) { 78*5eae8ebbSCole Faust InputSystem input = sSystemRegistry.inputSystem; 79*5eae8ebbSCole Faust final InputButton[] keys = input.getKeyboard().getKeys(); 80*5eae8ebbSCole Faust final InputXY orientation = input.getOrientationSensor(); 81*5eae8ebbSCole Faust 82*5eae8ebbSCole Faust // tilt is easy 83*5eae8ebbSCole Faust mTilt.clone(orientation); 84*5eae8ebbSCole Faust 85*5eae8ebbSCole Faust final InputTouchScreen touch = input.getTouchScreen(); 86*5eae8ebbSCole Faust final float gameTime = sSystemRegistry.timeSystem.getGameTime(); 87*5eae8ebbSCole Faust 88*5eae8ebbSCole Faust float sliderOffset = 0; 89*5eae8ebbSCole Faust 90*5eae8ebbSCole Faust // update movement inputs 91*5eae8ebbSCole Faust if (mUseOnScreenControls) { 92*5eae8ebbSCole Faust final InputXY sliderTouch = touch.findPointerInRegion( 93*5eae8ebbSCole Faust ButtonConstants.MOVEMENT_SLIDER_REGION_X, 94*5eae8ebbSCole Faust ButtonConstants.MOVEMENT_SLIDER_REGION_Y, 95*5eae8ebbSCole Faust ButtonConstants.MOVEMENT_SLIDER_REGION_WIDTH, 96*5eae8ebbSCole Faust ButtonConstants.MOVEMENT_SLIDER_REGION_HEIGHT); 97*5eae8ebbSCole Faust 98*5eae8ebbSCole Faust if (sliderTouch != null) { 99*5eae8ebbSCole Faust final float halfWidth = ButtonConstants.MOVEMENT_SLIDER_BAR_WIDTH / 2.0f; 100*5eae8ebbSCole Faust final float center = ButtonConstants.MOVEMENT_SLIDER_X + halfWidth; 101*5eae8ebbSCole Faust final float offset = sliderTouch.getX() - center; 102*5eae8ebbSCole Faust float magnitudeRamp = Math.abs(offset) > halfWidth ? 1.0f : (Math.abs(offset) / halfWidth); 103*5eae8ebbSCole Faust 104*5eae8ebbSCole Faust final float magnitude = magnitudeRamp * Utils.sign(offset) * SLIDER_FILTER * mMovementSensitivity; 105*5eae8ebbSCole Faust sliderOffset = magnitudeRamp * Utils.sign(offset); 106*5eae8ebbSCole Faust mDirectionalPad.press(gameTime, magnitude, 0.0f); 107*5eae8ebbSCole Faust } else { 108*5eae8ebbSCole Faust mDirectionalPad.release(); 109*5eae8ebbSCole Faust } 110*5eae8ebbSCole Faust } else if (mUseOrientationForMovement) { 111*5eae8ebbSCole Faust mDirectionalPad.clone(orientation); 112*5eae8ebbSCole Faust mDirectionalPad.setMagnitude( 113*5eae8ebbSCole Faust filterOrientationForMovement(orientation.getX()), 114*5eae8ebbSCole Faust filterOrientationForMovement(orientation.getY())); 115*5eae8ebbSCole Faust } else { 116*5eae8ebbSCole Faust // keys or trackball 117*5eae8ebbSCole Faust final InputXY trackball = input.getTrackball(); 118*5eae8ebbSCole Faust final InputButton left = keys[mLeftKeyCode]; 119*5eae8ebbSCole Faust final InputButton right = keys[mRightKeyCode]; 120*5eae8ebbSCole Faust final float leftPressedTime = left.getLastPressedTime(); 121*5eae8ebbSCole Faust final float rightPressedTime = right.getLastPressedTime(); 122*5eae8ebbSCole Faust 123*5eae8ebbSCole Faust 124*5eae8ebbSCole Faust if (trackball.getLastPressedTime() > Math.max(leftPressedTime, rightPressedTime)) { 125*5eae8ebbSCole Faust // The trackball never goes "up", so force it to turn off if it wasn't triggered in the last frame. 126*5eae8ebbSCole Faust // What follows is a bunch of code to filter trackball events into something like a dpad event. 127*5eae8ebbSCole Faust // The goals here are: 128*5eae8ebbSCole Faust // - For roll events that occur in quick succession to accumulate. 129*5eae8ebbSCole Faust // - For roll events that occur with more time between them, lessen the impact of older events 130*5eae8ebbSCole Faust // - In the absence of roll events, fade the roll out over time. 131*5eae8ebbSCole Faust if (gameTime - trackball.getLastPressedTime() < ROLL_TIMEOUT) { 132*5eae8ebbSCole Faust float newX; 133*5eae8ebbSCole Faust float newY; 134*5eae8ebbSCole Faust final float delay = Math.max(ROLL_RESET_DELAY, timeDelta); 135*5eae8ebbSCole Faust if (gameTime - mLastRollTime <= delay) { 136*5eae8ebbSCole Faust newX = mDirectionalPad.getX() + (trackball.getX() * ROLL_FILTER * mMovementSensitivity); 137*5eae8ebbSCole Faust newY = mDirectionalPad.getY() + (trackball.getY() * ROLL_FILTER * mMovementSensitivity); 138*5eae8ebbSCole Faust } else { 139*5eae8ebbSCole Faust float oldX = mDirectionalPad.getX() != 0.0f ? mDirectionalPad.getX() / 2.0f : 0.0f; 140*5eae8ebbSCole Faust float oldY = mDirectionalPad.getX() != 0.0f ? mDirectionalPad.getX() / 2.0f : 0.0f; 141*5eae8ebbSCole Faust newX = oldX + (trackball.getX() * ROLL_FILTER * mMovementSensitivity); 142*5eae8ebbSCole Faust newY = oldY + (trackball.getX() * ROLL_FILTER * mMovementSensitivity); 143*5eae8ebbSCole Faust } 144*5eae8ebbSCole Faust 145*5eae8ebbSCole Faust mDirectionalPad.press(gameTime, newX, newY); 146*5eae8ebbSCole Faust mLastRollTime = gameTime; 147*5eae8ebbSCole Faust trackball.release(); 148*5eae8ebbSCole Faust } else { 149*5eae8ebbSCole Faust float x = mDirectionalPad.getX(); 150*5eae8ebbSCole Faust float y = mDirectionalPad.getY(); 151*5eae8ebbSCole Faust if (x != 0.0f) { 152*5eae8ebbSCole Faust int sign = Utils.sign(x); 153*5eae8ebbSCole Faust x = x - (sign * ROLL_DECAY * timeDelta); 154*5eae8ebbSCole Faust if (Utils.sign(x) != sign) { 155*5eae8ebbSCole Faust x = 0.0f; 156*5eae8ebbSCole Faust } 157*5eae8ebbSCole Faust } 158*5eae8ebbSCole Faust 159*5eae8ebbSCole Faust if (y != 0.0f) { 160*5eae8ebbSCole Faust int sign = Utils.sign(y); 161*5eae8ebbSCole Faust y = y - (sign * ROLL_DECAY * timeDelta); 162*5eae8ebbSCole Faust if (Utils.sign(x) != sign) { 163*5eae8ebbSCole Faust y = 0.0f; 164*5eae8ebbSCole Faust } 165*5eae8ebbSCole Faust } 166*5eae8ebbSCole Faust 167*5eae8ebbSCole Faust 168*5eae8ebbSCole Faust if (x == 0 && y == 0) { 169*5eae8ebbSCole Faust mDirectionalPad.release(); 170*5eae8ebbSCole Faust } else { 171*5eae8ebbSCole Faust mDirectionalPad.setMagnitude(x, y); 172*5eae8ebbSCole Faust } 173*5eae8ebbSCole Faust } 174*5eae8ebbSCole Faust 175*5eae8ebbSCole Faust } else { 176*5eae8ebbSCole Faust float xMagnitude = 0.0f; 177*5eae8ebbSCole Faust float yMagnitude = 0.0f; 178*5eae8ebbSCole Faust float pressTime = 0.0f; 179*5eae8ebbSCole Faust // left and right are mutually exclusive 180*5eae8ebbSCole Faust if (leftPressedTime > rightPressedTime) { 181*5eae8ebbSCole Faust xMagnitude = -left.getMagnitude() * KEY_FILTER * mMovementSensitivity; 182*5eae8ebbSCole Faust pressTime = leftPressedTime; 183*5eae8ebbSCole Faust } else { 184*5eae8ebbSCole Faust xMagnitude = right.getMagnitude() * KEY_FILTER * mMovementSensitivity; 185*5eae8ebbSCole Faust pressTime = rightPressedTime; 186*5eae8ebbSCole Faust } 187*5eae8ebbSCole Faust 188*5eae8ebbSCole Faust if (xMagnitude != 0.0f) { 189*5eae8ebbSCole Faust mDirectionalPad.press(pressTime, xMagnitude, yMagnitude); 190*5eae8ebbSCole Faust } else { 191*5eae8ebbSCole Faust mDirectionalPad.release(); 192*5eae8ebbSCole Faust } 193*5eae8ebbSCole Faust } 194*5eae8ebbSCole Faust } 195*5eae8ebbSCole Faust 196*5eae8ebbSCole Faust // update other buttons 197*5eae8ebbSCole Faust final InputButton jumpKey = keys[mJumpKeyCode]; 198*5eae8ebbSCole Faust 199*5eae8ebbSCole Faust // when on-screen movement controls are on, the fly and attack buttons are flipped. 200*5eae8ebbSCole Faust float flyButtonRegionX = ButtonConstants.FLY_BUTTON_REGION_X; 201*5eae8ebbSCole Faust float stompButtonRegionX = ButtonConstants.STOMP_BUTTON_REGION_X; 202*5eae8ebbSCole Faust 203*5eae8ebbSCole Faust if (mUseOnScreenControls) { 204*5eae8ebbSCole Faust ContextParameters params = sSystemRegistry.contextParameters; 205*5eae8ebbSCole Faust flyButtonRegionX = params.gameWidth - ButtonConstants.FLY_BUTTON_REGION_WIDTH - ButtonConstants.FLY_BUTTON_REGION_X; 206*5eae8ebbSCole Faust stompButtonRegionX = params.gameWidth - ButtonConstants.STOMP_BUTTON_REGION_WIDTH - ButtonConstants.STOMP_BUTTON_REGION_X; 207*5eae8ebbSCole Faust } 208*5eae8ebbSCole Faust 209*5eae8ebbSCole Faust final InputXY jumpTouch = touch.findPointerInRegion( 210*5eae8ebbSCole Faust flyButtonRegionX, 211*5eae8ebbSCole Faust ButtonConstants.FLY_BUTTON_REGION_Y, 212*5eae8ebbSCole Faust ButtonConstants.FLY_BUTTON_REGION_WIDTH, 213*5eae8ebbSCole Faust ButtonConstants.FLY_BUTTON_REGION_HEIGHT); 214*5eae8ebbSCole Faust 215*5eae8ebbSCole Faust if (jumpKey.getPressed()) { 216*5eae8ebbSCole Faust mJumpButton.press(jumpKey.getLastPressedTime(), jumpKey.getMagnitude()); 217*5eae8ebbSCole Faust } else if (jumpTouch != null) { 218*5eae8ebbSCole Faust if (!mJumpButton.getPressed()) { 219*5eae8ebbSCole Faust mJumpButton.press(jumpTouch.getLastPressedTime(), 1.0f); 220*5eae8ebbSCole Faust } 221*5eae8ebbSCole Faust } else { 222*5eae8ebbSCole Faust mJumpButton.release(); 223*5eae8ebbSCole Faust } 224*5eae8ebbSCole Faust 225*5eae8ebbSCole Faust final InputButton attackKey = keys[mAttackKeyCode]; 226*5eae8ebbSCole Faust final InputButton clickButton = keys[KeyEvent.KEYCODE_DPAD_CENTER]; // special case 227*5eae8ebbSCole Faust 228*5eae8ebbSCole Faust final InputXY stompTouch = touch.findPointerInRegion( 229*5eae8ebbSCole Faust stompButtonRegionX, 230*5eae8ebbSCole Faust ButtonConstants.STOMP_BUTTON_REGION_Y, 231*5eae8ebbSCole Faust ButtonConstants.STOMP_BUTTON_REGION_WIDTH, 232*5eae8ebbSCole Faust ButtonConstants.STOMP_BUTTON_REGION_HEIGHT); 233*5eae8ebbSCole Faust 234*5eae8ebbSCole Faust if (mUseClickButtonForAttack && clickButton.getPressed()) { 235*5eae8ebbSCole Faust mAttackButton.press(clickButton.getLastPressedTime(), clickButton.getMagnitude()); 236*5eae8ebbSCole Faust } else if (attackKey.getPressed()) { 237*5eae8ebbSCole Faust mAttackButton.press(attackKey.getLastPressedTime(), attackKey.getMagnitude()); 238*5eae8ebbSCole Faust } else if (stompTouch != null) { 239*5eae8ebbSCole Faust // Since touch events come in constantly, we only want to press the attack button 240*5eae8ebbSCole Faust // here if it's not already down. That makes it act like the other buttons (down once then up). 241*5eae8ebbSCole Faust if (!mAttackButton.getPressed()) { 242*5eae8ebbSCole Faust mAttackButton.press(stompTouch.getLastPressedTime(), 1.0f); 243*5eae8ebbSCole Faust } 244*5eae8ebbSCole Faust } else { 245*5eae8ebbSCole Faust mAttackButton.release(); 246*5eae8ebbSCole Faust } 247*5eae8ebbSCole Faust 248*5eae8ebbSCole Faust // This doesn't seem like exactly the right place to write to the HUD, but on the other hand, 249*5eae8ebbSCole Faust // putting this code elsewhere causes dependencies between exact HUD content and physics, which 250*5eae8ebbSCole Faust // we sometimes wish to avoid. 251*5eae8ebbSCole Faust final HudSystem hud = sSystemRegistry.hudSystem; 252*5eae8ebbSCole Faust if (hud != null) { 253*5eae8ebbSCole Faust hud.setButtonState(mJumpButton.getPressed(), mAttackButton.getPressed(), mDirectionalPad.getPressed()); 254*5eae8ebbSCole Faust hud.setMovementSliderOffset(sliderOffset); 255*5eae8ebbSCole Faust } 256*5eae8ebbSCole Faust } 257*5eae8ebbSCole Faust 258*5eae8ebbSCole Faust filterOrientationForMovement(float magnitude)259*5eae8ebbSCole Faust private float filterOrientationForMovement(float magnitude) { 260*5eae8ebbSCole Faust float scaledMagnitude = magnitude * mOrientationSensitivityFactor; 261*5eae8ebbSCole Faust 262*5eae8ebbSCole Faust return deadZoneFilter(scaledMagnitude, mOrientationDeadZoneMin, mOrientationDeadZoneMax, mOrientationDeadZoneScale); 263*5eae8ebbSCole Faust } 264*5eae8ebbSCole Faust deadZoneFilter(float magnitude, float min, float max, float scale)265*5eae8ebbSCole Faust private float deadZoneFilter(float magnitude, float min, float max, float scale) { 266*5eae8ebbSCole Faust float smoothedMagnatude = magnitude; 267*5eae8ebbSCole Faust if (Math.abs(magnitude) < min) { 268*5eae8ebbSCole Faust smoothedMagnatude = 0.0f; // dead zone 269*5eae8ebbSCole Faust } else if (Math.abs(magnitude) < max) { 270*5eae8ebbSCole Faust smoothedMagnatude *= scale; 271*5eae8ebbSCole Faust } 272*5eae8ebbSCole Faust 273*5eae8ebbSCole Faust return smoothedMagnatude; 274*5eae8ebbSCole Faust } 275*5eae8ebbSCole Faust 276*5eae8ebbSCole Faust getDirectionalPad()277*5eae8ebbSCole Faust public final InputXY getDirectionalPad() { 278*5eae8ebbSCole Faust return mDirectionalPad; 279*5eae8ebbSCole Faust } 280*5eae8ebbSCole Faust getTilt()281*5eae8ebbSCole Faust public final InputXY getTilt() { 282*5eae8ebbSCole Faust return mTilt; 283*5eae8ebbSCole Faust } 284*5eae8ebbSCole Faust getJumpButton()285*5eae8ebbSCole Faust public final InputButton getJumpButton() { 286*5eae8ebbSCole Faust return mJumpButton; 287*5eae8ebbSCole Faust } 288*5eae8ebbSCole Faust getAttackButton()289*5eae8ebbSCole Faust public final InputButton getAttackButton() { 290*5eae8ebbSCole Faust return mAttackButton; 291*5eae8ebbSCole Faust } 292*5eae8ebbSCole Faust setKeys(int left, int right, int jump, int attack)293*5eae8ebbSCole Faust public void setKeys(int left, int right, int jump, int attack) { 294*5eae8ebbSCole Faust mLeftKeyCode = left; 295*5eae8ebbSCole Faust mRightKeyCode = right; 296*5eae8ebbSCole Faust mJumpKeyCode = jump; 297*5eae8ebbSCole Faust mAttackKeyCode = attack; 298*5eae8ebbSCole Faust } 299*5eae8ebbSCole Faust setUseClickForAttack(boolean click)300*5eae8ebbSCole Faust public void setUseClickForAttack(boolean click) { 301*5eae8ebbSCole Faust mUseClickButtonForAttack = click; 302*5eae8ebbSCole Faust } 303*5eae8ebbSCole Faust setUseOrientationForMovement(boolean orientation)304*5eae8ebbSCole Faust public void setUseOrientationForMovement(boolean orientation) { 305*5eae8ebbSCole Faust mUseOrientationForMovement = orientation; 306*5eae8ebbSCole Faust } 307*5eae8ebbSCole Faust setOrientationMovementSensitivity(float sensitivity)308*5eae8ebbSCole Faust public void setOrientationMovementSensitivity(float sensitivity) { 309*5eae8ebbSCole Faust mOrientationSensitivity = sensitivity; 310*5eae8ebbSCole Faust mOrientationSensitivityFactor = 2.9f * sensitivity + 0.1f; 311*5eae8ebbSCole Faust } 312*5eae8ebbSCole Faust setMovementSensitivity(float sensitivity)313*5eae8ebbSCole Faust public void setMovementSensitivity(float sensitivity) { 314*5eae8ebbSCole Faust mMovementSensitivity = sensitivity; 315*5eae8ebbSCole Faust } 316*5eae8ebbSCole Faust setUseOnScreenControls(boolean onscreen)317*5eae8ebbSCole Faust public void setUseOnScreenControls(boolean onscreen) { 318*5eae8ebbSCole Faust mUseOnScreenControls = onscreen; 319*5eae8ebbSCole Faust } 320*5eae8ebbSCole Faust 321*5eae8ebbSCole Faust } 322