Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (476)
Games in Android Showcase (106)
games submitted by our members
Games in WIP (530)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Time to multithread?  (Read 737 times)
0 Members and 1 Guest are viewing this topic.
Offline Gibbo3771
« Posted 2014-03-15 15:34:43 »

I am in the process of working out a way to handle entities in my game. I decided to go with a Factory class that handles this stuff.

It will be responsible for updating and deleting entites from the world, from drops, bullets, particles etc etc.

Problem being, it seems to freeze my game when doing large operations. I have a Grenade class that you can throw, it explodes and creates around 45 Shrapnel objects around it (box2d) and accelerates them away from the explosion point.

This does 3 things, it first loops through the Explosives array of Shrapnel, fires them all in there direction.
It adds these shrapnels objects to another array in the Factory class which updates them, then removes them if needed
The renderer, well it renderes the graphics.

This means there is pretty much 3 loops running, only 1 of which handles any graphics. Should I move my logic onto a seperate thread? I have the thread setup and ready to go but is there something else I can do?

Here is some code for you to gander over:

Player presses G, it calls this method and creates a small rectangle which acts as a grenade
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
/**
    * Throw this explosive in the direction of the thrower
    *
    * @param postion
    *            the starting position
    * @param angle
    *            the angle to be thrown, used to calculate the trajectory
    * @param power
    *            power of the throw
    */

   public void throwExplosive(Vector2 postion, float angle, float power) {
      createBody(BodyType.DynamicBody, postion.x, postion.y, angle);
      createPolyFixture(0.10f, 0.10f, 0.10f, 0.10f, 0.15f, false);

      createTime = TimeUtils.nanoTime();

      body.applyLinearImpulse(power * MathUtils.cos(angle),
            power * MathUtils.sin(angle), 0, 0, true);

      body.setUserData(this);
      isThrown = true;
   }


Then this grenade gets added to an array for updating

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
/**
    * Update this explosive object, keeps detonation timers in check
    */

   public void update() {
      if (isThrown) {
         if (TimeUtils.nanoTime() - createTime > fragTime) {
            detonate(body.getPosition());
            isThrown = false;
         }
      }

   }


Then this is called

1  
2  
3  
4  
5  
6  
7  
8  
9  
/**
    * Detonate this explosive and send shrapnel flying out
    */

   public void detonate(Vector2 position) {
      for (Shrapnel shrapnel : this.shrapnel) {
         shrapnel.fire(position);
      }

   }


Which basically does this

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
/**
    * Fire this shrapnel in its assigned direction, call this to create an
    * explosion type effect
    */

   public void fire(Vector2 position) {
      createBody(BodyType.DynamicBody, position.x, position.y, angle);
      createPolyFixture(0.1f, 0.1f, 0.75f, 0, 0.2f, true);
      createTime = TimeUtils.nanoTime();
      body.applyLinearImpulse(speed * MathUtils.cos(angle),
            speed * MathUtils.sin(angle), 0, 0, true);
     
      Level.factory.projectiles.add(this);

      body.setUserData(this);
   }


If you are wondering when the shrapnel gets added to the array, it happens in the constructor of whatever explosive class is being called, currently I just have a Grenade class:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
public Grenade() {

      fragTime = MathUtility.secondToNano(3);

      float angle = 0;
      for (int count = 0; count < 45; count++) {
         Shrapnel shrapnel = new Shrapnel(this, true, position, angle,
               MathUtility.secondToNano(5), 0.05f, 3);
         this.shrapnel.add(shrapnel);
         angle += 8 * MathUtils.degRad;
      }

   }

"This code works flawlessly first time and exactly how I wanted it"
Said no programmer ever
Offline princec

JGO Kernel


Medals: 339
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #1 - Posted 2014-03-15 17:41:59 »

This is one of "those" kinds of replies but... if you're asking others whether it's time to multithread... it's not.

Cas Smiley

Offline Gibbo3771
« Reply #2 - Posted 2014-03-15 17:57:08 »

This is one of "those" kinds of replies but... if you're asking others whether it's time to multithread... it's not.

Cas Smiley

Ah right I guess it is one of those things that "if it's time, you will know".

However I shall define my question into a more general one....

I have like 3 for loops that run on the same thread, as well as the rendering...should I multithread in order to prevent lockups? Considering in the future I intend to have plenty of shit flying around (bullets, bombs, particles etc etc)

"This code works flawlessly first time and exactly how I wanted it"
Said no programmer ever
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #3 - Posted 2014-03-15 18:10:37 »

You're having performance problems with 45 entities?

As Cas said, if you think multithreading is the right direction, it's not.  I won't deny that you might alleviate the initial performance issue while going down this route but you really haven't solved your problem.  You now have multithreading (adding huge complexity) while the underlying root problem (why 45 entities cannot be processed in one frame) is still not solved.

