3
\$\begingroup\$

I am working on an RPG type game in Java and I would like to know a few things relating to threading,

What is the best way to implement a "wait for this then do this" without hanging the whole thread? Like waiting for a player to move to a location then pick up an item? or to wait one second then attack?

Currently I am spawning new threads every time I need to wait for something, but that doesn't feel like the best solution.

Any help is appreciated.

EDIT: Clarification and an example of how I currently do things.

User clicks on an item The function walkToAndPickUp(item) is called which is basically this:

Make a new thread so we don't freeze the thread handling input while the player moves.
Tell player to move to the item
While the player is not at the item(The player moves through an update() function called in a different thread, I don't know how else to do it without freezing threads)
Repeat until the player is at the item
If the player is at the item then call delete item from map and add to inventory.

\$\endgroup\$
1
  • 4
    \$\begingroup\$ Please split your questions up into separate questions. \$\endgroup\$
    – user744
    Nov 16, 2010 at 14:35

4 Answers 4

5
\$\begingroup\$

The short answer is: don't. Multithreading will give you more headaches than it saves.

Taking your example in particular:

User clicks on an item The function walkToAndPickUp(item) is called which is basically this:

I'd rethink things a bit. At any point the state contains (among other things) the PC's target location and the PC's target item.

  • A click clears the target item
  • The items are ignored in determining the click location. The PC's target location is updated to the point clicked.
  • If the point clicked was on an item the target item is set to that item.

Then your game loop will include a move() which checks whether the PC can move towards the target location and if so does, and an interact() which interacts with objects near the PC. Among the interactions are items checking "Am I the target item and within a certain distance of the PC?" If so, they call a pick-me-up routine.

No threads required. No movement code duplicated between moving and picking up items.

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

Sounds like what you need aren't multiple threads, but coroutines.

See this SO question for more information: https://stackoverflow.com/questions/1247894/coroutines-for-game-design

\$\endgroup\$
1
  • \$\begingroup\$ Coroutines sounds like a good way to do it, but after some searching it seems that coroutines are supported in Java \$\endgroup\$
    – MESLewis
    Nov 16, 2010 at 15:44
3
\$\begingroup\$

At some point in the thread you've spawned you're checking for the player to "be in a location". Normally, the check you're doing there isn't blocking in itself, so these conditions are checked by the main logic thread. Checked but not waited on. That's the key, every frame if you like, check for the condition being met, if it is, do the "then" case.

How you implement the condition checking is up to you, but usually there's an array/list of things to check against (in code or data) and the resultant state change function or functor.

It sounds like what you're doing is:

while( !condition );
doSomething();

Whereas what you need to be doing is more like:

if( interestedInDoingSomething && condition )
  doSomething();

"User clicks on an item The function walkToAndPickUp(item)" In this case you have a functor called WalkToAndPickup, that is created with the item as an argument, and it ticks until it returns that it's done. Instead of having thread for the fact that you are moving, the object's existence provides the information you need to determine where to walk to and what object to pick up once you get there.

functors.insert( new WalkToAndPickup( item ) );
...
while( gameActive )
{
  for functor in functors
  {
    functor.Update();
    if( functor.Done() )
    {
      functors.remove( functor );
      delete functor;
    }
  }
}

So what you have here is an impementation that inserts a new functor/task into a container of tasks that are always running. If a task (like walktoitem) finishes, then it gets deleted. What you do inside the functor update is up to you, and will mirror the contents of your threaded system, except you will probably want to either spawn a new functor for each stage of your tasks, or have another internal state for controlling what code to run at what point in the task's sequence of events.

an example of what you might write in your functor's update:

update()
{
  switch( state )
  {
    case 0: walkto( item ); if( atItem( item) ) state = 1; break;
    case 1: takeitem( item ); if( gotItem( item) ) state = 2; break;
    case 2: setAsFinished(); break;
  }
}

also, don't forget you can insert new functors in the functor list from inside an update. That's how you can chain your dependencies.

\$\endgroup\$
1
  • \$\begingroup\$ Checking for conditions all the time would mean a lot of variables saying things like doesPlayerWantToPickUpItem, whatItem, isPlayerGoingToPlayDanceAnimationWhenDoneWalking and I don't want to have to deal with a variable for every possible action to be performed next. Please read my edit in the original post for clarification on what I want to accomplish. \$\endgroup\$
    – MESLewis
    Nov 16, 2010 at 16:01
1
\$\begingroup\$

Look at animation systems for inspiration. Don't spawn a thread for every item that needs animating! Consider what happens if the user clicks on a different item while your character is still moving towards another item. Then you'll have two threads simultaneously trying to change the same object.

Instead, put actions in a list. Each frame you update each action in the list. When an action is finished or cancelled remove it from the list.

In your walkToAndPickUp example, I would enqueue an action object containing the character and the target location. Each frame I would move the character closer to the target location. On the frame that the location is reached, pick up the item and finish the action by removing it from the list.

To make things simpler, you can compose complex actions out of primitive actions, using an action sequence object. For example, you could make your first example by combining a walkTo action and a pickUp action. Your other example could be combining a wait action followed by an attack action. Then you can easily make new actions, like walkToThenAttack or waitThenWalkTo, without duplicating lots of code.

All characters, NPCs, projectiles, basically anything in the game, should use this system to update and animate their actions.

If the player interrupts the action by clicking elsewhere, the old actions for that character would be removed (or you could block the user from performing more actions until the current one has finished).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .