4
\$\begingroup\$

I have objects, and each object has a function pointer that will be assigned a function. When the object is clicked, the assigned function will be called. I want to have a function do things with delay, meaning it would look something like this:

void function() {
    doSomething();
    wait(1000);     // either 1000 frames, or 1000 miliseconds
    doSomethingElse();
}

I heard threading shouldn't be abused, and main script should all be put in the same thread. There are lots of game engines out there that can handle such functions with a delay in time. My idea was to call the function in a new thread every time.

Is this a bad idea? If it is, how else would I manage to achieve this functionality?

Edit: the website asked to confirm it's not a duplicate question and I think it's not because it's a bit more complicated of an issue, even though it may use a similar solution.

\$\endgroup\$
  • 3
    \$\begingroup\$ Possible duplicate of Updating bots/AI behavior after a fixed elapsed timestamp in game loop? \$\endgroup\$ – congusbongus May 5 '17 at 2:50
  • \$\begingroup\$ This sounds a lot like a coroutine... \$\endgroup\$ – DMGregory May 5 '17 at 10:16
  • \$\begingroup\$ Yes, it looks similar, I have done this with counting some other stuff, it just feels inefficient and sloppy to use overall and what I need to do I feel is more complicated than that because it involves multiple sequences of delayed instructions happening in a function. I figured having a subfunction for each delayed sequence of instructions would be spaghetti \$\endgroup\$ – Dave Jecs May 5 '17 at 11:50
5
\$\begingroup\$

You could try a central Job manager that performs jobs in an asynchronous way.

The skeleton of the feature could look like this bastard c++/pseudocode:

struct Job
  double mTimer;
  std::function<void>() mFunction;

class JobManager
  addJob(Job job) { mJobs.insert( job ); }

  std::list<Job> mJobs;

  perFrameExecuteJob(deltaTime){
    // Iterate through all the jobs that are to be done, reduce the time left by the dt.
    // If the delay has expired, perform the job, and remove it from the set of jobs to 
    // do. 
    std::list<Job>::iterator it = mJobs.begin();

    while( it != mJobs.end() ) {
      it->mTimer -= deltaTime;
      if ( it->mTimer <= 0 ) {
        it->mFunction();
        it = mJobs.remove(it);
      }
      else {
        it++;
      }
    }
  }

Basically, a Job represents a unit of work and it can be delayed.

You'd do something like this to add a Job to the JobManager:

void function(JobManager& aJobManager){
    doSomething();
    Job job;
    job.mTimer = 1000;
    job.mFunction = doSomethingElse;
    aJobManager.addJob( job );
}

And you'd call

mJobManager.perFrameExecuteJob( dt ); 

every frame from your main loop.

\$\endgroup\$
  • \$\begingroup\$ I have seen this used before, but isn't it terribly inefficient? If I had a ton of such functions, wouldn't it slow down the program a lot more than threads? \$\endgroup\$ – Dave Jecs May 5 '17 at 11:45
  • \$\begingroup\$ @DaveJecs I guess you'll have to test it. I guess with this implementation, the price to pay is that you'll get some cache misses, while with threads you'll need a context switch.. \$\endgroup\$ – Vaillancourt May 5 '17 at 12:13
  • \$\begingroup\$ You do not need to iterate through all jobs to be performed, or alter timestamps in the list. Let them be static, somewhere in future. Instead sort the list when inserting a new job (happens more sparsely), so the closest upcoming is topmost. Then just check the (advancing) game clock/whatever against the topmost/first job item only. Takes 3.14 nanosecs. If elapsed, then execute. This also means max 1 job will be executed per frame (if doing this work in thread 0), which may be good for balancing. \$\endgroup\$ – Stormwind May 5 '17 at 14:25
  • \$\begingroup\$ @Stormwind You're right, there are a couple of ways to implement this. \$\endgroup\$ – Vaillancourt May 5 '17 at 14:41
  • \$\begingroup\$ @Stormwind good idea, I'll try that out. On a side note, I made a rough test how much my laptop can go up to (it's pretty old) and it seems to be able to draw up to around 900 64x64 images/frame and keep the 60 frames per second (only drawing, nothing more). That is a lot more than I expected, so I guess performance may not be that much of an issue. \$\endgroup\$ – Dave Jecs May 6 '17 at 0:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.