> should I multithread in order to prevent lockups?

No.  Chances are you'll introduce new lockups (deadlocks) and erroneous behavior that's going to be a bitch to debug because of the multiple threads.

After looking at your code, allocating each shrapnel object on the heap is not going to scale properly.  A grenade is going to explode anyway right?  It's going to have shrapnel?  Why not when creating the grenade ensure that its data includes its shrapnel.

After going down this route, ask yourself, should each individual grenade be allocated on the heap too?
Offline Gibbo3771
« Reply #4 - Posted 2014-03-15 18:28:12 »

You're having performance problems with 45 entities?

At this stage yes, my code is ofc not refactored at all. However I have the fear that with thousands of entities I might have the problem.

Saying this, by the time I wrote the OP and replied to this I fixed the performance issue by fixing how the collision, creation and destruction of the shrapnel is handled.

> should I multithread in order to prevent lockups?

No.  Chances are you'll introduce new lockups (deadlocks) and erroneous behavior that's going to be a bitch to debug because of the multiple threads.

Right, got it. I will read further however to learn why these things can happen. Thanks.

After looking at your code, allocating each shrapnel object on the heap is not going to scale properly.  A grenade is going to explode anyway right?  It's going to have shrapnel?  Why not when creating the grenade ensure that its data includes its shrapnel.

After going down this route, ask yourself, should each individual grenade be allocated on the heap too?

Ok regarding how it is allocated, unless my game is taking up several gigs of ram while running, it should be ok right?

Currently as it stands, upon creation of a grenade, as in if one is lying on the ground ready to be picked up, in the inventory of an entity or whatever...each grenade object has an array that holds all it's shrapnel (this makes sense, since this is technically what grenades do). So upon explosion I simply loop through this array, toss every piece of shrapnel out and remove each peice from that array and hand it to the factory to update and process/remove them from the world.

"This code works flawlessly first time and exactly how I wanted it"
Said no programmer ever
Offline princec

JGO Kernel


Medals: 339
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #5 - Posted 2014-03-15 18:39:31 »

Don't worry about threads right now as they really are a monumental pain to get right. Single-threaded you should be good for a couple of thousand "things" all doing their business in your game loop, and time enough for rendering too.

Single-threaded you'll have no chance of lock-ups at all.

Cas Smiley

Offline loom_weaver

JGO Coder


Medals: 17



« Reply #6 - Posted 2014-03-15 18:43:26 »

Ok regarding how it is allocated, unless my game is taking up several gigs of ram while running, it should be ok right?

What I am saying is that having dynamically allocated memory (new) and manipulating dynamic collections (e.g. Lists) comes with a performance cost.  For example, removing a shrapnel piece from a basic list can be on the order of O(n).  That's a price you won't want to be paying every frame.


Currently as it stands, upon creation of a grenade, as in if one is lying on the ground ready to be picked up, in the inventory of an entity or whatever...each grenade object has an array that holds all it's shrapnel (this makes sense, since this is technically what grenades do). So upon explosion I simply loop through this array, toss every piece of shrapnel out and remove each peice from that array and hand it to the factory to update and process/remove them from the world.

Others may disagree but I don't believe that classic OOP should used to the same extent in games.  Before OOP imagine writing a game where performance and memory usage was a huge concern.  Most games can be written to manipulate a fixed set of data.  Think data-driven instead of OO.

Take for example grenades and shrapnel.  Let's put a reasonable limit... no more than 200 grenades on screen at once.

The grenade structure looks like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
class Shrapnel {
  boolean visible;
  int x;
  int y;
}

class Grenade {
  boolean visible;
  int x;
  int y;
  Shrapnel[45] shrapnel;
}


Now allocate it all just once at the start of the game:

1  
Grenade[200] grenades = new ...


During your game loop you can iterate over the grenades array updating data as needed.  No allocation is happening, no list insertion, no list deletion, no GC worries.

Offline jonjava
« Reply #7 - Posted 2014-03-15 20:34:10 »

What does your factory's add and delete methods look like?

Online trollwarrior1
« Reply #8 - Posted 2014-03-15 20:42:15 »

Don't fix the problem that doesn't exist..
Online Roquen
« Reply #9 - Posted 2014-03-15 21:58:35 »

I agree with the multithreading isn't a good question here, but some comments.

You don't want to call nanoTime at a high rate.  Not an issue here, but worth noting.  (serializing instruction)

dead-locks: they're dead easy to avoid.  Never use locks.  That way you avoid starvation as well and the main reason why multithreading has the rep of being hard.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

JGO Kernel


Medals: 339
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #10 - Posted 2014-03-15 22:10:31 »

Lock-free multi-threaded programming is a different kind of hard, though...

