package com.jonathan.survivor.renderers;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Array;
import com.esotericsoftware.spine.Event;
import com.esotericsoftware.spine.Skeleton;
import com.jonathan.survivor.Assets;
import com.jonathan.survivor.entity.Box;
import com.jonathan.survivor.entity.InteractiveObject;
import com.jonathan.survivor.entity.InteractiveObject.InteractiveState;
import com.jonathan.survivor.entity.Tree;
public class InteractiveObjectRenderer
{
/** Stores the SpriteBatcher used to draw the GameObjects. */
private SpriteBatch batcher;
/** Stores the Assets singleton which stores all of the visual assets needed to draw the interactive GameObjects. */
private Assets assets = Assets.instance;
/** Stores the color of transparent GameObjects. */
private static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0.4f);
/** Helper Color instance used to color GameObjects and avoid creating new color instances. */
private Color workingColor;
//Helper Array that's passed to the Animation.set() method.
private Array<Event> events = new Array<Event>();
/** Accepts the SpriteBatch instance used to draw the Interactive GameObjects. */
public InteractiveObjectRenderer(SpriteBatch batcher)
{
//Stores the SpriteBatch instance used to draw the Interactive GameObjects.
this.batcher = batcher;
//Helper Color instance used to avoid instantiation. Defaults to white.
workingColor = new Color(Color.WHITE);
}
/** Draws the given InteractiveObject. Accepts whether or not the GameObject should be drawn transparent. */
public void draw(InteractiveObject gameObject, boolean transparent)
{
//If the GameObject is a Tree
if(gameObject instanceof Tree)
//Delegate the drawing to the drawTree() method.
drawTree((Tree)gameObject, transparent);
//Else, if the GameObject to draw is a box
else if(gameObject instanceof Box)
//Delegate the rendering call to the drawBox() method.
drawBox((Box)gameObject, transparent);
}
/** Renders a Tree GameObject, which contains a Spine Skeleton instance which can be drawn to the screen. Accepts whether or not it should be drawn transparent. */
private void drawTree(Tree tree, boolean drawTransparent)
{
//Stores the Spine skeleton of the tree which controls its appearance.
Skeleton skeleton = tree.getSkeleton();
//Sets the bottom-center position of the skeleton to the tree's bottom-center position. Note that Skeleton/GameObject.position hold the bottom-center of the tree.
skeleton.setX(tree.getX());
skeleton.setY(tree.getY());
//Set the default color of the tree to white, using the workingColor instance as a helper object.
workingColor.set(Color.WHITE);
//If the tree has jump spawned
if(tree.getInteractiveState() == InteractiveState.SPAWN)
{
//Reset the tree's skeleton to its setup pose to undo any changes previously done to the skeleton's bones.
skeleton.setToSetupPose();
//Sets the state time of the tree to a random time so that the idle animation starts playing at a random place for every tree.
tree.setStateTime((float)Math.random() * 10);
//Sets the tree's state to IDLE, indicating that the renderer has received the message that the tree has spawned.
tree.setInteractiveState(InteractiveState.IDLE);
}
//Else, if the tree is in IDLE state
else if(tree.getInteractiveState() == InteractiveState.IDLE)
{
//Apply the 'treeIdle' animation to the tree's skeleton. Second and third arguments specify how much time the tree has been idle, third indicates we want to
//loop the animation, and last is an array where any possible animation events are delegated.
assets.treeIdle.apply(skeleton, tree.getStateTime(), tree.getStateTime(), true, events);
}
//Else, if the tree was clicked
else if(tree.getInteractiveState() == InteractiveState.CLICKED)
{
//Apply the 'treeIdle' animation to the tree's skeleton. Second and third arguments specify how much time the tree has been idle, third indicates we want to
//loop the animation, and last is an array where any possible animation events are delegated.
assets.treeClicked.apply(skeleton, tree.getStateTime(), tree.getStateTime(), false, events);
}
//Else, if the tree was hit
else if(tree.getInteractiveState() == InteractiveState.HIT)
{
//Apply the 'treeIdle' animation to the tree's skeleton. Second and third arguments specify how much time the tree has been idle, third indicates we want to
//play the animation once, and last is an array where any possible animation events are delegated.
assets.treeHit.apply(skeleton, tree.getStateTime(), tree.getStateTime(), false, events);
if(tree.getStateTime() > assets.treeHit.getDuration())
//The tree renderer has received the HIT message, so the tree can be reset to its CLICKED state.
tree.setInteractiveState(InteractiveState.CLICKED);
}
//Else, if the tree has been scavenged (i.e., its health has dropped below zero)
else if(tree.getInteractiveState() == InteractiveState.SCAVENGED)
{
//Apply the 'treeScavenged' animation to the tree's skeleton. Second and third arguments specify how much time the tree has been idle, third indicates we want to
//play the animation once, and last is an array where any possible animation events are delegated.
assets.treeScavenged.apply(skeleton, tree.getStateTime(), tree.getStateTime(), false, events);
}
//If the tree is supposed to be transparent
if(drawTransparent)
//Apply transparency to the working color.
workingColor.mul(TRANSPARENT_COLOR);
//Color the tree's skeleton to the working color.
skeleton.getColor().set(workingColor);
//Updates the Skeleton in the world.
skeleton.updateWorldTransform();
//Draws the tree's skeleton using the universal SkeletonRenderer instance, along with the GameScreen's SpriteBatch.
assets.skeletonRenderer.draw(batcher, skeleton);
}
/** Helper method called when a Box instance needs to be rendered. Second parameter accepts whether box should be drawn transparent. */
private void drawBox(Box box, boolean drawTransparent)
{
//Stores the skeleton used to render the box to the screen. Each skeleton is unique to each box, and acts as an actor on-screen.
Skeleton skeleton = box.getSkeleton();
//Sets the skeleton's position to that of the box. Note that the box's position is the bottom-center, just like the skeleton.
skeleton.setX(box.getX());
skeleton.setY(box.getY());
//Reset the workingColor to a blank WHITE slate. Used to modify the color white accordingly and apply it as the box's final color.
workingColor.set(Color.WHITE);
//If the box has jump spawned
if(box.getInteractiveState() == InteractiveState.SPAWN)
{
//Reset the box's skeleton to its setup pose to undo any changes previously done to the skeleton's bones.
skeleton.setToSetupPose();
//Sets the box IDLE state, indicating that the renderer has received the message that the box has spawned.
box.setInteractiveState(InteractiveState.IDLE);
}
//Else, if the box is in IDLE state
else if(box.getInteractiveState() == InteractiveState.IDLE)
{
//Apply the 'boxIdle' animation to the box's skeleton. Second and third arguments specify how much time the box has been idle, third indicates we want to
//loop the animation, and last is an array where any possible animation events are delegated.
assets.boxIdle.apply(skeleton, box.getStateTime(), box.getStateTime(), true, events);
}
//Else, if the box was clicked
else if(box.getInteractiveState() == InteractiveState.CLICKED)
{
//Apply the 'boxIdle' animation to the box's skeleton. Second and third arguments specify how much time the box has been idle, third indicates we want to
//loop the animation, and last is an array where any possible animation events are delegated.
assets.boxClicked.apply(skeleton, box.getStateTime(), box.getStateTime(), false, events);
}
//Else, if the box has been scavenged (i.e., it has been opened by the player)
else if(box.getInteractiveState() == InteractiveState.SCAVENGED)
{
//Apply the 'boxScavenged' animation to the box's skeleton. Second and third arguments specify how much time the box has been idle, third indicates we want to
//play the animation once, and last is an array where any possible animation events are delegated.
assets.boxScavenged.apply(skeleton, box.getStateTime(), box.getStateTime(), false, events);
}
//If the box is supposed to be transparent
if(drawTransparent)
//Apply transparency to the working color.
workingColor.mul(TRANSPARENT_COLOR);
//Set the box's color to the working color, which holds the box's final color.
skeleton.getColor().set(workingColor);
//Updates the Skeleton in the world.
skeleton.updateWorldTransform();
//Draws the box's skeleton using the universal SkeletonRenderer instance, along with the GameScreen's SpriteBatch.
assets.skeletonRenderer.draw(batcher, skeleton);
}
}