package dan.dit.whatsthat.riddle.control;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Holds and manages a list of RiddleAnimations that are drawn in different layers. The drawing
* can be controlled by the client of this controller, the sorting of the RiddleAnimations in
* different layers is done by the animations and the client. The controller reports changes in
* the amount of current animations to the associated listener.
* Animations can be added with a delay. Animations will always be born when they first are added
* and the delay has passed on the running controller. They will die if no longer alive (huh) or
* can get murdered when the controller force clears any associated animations.
* Created by daniel on 04.11.15.
*/
public class RiddleAnimationController {
/**
* Will be drawn on a cleared canvas before anything else is drawn.
*/
public static final int LEVEL_GROUNDING = -1;
/**
* Will be drawn before any drawing of the riddle happens.
*/
public static final int LEVEL_BACKGROUND = 0;
/**
* Will be drawn after all drawing of the riddle happened.
*/
public static final int LEVEL_ON_TOP = 100;
private final List<RiddleAnimation> mAnimations = Collections.synchronizedList(new
ArrayList<RiddleAnimation>());
private final OnAnimationCountChangedListener mListener;
private List<RiddleAnimation> mAnimationsIterateData = new ArrayList<>();
private long mTime;
public interface OnAnimationCountChangedListener {
void onAnimationCountChanged();
}
public RiddleAnimationController(@NonNull OnAnimationCountChangedListener listener) {
mListener = listener;
}
// in GameThread
public void update(long updatePeriod) {
mTime += updatePeriod; // so birth time is guaranteed to be > 0
List<RiddleAnimation> animationIterate = mAnimationsIterateData;
for (int i = 0; i < animationIterate.size(); i++) {
RiddleAnimation curr = animationIterate.get(i);
if (curr.mBirthTime <= 0) {
// not yet born
if (-curr.mBirthTime <= mTime) {
// Happy birth millisecond!!
curr.mBirthTime = mTime;
curr.onBorn();
} else {
continue; // let time pass and wait
}
}
curr.update(updatePeriod);
if (!curr.isAlive()) {
removeAnimation(curr);
}
}
}
public int getActiveAnimationsCount() {
return mAnimations.size();
}
public void addAnimation(@NonNull RiddleAnimation animation) {
addAnimation(animation, 0L);
}
public void addAnimation(@NonNull RiddleAnimation animation, long delay) {
mAnimations.add(animation);
animation.mBirthTime = -(mTime + Math.max(delay, 0L)); // non positive values mark not yet
Log.d("Riddle", "Animation added " + animation + " with delay " + delay + " birthtime is " +
"" + animation.mBirthTime + " current is " + mTime);
// born animation
synchronized (mAnimations) {
mAnimationsIterateData = new ArrayList<>(mAnimations);
}
mListener.onAnimationCountChanged();
}
public void clear() {
// remove all animations, making sure they are killed
List<RiddleAnimation> animationIterate = mAnimations;
for (int i = 0; i < animationIterate.size(); i++) {
RiddleAnimation curr = animationIterate.get(i);
curr.murder();
}
mAnimations.clear();
mAnimationsIterateData.clear();
}
private void removeAnimation(@NonNull RiddleAnimation animation) {
if (mAnimations.remove(animation)) {
animation.onKilled(false);
synchronized (mAnimations) {
mAnimationsIterateData = new ArrayList<>(mAnimations);
}
mListener.onAnimationCountChanged();
}
}
// in GameThread
public void draw(@NonNull Canvas canvas, @Nullable Paint paint, int level) {
List<RiddleAnimation> animationIterate = mAnimationsIterateData;
for (int i = 0; i < animationIterate.size(); i++) {
RiddleAnimation curr = animationIterate.get(i);
if (curr.mDrawingLevel == level && curr.mBirthTime <= mTime) {
curr.draw(canvas, paint);
}
}
}
}