Cas Smiley

Offline Gibbo3771
« Reply #11 - Posted 2014-03-15 22:11:44 »

Ok regarding how it is allocated, unless my game is taking up several gigs of ram while running, it should be ok right?

What I am saying is that having dynamically allocated memory (new) and manipulating dynamic collections (e.g. Lists) comes with a performance cost.  For example, removing a shrapnel piece from a basic list can be on the order of O(n).  That's a price you won't want to be paying every frame.


Currently as it stands, upon creation of a grenade, as in if one is lying on the ground ready to be picked up, in the inventory of an entity or whatever...each grenade object has an array that holds all it's shrapnel (this makes sense, since this is technically what grenades do). So upon explosion I simply loop through this array, toss every piece of shrapnel out and remove each peice from that array and hand it to the factory to update and process/remove them from the world.

Others may disagree but I don't believe that classic OOP should used to the same extent in games.  Before OOP imagine writing a game where performance and memory usage was a huge concern.  Most games can be written to manipulate a fixed set of data.  Think data-driven instead of OO.

Take for example grenades and shrapnel.  Let's put a reasonable limit... no more than 200 grenades on screen at once.

The grenade structure looks like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
class Shrapnel {
  boolean visible;
  int x;
  int y;
}

class Grenade {
  boolean visible;
  int x;
  int y;
  Shrapnel[45] shrapnel;
}


Now allocate it all just once at the start of the game:

1  
Grenade[200] grenades = new ...


During your game loop you can iterate over the grenades array updating data as needed.  No allocation is happening, no list insertion, no list deletion, no GC worries.



This is very good, I never though of it like that.

What does your factory's add and delete methods look like?

At the moment it is mainly just an update method, it runs constantly looping through currently 2 arrays:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
/* If the world is not in a timestep, start removing bodies */
         if (!world.isLocked()) {
            for (Box2DObject object : toDelete) {
               if (object.getBody() != null)
                  world.destroyBody(object.getBody());
               toDelete.removeValue(object, true);
            }

         }
         /*
          * Update all the bullets currently in flight and remove as
          * necessary
          */

         for (int projectile = 0; projectile < projectiles.size; projectile++) {
            Projectile p = projectiles.get(projectile);
            p.update();
            if (p.isCanExpire()) {
               toDelete.add(p);
               this.projectiles.removeValue(p, true);

            }
         }


This is not optimal however, there is no need to loop over arrays like this, for instance there is no real need to update things that are not moving and such, if that makes sense. It needs greatly optimized but as it stands, it is doing the job.

I will later add a timer/check mechanics that only runs when needed, spread it out via methods.

"This code works flawlessly first time and exactly how I wanted it"
Said no programmer ever
Offline jonjava
« Reply #12 - Posted 2014-03-15 22:23:55 »

Usually removing something from a Collection such as a List is a very expensive process.

Try this e.g.: http://www.java-gaming.org/index.php?topic=27017.0

Offline philfrei
« Reply #13 - Posted 2014-03-16 06:22:58 »

Lock-free multi-threaded programming is a different kind of hard, though...

Cas Smiley

But fascinating and kind of fun. I recommend perusing principles of "Functional Programming" for ideas.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline princec

JGO Kernel


Medals: 339
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #14 - Posted 2014-03-16 11:45:04 »

It's quite a new concept to me, and I like what I see so far. Unfortunately Java "the language" doesn't have a lot of sugar to support it like it had for old-fashioned synchronization.

Cas Smiley

Offline Gibbo3771
« Reply #15 - Posted 2014-03-16 12:23:30 »

I would like to thank everyone for their replies, I have taken a step back to have a look at my code and fixed quite a few badly (very) written bits that were the main cause for lock ups.

The main one was upon explosion of my grenade, I was setting the shrapnels collision data...So briefly every single piece of shrapnel was overlapping for 1 frame before they were told "don't hit each other".

Fixed that.

But this is just some fun stuff I am screwing with on the side while I implement path finding, just to give me a break from debugging that code.

Really enjoying it so far Cheesy

"This code works flawlessly first time and exactly how I wanted it"
Said no programmer ever
Pages: [1]
  ignore  |  Print  
 
 

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

pw (12 views)
2014-07-24 01:59:36

Riven (10 views)
2014-07-23 21:16:32

Riven (11 views)
2014-07-23 21:07:15

Riven (12 views)
2014-07-23 20:56:16

ctomni231 (43 views)
2014-07-18 06:55:21

Zero Volt (38 views)
2014-07-17 23:47:54

danieldean (32 views)
2014-07-17 23:41:23

MustardPeter (34 views)
2014-07-16 23:30:00

Cero (50 views)
2014-07-16 00:42:17

Riven (50 views)
2014-07-14 18:02:53
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!