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 17 package com.replica.replicaisland; 18 19 /** 20 * A very simple manager for orthographic in-game UI elements. 21 * TODO: This should probably manage a number of hud objects in keeping with the component-centric 22 * architecture of this engine. The current code is monolithic and should be refactored. 23 */ 24 public class HudSystem extends BaseObject { 25 private static final int FUEL_BAR_EDGE_PADDING = 15; 26 private static final float FUEL_DECREASE_BAR_SPEED = 0.75f; 27 private static final float FUEL_INCREASE_BAR_SPEED = 2.0f; 28 private static final float FLY_BUTTON_X = -12.0f; 29 private static final float FLY_BUTTON_Y = -5.0f; 30 private static final float STOMP_BUTTON_X = 85.0f; 31 private static final float STOMP_BUTTON_Y = -10.0f; 32 private static final float STOMP_BUTTON_SCALE = 0.65f; 33 private static final int COLLECTABLE_EDGE_PADDING = 8; 34 private static final int MAX_DIGITS = 4; 35 private static final float MOVEMENT_SLIDER_BASE_X = 20.0f; 36 private static final float MOVEMENT_SLIDER_BASE_Y = 32.0f; 37 private static final float MOVEMENT_SLIDER_BUTTON_X = MOVEMENT_SLIDER_BASE_X + 32.0f; 38 private static final float MOVEMENT_SLIDER_BUTTON_Y = MOVEMENT_SLIDER_BASE_Y - 16.0f; 39 private static final float FLY_BUTTON_WIDTH = 128; 40 private static final float STOMP_BUTTON_WIDTH = FLY_BUTTON_WIDTH * STOMP_BUTTON_SCALE; 41 private static final float MOVEMENT_SLIDER_WIDTH = 128; 42 43 private DrawableBitmap mFuelDrawable; 44 private DrawableBitmap mFuelBackgroundDrawable; 45 private float mFuelPercent; 46 private float mFuelTargetPercent; 47 48 private Texture mFadeTexture; 49 private float mFadeStartTime; 50 private float mFadeDuration; 51 private boolean mFadeIn; 52 private boolean mFading; 53 private int mFadePendingEventType; 54 private int mFadePendingEventIndex; 55 56 private DrawableBitmap mFlyButtonEnabledDrawable; 57 private DrawableBitmap mFlyButtonDisabledDrawable; 58 private DrawableBitmap mFlyButtonDepressedDrawable; 59 60 private DrawableBitmap mStompButtonEnabledDrawable; 61 private DrawableBitmap mStompButtonDepressedDrawable; 62 63 private DrawableBitmap mMovementSliderBaseDrawable; 64 private DrawableBitmap mMovementSliderButtonDrawable; 65 private DrawableBitmap mMovementSliderButtonDepressedDrawable; 66 67 68 private Vector2 mFlyButtonLocation; 69 private boolean mFlyButtonActive; 70 private boolean mFlyButtonPressed; 71 72 private Vector2 mStompButtonLocation; 73 private boolean mStompButtonPressed; 74 75 private Vector2 mMovementSliderBaseLocation; 76 private Vector2 mMovementSliderButtonLocation; 77 private boolean mMovementSliderMode; 78 private boolean mMovementSliderButtonPressed; 79 80 private DrawableBitmap mRubyDrawable; 81 private DrawableBitmap mCoinDrawable; 82 83 private int mCoinCount; 84 private int mRubyCount; 85 private Vector2 mCoinLocation; 86 private Vector2 mRubyLocation; 87 private int[] mCoinDigits; 88 private int[] mRubyDigits; 89 private boolean mCoinDigitsChanged; 90 private boolean mRubyDigitsChanged; 91 92 private int mFPS; 93 private Vector2 mFPSLocation; 94 private int[] mFPSDigits; 95 private boolean mFPSDigitsChanged; 96 private boolean mShowFPS; 97 98 private DrawableBitmap[] mDigitDrawables; 99 private DrawableBitmap mXDrawable; 100 101 HudSystem()102 public HudSystem() { 103 super(); 104 mFlyButtonLocation = new Vector2(); 105 mStompButtonLocation = new Vector2(); 106 mCoinLocation = new Vector2(); 107 mRubyLocation = new Vector2(); 108 mFPSLocation = new Vector2(); 109 mDigitDrawables = new DrawableBitmap[10]; 110 mCoinDigits = new int[MAX_DIGITS]; 111 mRubyDigits = new int[MAX_DIGITS]; 112 mFPSDigits = new int[MAX_DIGITS]; 113 mMovementSliderBaseLocation = new Vector2(); 114 mMovementSliderButtonLocation = new Vector2(); 115 116 reset(); 117 } 118 119 @Override reset()120 public void reset() { 121 mFuelDrawable = null; 122 mFadeTexture = null; 123 mFuelPercent = 1.0f; 124 mFuelTargetPercent = 1.0f; 125 mFading = false; 126 mFlyButtonDisabledDrawable = null; 127 mFlyButtonEnabledDrawable = null; 128 mFlyButtonDepressedDrawable = null; 129 mFlyButtonLocation.set(FLY_BUTTON_X, FLY_BUTTON_Y); 130 mFlyButtonActive = true; 131 mFlyButtonPressed = false; 132 mStompButtonEnabledDrawable = null; 133 mStompButtonDepressedDrawable = null; 134 mStompButtonLocation.set(STOMP_BUTTON_X, STOMP_BUTTON_Y); 135 mStompButtonPressed = false; 136 mCoinCount = 0; 137 mRubyCount = 0; 138 mCoinDigits[0] = 0; 139 mCoinDigits[1] = -1; 140 mRubyDigits[0] = 0; 141 mRubyDigits[1] = -1; 142 mCoinDigitsChanged = true; 143 mRubyDigitsChanged = true; 144 mFPS = 0; 145 mFPSDigits[0] = 0; 146 mFPSDigits[1] = -1; 147 mFPSDigitsChanged = true; 148 mShowFPS = false; 149 for (int x = 0; x < mDigitDrawables.length; x++) { 150 mDigitDrawables[x] = null; 151 } 152 mXDrawable = null; 153 mFadePendingEventType = GameFlowEvent.EVENT_INVALID; 154 mFadePendingEventIndex = 0; 155 156 mMovementSliderBaseDrawable = null; 157 mMovementSliderButtonDrawable = null; 158 mMovementSliderButtonDepressedDrawable = null; 159 mMovementSliderBaseLocation.set(MOVEMENT_SLIDER_BASE_X, MOVEMENT_SLIDER_BASE_Y); 160 mMovementSliderButtonLocation.set(MOVEMENT_SLIDER_BUTTON_X, MOVEMENT_SLIDER_BUTTON_Y); 161 mMovementSliderMode = false; 162 mMovementSliderButtonPressed = false; 163 } 164 setFuelPercent(float percent)165 public void setFuelPercent(float percent) { 166 mFuelTargetPercent = percent; 167 } 168 setFuelDrawable(DrawableBitmap fuel, DrawableBitmap background)169 public void setFuelDrawable(DrawableBitmap fuel, DrawableBitmap background) { 170 mFuelDrawable = fuel; 171 mFuelBackgroundDrawable = background; 172 } 173 setFadeTexture(Texture texture)174 public void setFadeTexture(Texture texture) { 175 mFadeTexture = texture; 176 } 177 setButtonDrawables(DrawableBitmap disabled, DrawableBitmap enabled, DrawableBitmap depressed, DrawableBitmap stompEnabled, DrawableBitmap stompDepressed, DrawableBitmap sliderBase, DrawableBitmap sliderButton, DrawableBitmap sliderDepressed)178 public void setButtonDrawables(DrawableBitmap disabled, DrawableBitmap enabled, DrawableBitmap depressed, 179 DrawableBitmap stompEnabled, DrawableBitmap stompDepressed, 180 DrawableBitmap sliderBase, DrawableBitmap sliderButton, DrawableBitmap sliderDepressed) { 181 mFlyButtonDisabledDrawable = disabled; 182 mFlyButtonEnabledDrawable = enabled; 183 mFlyButtonDepressedDrawable = depressed; 184 mStompButtonEnabledDrawable = stompEnabled; 185 mStompButtonDepressedDrawable = stompDepressed; 186 mMovementSliderBaseDrawable = sliderBase; 187 mMovementSliderButtonDrawable = sliderButton; 188 mMovementSliderButtonDepressedDrawable = sliderDepressed; 189 } 190 setDigitDrawables(DrawableBitmap[] digits, DrawableBitmap xMark)191 public void setDigitDrawables(DrawableBitmap[] digits, DrawableBitmap xMark) { 192 mXDrawable = xMark; 193 for (int x = 0; x < mDigitDrawables.length && x < digits.length; x++) { 194 mDigitDrawables[x] = digits[x]; 195 } 196 } 197 setCollectableDrawables(DrawableBitmap coin, DrawableBitmap ruby)198 public void setCollectableDrawables(DrawableBitmap coin, DrawableBitmap ruby) { 199 mCoinDrawable = coin; 200 mRubyDrawable = ruby; 201 } 202 setButtonState(boolean pressed, boolean attackPressed, boolean sliderPressed)203 public void setButtonState(boolean pressed, boolean attackPressed, boolean sliderPressed) { 204 mFlyButtonPressed = pressed; 205 mStompButtonPressed = attackPressed; 206 mMovementSliderButtonPressed = sliderPressed; 207 } 208 startFade(boolean in, float duration)209 public void startFade(boolean in, float duration) { 210 mFadeStartTime = sSystemRegistry.timeSystem.getRealTime(); 211 mFadeDuration = duration; 212 mFadeIn = in; 213 mFading = true; 214 } 215 clearFade()216 public void clearFade() { 217 mFading = false; 218 } 219 isFading()220 public boolean isFading() { 221 return mFading; 222 } 223 updateInventory(InventoryComponent.UpdateRecord newInventory)224 public void updateInventory(InventoryComponent.UpdateRecord newInventory) { 225 mCoinDigitsChanged = (mCoinCount != newInventory.coinCount); 226 mRubyDigitsChanged = (mRubyCount != newInventory.rubyCount); 227 228 mCoinCount = newInventory.coinCount; 229 mRubyCount = newInventory.rubyCount; 230 } 231 setFPS(int fps)232 public void setFPS(int fps) { 233 mFPSDigitsChanged = (fps != mFPS); 234 mFPS = fps; 235 } 236 setShowFPS(boolean show)237 public void setShowFPS(boolean show) { 238 mShowFPS = show; 239 } 240 setMovementSliderMode(boolean sliderOn)241 public void setMovementSliderMode(boolean sliderOn) { 242 mMovementSliderMode = sliderOn; 243 if (sliderOn) { 244 ContextParameters params = sSystemRegistry.contextParameters; 245 mFlyButtonLocation.set(params.gameWidth - FLY_BUTTON_WIDTH - FLY_BUTTON_X, FLY_BUTTON_Y); 246 mStompButtonLocation.set(params.gameWidth - STOMP_BUTTON_WIDTH - STOMP_BUTTON_X, STOMP_BUTTON_Y); 247 } else { 248 mFlyButtonLocation.set(FLY_BUTTON_X, FLY_BUTTON_Y); 249 mStompButtonLocation.set(STOMP_BUTTON_X, STOMP_BUTTON_Y); 250 } 251 } setMovementSliderOffset(float offset)252 public void setMovementSliderOffset(float offset) { 253 mMovementSliderButtonLocation.set(MOVEMENT_SLIDER_BUTTON_X + (offset * (MOVEMENT_SLIDER_WIDTH / 2.0f)), MOVEMENT_SLIDER_BUTTON_Y); 254 } 255 256 @Override update(float timeDelta, BaseObject parent)257 public void update(float timeDelta, BaseObject parent) { 258 final RenderSystem render = sSystemRegistry.renderSystem; 259 final VectorPool pool = sSystemRegistry.vectorPool; 260 final ContextParameters params = sSystemRegistry.contextParameters; 261 final DrawableFactory factory = sSystemRegistry.drawableFactory; 262 263 final GameObjectManager manager = sSystemRegistry.gameObjectManager; 264 265 if (manager != null && manager.getPlayer() != null) { 266 // Only draw player-specific HUD elements when there's a player. 267 if (mFuelDrawable != null && mFuelBackgroundDrawable != null 268 && render != null && pool != null && factory != null && params != null) { 269 if (mFuelPercent < mFuelTargetPercent) { 270 mFuelPercent += (FUEL_INCREASE_BAR_SPEED * timeDelta); 271 if (mFuelPercent > mFuelTargetPercent) { 272 mFuelPercent = mFuelTargetPercent; 273 } 274 } else if (mFuelPercent > mFuelTargetPercent) { 275 mFuelPercent -= (FUEL_DECREASE_BAR_SPEED * timeDelta); 276 if (mFuelPercent < mFuelTargetPercent) { 277 mFuelPercent = mFuelTargetPercent; 278 } 279 } 280 281 if (mFuelBackgroundDrawable.getWidth() == 0) { 282 // first time init 283 Texture tex = mFuelDrawable.getTexture(); 284 mFuelDrawable.resize(tex.width, tex.height); 285 Texture backgroundTex = mFuelBackgroundDrawable.getTexture(); 286 mFuelBackgroundDrawable.resize(backgroundTex.width, backgroundTex.height); 287 } 288 289 final int height = mFuelDrawable.getHeight(); 290 291 292 Vector2 location = pool.allocate(); 293 location.set(FUEL_BAR_EDGE_PADDING, 294 params.gameHeight - height - FUEL_BAR_EDGE_PADDING); 295 render.scheduleForDraw(mFuelBackgroundDrawable, location, SortConstants.HUD, false); 296 location.x += 2; 297 location.y += 2; 298 final int barWidth = (int)((100 - 4) * mFuelPercent); 299 if (barWidth >= 1) { 300 DrawableBitmap bitmap = factory.allocateDrawableBitmap(); 301 if (bitmap != null) { 302 bitmap.resize(barWidth, mFuelDrawable.getHeight()); 303 bitmap.setTexture(mFuelDrawable.getTexture()); 304 render.scheduleForDraw(bitmap, location, SortConstants.HUD + 1, false); 305 } 306 } 307 308 pool.release(location); 309 } 310 311 if (mFlyButtonDisabledDrawable != null && mFlyButtonEnabledDrawable != null 312 && mFlyButtonDepressedDrawable != null) { 313 314 DrawableBitmap bitmap = mFlyButtonEnabledDrawable; 315 if (mFlyButtonActive && mFlyButtonPressed) { 316 bitmap = mFlyButtonDepressedDrawable; 317 } else if (!mFlyButtonActive) { 318 bitmap = mFlyButtonDisabledDrawable; 319 } 320 321 if (bitmap.getWidth() == 0) { 322 // first time init 323 Texture tex = bitmap.getTexture(); 324 bitmap.resize(tex.width, tex.height); 325 } 326 327 render.scheduleForDraw(bitmap, mFlyButtonLocation, SortConstants.HUD, false); 328 } 329 330 331 332 if (mStompButtonEnabledDrawable != null && mStompButtonDepressedDrawable != null) { 333 334 DrawableBitmap bitmap = mStompButtonEnabledDrawable; 335 if (mStompButtonPressed) { 336 bitmap = mStompButtonDepressedDrawable; 337 } 338 339 if (bitmap.getWidth() == 0) { 340 // first time init 341 Texture tex = bitmap.getTexture(); 342 bitmap.resize(tex.width, tex.height); 343 bitmap.setWidth((int)(tex.width * STOMP_BUTTON_SCALE)); 344 bitmap.setHeight((int)(tex.height * STOMP_BUTTON_SCALE)); 345 } 346 347 render.scheduleForDraw(bitmap, mStompButtonLocation, SortConstants.HUD, false); 348 } 349 350 if (mMovementSliderMode && 351 mMovementSliderBaseDrawable != null && mMovementSliderButtonDrawable != null) { 352 353 if (mMovementSliderBaseDrawable.getWidth() == 0) { 354 // first time init 355 Texture tex = mMovementSliderBaseDrawable.getTexture(); 356 mMovementSliderBaseDrawable.resize(tex.width, tex.height); 357 } 358 359 if (mMovementSliderButtonDrawable.getWidth() == 0) { 360 // first time init 361 Texture tex = mMovementSliderButtonDrawable.getTexture(); 362 mMovementSliderButtonDrawable.resize(tex.width, tex.height); 363 } 364 365 if (mMovementSliderButtonDepressedDrawable.getWidth() == 0) { 366 // first time init 367 Texture tex = mMovementSliderButtonDepressedDrawable.getTexture(); 368 mMovementSliderButtonDepressedDrawable.resize(tex.width, tex.height); 369 } 370 371 DrawableBitmap bitmap = mMovementSliderButtonDrawable; 372 373 if (mMovementSliderButtonPressed) { 374 bitmap = mMovementSliderButtonDepressedDrawable; 375 } 376 377 render.scheduleForDraw(mMovementSliderBaseDrawable, mMovementSliderBaseLocation, SortConstants.HUD, false); 378 render.scheduleForDraw(bitmap, mMovementSliderButtonLocation, SortConstants.HUD + 1, false); 379 380 } 381 382 383 if (mCoinDrawable != null) { 384 if (mCoinDrawable.getWidth() == 0) { 385 // first time init 386 Texture tex = mCoinDrawable.getTexture(); 387 mCoinDrawable.resize(tex.width, tex.height); 388 mCoinLocation.x = (params.gameWidth / 2.0f) - tex.width / 2.0f; 389 mCoinLocation.y = params.gameHeight - tex.height - COLLECTABLE_EDGE_PADDING; 390 } 391 392 render.scheduleForDraw(mCoinDrawable, mCoinLocation, SortConstants.HUD, false); 393 if (mCoinDigitsChanged) { 394 intToDigitArray(mCoinCount, mCoinDigits); 395 mCoinDigitsChanged = false; 396 } 397 final float offset = mCoinDrawable.getWidth() * 0.75f; 398 mCoinLocation.x += offset; 399 drawNumber(mCoinLocation, mCoinDigits, true); 400 mCoinLocation.x -= offset; 401 } 402 403 if (mRubyDrawable != null) { 404 if (mRubyDrawable.getWidth() == 0) { 405 // first time init 406 Texture tex = mRubyDrawable.getTexture(); 407 mRubyDrawable.resize(tex.width, tex.height); 408 mRubyLocation.x = (params.gameWidth / 2.0f) + 100.0f; 409 mRubyLocation.y = params.gameHeight - tex.height - COLLECTABLE_EDGE_PADDING; 410 } 411 render.scheduleForDraw(mRubyDrawable, mRubyLocation, SortConstants.HUD, false); 412 if (mRubyDigitsChanged) { 413 intToDigitArray(mRubyCount, mRubyDigits); 414 mRubyDigitsChanged = false; 415 } 416 final float offset = mRubyDrawable.getWidth() * 0.75f; 417 mRubyLocation.x += offset; 418 drawNumber(mRubyLocation, mRubyDigits, true); 419 mRubyLocation.x -= offset; 420 } 421 } 422 423 if (mShowFPS) { 424 if (mFPSDigitsChanged) { 425 int count = intToDigitArray(mFPS, mFPSDigits); 426 mFPSDigitsChanged = false; 427 mFPSLocation.set(params.gameWidth - 10.0f - ((count + 1) * (mDigitDrawables[0].getWidth() / 2.0f)), 10.0f); 428 429 } 430 drawNumber(mFPSLocation, mFPSDigits, false); 431 } 432 433 if (mFading && factory != null) { 434 435 final float time = sSystemRegistry.timeSystem.getRealTime(); 436 final float fadeDelta = (time - mFadeStartTime); 437 438 float percentComplete = 1.0f; 439 if (fadeDelta < mFadeDuration) { 440 percentComplete = fadeDelta / mFadeDuration; 441 } else if (mFadeIn) { 442 // We've faded in. Turn fading off. 443 mFading = false; 444 } 445 446 if (percentComplete < 1.0f || !mFadeIn) { 447 float opacityValue = percentComplete; 448 if (mFadeIn) { 449 opacityValue = 1.0f - percentComplete; 450 } 451 452 DrawableBitmap bitmap = factory.allocateDrawableBitmap(); 453 if (bitmap != null) { 454 bitmap.setWidth(params.gameWidth); 455 bitmap.setHeight(params.gameHeight); 456 bitmap.setTexture(mFadeTexture); 457 bitmap.setCrop(0, mFadeTexture.height, mFadeTexture.width, mFadeTexture.height); 458 bitmap.setOpacity(opacityValue); 459 render.scheduleForDraw(bitmap, Vector2.ZERO, SortConstants.FADE, false); 460 } 461 } 462 463 if (percentComplete >= 1.0f && mFadePendingEventType != GameFlowEvent.EVENT_INVALID) { 464 LevelSystem level = sSystemRegistry.levelSystem; 465 if (level != null) { 466 level.sendGameEvent(mFadePendingEventType, mFadePendingEventIndex, false); 467 mFadePendingEventType = GameFlowEvent.EVENT_INVALID; 468 mFadePendingEventIndex = 0; 469 } 470 } 471 } 472 } 473 drawNumber(Vector2 location, int[] digits, boolean drawX)474 private void drawNumber(Vector2 location, int[] digits, boolean drawX) { 475 final RenderSystem render = sSystemRegistry.renderSystem; 476 477 if (mDigitDrawables[0].getWidth() == 0) { 478 // first time init 479 for (int x = 0; x < mDigitDrawables.length; x++) { 480 Texture tex = mDigitDrawables[x].getTexture(); 481 mDigitDrawables[x].resize(tex.width, tex.height); 482 } 483 } 484 485 if (mXDrawable.getWidth() == 0) { 486 // first time init 487 Texture tex = mXDrawable.getTexture(); 488 mXDrawable.resize(tex.width, tex.height); 489 } 490 491 final float characterWidth = mDigitDrawables[0].getWidth() / 2.0f; 492 float offset = 0.0f; 493 494 if (mXDrawable != null && drawX) { 495 render.scheduleForDraw(mXDrawable, location, SortConstants.HUD, false); 496 location.x += characterWidth; 497 offset += characterWidth; 498 } 499 500 for (int x = 0; x < digits.length && digits[x] != -1; x++) { 501 int index = digits[x]; 502 DrawableBitmap digit = mDigitDrawables[index]; 503 if (digit != null) { 504 render.scheduleForDraw(digit, location, SortConstants.HUD, false); 505 location.x += characterWidth; 506 offset += characterWidth; 507 } 508 } 509 510 location.x -= offset; 511 512 513 } 514 intToDigitArray(int value, int[] digits)515 public int intToDigitArray(int value, int[] digits) { 516 int characterCount = 1; 517 if (value >= 1000) { 518 characterCount = 4; 519 } else if (value >= 100) { 520 characterCount = 3; 521 } else if (value >= 10) { 522 characterCount = 2; 523 } 524 525 int remainingValue = value; 526 int count = 0; 527 do { 528 int index = remainingValue != 0 ? remainingValue % 10 : 0; 529 remainingValue /= 10; 530 digits[characterCount - 1 - count] = index; 531 count++; 532 } while (remainingValue > 0 && count < digits.length); 533 534 if (count < digits.length) { 535 digits[count] = -1; 536 } 537 return characterCount; 538 } 539 sendGameEventOnFadeComplete(int eventType, int eventIndex)540 public void sendGameEventOnFadeComplete(int eventType, int eventIndex) { 541 mFadePendingEventType = eventType; 542 mFadePendingEventIndex = eventIndex; 543 } 544 545 546 } 547