/*
* Copyright (C) 2016 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.android.apps.santatracker.doodles.pursuit;
import android.content.res.Resources;
import android.graphics.Canvas;
import com.google.android.apps.santatracker.doodles.R;
import com.google.android.apps.santatracker.doodles.shared.Actor;
import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite;
import com.google.android.apps.santatracker.doodles.shared.AnimatedSprite.AnimatedSpriteListener;
import com.google.android.apps.santatracker.doodles.shared.Sprites;
/**
* A fruit that runs down the screen.
*/
public class RunnerActor extends Actor {
/**
* Currently there are four different kinds of fruits.
*/
public enum RunnerType {
STRAWBERRY(Sprites.snowballrun_running_normal, R.drawable.snowballrun_running_starting_runner,
Sprites.snowballrun_running_sidestep, Sprites.snowballrun_running_appearing, R.drawable.snowballrun_standing_elf,
Sprites.snowballrun_elf_squish, R.drawable.snowballrun_elf_squished_05),
APRICOT(Sprites.snowballrun_running_snowman_opponent, R.drawable.snowballrun_running_starting_snowman,
Sprites.empty_frame, Sprites.empty_frame, R.drawable.snowballrun_standing_snowman,
Sprites.running_apricot_squish, R.drawable.snowballrun_snowman_squished_09),
GRAPE(Sprites.snowballrun_running_elf_opponent, R.drawable.snowballrun_running_starting_elfopponent,
Sprites.empty_frame, Sprites.empty_frame, R.drawable.snowballrun_standing_elfopponent,
Sprites.running_elfopponent_squish, R.drawable.snowballrun_elfopponent_squished_09),
MANGO(Sprites.snowballrun_running_reindeer_opponent, R.drawable.snowballrun_running_starting_reindeer,
Sprites.empty_frame, Sprites.empty_frame, R.drawable.snowballrun_standing_reindeer,
Sprites.snowballrun_reindeer_squish, R.drawable.snowballrun_reindeer_squished_05);
public int[] runRes, crouchRes, runLeftRes, enteringRes, standRes, dyingRes, deadRes;
RunnerType(int[] runRes, int crouchRes,
int[] runLeftRes, int[] enteringRes, int standRes,
int[] dyingRes, int deadRes) {
this.runRes = runRes;
this.crouchRes = new int[] { crouchRes };
this.runLeftRes = runLeftRes;
this.enteringRes = enteringRes;
this.standRes = new int[] { standRes };
this.dyingRes = dyingRes;
this.deadRes = new int[] { deadRes };
}
}
// TODO: Because the running left animation is no longer used for the opponents'
// entrance, consider moving RUNNING_LEFT and RUNNING_RIGHT to PlayerActor.
enum RunnerState {
RUNNING,
CROUCH,
ENTERING,
RUNNING_LEFT,
RUNNING_RIGHT,
STANDING,
DYING,
DEAD,
}
private static final long EYE_BLINK_DELAY_MILLISECONDS = 1300;
private static final int RUNNING_Z_INDEX = 10;
private static final int DEAD_Z_INDEX = 3;
protected int lane;
protected RunnerType type;
protected RunnerState state;
protected float radius;
protected AnimatedSprite currentSprite;
protected AnimatedSprite runningSprite;
protected AnimatedSprite crouchSprite;
protected AnimatedSprite enteringSprite;
protected AnimatedSprite runningLeftSprite;
protected AnimatedSprite runningRightSprite;
protected AnimatedSprite standingSprite;
protected AnimatedSprite deadSprite;
protected AnimatedSprite dyingSprite;
RunnerActor(Resources resources, RunnerType type, int lane) {
this.lane = lane;
this.type = type;
runningSprite = AnimatedSprite.fromFrames(resources, type.runRes);
crouchSprite = AnimatedSprite.fromFrames(resources, type.crouchRes);
enteringSprite = AnimatedSprite.fromFrames(resources, type.enteringRes);
runningLeftSprite = AnimatedSprite.fromFrames(resources, type.runLeftRes);
runningRightSprite = AnimatedSprite.fromFrames(resources, type.runLeftRes);
standingSprite = AnimatedSprite.fromFrames(resources, type.standRes);
deadSprite = AnimatedSprite.fromFrames(resources, type.deadRes);
dyingSprite = AnimatedSprite.fromFrames(resources, type.dyingRes);
enteringSprite.setLoop(false);
enteringSprite.setFPS((int) ((enteringSprite.getNumFrames() + 1) / PursuitModel.RUNNER_ENTER_DURATION));
setSpriteAnchorUpright(runningSprite);
setSpriteAnchorWithYOffset(crouchSprite, 0);
setSpriteAnchorUpright(enteringSprite);
setSpriteAnchorUpright(runningLeftSprite);
setSpriteAnchorUpright(runningRightSprite);
setSpriteAnchorUpright(standingSprite);
setSpriteAnchorCenter(deadSprite);
switch (type) {
case STRAWBERRY:
setSpriteAnchorWithYOffset(dyingSprite, 0);
break;
case MANGO:
setSpriteAnchorWithYOffset(dyingSprite, 0);
break;
case GRAPE:
setSpriteAnchorWithYOffset(dyingSprite, 0);
break;
case APRICOT:
setSpriteAnchorWithYOffset(dyingSprite, 0);
break;
}
currentSprite = runningSprite;
state = RunnerState.RUNNING;
zIndex = RUNNING_Z_INDEX;
}
@Override
public void update(float deltaMs) {
super.update(deltaMs);
if (state == RunnerState.RUNNING) {
currentSprite.setFPS(3 + (int) (5 * velocity.y / PursuitModel.BASE_SPEED));
}
currentSprite.update(deltaMs);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (currentSprite == null) {
return;
}
float runnerScale = scale * 1.50f;
currentSprite.setScale(runnerScale, runnerScale);
currentSprite.setPosition(position.x, position.y);
if (currentSprite == runningRightSprite) {
currentSprite.setScale(-runnerScale, runnerScale);
}
currentSprite.draw(canvas);
}
public void setLane(int lane) {
this.lane = lane;
}
public int getLane() {
return lane;
}
public void setRadius(float radius) {
this.radius = radius;
}
public float getRadius() {
return radius;
}
public void setRunnerState(RunnerState state) {
if (this.state == state) {
return;
}
this.state = state;
switch (state) {
case RUNNING:
currentSprite = runningSprite;
break;
case CROUCH:
currentSprite = crouchSprite;
break;
case ENTERING:
currentSprite = enteringSprite;
break;
case RUNNING_LEFT:
currentSprite = runningLeftSprite;
break;
case RUNNING_RIGHT:
currentSprite = runningRightSprite;
break;
case STANDING:
currentSprite = standingSprite;
break;
case DYING:
currentSprite = dyingSprite;
dyingSprite.setLoop(false);
dyingSprite.setFrameIndex(0);
dyingSprite.clearListeners();
int frame = 3;
switch(type) {
case APRICOT:
frame = 2;
break;
case GRAPE:
frame = 2;
break;
}
final int finalFrame = frame;
dyingSprite.addListener(new AnimatedSpriteListener() {
@Override
public void onFrame(int index) {
super.onFrame(index);
if (index == finalFrame) {
setRunnerState(RunnerState.DEAD);
}
}
});
break;
case DEAD:
currentSprite = deadSprite;
break;
}
if (state == RunnerState.DEAD) {
zIndex = DEAD_Z_INDEX;
} else {
zIndex = RUNNING_Z_INDEX;
}
}
public RunnerState getRunnerState() {
return state;
}
// yOffset is in percentage not game units, or pixels
// yOffset of 0.5f centers the sprite vertically
// yOffset of 0 draws the sprite starting from its y position
protected static void setSpriteAnchorCenter(AnimatedSprite sprite) {
setSpriteAnchorWithYOffset(sprite, sprite.frameHeight * 0.5f);
}
protected static void setSpriteAnchorUpright(AnimatedSprite sprite) {
setSpriteAnchorWithYOffset(sprite, 0);
}
protected static void setSpriteAnchorWithYOffset(AnimatedSprite sprite, float yOffset) {
sprite.setAnchor(sprite.frameWidth * 0.5f, sprite.frameHeight - yOffset);
}
}