/*******************************************************************************
* Copyright 2015 See AUTHORS file.
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.mygdx.game.objects.dog;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.ai.GdxAI;
import com.badlogic.gdx.ai.btree.LeafTask;
import com.badlogic.gdx.ai.btree.Task;
import com.badlogic.gdx.graphics.g3d.utils.AnimationController.AnimationDesc;
import com.mygdx.game.objects.DogCharacter;
import com.mygdx.game.objects.DogCharacter.DogSteerSettings;
import com.mygdx.game.settings.GameSettings;
import com.mygdx.game.utilities.AnimationListener;
/**
* The base class for dog's animated tasks. This class will use the animation defined by the task as long as the dog's speed is close to 0.
* As soon as the dog moves a proper animation based on its linear speed will be used: {@link TaskAnimation#Run run} animation if
* speed is higher than {@link DogSteerSettings#maxLinearSpeed}; {@link TaskAnimation#Walk walk} animation otherwise. This allows idle tasks
* to adapt silently the animation to variations in speed. The typical use case occurs when you enter an idle task while the dog is moving
* because of some residual speed not consumed by a previous movement task.
*
* @author davebaol
*/
public abstract class LoopedAnimationTaskBase extends LeafTask<DogCharacter> {
protected AnimationListener animationListener;
public LoopedAnimationTaskBase () {
this(false);
}
public LoopedAnimationTaskBase (boolean useAnimationListener) {
this.animationListener = useAnimationListener ? new AnimationListener() : null;
}
protected abstract TaskAnimation getTaskAnimation();
protected void setSteeringLimits (DogCharacter dog, float steeringMultiplier) {
}
protected int getAnimationLoopCount () {
return -1; // endless loop count
}
protected AnimationDesc startAnimation (DogCharacter dog) {
int loopCount = -1;
// if (animationListener != null && animationListener != dog.currentAnimationListener) {
if (animationListener != null) {
animationListener.setAnimationCompleted(false);
loopCount = getAnimationLoopCount();
}
dog.currentAnimationListener = animationListener;
return dog.animations.animate(dog.currentTaskAnimation.animationId, loopCount, 1, animationListener, 0.1f);
}
@Override
public void start () {
float steeringMultiplier = getTaskAnimation().getSteeringMultiplier();
if (steeringMultiplier >= 0) {
setSteeringLimits(getObject(), steeringMultiplier);
}
}
protected void monitorAnimationTransition(DogCharacter dog, TaskAnimation ta) {
if (dog.monitoredTaskAnimation != ta) {
if (dog.currentTaskAnimation != null) {
dog.monitoredTaskAnimation = ta;
dog.switchAnimationTime = GdxAI.getTimepiece().getTime() + 0.2f;
return;
}
}
else if (dog.switchAnimationTime < GdxAI.getTimepiece().getTime()) {
return;
}
// Start the new animation since the dog has maintained appropriate speed for long enough
dog.currentTaskAnimation = ta;
dog.monitoredTaskAnimation = null;
dog.switchAnimationTime = -1;
startAnimation(dog);
}
/**
* Switches the animation based on the linear speed, if needed.
* @param dog the dog
* @param speed the linear speed
*/
protected void switchAnimation(DogCharacter dog, float speed) {
if (speed > DogSteerSettings.maxLinearSpeed + .2f) {
if (dog.currentTaskAnimation != TaskAnimation.Run) {
monitorAnimationTransition(dog, TaskAnimation.Run);
}
} else if (speed > dog.getZeroLinearSpeedThreshold() + .1f) {
if (dog.currentTaskAnimation != TaskAnimation.Walk) {
monitorAnimationTransition(dog, TaskAnimation.Walk);
}
} else {
TaskAnimation taskAnimation = getTaskAnimation();
if (taskAnimation.idleTaskAnimation != null) {
taskAnimation = taskAnimation.idleTaskAnimation;
}
if (dog.currentTaskAnimation != taskAnimation) {
monitorAnimationTransition(dog, taskAnimation);
}
}
}
protected void updateAnimation(DogCharacter dog) {
// Switch animation based on linear velocity if needed
float speed = dog.getLinearVelocity().len();
switchAnimation(dog, speed);
float deltaTime = Gdx.graphics.getDeltaTime();
if (dog.currentTaskAnimation != null && dog.currentTaskAnimation.animationSpeedMultiplier >= 0) {
deltaTime *= speed * dog.currentTaskAnimation.animationSpeedMultiplier;
}
dog.animations.update(deltaTime * GameSettings.GAME_SPEED);
}
@Override
public Status execute () {
updateAnimation(getObject());
return Status.RUNNING;
}
@Override
public void end() {
// if (animationListener != null)
// animationListener.animationFinished = true;
}
@Override
protected Task<DogCharacter> copyTo (Task<DogCharacter> task) {
LoopedAnimationTaskBase dogTask = (LoopedAnimationTaskBase)task;
dogTask.animationListener = animationListener == null? null : new AnimationListener();
return task;
}
}