2
\$\begingroup\$

I have been implementing behavior for enemies in my game and so far I have been doing it sort of like below:

public void update()
{
    if (frame > 60 && frame % 30 == 0)
    {
        shootAtPlayer();
    }
    frame++;
}

Which is meaning after frame 60 shoot the player every 30 frames. The frame-count is important as the game is fixed frame-rate and everything is relying on this at the moment. There are many small scripts for enemy behavior like above and I currently iterate through each one calling update(). I have realized it will quickly get unweildy dealing in absolute frames and I want to move towards a pattern where I can specify to do X for 60 frames then do Y e.t.c, something that is easily understandable and easy to write. I want to go for something like below:

wait(60)
while(true)
{
    shootAtPlayer();
    wait(30);
}

I was wondering if there is a design pattern that would easily support such a syntax. My initial thoughts were to create a thread for each script object and have the wait implemented similar to below:

wait(int frames)
{
    while(frames > 0)
    {
        frames--;
        suspend();
    }
}

with the method running the scripts calling resume in turn on each script. I could potentially have up to 300 scripts running at once which would mean 300 threads to handle. Am I taking the correct approach to solving this problem?

I am programming this in C# XNA.

\$\endgroup\$
3
\$\begingroup\$

It would be simpler to create to use events and fibers

Using a fiber means you can yield and return how many frames to wait until it should be called it again.

Then with a priority queue you can iterate over all events scheduled for the current frame.

IEnumerator<int> ai_script() 
    yield return 60;
    while(true)
    {
        shootAtPlayer();
        yield return 30;
    }
}

and then in the gameloop

while(running){

    frame++;
    updateFysics();

    IEnumerator<int> ie;
    while((ie = delayQueue.Pop(frame))!=null){
        if(ie.MoveNext()){//move next then does the call true means there is another wait, false means the task is done
            delayQueue.add(ie,ie.Current+frame);//Current holds the delay requested
        }
    }

}

This solution is heavy misuse of C# syntax, but you can use explicit Fibers instead.

\$\endgroup\$

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.