Task queue & timing

For only tutorials. If you would like to post a tutorial here, first post it elsewhere (scripts, general, etc.) and private message me (Administrator) a link to the thread. I'll move it for you.
Post Reply
User avatar
Site Admin
Posts: 4849
Joined: Sat Jan 05, 2008 4:21 pm

Task queue & timing

#1 Post by Administrator » Wed Jul 09, 2014 9:35 pm

I wrote up a simple tutorial on timing that explains the two different timing approaches and the pros and cons of them: http://www.solarstrike.net/wiki/index.p ... 6_Examples

I also made a simple task queue to aid with timing things. There are two classes: task (which tracks time and then calls the function requested), and taskqueue (which holds tasks).


Code: Select all

Task = class.new();

function Task:constructor(_func, _time)

	-- Ensure that we were given a function to execute.
	if( type(_func) ~= "function" ) then

	self.fullTime = _time;	-- Save time between runs
	self.func = _func;		-- And the actual function to run
	self.timeLeft = _time;	-- And set our timer to full

function Task:update()
	-- Remove a small piece of time from our timer
	self.timeLeft = self.timeLeft - time.deltaTime();

	-- Now check if it is ready to run
	if( self.timeLeft < 0 ) then
		local ret = self.func();

		-- Reset it if requested to keep
		if( ret ) then
			self.timeLeft = self.fullTime;

		-- Return our functions return value to the task queue
		return ret;

	-- Return true to signal that we need to keep this task for now.
	return true;

Code: Select all

TaskQueue = class.new();

function TaskQueue:constructor()
	-- This is our table for holding upcomming tasks
	self.tasks = {};

function TaskQueue:push(task, secsTilExecute)
	-- Make sure we were given a task object
	if( type(task) ~= "function" ) then
		error("Not given a function to execute for argument #1.", 2);

	-- Need to also know how long until we execute
	if( type(secsTilExecute) ~= "number" ) then
		error("Argument #2 to TaskQueue:push() needs to be a number.", 2);

	table.insert(self.tasks, Task(task, secsTilExecute));

function TaskQueue:update()
	for i,v in pairs(self.tasks) do
		local ret = v:update();

		-- Check if we need to remove this task
		if( not ret ) then
			table.remove(self.tasks, i);

Now you can create a task that will automatically be called after the specified amount of time (in seconds), and may be repeated or not. If the task function returns true, the task will be reset instead of removed from the queue. So, now we can do this:

Code: Select all

function macro.init()
	taskqueue = TaskQueue();

	taskqueue:push(function() print("Hello") end, 1);
	taskqueue:push(function() print("How") end, 1.5);
	taskqueue:push(function() print("Are") end, 2);
	taskqueue:push(function() print("You") end, 2.5);
	taskqueue:push(function() print("Spam"); return true end, 3);

function macro.main()
That is a silly example, but it might be nice if you want to queue up something to be run in a few seconds without having to track it manually.

Certain things would still be recommended to be built into a class rather than this kind of queue. For instance, a player class might have two timers: 1 for global cooldown (reset every time you perform an action), and 1 for cast time/channel time. In this way, that player can take no action while waiting on those two timers. Why two? Well, the global cooldown is always required to be over before the player could possibly take action. The cast/channel, however, could be interrupted for important events (such as low health). When a skill is cast, you would simply set the global cooldown timer to the actual global cooldown (probably 1 second in most games), and set the skill timer to the skill's cast time. If both of them are > 0, then you know you cannot take any action and should instead return from that function.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest