/*
* Copyright 2014 Google Inc. All rights reserved.
*
* 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.google.fpl.gamecontroller.particles;
import com.google.fpl.gamecontroller.GameState;
import com.google.fpl.gamecontroller.Utils;
/**
* Manages particles that makeup the background of the map.
*/
public class BackgroundParticleSystem extends ParticleSystem {
// Parameters used for creating the animated background particles.
private static final float BACKGROUND_SQUARE_MIN_LIFETIME = 2.0f; // seconds
private static final float BACKGROUND_SQUARE_MAX_LIFETIME = 5.0f; // seconds
private static final float BACKGROUND_SQUARE_MIN_SIZE = 5.0f;
private static final float BACKGROUND_SQUARE_MAX_SIZE = 30.0f;
private static final float BACKGROUND_SQUARE_MIN_VELOCITY_Y = 0.5f;
private static final float BACKGROUND_SQUARE_MAX_VELOCITY_Y = 1.5f;
private static final float BACKGROUND_SQUARE_MAX_ALPHA = 0.25f;
// The number of frames it takes to transition to the winning player's color.
private static final float WINNING_ANIMATION_TRANSITION_FRAME_DELTA
= GameState.secondsToFrameDelta(1.5f);
// The number of frames the background will show the winning player's color.
private static final float WINNING_ANIMATION_PAUSE_FRAME_DELTA
= GameState.secondsToFrameDelta(4.0f);
// Default background color is dark blue.
private static final Utils.Color DEFAULT_COLOR = new Utils.Color(0.0f, 0.0f, 0.5f, 1.0f);
// The color for this frame.
private final Utils.Color mCurrentColor = new Utils.Color(DEFAULT_COLOR);
// The background color before the animation started.
private final Utils.Color mOriginalColor = new Utils.Color(DEFAULT_COLOR);
// The color of the background at the end of the animation.
private final Utils.Color mTargetColor = new Utils.Color(DEFAULT_COLOR);
// The amount of time needed to transition from the original color to target color.
private float mTotalTransitionFrameDelta = 0.0f;
// The current elapsed time.
private float mCurrentTransitionFrameDelta = 0.0f;
// After transitioning to the target color, the background will return to its original
// color after the pause time has expired.
private float mPauseFrameDeltaRemaining = 0.0f;
public BackgroundParticleSystem(int maxActiveParticles) {
super(maxActiveParticles, false);
}
public void update(float frameDelta) {
// Add a new square every frame (the particles time out after a few seconds, so this
// replaces them).
addRandomSquare();
if (mTotalTransitionFrameDelta > 0.0f
&& mCurrentTransitionFrameDelta < mTotalTransitionFrameDelta) {
// We are transitioning from one color to another.
mCurrentTransitionFrameDelta += frameDelta;
if (mCurrentTransitionFrameDelta >= mTotalTransitionFrameDelta) {
// The transition is complete, so clamp to the target color.
mCurrentColor.set(mTargetColor);
if (mPauseFrameDeltaRemaining <= 0.0f) {
// We will not be returning to the original color, so mark the transition
// as complete.
mCurrentTransitionFrameDelta = 0.0f;
mTotalTransitionFrameDelta = 0.0f;
}
} else {
// Compute the interpolated color between the original and final colors.
float transitionRatio = mCurrentTransitionFrameDelta / mTotalTransitionFrameDelta;
mCurrentColor.setToLerp(mTargetColor, mOriginalColor, transitionRatio);
}
} else if (mPauseFrameDeltaRemaining > 0.0f) {
// We have completed a transition and are pausing before switching back to our original
// color.
mPauseFrameDeltaRemaining -= frameDelta;
if (mPauseFrameDeltaRemaining <= 0.0f) {
// The pause is over, so kick off a transition back to our original color.
// Use "0" for the pause duration so that the transition will stop after
// the target color is reached.
flashColorTo(mOriginalColor, mTotalTransitionFrameDelta, 0.0f);
}
}
// Update all our particles to the current background color.
for (BaseParticle square : mParticles) {
if (square.isActive()) {
square.getColor().set(mCurrentColor);
}
}
super.update(frameDelta);
}
/**
* Changes the color of the background particles over time.
*
* Calling this function while an animated transition is in progress has no effect.
*
* @param winningColor The new color for the background particles.
*/
public void flashWinningColor(Utils.Color winningColor) {
// Make sure we're not already in the middle of an animation.
if ((mTotalTransitionFrameDelta == 0.0f) && (mPauseFrameDeltaRemaining == 0.0f)) {
flashColorTo(winningColor, WINNING_ANIMATION_TRANSITION_FRAME_DELTA,
WINNING_ANIMATION_PAUSE_FRAME_DELTA);
} else {
Utils.logDebug("flashWinningColor() already in progress.");
}
}
/**
* Creates a new square particle.
*/
private void addRandomSquare() {
float lifetimeInSeconds = Utils.randFloatInRange(
BACKGROUND_SQUARE_MIN_LIFETIME,
BACKGROUND_SQUARE_MAX_LIFETIME);
BaseParticle square = spawnParticle(lifetimeInSeconds);
if (square != null) {
// The particles start towards the bottom of the map.
float x = Utils.randFloatInRange(GameState.MAP_LEFT_COORDINATE,
GameState.MAP_RIGHT_COORDINATE);
float y = Utils.randFloatInRange(
GameState.WORLD_BOTTOM_COORDINATE - BACKGROUND_SQUARE_MAX_SIZE, 0.0f);
square.setPosition(x, y);
// The particles move from the bottom of the screen towards the top of the screen.
float velocityY = Utils.randFloatInRange(
BACKGROUND_SQUARE_MIN_VELOCITY_Y,
BACKGROUND_SQUARE_MAX_VELOCITY_Y);
square.setSpeed(0.0f, velocityY);
square.setColor(mCurrentColor);
square.setMaxAlpha(BACKGROUND_SQUARE_MAX_ALPHA);
square.setSize(Utils.randFloatInRange(BACKGROUND_SQUARE_MIN_SIZE,
BACKGROUND_SQUARE_MAX_SIZE));
square.setDieOffscreen(false);
}
}
/**
* Changes the color of the background particles over time.
*
* @param targetColor The new color for the background particles.
* @param transitionFrameDelta The number of frames over which the color change
* will occur.
* @param pauseFrameDelta If greater than zero, the number of frames to draw
* before transitioning the background particles back to their
* original color. If zero, the background particles will continue to
* use targetColor after the transition is complete.
*/
private void flashColorTo(Utils.Color targetColor, float transitionFrameDelta,
float pauseFrameDelta) {
mTargetColor.set(targetColor);
mOriginalColor.set(mCurrentColor);
mTotalTransitionFrameDelta = Math.max(transitionFrameDelta, 0.0f);
mCurrentTransitionFrameDelta = 0.0f;
if (mTotalTransitionFrameDelta <= 0.0f) {
// Make the transition instantaneous.
mCurrentColor.set(mTargetColor);
mTotalTransitionFrameDelta = 0.0f;
}
mPauseFrameDeltaRemaining = Math.max(pauseFrameDelta, 0.0f);
}
}