blob: 80db673fc57660a53f3d626154510e6b991519ef [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.replica.replicaisland;
import android.view.KeyEvent;
public class InputGameInterface extends BaseObject {
private static final float ORIENTATION_DEAD_ZONE_MIN = 0.03f;
private static final float ORIENTATION_DEAD_ZONE_MAX = 0.1f;
private static final float ORIENTATION_DEAD_ZONE_SCALE = 0.75f;
private final static float ROLL_TIMEOUT = 0.1f;
private final static float ROLL_RESET_DELAY = 0.075f;
// Raw trackball input is filtered by this value. Increasing it will
// make the control more twitchy, while decreasing it will make the control more precise.
private final static float ROLL_FILTER = 0.4f;
private final static float ROLL_DECAY = 8.0f;
private final static float KEY_FILTER = 0.25f;
private final static float SLIDER_FILTER = 0.25f;
private InputButton mJumpButton = new InputButton();
private InputButton mAttackButton = new InputButton();
private InputXY mDirectionalPad = new InputXY();
private InputXY mTilt = new InputXY();
private int mLeftKeyCode = KeyEvent.KEYCODE_DPAD_LEFT;
private int mRightKeyCode = KeyEvent.KEYCODE_DPAD_RIGHT;
private int mJumpKeyCode = KeyEvent.KEYCODE_SPACE;
private int mAttackKeyCode = KeyEvent.KEYCODE_SHIFT_LEFT;
private float mOrientationDeadZoneMin = ORIENTATION_DEAD_ZONE_MIN;
private float mOrientationDeadZoneMax = ORIENTATION_DEAD_ZONE_MAX;
private float mOrientationDeadZoneScale = ORIENTATION_DEAD_ZONE_SCALE;
private float mOrientationSensitivity = 1.0f;
private float mOrientationSensitivityFactor = 1.0f;
private float mMovementSensitivity = 1.0f;
private boolean mUseClickButtonForAttack = true;
private boolean mUseOrientationForMovement = false;
private boolean mUseOnScreenControls = false;
private float mLastRollTime;
public InputGameInterface() {
super();
reset();
}
@Override
public void reset() {
mJumpButton.release();
mAttackButton.release();
mDirectionalPad.release();
mTilt.release();
}
@Override
public void update(float timeDelta, BaseObject parent) {
InputSystem input = sSystemRegistry.inputSystem;
final InputButton[] keys = input.getKeyboard().getKeys();
final InputXY orientation = input.getOrientationSensor();
// tilt is easy
mTilt.clone(orientation);
final InputTouchScreen touch = input.getTouchScreen();
final float gameTime = sSystemRegistry.timeSystem.getGameTime();
float sliderOffset = 0;
// update movement inputs
if (mUseOnScreenControls) {
final InputXY sliderTouch = touch.findPointerInRegion(
ButtonConstants.MOVEMENT_SLIDER_REGION_X,
ButtonConstants.MOVEMENT_SLIDER_REGION_Y,
ButtonConstants.MOVEMENT_SLIDER_REGION_WIDTH,
ButtonConstants.MOVEMENT_SLIDER_REGION_HEIGHT);
if (sliderTouch != null) {
final float halfWidth = ButtonConstants.MOVEMENT_SLIDER_BAR_WIDTH / 2.0f;
final float center = ButtonConstants.MOVEMENT_SLIDER_X + halfWidth;
final float offset = sliderTouch.getX() - center;
float magnitudeRamp = Math.abs(offset) > halfWidth ? 1.0f : (Math.abs(offset) / halfWidth);
final float magnitude = magnitudeRamp * Utils.sign(offset) * SLIDER_FILTER * mMovementSensitivity;
sliderOffset = magnitudeRamp * Utils.sign(offset);
mDirectionalPad.press(gameTime, magnitude, 0.0f);
} else {
mDirectionalPad.release();
}
} else if (mUseOrientationForMovement) {
mDirectionalPad.clone(orientation);
mDirectionalPad.setMagnitude(
filterOrientationForMovement(orientation.getX()),
filterOrientationForMovement(orientation.getY()));
} else {
// keys or trackball
final InputXY trackball = input.getTrackball();
final InputButton left = keys[mLeftKeyCode];
final InputButton right = keys[mRightKeyCode];
final float leftPressedTime = left.getLastPressedTime();
final float rightPressedTime = right.getLastPressedTime();
if (trackball.getLastPressedTime() > Math.max(leftPressedTime, rightPressedTime)) {
// The trackball never goes "up", so force it to turn off if it wasn't triggered in the last frame.
// What follows is a bunch of code to filter trackball events into something like a dpad event.
// The goals here are:
// - For roll events that occur in quick succession to accumulate.
// - For roll events that occur with more time between them, lessen the impact of older events
// - In the absence of roll events, fade the roll out over time.
if (gameTime - trackball.getLastPressedTime() < ROLL_TIMEOUT) {
float newX;
float newY;
final float delay = Math.max(ROLL_RESET_DELAY, timeDelta);
if (gameTime - mLastRollTime <= delay) {
newX = mDirectionalPad.getX() + (trackball.getX() * ROLL_FILTER * mMovementSensitivity);
newY = mDirectionalPad.getY() + (trackball.getY() * ROLL_FILTER * mMovementSensitivity);
} else {
float oldX = mDirectionalPad.getX() != 0.0f ? mDirectionalPad.getX() / 2.0f : 0.0f;
float oldY = mDirectionalPad.getX() != 0.0f ? mDirectionalPad.getX() / 2.0f : 0.0f;
newX = oldX + (trackball.getX() * ROLL_FILTER * mMovementSensitivity);
newY = oldY + (trackball.getX() * ROLL_FILTER * mMovementSensitivity);
}
mDirectionalPad.press(gameTime, newX, newY);
mLastRollTime = gameTime;
trackball.release();
} else {
float x = mDirectionalPad.getX();
float y = mDirectionalPad.getY();
if (x != 0.0f) {
int sign = Utils.sign(x);
x = x - (sign * ROLL_DECAY * timeDelta);
if (Utils.sign(x) != sign) {
x = 0.0f;
}
}
if (y != 0.0f) {
int sign = Utils.sign(y);
y = y - (sign * ROLL_DECAY * timeDelta);
if (Utils.sign(x) != sign) {
y = 0.0f;
}
}
if (x == 0 && y == 0) {
mDirectionalPad.release();
} else {
mDirectionalPad.setMagnitude(x, y);
}
}
} else {
float xMagnitude = 0.0f;
float yMagnitude = 0.0f;
float pressTime = 0.0f;
// left and right are mutually exclusive
if (leftPressedTime > rightPressedTime) {
xMagnitude = -left.getMagnitude() * KEY_FILTER * mMovementSensitivity;
pressTime = leftPressedTime;
} else {
xMagnitude = right.getMagnitude() * KEY_FILTER * mMovementSensitivity;
pressTime = rightPressedTime;
}
if (xMagnitude != 0.0f) {
mDirectionalPad.press(pressTime, xMagnitude, yMagnitude);
} else {
mDirectionalPad.release();
}
}
}
// update other buttons
final InputButton jumpKey = keys[mJumpKeyCode];
// when on-screen movement controls are on, the fly and attack buttons are flipped.
float flyButtonRegionX = ButtonConstants.FLY_BUTTON_REGION_X;
float stompButtonRegionX = ButtonConstants.STOMP_BUTTON_REGION_X;
if (mUseOnScreenControls) {
ContextParameters params = sSystemRegistry.contextParameters;
flyButtonRegionX = params.gameWidth - ButtonConstants.FLY_BUTTON_REGION_WIDTH - ButtonConstants.FLY_BUTTON_REGION_X;
stompButtonRegionX = params.gameWidth - ButtonConstants.STOMP_BUTTON_REGION_WIDTH - ButtonConstants.STOMP_BUTTON_REGION_X;
}
final InputXY jumpTouch = touch.findPointerInRegion(
flyButtonRegionX,
ButtonConstants.FLY_BUTTON_REGION_Y,
ButtonConstants.FLY_BUTTON_REGION_WIDTH,
ButtonConstants.FLY_BUTTON_REGION_HEIGHT);
if (jumpKey.getPressed()) {
mJumpButton.press(jumpKey.getLastPressedTime(), jumpKey.getMagnitude());
} else if (jumpTouch != null) {
if (!mJumpButton.getPressed()) {
mJumpButton.press(jumpTouch.getLastPressedTime(), 1.0f);
}
} else {
mJumpButton.release();
}
final InputButton attackKey = keys[mAttackKeyCode];
final InputButton clickButton = keys[KeyEvent.KEYCODE_DPAD_CENTER]; // special case
final InputXY stompTouch = touch.findPointerInRegion(
stompButtonRegionX,
ButtonConstants.STOMP_BUTTON_REGION_Y,
ButtonConstants.STOMP_BUTTON_REGION_WIDTH,
ButtonConstants.STOMP_BUTTON_REGION_HEIGHT);
if (mUseClickButtonForAttack && clickButton.getPressed()) {
mAttackButton.press(clickButton.getLastPressedTime(), clickButton.getMagnitude());
} else if (attackKey.getPressed()) {
mAttackButton.press(attackKey.getLastPressedTime(), attackKey.getMagnitude());
} else if (stompTouch != null) {
// Since touch events come in constantly, we only want to press the attack button
// here if it's not already down. That makes it act like the other buttons (down once then up).
if (!mAttackButton.getPressed()) {
mAttackButton.press(stompTouch.getLastPressedTime(), 1.0f);
}
} else {
mAttackButton.release();
}
// This doesn't seem like exactly the right place to write to the HUD, but on the other hand,
// putting this code elsewhere causes dependencies between exact HUD content and physics, which
// we sometimes wish to avoid.
final HudSystem hud = sSystemRegistry.hudSystem;
if (hud != null) {
hud.setButtonState(mJumpButton.getPressed(), mAttackButton.getPressed(), mDirectionalPad.getPressed());
hud.setMovementSliderOffset(sliderOffset);
}
}
private float filterOrientationForMovement(float magnitude) {
float scaledMagnitude = magnitude * mOrientationSensitivityFactor;
return deadZoneFilter(scaledMagnitude, mOrientationDeadZoneMin, mOrientationDeadZoneMax, mOrientationDeadZoneScale);
}
private float deadZoneFilter(float magnitude, float min, float max, float scale) {
float smoothedMagnatude = magnitude;
if (Math.abs(magnitude) < min) {
smoothedMagnatude = 0.0f; // dead zone
} else if (Math.abs(magnitude) < max) {
smoothedMagnatude *= scale;
}
return smoothedMagnatude;
}
public final InputXY getDirectionalPad() {
return mDirectionalPad;
}
public final InputXY getTilt() {
return mTilt;
}
public final InputButton getJumpButton() {
return mJumpButton;
}
public final InputButton getAttackButton() {
return mAttackButton;
}
public void setKeys(int left, int right, int jump, int attack) {
mLeftKeyCode = left;
mRightKeyCode = right;
mJumpKeyCode = jump;
mAttackKeyCode = attack;
}
public void setUseClickForAttack(boolean click) {
mUseClickButtonForAttack = click;
}
public void setUseOrientationForMovement(boolean orientation) {
mUseOrientationForMovement = orientation;
}
public void setOrientationMovementSensitivity(float sensitivity) {
mOrientationSensitivity = sensitivity;
mOrientationSensitivityFactor = 2.9f * sensitivity + 0.1f;
}
public void setMovementSensitivity(float sensitivity) {
mMovementSensitivity = sensitivity;
}
public void setUseOnScreenControls(boolean onscreen) {
mUseOnScreenControls = onscreen;
}
}