Task Scheduling, or Getting my minions to wait their turn

I have a series of 8 animations that I was unable to get to run in the tweener since there is some setup that has to go along before the job can be sent out. Fine. So I wrote my own Task queue, cleverly named Tasks.

Tasks = class()
local timer = 0
local waiting = false

function Tasks:init()
end

function Tasks:add(action, wait)
    table.insert(self,{action, wait})
end

function Tasks:draw()
    timer = timer - DeltaTime
    if not waiting then
        if #self > 0 then
            waiting = true
            timer = self[1].wait
            self[1]:action()
            table.remove(self, 1)
        end   
    elseif timer<=0 then
        waiting = false
    end
end

-- in Main:
draw()
   .
   .
   .
    taskList:draw()
end

It seems to work fine until I try to queue up a function that takes parameters. I keep getting nil stored in the queue rather than a function pointer. I seem to have again gotten caught up in Lua syntax.

Have I written something wrong above that I cannot do

taskList:add(f(a,b), 1)  -- do func f and then wait 1 second 

but:

taskList:add(f(), 1)  

works fine? do I need dots (…) somewhere?

I’m making terrific progress, except for this loose syntax where anything seems to go. Except when it doesn’t. :frowning:

By placing parenthesis after your function, you are calling the function, and returning the result. If you want to pass parameters to a function the best way to do it AFAIK is

taskList:add(function () f(a, b) end, 1)

@Jordan, if the second one works, I think this is not the problem. I think he does want to return the result, but it does not?

So, f() invokes f, but just plain f passes a pointer to the function?

That is, if my function requires parameters, I have to wrap it in an an anonymous function?

I know I’ll get this someday here soon… I’ll go another round with it later as it’s late and I hear reindeer on the rooftop. :slight_smile:

@JakAttak I don’t need any return, just trying to pass some parameters with function. I think Jordan is at least partly right.

@Jordan That’s a no go. All 8 animations are fired at once, and the Tasks are still nil… I’ve done something wrong in my code above in handling parameters.

Oh well, time for bed… Good night all!

How about this?

-- Game
function setup()
    t=Tasks
    t:add(p,{"1","11"},2)
    t:add(p,{"2","22"},2)
    t:add(p,{"3","33"},2)
end

function p(t)
    print(t[1],t[2])
end

function draw()
    t:draw()
end

Tasks = class()
local timer = 0
local waiting = false

function Tasks:init()
end

function Tasks:add(action,p, wait)
    table.insert(self,{action,p, wait})
end

function Tasks:draw()
    timer = timer - DeltaTime
    if not waiting then
        if #self > 0 then
            waiting = true
            timer = self[1][3]
            self[1][1](self[1][2])
            table.remove(self, 1)
        end   
    elseif timer<=0 then
        waiting = false
    end
end

Key changes are

  1. You can’t call self[1].wait or self[1]:action unless you have specifically named the table fields, like this
table.insert(self,{action=action,params=p, wait=wait})

The way you did it, you need to refer to them by table position as I have done above

  1. You can pass through parameters in their own little table, store them along with the action function address, then apply them when the function runs.

obsessive me finally got it…

table.insert(self, {["action"]=action, ["wait"]=wait})

Probably the long way of writing it, but now it works beautifully! And no ugly global flag business like I used to have…

Thanks, Ignatz. Looks like you got there before me. :slight_smile:

Well you both were faster. I’ll post it anyway. @syntonica you can chack that too, to see how to 1/ pass values to tween.delay, and 2/ manage case when the values are initiated later. Merry Christmas!




task = class()
function task:init()
    print("created, but values not here")
end
function task:draw()
    resetMatrix()
    fill(self.c)
    translate(self.x,self.y)
    rotate(ElapsedTime*100)
    rect(-50,-50,100,100)
end
function task:setXYC(x,y,c)
    self.x = x
    self.y = y
    self.c = c
    print("values ready!")
end

function setup()
    task1 = task()
    task2 = task()
    task3 = task()
    tween.delay(1,task1.setXYC,task1,200,400, color(255, 0, 0, 255))
    tween.delay(3,task2.setXYC,task2,400,400, color(255, 217, 0, 255))
    tween.delay(6,task3.setXYC,task3,600,400, color(4, 0, 255, 255))
end
function draw()
    background(0)
    if task1.c then task1:draw() end
    if task2.c then task2:draw() end
    if task3.c then task3:draw() end
end



@Jmv38 Thanks! That was solution #1, but If I was going to have a table full of tasks, it was easier to write my routine rather than do this. I will be reusing my task list handler in several places in my code.

I originally had a global flag I was using, although I’m not sure how I managed it originally. lol. After discovering how functions are passed and how they are not really serializable, I had to do some recoding ( as in, I rewrote most of it) to be able to serialize my game state and reconstruct the game if reloaded. I also got rid of half my code. :smiley: AirCode is marvelous for copying code from TextWrangler, my favorite tool of choice. My iPad mini is just too mini to effectively code by touch.

2 days later, I am back to my original functionality, but I can now write my GUIs as tables and read them in. My only compromise is a table of actions to derefernce string names of functions to actual functions.