/* * 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; } }