package loon.action;
import loon.utils.MathUtils;
@SuppressWarnings("unchecked")
public abstract class ActionTweenBase<T> {
protected ActionBind _target;
private int step;
private boolean isIterationStep;
private boolean isBackward;
protected int repeatSize;
protected float delay;
protected float duration;
private float repeatDelay;
private float currentTime;
private float deltaTime;
private boolean isStarted;
private boolean isInitialized;
private boolean isFinished;
private boolean isKilled;
private boolean isPaused;
private ActionCallback callback;
private int callbackTriggers;
boolean _isAutoRemoveEnabled;
boolean _isAutoStartEnabled;
protected void reset() {
step = -2;
repeatSize = 0;
isIterationStep = isBackward = false;
delay = duration = repeatDelay = currentTime = deltaTime = 0;
isStarted = isInitialized = isFinished = isKilled = isPaused = false;
callback = null;
callbackTriggers = ActionMode.COMPLETE;
_isAutoRemoveEnabled = _isAutoStartEnabled = true;
}
public TweenTo<T> start() {
build();
currentTime = 0;
isStarted = true;
TweenTo<T> act = new TweenTo<T>(this);
ActionControl.get().addAction(act, _target);
return act;
}
public T build() {
return (T) this;
}
public T delay(float delay) {
this.delay += delay;
return (T) this;
}
public void kill() {
isKilled = true;
}
public void free() {
}
public void pause() {
isPaused = true;
}
public void resume() {
isPaused = false;
}
public T repeat(int count, float delay) {
if (isStarted) {
return (T) this;
}
repeatSize = count;
repeatDelay = delay >= 0 ? delay : 0;
isBackward = false;
return (T) this;
}
public T repeatBackward(int count, float delay) {
if (isStarted) {
return (T) this;
}
repeatSize = count;
repeatDelay = delay >= 0 ? delay : 0;
isBackward = true;
return (T) this;
}
public T setCallback(ActionCallback callback) {
this.callback = callback;
return (T) this;
}
public T setCallbackTriggers(int flags) {
this.callbackTriggers = flags;
return (T) this;
}
public float getDelay() {
return delay;
}
public float getDuration() {
return duration;
}
public int getRepeatCount() {
return repeatSize;
}
public float getRepeatDelay() {
return repeatDelay;
}
public float getFullDuration() {
if (repeatSize < 0) {
return -1;
}
return delay + duration + (repeatDelay + duration) * repeatSize;
}
public int getStep() {
return step;
}
public float getCurrentTime() {
return currentTime;
}
public boolean isStarted() {
return isStarted;
}
public boolean isInitialized() {
return isInitialized;
}
public boolean isFinished() {
return isFinished || isKilled;
}
public boolean isBackward() {
return isBackward;
}
public boolean isPaused() {
return isPaused;
}
protected abstract void forceStartValues();
protected abstract void forceEndValues();
protected abstract boolean containsTarget(ActionBind target);
protected abstract boolean containsTarget(ActionBind target, int tweenType);
protected void initializeOverride() {
}
protected void update(int step, int lastStep, boolean isIterationStep,
float delta) {
}
protected void forceToStart() {
currentTime = -delay;
step = -1;
isIterationStep = false;
if (isReverse(0)) {
forceEndValues();
} else {
forceStartValues();
}
}
protected void forceToEnd(float time) {
currentTime = time - getFullDuration();
step = repeatSize * 2 + 1;
isIterationStep = false;
if (isReverse(repeatSize * 2)) {
forceStartValues();
} else {
forceEndValues();
}
}
protected void callCallback(int type) {
if (callback != null && (callbackTriggers & type) > 0)
callback.onEvent(type, this);
}
protected boolean isReverse(int step) {
return isBackward && MathUtils.abs(step % 4) == 2;
}
protected boolean isValid(int step) {
return (step >= 0 && step <= repeatSize * 2) || repeatSize < 0;
}
protected void killTarget(ActionBind _target) {
if (containsTarget(_target)) {
kill();
}
}
protected void killTarget(ActionBind _target, int tweenType) {
if (containsTarget(_target, tweenType)) {
kill();
}
}
private void checkCompletion() {
isFinished = repeatSize >= 0 && (step > repeatSize * 2 || step < 0);
}
protected boolean actionEventOver() {
return true;
}
public void update(float delta) {
if (!isStarted || isPaused || isKilled) {
return;
}
deltaTime = delta;
if (!isInitialized) {
initialize();
}
if (isInitialized) {
checkRelaunch();
updateStep();
checkCompletion();
}
currentTime += deltaTime;
deltaTime = 0;
}
private void initialize() {
if (currentTime + deltaTime >= delay) {
initializeOverride();
isInitialized = true;
isIterationStep = true;
step = 0;
deltaTime -= delay - currentTime;
currentTime = 0;
callCallback(ActionMode.BEGIN);
callCallback(ActionMode.START);
}
}
private void checkRelaunch() {
if (!isIterationStep && repeatSize >= 0 && step < 0
&& currentTime + deltaTime >= 0) {
isIterationStep = true;
step = 0;
float delta = 0 - currentTime;
deltaTime -= delta;
currentTime = 0;
callCallback(ActionMode.BEGIN);
callCallback(ActionMode.START);
update(step, step - 1, isIterationStep, delta);
} else if (!isIterationStep && repeatSize >= 0 && step > repeatSize * 2
&& currentTime + deltaTime < 0) {
isIterationStep = true;
step = repeatSize * 2;
float delta = 0 - currentTime;
deltaTime -= delta;
currentTime = duration;
callCallback(ActionMode.BACK_BEGIN);
callCallback(ActionMode.BACK_START);
update(step, step + 1, isIterationStep, delta);
}
}
private void updateStep() {
for (; isValid(step);) {
if (!isIterationStep && currentTime + deltaTime <= 0) {
isIterationStep = true;
step -= 1;
float delta = -currentTime;
deltaTime -= delta;
currentTime = duration;
if (isReverse(step)) {
forceStartValues();
} else {
forceEndValues();
}
callCallback(ActionMode.BACK_START);
update(step, step + 1, isIterationStep, delta);
} else if (!isIterationStep
&& currentTime + deltaTime >= repeatDelay) {
isIterationStep = true;
step += 1;
float delta = repeatDelay - currentTime;
deltaTime -= delta;
currentTime = 0;
if (isReverse(step)) {
forceEndValues();
} else {
forceStartValues();
}
callCallback(ActionMode.START);
update(step, step - 1, isIterationStep, delta);
} else if (isIterationStep && currentTime + deltaTime < 0) {
isIterationStep = false;
step -= 1;
float delta = -currentTime;
deltaTime -= delta;
currentTime = 0;
update(step, step + 1, isIterationStep, delta);
callCallback(ActionMode.BACK_END);
if (step < 0 && repeatSize >= 0) {
callCallback(ActionMode.BACK_COMPLETE);
} else {
currentTime = repeatDelay;
}
} else if (isIterationStep && currentTime + deltaTime > duration) {
isIterationStep = false;
step += 1;
float delta = duration - currentTime;
deltaTime -= delta;
currentTime = duration;
update(step, step - 1, isIterationStep, delta);
callCallback(ActionMode.END);
if (step > repeatSize * 2 && repeatSize >= 0) {
callCallback(ActionMode.COMPLETE);
}
currentTime = 0;
} else if (isIterationStep) {
float delta = deltaTime;
deltaTime -= delta;
currentTime += delta;
update(step, step, isIterationStep, delta);
break;
} else {
float delta = deltaTime;
deltaTime -= delta;
currentTime += delta;
break;
}
}
}
}