| /* |
| * 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; |
| |
| /** |
| * A very simple manager for orthographic in-game UI elements. |
| * TODO: This should probably manage a number of hud objects in keeping with the component-centric |
| * architecture of this engine. The current code is monolithic and should be refactored. |
| */ |
| public class HudSystem extends BaseObject { |
| private static final int FUEL_BAR_EDGE_PADDING = 15; |
| private static final float FUEL_DECREASE_BAR_SPEED = 0.75f; |
| private static final float FUEL_INCREASE_BAR_SPEED = 2.0f; |
| private static final float FLY_BUTTON_X = -12.0f; |
| private static final float FLY_BUTTON_Y = -5.0f; |
| private static final float STOMP_BUTTON_X = 85.0f; |
| private static final float STOMP_BUTTON_Y = -10.0f; |
| private static final float STOMP_BUTTON_SCALE = 0.65f; |
| private static final int COLLECTABLE_EDGE_PADDING = 8; |
| private static final int MAX_DIGITS = 4; |
| private static final float MOVEMENT_SLIDER_BASE_X = 20.0f; |
| private static final float MOVEMENT_SLIDER_BASE_Y = 32.0f; |
| private static final float MOVEMENT_SLIDER_BUTTON_X = MOVEMENT_SLIDER_BASE_X + 32.0f; |
| private static final float MOVEMENT_SLIDER_BUTTON_Y = MOVEMENT_SLIDER_BASE_Y - 16.0f; |
| private static final float FLY_BUTTON_WIDTH = 128; |
| private static final float STOMP_BUTTON_WIDTH = FLY_BUTTON_WIDTH * STOMP_BUTTON_SCALE; |
| private static final float MOVEMENT_SLIDER_WIDTH = 128; |
| |
| private DrawableBitmap mFuelDrawable; |
| private DrawableBitmap mFuelBackgroundDrawable; |
| private float mFuelPercent; |
| private float mFuelTargetPercent; |
| |
| private Texture mFadeTexture; |
| private float mFadeStartTime; |
| private float mFadeDuration; |
| private boolean mFadeIn; |
| private boolean mFading; |
| private int mFadePendingEventType; |
| private int mFadePendingEventIndex; |
| |
| private DrawableBitmap mFlyButtonEnabledDrawable; |
| private DrawableBitmap mFlyButtonDisabledDrawable; |
| private DrawableBitmap mFlyButtonDepressedDrawable; |
| |
| private DrawableBitmap mStompButtonEnabledDrawable; |
| private DrawableBitmap mStompButtonDepressedDrawable; |
| |
| private DrawableBitmap mMovementSliderBaseDrawable; |
| private DrawableBitmap mMovementSliderButtonDrawable; |
| private DrawableBitmap mMovementSliderButtonDepressedDrawable; |
| |
| |
| private Vector2 mFlyButtonLocation; |
| private boolean mFlyButtonActive; |
| private boolean mFlyButtonPressed; |
| |
| private Vector2 mStompButtonLocation; |
| private boolean mStompButtonPressed; |
| |
| private Vector2 mMovementSliderBaseLocation; |
| private Vector2 mMovementSliderButtonLocation; |
| private boolean mMovementSliderMode; |
| private boolean mMovementSliderButtonPressed; |
| |
| private DrawableBitmap mRubyDrawable; |
| private DrawableBitmap mCoinDrawable; |
| |
| private int mCoinCount; |
| private int mRubyCount; |
| private Vector2 mCoinLocation; |
| private Vector2 mRubyLocation; |
| private int[] mCoinDigits; |
| private int[] mRubyDigits; |
| private boolean mCoinDigitsChanged; |
| private boolean mRubyDigitsChanged; |
| |
| private int mFPS; |
| private Vector2 mFPSLocation; |
| private int[] mFPSDigits; |
| private boolean mFPSDigitsChanged; |
| private boolean mShowFPS; |
| |
| private DrawableBitmap[] mDigitDrawables; |
| private DrawableBitmap mXDrawable; |
| |
| |
| public HudSystem() { |
| super(); |
| mFlyButtonLocation = new Vector2(); |
| mStompButtonLocation = new Vector2(); |
| mCoinLocation = new Vector2(); |
| mRubyLocation = new Vector2(); |
| mFPSLocation = new Vector2(); |
| mDigitDrawables = new DrawableBitmap[10]; |
| mCoinDigits = new int[MAX_DIGITS]; |
| mRubyDigits = new int[MAX_DIGITS]; |
| mFPSDigits = new int[MAX_DIGITS]; |
| mMovementSliderBaseLocation = new Vector2(); |
| mMovementSliderButtonLocation = new Vector2(); |
| |
| reset(); |
| } |
| |
| @Override |
| public void reset() { |
| mFuelDrawable = null; |
| mFadeTexture = null; |
| mFuelPercent = 1.0f; |
| mFuelTargetPercent = 1.0f; |
| mFading = false; |
| mFlyButtonDisabledDrawable = null; |
| mFlyButtonEnabledDrawable = null; |
| mFlyButtonDepressedDrawable = null; |
| mFlyButtonLocation.set(FLY_BUTTON_X, FLY_BUTTON_Y); |
| mFlyButtonActive = true; |
| mFlyButtonPressed = false; |
| mStompButtonEnabledDrawable = null; |
| mStompButtonDepressedDrawable = null; |
| mStompButtonLocation.set(STOMP_BUTTON_X, STOMP_BUTTON_Y); |
| mStompButtonPressed = false; |
| mCoinCount = 0; |
| mRubyCount = 0; |
| mCoinDigits[0] = 0; |
| mCoinDigits[1] = -1; |
| mRubyDigits[0] = 0; |
| mRubyDigits[1] = -1; |
| mCoinDigitsChanged = true; |
| mRubyDigitsChanged = true; |
| mFPS = 0; |
| mFPSDigits[0] = 0; |
| mFPSDigits[1] = -1; |
| mFPSDigitsChanged = true; |
| mShowFPS = false; |
| for (int x = 0; x < mDigitDrawables.length; x++) { |
| mDigitDrawables[x] = null; |
| } |
| mXDrawable = null; |
| mFadePendingEventType = GameFlowEvent.EVENT_INVALID; |
| mFadePendingEventIndex = 0; |
| |
| mMovementSliderBaseDrawable = null; |
| mMovementSliderButtonDrawable = null; |
| mMovementSliderButtonDepressedDrawable = null; |
| mMovementSliderBaseLocation.set(MOVEMENT_SLIDER_BASE_X, MOVEMENT_SLIDER_BASE_Y); |
| mMovementSliderButtonLocation.set(MOVEMENT_SLIDER_BUTTON_X, MOVEMENT_SLIDER_BUTTON_Y); |
| mMovementSliderMode = false; |
| mMovementSliderButtonPressed = false; |
| } |
| |
| public void setFuelPercent(float percent) { |
| mFuelTargetPercent = percent; |
| } |
| |
| public void setFuelDrawable(DrawableBitmap fuel, DrawableBitmap background) { |
| mFuelDrawable = fuel; |
| mFuelBackgroundDrawable = background; |
| } |
| |
| public void setFadeTexture(Texture texture) { |
| mFadeTexture = texture; |
| } |
| |
| public void setButtonDrawables(DrawableBitmap disabled, DrawableBitmap enabled, DrawableBitmap depressed, |
| DrawableBitmap stompEnabled, DrawableBitmap stompDepressed, |
| DrawableBitmap sliderBase, DrawableBitmap sliderButton, DrawableBitmap sliderDepressed) { |
| mFlyButtonDisabledDrawable = disabled; |
| mFlyButtonEnabledDrawable = enabled; |
| mFlyButtonDepressedDrawable = depressed; |
| mStompButtonEnabledDrawable = stompEnabled; |
| mStompButtonDepressedDrawable = stompDepressed; |
| mMovementSliderBaseDrawable = sliderBase; |
| mMovementSliderButtonDrawable = sliderButton; |
| mMovementSliderButtonDepressedDrawable = sliderDepressed; |
| } |
| |
| public void setDigitDrawables(DrawableBitmap[] digits, DrawableBitmap xMark) { |
| mXDrawable = xMark; |
| for (int x = 0; x < mDigitDrawables.length && x < digits.length; x++) { |
| mDigitDrawables[x] = digits[x]; |
| } |
| } |
| |
| public void setCollectableDrawables(DrawableBitmap coin, DrawableBitmap ruby) { |
| mCoinDrawable = coin; |
| mRubyDrawable = ruby; |
| } |
| |
| public void setButtonState(boolean pressed, boolean attackPressed, boolean sliderPressed) { |
| mFlyButtonPressed = pressed; |
| mStompButtonPressed = attackPressed; |
| mMovementSliderButtonPressed = sliderPressed; |
| } |
| |
| public void startFade(boolean in, float duration) { |
| mFadeStartTime = sSystemRegistry.timeSystem.getRealTime(); |
| mFadeDuration = duration; |
| mFadeIn = in; |
| mFading = true; |
| } |
| |
| public void clearFade() { |
| mFading = false; |
| } |
| |
| public boolean isFading() { |
| return mFading; |
| } |
| |
| public void updateInventory(InventoryComponent.UpdateRecord newInventory) { |
| mCoinDigitsChanged = (mCoinCount != newInventory.coinCount); |
| mRubyDigitsChanged = (mRubyCount != newInventory.rubyCount); |
| |
| mCoinCount = newInventory.coinCount; |
| mRubyCount = newInventory.rubyCount; |
| } |
| |
| public void setFPS(int fps) { |
| mFPSDigitsChanged = (fps != mFPS); |
| mFPS = fps; |
| } |
| |
| public void setShowFPS(boolean show) { |
| mShowFPS = show; |
| } |
| |
| public void setMovementSliderMode(boolean sliderOn) { |
| mMovementSliderMode = sliderOn; |
| if (sliderOn) { |
| ContextParameters params = sSystemRegistry.contextParameters; |
| mFlyButtonLocation.set(params.gameWidth - FLY_BUTTON_WIDTH - FLY_BUTTON_X, FLY_BUTTON_Y); |
| mStompButtonLocation.set(params.gameWidth - STOMP_BUTTON_WIDTH - STOMP_BUTTON_X, STOMP_BUTTON_Y); |
| } else { |
| mFlyButtonLocation.set(FLY_BUTTON_X, FLY_BUTTON_Y); |
| mStompButtonLocation.set(STOMP_BUTTON_X, STOMP_BUTTON_Y); |
| } |
| } |
| public void setMovementSliderOffset(float offset) { |
| mMovementSliderButtonLocation.set(MOVEMENT_SLIDER_BUTTON_X + (offset * (MOVEMENT_SLIDER_WIDTH / 2.0f)), MOVEMENT_SLIDER_BUTTON_Y); |
| } |
| |
| @Override |
| public void update(float timeDelta, BaseObject parent) { |
| final RenderSystem render = sSystemRegistry.renderSystem; |
| final VectorPool pool = sSystemRegistry.vectorPool; |
| final ContextParameters params = sSystemRegistry.contextParameters; |
| final DrawableFactory factory = sSystemRegistry.drawableFactory; |
| |
| final GameObjectManager manager = sSystemRegistry.gameObjectManager; |
| |
| if (manager != null && manager.getPlayer() != null) { |
| // Only draw player-specific HUD elements when there's a player. |
| if (mFuelDrawable != null && mFuelBackgroundDrawable != null |
| && render != null && pool != null && factory != null && params != null) { |
| if (mFuelPercent < mFuelTargetPercent) { |
| mFuelPercent += (FUEL_INCREASE_BAR_SPEED * timeDelta); |
| if (mFuelPercent > mFuelTargetPercent) { |
| mFuelPercent = mFuelTargetPercent; |
| } |
| } else if (mFuelPercent > mFuelTargetPercent) { |
| mFuelPercent -= (FUEL_DECREASE_BAR_SPEED * timeDelta); |
| if (mFuelPercent < mFuelTargetPercent) { |
| mFuelPercent = mFuelTargetPercent; |
| } |
| } |
| |
| if (mFuelBackgroundDrawable.getWidth() == 0) { |
| // first time init |
| Texture tex = mFuelDrawable.getTexture(); |
| mFuelDrawable.resize(tex.width, tex.height); |
| Texture backgroundTex = mFuelBackgroundDrawable.getTexture(); |
| mFuelBackgroundDrawable.resize(backgroundTex.width, backgroundTex.height); |
| } |
| |
| final int height = mFuelDrawable.getHeight(); |
| |
| |
| Vector2 location = pool.allocate(); |
| location.set(FUEL_BAR_EDGE_PADDING, |
| params.gameHeight - height - FUEL_BAR_EDGE_PADDING); |
| render.scheduleForDraw(mFuelBackgroundDrawable, location, SortConstants.HUD, false); |
| location.x += 2; |
| location.y += 2; |
| final int barWidth = (int)((100 - 4) * mFuelPercent); |
| if (barWidth >= 1) { |
| DrawableBitmap bitmap = factory.allocateDrawableBitmap(); |
| if (bitmap != null) { |
| bitmap.resize(barWidth, mFuelDrawable.getHeight()); |
| bitmap.setTexture(mFuelDrawable.getTexture()); |
| render.scheduleForDraw(bitmap, location, SortConstants.HUD + 1, false); |
| } |
| } |
| |
| pool.release(location); |
| } |
| |
| if (mFlyButtonDisabledDrawable != null && mFlyButtonEnabledDrawable != null |
| && mFlyButtonDepressedDrawable != null) { |
| |
| DrawableBitmap bitmap = mFlyButtonEnabledDrawable; |
| if (mFlyButtonActive && mFlyButtonPressed) { |
| bitmap = mFlyButtonDepressedDrawable; |
| } else if (!mFlyButtonActive) { |
| bitmap = mFlyButtonDisabledDrawable; |
| } |
| |
| if (bitmap.getWidth() == 0) { |
| // first time init |
| Texture tex = bitmap.getTexture(); |
| bitmap.resize(tex.width, tex.height); |
| } |
| |
| render.scheduleForDraw(bitmap, mFlyButtonLocation, SortConstants.HUD, false); |
| } |
| |
| |
| |
| if (mStompButtonEnabledDrawable != null && mStompButtonDepressedDrawable != null) { |
| |
| DrawableBitmap bitmap = mStompButtonEnabledDrawable; |
| if (mStompButtonPressed) { |
| bitmap = mStompButtonDepressedDrawable; |
| } |
| |
| if (bitmap.getWidth() == 0) { |
| // first time init |
| Texture tex = bitmap.getTexture(); |
| bitmap.resize(tex.width, tex.height); |
| bitmap.setWidth((int)(tex.width * STOMP_BUTTON_SCALE)); |
| bitmap.setHeight((int)(tex.height * STOMP_BUTTON_SCALE)); |
| } |
| |
| render.scheduleForDraw(bitmap, mStompButtonLocation, SortConstants.HUD, false); |
| } |
| |
| if (mMovementSliderMode && |
| mMovementSliderBaseDrawable != null && mMovementSliderButtonDrawable != null) { |
| |
| if (mMovementSliderBaseDrawable.getWidth() == 0) { |
| // first time init |
| Texture tex = mMovementSliderBaseDrawable.getTexture(); |
| mMovementSliderBaseDrawable.resize(tex.width, tex.height); |
| } |
| |
| if (mMovementSliderButtonDrawable.getWidth() == 0) { |
| // first time init |
| Texture tex = mMovementSliderButtonDrawable.getTexture(); |
| mMovementSliderButtonDrawable.resize(tex.width, tex.height); |
| } |
| |
| if (mMovementSliderButtonDepressedDrawable.getWidth() == 0) { |
| // first time init |
| Texture tex = mMovementSliderButtonDepressedDrawable.getTexture(); |
| mMovementSliderButtonDepressedDrawable.resize(tex.width, tex.height); |
| } |
| |
| DrawableBitmap bitmap = mMovementSliderButtonDrawable; |
| |
| if (mMovementSliderButtonPressed) { |
| bitmap = mMovementSliderButtonDepressedDrawable; |
| } |
| |
| render.scheduleForDraw(mMovementSliderBaseDrawable, mMovementSliderBaseLocation, SortConstants.HUD, false); |
| render.scheduleForDraw(bitmap, mMovementSliderButtonLocation, SortConstants.HUD + 1, false); |
| |
| } |
| |
| |
| if (mCoinDrawable != null) { |
| if (mCoinDrawable.getWidth() == 0) { |
| // first time init |
| Texture tex = mCoinDrawable.getTexture(); |
| mCoinDrawable.resize(tex.width, tex.height); |
| mCoinLocation.x = (params.gameWidth / 2.0f) - tex.width / 2.0f; |
| mCoinLocation.y = params.gameHeight - tex.height - COLLECTABLE_EDGE_PADDING; |
| } |
| |
| render.scheduleForDraw(mCoinDrawable, mCoinLocation, SortConstants.HUD, false); |
| if (mCoinDigitsChanged) { |
| intToDigitArray(mCoinCount, mCoinDigits); |
| mCoinDigitsChanged = false; |
| } |
| final float offset = mCoinDrawable.getWidth() * 0.75f; |
| mCoinLocation.x += offset; |
| drawNumber(mCoinLocation, mCoinDigits, true); |
| mCoinLocation.x -= offset; |
| } |
| |
| if (mRubyDrawable != null) { |
| if (mRubyDrawable.getWidth() == 0) { |
| // first time init |
| Texture tex = mRubyDrawable.getTexture(); |
| mRubyDrawable.resize(tex.width, tex.height); |
| mRubyLocation.x = (params.gameWidth / 2.0f) + 100.0f; |
| mRubyLocation.y = params.gameHeight - tex.height - COLLECTABLE_EDGE_PADDING; |
| } |
| render.scheduleForDraw(mRubyDrawable, mRubyLocation, SortConstants.HUD, false); |
| if (mRubyDigitsChanged) { |
| intToDigitArray(mRubyCount, mRubyDigits); |
| mRubyDigitsChanged = false; |
| } |
| final float offset = mRubyDrawable.getWidth() * 0.75f; |
| mRubyLocation.x += offset; |
| drawNumber(mRubyLocation, mRubyDigits, true); |
| mRubyLocation.x -= offset; |
| } |
| } |
| |
| if (mShowFPS) { |
| if (mFPSDigitsChanged) { |
| int count = intToDigitArray(mFPS, mFPSDigits); |
| mFPSDigitsChanged = false; |
| mFPSLocation.set(params.gameWidth - 10.0f - ((count + 1) * (mDigitDrawables[0].getWidth() / 2.0f)), 10.0f); |
| |
| } |
| drawNumber(mFPSLocation, mFPSDigits, false); |
| } |
| |
| if (mFading && factory != null) { |
| |
| final float time = sSystemRegistry.timeSystem.getRealTime(); |
| final float fadeDelta = (time - mFadeStartTime); |
| |
| float percentComplete = 1.0f; |
| if (fadeDelta < mFadeDuration) { |
| percentComplete = fadeDelta / mFadeDuration; |
| } else if (mFadeIn) { |
| // We've faded in. Turn fading off. |
| mFading = false; |
| } |
| |
| if (percentComplete < 1.0f || !mFadeIn) { |
| float opacityValue = percentComplete; |
| if (mFadeIn) { |
| opacityValue = 1.0f - percentComplete; |
| } |
| |
| DrawableBitmap bitmap = factory.allocateDrawableBitmap(); |
| if (bitmap != null) { |
| bitmap.setWidth(params.gameWidth); |
| bitmap.setHeight(params.gameHeight); |
| bitmap.setTexture(mFadeTexture); |
| bitmap.setCrop(0, mFadeTexture.height, mFadeTexture.width, mFadeTexture.height); |
| bitmap.setOpacity(opacityValue); |
| render.scheduleForDraw(bitmap, Vector2.ZERO, SortConstants.FADE, false); |
| } |
| } |
| |
| if (percentComplete >= 1.0f && mFadePendingEventType != GameFlowEvent.EVENT_INVALID) { |
| LevelSystem level = sSystemRegistry.levelSystem; |
| if (level != null) { |
| level.sendGameEvent(mFadePendingEventType, mFadePendingEventIndex, false); |
| mFadePendingEventType = GameFlowEvent.EVENT_INVALID; |
| mFadePendingEventIndex = 0; |
| } |
| } |
| } |
| } |
| |
| private void drawNumber(Vector2 location, int[] digits, boolean drawX) { |
| final RenderSystem render = sSystemRegistry.renderSystem; |
| |
| if (mDigitDrawables[0].getWidth() == 0) { |
| // first time init |
| for (int x = 0; x < mDigitDrawables.length; x++) { |
| Texture tex = mDigitDrawables[x].getTexture(); |
| mDigitDrawables[x].resize(tex.width, tex.height); |
| } |
| } |
| |
| if (mXDrawable.getWidth() == 0) { |
| // first time init |
| Texture tex = mXDrawable.getTexture(); |
| mXDrawable.resize(tex.width, tex.height); |
| } |
| |
| final float characterWidth = mDigitDrawables[0].getWidth() / 2.0f; |
| float offset = 0.0f; |
| |
| if (mXDrawable != null && drawX) { |
| render.scheduleForDraw(mXDrawable, location, SortConstants.HUD, false); |
| location.x += characterWidth; |
| offset += characterWidth; |
| } |
| |
| for (int x = 0; x < digits.length && digits[x] != -1; x++) { |
| int index = digits[x]; |
| DrawableBitmap digit = mDigitDrawables[index]; |
| if (digit != null) { |
| render.scheduleForDraw(digit, location, SortConstants.HUD, false); |
| location.x += characterWidth; |
| offset += characterWidth; |
| } |
| } |
| |
| location.x -= offset; |
| |
| |
| } |
| |
| public int intToDigitArray(int value, int[] digits) { |
| int characterCount = 1; |
| if (value >= 1000) { |
| characterCount = 4; |
| } else if (value >= 100) { |
| characterCount = 3; |
| } else if (value >= 10) { |
| characterCount = 2; |
| } |
| |
| int remainingValue = value; |
| int count = 0; |
| do { |
| int index = remainingValue != 0 ? remainingValue % 10 : 0; |
| remainingValue /= 10; |
| digits[characterCount - 1 - count] = index; |
| count++; |
| } while (remainingValue > 0 && count < digits.length); |
| |
| if (count < digits.length) { |
| digits[count] = -1; |
| } |
| return characterCount; |
| } |
| |
| public void sendGameEventOnFadeComplete(int eventType, int eventIndex) { |
| mFadePendingEventType = eventType; |
| mFadePendingEventIndex = eventIndex; |
| } |
| |
| |
| } |