/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* 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 stu.tnt.gdx.core;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
/**
* Executes tasks in the future on the main loop thread.
*
* @FileName: Timer.java
* @CreateOn: Sep 15, 2012 - 11:10:47 AM
* @Author: Nathan Sweet
* @Author: TrungNT
*/
public final class Timer {
static public final int CANCELLED = 0;
static public final int FOREVER = -2;
private final Array<Task> tasks = new Array(false, 13);
private boolean stopped, posted;
private final Runnable timerRunnable = new Runnable() {
public void run() {
update();
}
};
/*********************************************************** Constructor ***********************************************************/
Timer() {
}
/*********************************************************** Methods ***********************************************************/
/** Schedules a task to occur once at the start of the next frame. */
void postTask(Task task) {
scheduleTask(task, 0, 0, 1);
}
/** Schedules a task to occur every frame until cancelled. */
void scheduleTask(Task task) {
scheduleTask(task, 0, 0, FOREVER);
}
/** Schedules a task to occur once after the specified delay. */
void scheduleTask(Task task, float delaySeconds) {
scheduleTask(task, delaySeconds, 0, 1);
}
/**
* Schedules a task to occur once after the specified delay and then
* repeatedly at the specified interval until cancelled.
*/
void scheduleTask(Task task, float delaySeconds, float intervalSeconds) {
scheduleTask(task, delaySeconds, intervalSeconds, FOREVER);
}
/**
* Schedules a task to occur once after the specified delay and then a
* number of additional times at the specified interval.
*/
void scheduleTask(Task task, float delaySeconds, float intervalSeconds,
int repeatCount) {
if (task.repeatCount != CANCELLED) {
Gdx.app.log("IllegalArgumentException",
"The same task may not be scheduled twice.");
return;
}
task.delaySeconds = delaySeconds;
task.intervalSeconds = intervalSeconds;
task.repeatCount = repeatCount;
tasks.add(task);
postRunnable();
}
/**
* Schedule a task base on frames per second for it
*
* @param fps
* the number of fps you want your task run
* @param task
*/
void scheduleTask(float fps, Task task) {
float interval = 1 / fps;
scheduleTask(task, 0, interval, FOREVER);
}
void removeTask(Task task) {
tasks.removeValue(task, true);
task.repeatCount = CANCELLED;
}
/**
* Stops the timer, tasks will not be executed and time that passes will not
* be applied to the task delays.
*/
void stop() {
stopped = true;
posted = false;
}
/** Starts the timer if it was stopped. */
void start() {
stopped = false;
postRunnable();
}
void reset() {
posted = false;
stopped = false;
clear();
}
/** Cancels all tasks. */
void clear() {
for (int i = 0, n = tasks.size; i < n; i++)
tasks.get(i).cancel();
tasks.clear();
}
private void postRunnable() {
if (stopped || posted)
return;
posted = true;
eAdmin.egame.postRunnable(timerRunnable);
}
void update() {
if (stopped) {
return;
}
float delta = Gdx.graphics.getDeltaTime();
for (int i = 0, n = tasks.size; i < n; i++) {
final Task task = tasks.get(i);
task.delaySeconds -= delta;
// ============= check if task need to execute =============
if (task.delaySeconds > 0)
continue;
if (task.repeatCount != CANCELLED) {
if (task.repeatCount == 1)
task.repeatCount = CANCELLED;
task.run();
}
// ============= Done execute task =============
if (task.repeatCount == CANCELLED) {
tasks.removeIndex(i);
i--;
n--;
} else {
task.delaySeconds = task.intervalSeconds;
if (task.repeatCount > 0)
task.repeatCount--;
}
}
if (tasks.size == 0)
posted = false;
else
eAdmin.egame.postRunnable(timerRunnable);
}
/**
* Runnable with a cancel method.
*
* @see Timer
* @author Nathan Sweet
*/
static abstract public class Task implements Runnable {
protected float delaySeconds;
protected float intervalSeconds;
protected int repeatCount = CANCELLED;
/**
* If this is the last time the task will be ran or the task is first
* cancelled, it may be scheduled again in this method.
*/
abstract public void run();
/**
* Cancels the task. It will not be executed until it is scheduled
* again. This method can be called at any time.
*/
public void cancel() {
delaySeconds = 0;
repeatCount = CANCELLED;
}
/**
* Returns true if this task is scheduled to be executed in the future
* by a timer.
*/
public boolean isScheduled() {
return repeatCount != CANCELLED;
}
}
static public class TaskGroup extends Task implements Disposable {
private final Array<Task> taskList;
private int tmp;
public TaskGroup() {
taskList = new Array<Timer.Task>();
}
public TaskGroup(int init) {
taskList = new Array<Timer.Task>(init);
}
/*****************************************************
*
*****************************************************/
/** schedule task with given information */
public TaskGroup add(Task task, float delaySeconds,
float intervalSeconds, int repeatCount) {
task.delaySeconds = delaySeconds;
task.intervalSeconds = intervalSeconds;
task.repeatCount = repeatCount;
taskList.add(task);
return this;
}
/** schedule task base on desire frames per second */
public TaskGroup add(Task task, float fps) {
task.delaySeconds = 0;
task.intervalSeconds = 1 / fps;
task.repeatCount = FOREVER;
taskList.add(task);
return this;
}
/** schedule task forever with max FPS */
public TaskGroup add(Task task) {
task.delaySeconds = 0;
task.intervalSeconds = 0;
task.repeatCount = FOREVER;
taskList.add(task);
return this;
}
/*****************************************************
*
*****************************************************/
public void start() {
eAdmin.egame.postTask(this);
}
@Override
public void run() {
for (Task t : taskList) {
tmp = t.repeatCount;
t.repeatCount = CANCELLED;
eAdmin.egame
.schedule(t, t.delaySeconds, t.intervalSeconds, tmp);
}
}
/*****************************************************
*
*****************************************************/
/** Cancel all tasks */
public void cancel() {
for (Task t : taskList)
t.cancel();
}
public int size() {
return taskList.size;
}
@Override
public void dispose() {
cancel();
taskList.clear();
}
}
}