Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (763)
Games in Android Showcase (229)
games submitted by our members
Games in WIP (852)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  [Libgdx] Huge world with alot of entities fps drop [solved]  (Read 7340 times)
0 Members and 1 Guest are viewing this topic.
Offline printer

Junior Devvie


Medals: 1



« Posted 2017-12-29 13:04:50 »

Hello,

i would love open a huge rpg world with alot of entities. But the fps drops alot more entities are on the map. Worth to metion entities who are outside of the player range are not rendererd.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
        int count = 200000;

        blockArray = new Array<Creature>(true, count);

        while (count > 0) {
            blockArray.add(new Monster("Dragon", new Vector2(0, 5 * count), game.asset.getAtlas().findRegion("dragon")));
            count--;
        }

        // Set up the quad tree
        quadTree = new QuadTreeNode(0, new Rectangle(0, 0, Main.V_SCREEN_WIDTH / game.UNIT_SCALE, Main.V_SCREEN_HEIGHT / game.UNIT_SCALE));
        entitiesToCheck = new Array<Creature>(true, QuadTreeNode.MAX_ENTITIES);


Profiler:
https://imgur.com/a/eADBM
Offline 65K
« Reply #1 - Posted 2017-12-29 13:52:54 »

Seems like each monster gets its own texture region - I don't assume each monster has a unique look.

Lethal Running - a RPG about a deadly game show held in a futuristic dystopian society.
Offline printer

Junior Devvie


Medals: 1



« Reply #2 - Posted 2017-12-29 14:16:41 »

No they are not, how can i tackle this problem?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline 65K
« Reply #3 - Posted 2017-12-29 14:26:28 »

If they all look alike, just reuse one texture and draw it 2.000.000 times each frame...
But I really, really recommend to get your game first working with 20 monsters, then 200 maybe, ...

Lethal Running - a RPG about a deadly game show held in a futuristic dystopian society.
Offline printer

Junior Devvie


Medals: 1



« Reply #4 - Posted 2017-12-29 19:15:26 »

How can i reuse the texture? Since i tried create it outside the loop and there is no difference on the fps increase:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
        int count = 200000;

        blockArray = new Array<Creature>(true, count);

   dragonTexture = game.asset.getAtlas().findRegion("dragon");
        while (count > 0) {
            blockArray.add(new Monster("Dragon", new Vector2(0, 5 * count), dragonTexture));
            count--;
        }

        // Set up the quad tree
        quadTree = new QuadTreeNode(0, new Rectangle(0, 0, Main.V_SCREEN_WIDTH / game.UNIT_SCALE, Main.V_SCREEN_HEIGHT / game.UNIT_SCALE));
        entitiesToCheck = new Array<Creature>(true, QuadTreeNode.MAX_ENTITIES);
Offline bmanmcfly
« Reply #5 - Posted 2017-12-29 20:43:12 »

20k of entities is WAYY too many.

First, if you loop like for each entity, move, draw.  Then, on a PC there is probably nothing to worry about.
Thing is, you want each entity to examine its surrounndings, make decisions, etc...

So, are these 20k entities on the screen?  If not, then only draw what is actually on the screen.
The map is huge, so, unless you need actions from them across the world (unlikely in a single player game), why not just let them sleep if they are more than a few screens away?

In something similar, it didnt take much more than 50 entites with full decision making, etc, to start seeing an impact in performance on an android device (there were other limiters, but thats less important)

i hope you are not thinking of building an MMO game as the reasoning for so many active entities?
Offline printer

Junior Devvie


Medals: 1



« Reply #6 - Posted 2017-12-29 20:45:40 »

The thing is they are not getting drawn or render when they are outside the screen. Problem is bigger the array become more fps drops i notice. I think problem is with the creating new Texture for a monster 2milion times when i can do it once. Since they are using the same. But how can i reuse a texture?
Offline bmanmcfly
« Reply #7 - Posted 2017-12-29 21:01:22 »

Thats not quite right, just because it does not appear on screen, it will still make a draw call and process it as though it was on the screen. 

Offline printer

Junior Devvie


Medals: 1



« Reply #8 - Posted 2017-12-29 21:10:19 »

What should i do? Since it should be possible to have a alot of creatures without any problems. Those Who are not displayed has a idleState and only checking if they are being seen or not.
Offline bmanmcfly
« Reply #9 - Posted 2017-12-29 22:26:36 »

Are you using Ashley?

Anyway, the answer will vary... How much of the world will the player be able see at any given time?
Is the entire world in a singular map?

How much processing will each entity be doing?
Can you limit how many checks to "isactive"? Consider; if(isActive) x 20k is going to be alot.  So, Even if you have 20k predetermined entities walking around, you'll need to split things up so you only consider a reasonable amount at any given time.

Lets say in a rogue type, you wouldn't load the entities into memory until they are within a proximity, and even then probably keep them sleeping until appropriate... 
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline printer

Junior Devvie


Medals: 1



« Reply #10 - Posted 2017-12-29 22:55:31 »

No i'm not using Ashley.

The default state is idle. So they only check for when player is in screen. Also even tho they are not doing anything. I think the main cause, is that i'm loading everyone instant into the world.

It's a single map that's very small, but the monsters are positioned very far from eachother.

So i suspect that Array where i adding the dragon is to big and taking to long time to loop through it.

I'm using TMX map.
Offline KevinWorkman

« JGO Plugged Duke »


Medals: 283
Projects: 12
Exp: 12 years


HappyCoding.io - Coding Tutorials!


« Reply #11 - Posted 2017-12-30 18:18:43 »

I'm not sure what you want us to tell you. You're handling too many enemies at once. Decrease the number of enemies.

Do some profiling to figure out exactly where the bottleneck is. What do you spend the most time doing? Decrease the number of times you do that.

There are a number of approaches to this: for example you could split your world up into sections, and only handle enemies that are in that section.

But until you do some profiling, then everything we could tell you is just a guess. Profile first, and then think about optimizations.

HappyCoding.io - Coding Tutorials!
Happy Coding forum - Come say hello!
Offline printer

Junior Devvie


Medals: 1



« Reply #12 - Posted 2018-01-01 18:57:18 »

I had already profiling image on the first post. Issue is not that they are too many enemies on the screen. Since those Who are not seen by the player are not moving, redering and etc... The issue is that if i add to many enemies to the array it seems to decrease the fps.
Offline KevinWorkman

« JGO Plugged Duke »


Medals: 283
Projects: 12
Exp: 12 years


HappyCoding.io - Coding Tutorials!


« Reply #13 - Posted 2018-01-01 19:37:02 »

The issue is that if i add to many enemies to the array it seems to decrease the fps.

Yes, probably because you're still iterating over all of the enemies and checking whether they're on screen? Again, you need to profile to see what's taking up the most time.

HappyCoding.io - Coding Tutorials!
Happy Coding forum - Come say hello!
Offline VaTTeRGeR
« Reply #14 - Posted 2018-01-01 19:52:40 »

...what a trainwreck of a thread, holy shit.

First thing, your quadtree is basically getting ass-raped with a cactus right now with how you place your monsters, this structure is not ideal at all for an ever growing straight line of enemies. Try placing them randomly in a fixed size square region, that'll suit your quadtree way better and is a more realistic representation of how they'll be placed later in the real game anyway.

I mean this part:
1  
new Vector2(0, 5 * count)


Try this instead:
1  
new Vector2(random(min_X,max_X), random(min_Y,max_Y))



Second thing, where the hell is your main game loop, you didn't post it here right? How is anybody going to be able to help you without that crucial piece of information?

The most interesting parts are how you check your units for processing and how you handle the quadtree, please post the whole thing.


Third thing, do you really think it is a good idea to make the quad-tree only as big as your screen, why do you even need the quadtree then?
1  
new QuadTreeNode(0, new Rectangle(0, 0, Main.V_SCREEN_WIDTH / game.UNIT_SCALE, Main.V_SCREEN_HEIGHT / game.UNIT_SCALE));

Make it as big as your game world instead!


Fourth thing, implement some static global counter that counts how often certain methods (monster.idle()/update()/render() and whatever) are called per frame, so that you know what gets invoked how often. Do this for the monsters methods and everything else that gets called repeatedly.

Or use the profiler:
Quote
Again, you need to profile to see what's taking up the most time.
Listen to him, he's right! You didn't profile method calls/execution times yet. Instead you've just shown us instance counts.



My spidey-sense tells me you're simply processing too many entities way too often, 200K is a lot.

1  
entitiesToCheck = new Array<Creature>(true, QuadTreeNode.MAX_ENTITIES);

Does this line mean you "check" (whatever that means, we don't know, post your code...) every entity? This is the perfect recipe for long execution times.
Just doing a simple check per entity is enough to bring down frame-times with your entity-count.
Offline bmanmcfly
« Reply #15 - Posted 2018-01-02 02:45:53 »

Agreed...

I first found that out when drawing shaperender stuff across tiled maps to make sure that things were being parsed correctly.... it didnt take long for frame rates to drop.

I really dont see how you need 20k of entities that are being processed at any given time.

Better to start things small and then scale up... like, to get controls constrain it to a simple box that suits the test, etc.

Its a lot easier to get lost when you build a massive list of things that are partially done adn then sorting out the stuff that winds up breaking.

also, agreed, figure out where time is being lost...
Offline printer

Junior Devvie


Medals: 1



« Reply #16 - Posted 2018-01-13 13:02:50 »

Question, since i use a quad tree to handle collision. Should i also store objects inside there? Such as walls, trees, water tiles and etc... Since they are also collision object? Or is it bad practise
Offline VaTTeRGeR
« Reply #17 - Posted 2018-01-13 13:43:56 »

I think it would be a good idea to sort moving and static entities into two separate quad-trees, if you want a little bit of extra performance.

Walls, houses and roads do not change their position in the world (=> in the quad-tree).
Moving objects on the other hand change the tree when moving around, they for example split nodes, or collapse nodes, etc. When this happens, all the entities (even the static ones!) in these nodes need to be re-inserted. Having more objects in a node means more overhead when stuff changes!

This might be a total non-issue though depending on how your game utilizes the quad-tree.

I suggest you do whatever is more practical/easy for you to implement.
Offline printer

Junior Devvie


Medals: 1



« Reply #18 - Posted 2018-01-13 17:23:56 »

I agree with you to use seperate quad tree for objects. But If there is alot of collision objects on the screen. What is the optimal values for these two:

1  
2  
    public static final int MAX_ENTITIES = 4;
    private static final int MAX_LEVELS = 5;
Offline VaTTeRGeR
« Reply #19 - Posted 2018-01-13 19:51:01 »

Test different values when you have the game up and running Wink

There is a perfect number for this and one could calculate it at least approximately, but that would be a waste of time for an unfinished project.
Offline printer

Junior Devvie


Medals: 1



« Reply #20 - Posted 2018-01-13 19:53:44 »

Okay cheers man, well last question. Should i draw rectangle on every collidable object? Since on Tiled you can draw a huge rectangle or a one grid rectangle. Which is the best option? Since this is a grid based game.
Offline printer

Junior Devvie


Medals: 1



« Reply #21 - Posted 2018-01-14 13:09:03 »

I used collision based on this: https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/superkoalio/SuperKoalio.java

But question is should i have collision tile layer or collision object layer. Object layer seems more fitting. But how will i then check only area around the enitity and not the whole map with a object layer.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
    private void getTiles(int startX, int startY, int endX, int endY, Array<Rectangle> tiles) {
        TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().get("collision");
        rectPool.freeAll(tiles);
        tiles.clear();
        for (int y = startY; y <= endY; y++) {
            for (int x = startX; x <= endX; x++) {
                TiledMapTileLayer.Cell cell = layer.getCell(x, y);
                if (cell != null) {
                    Rectangle rect = rectPool.obtain();
                    rect.set(x, y, 1, 1);
                    tiles.add(rect);
                }
            }
        }
    }
Offline VaTTeRGeR
« Reply #22 - Posted 2018-01-14 16:55:58 »

I don't know how to answer that and i doubt it would help you if i say "use this!" or "use that!".

Is your problem that some objects are stretched across multiple tiles?

Why don't you use a structure different from the tile-map layers if it doesn't work within the constraints of tiles?
Offline KevinWorkman

« JGO Plugged Duke »


Medals: 283
Projects: 12
Exp: 12 years


HappyCoding.io - Coding Tutorials!


« Reply #23 - Posted 2018-01-14 17:13:01 »

i doubt it would help you if i say "use this!" or "use that!".

Exactly. The only right answer to these types of questions is to try it out yourself and see which one works best for you and your game. There isn't a one-size-fits-all solution. It all depends on your preferences and your exact context, which only you know.

Don't be afraid to test stuff out. Write a bunch of smaller example programs that try out different approaches. Do some profiling if that's what you're worried about. Otherwise just do whatever fits in your head the best.

HappyCoding.io - Coding Tutorials!
Happy Coding forum - Come say hello!
Offline printer

Junior Devvie


Medals: 1



« Reply #24 - Posted 2018-01-14 17:34:13 »

I agree with you guys, honestly i'm not worried about perfomence since i going to split the world map into several different parts. I think object layer makes it perfect and also be able to fetch properties from it.
Offline printer

Junior Devvie


Medals: 1



« Reply #25 - Posted 2018-01-16 14:39:10 »

While we are talking about this. Is it even possible to have a huge tmx map. Or do i need to break it down into smaller files? Since i remember i tried once and the game got out of memory. Is it possible to store the map inside a quadtree or something?
Offline KevinWorkman

« JGO Plugged Duke »


Medals: 283
Projects: 12
Exp: 12 years


HappyCoding.io - Coding Tutorials!


« Reply #26 - Posted 2018-01-17 03:50:59 »

Why would you want to store the map in a quadtree? Why would you need to test for collision between map tiles?

Yes it's possible to have a huge map. But it might not be possible to have the whole thing in memory at one time.

Again, the answer is to try it out and see what works for you.

HappyCoding.io - Coding Tutorials!
Happy Coding forum - Come say hello!
Offline printer

Junior Devvie


Medals: 1



« Reply #27 - Posted 2018-01-17 15:57:22 »

You're right, thanks for sticking up to me and answer all my questions Smiley
Offline printer

Junior Devvie


Medals: 1



« Reply #28 - Posted 2018-01-20 18:14:16 »

I actually found solution for frame drop, since i looped through the quadtree on everyframe and cleared the tree. Caused that fps drop. Now it works great, but problem is some monsters and flickering. Like they are getting removed and readded, even tho they are inside my screen and that should not happen:

Here is my main loop:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
package com.game.rpg;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.MapObjects;
import com.badlogic.gdx.maps.MapProperties;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapRenderer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.game.rpg.Entities.Creature;
import com.game.rpg.Entities.Monster;
import com.game.rpg.Entities.Object;
import com.game.rpg.Entities.Player;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class World {
    private Main game;

    private OrthographicCamera camera;

    private final int EVENT_CREATURE_THINK_INTERVAL = 1000;

    private TiledMap map;
    private TiledMapRenderer mapRenderer;

    // QuadTree Creatures
    private QuadTreeNode quadTree;
    private Array<Creature> blockArray;
    private Array<Creature> entitiesToCheck;

    private Player player;

    private int worldWidth = 0;
    private int worldHeight = 0;

    public World(Main game, OrthographicCamera camera) {
        this.game = game;
        this.camera = camera;

        player = new Player("Player", new Vector2(0, 0), game.asset.getAtlas().findRegion("player"), this);

        // Loading map
        loadWorld("world");

        MapProperties mapProperties = map.getProperties();
        worldWidth = mapProperties.get("width", Integer.class);
        worldHeight = mapProperties.get("height", Integer.class);

        // Set up the quad tree
        quadTree = new QuadTreeNode(0, new Rectangle(0, 0, worldWidth, worldHeight));
        entitiesToCheck = new Array<Creature>(true, QuadTreeNode.MAX_CREATURES);
    }

    private void loadWorld(String mapName) {
        map = game.asset.getAssetManager().get("map/" + mapName + ".tmx");
        mapRenderer = new OrthogonalTiledMapRenderer(map, game.UNIT_SCALE, game.batch);

        blockArray = new Array<Creature>(true, entityCount);
        blockArray.add(player);

        loadMonsters();
        checkCreatures();
    }

    private void loadMonsters() {
        int counter = 200000;
        while (counter > 0) {
            blockArray.add(new Monster("Dragon", new Vector2(0, 3 + counter + counter), game.asset.getAtlas().findRegion("bat"), this));
            counter--;
        }
    }

    public void update(float deltaTime) {
        game.batch.setShader(null);
        mapRenderer.setView(camera);
        mapRenderer.render();

        game.batch.setProjectionMatrix(camera.combined);
        camera.position.set(player.getPosition().x + (player.getWidth() / 2), player.getPosition().y + (player.getHeight() / 2), 0);
        camera.update();
    }

    public void render(float deltaTime) {
        game.batch.begin();
        renderCreatures(deltaTime);
        game.batch.end();
    }

    private void renderCreatures(float deltaTime) {
        entitiesToCheck.clear();

        // Retrieve the entities we might be able to compare against
        quadTree.retrieve(entitiesToCheck, player);

        for (Creature creature : entitiesToCheck) {
            creature.onWalk(deltaTime);
            game.batch.draw(creature.getTexture(), creature.getPosition().x, creature.getPosition().y, creature.getWidth(), creature.getHeight());
        }
    }

    private void checkCreatures() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                updateEntities();
                for (int i = 0; i < entitiesToCheck.size; i++) {
                    Creature creature = entitiesToCheck.get(i);
                    //creature.onThink(EVENT_CREATURE_THINK_INTERVAL);
                }
            }
        }, 1000, 1000);
    }

    private void updateEntities() {
        // Clear out the quadtree
        quadTree.clear();

        for (int i = 0; i < blockArray.size; i++) {
            // Fetch the current block
            Creature creature = blockArray.get(i);

            // Update objects based on player can see creature, insert them into the quad tree
            if (player.canSee(creature.getPosition())) {
                quadTree.insert(creature);

                if (!creature.isObject())
                    creature.setIdle(false);
            } else {
                creature.setIdle(true);
            }
        }
    }

    public Player getPlayer() {
        return player;
    }

    public void dispose() {
    }
}


I'm using this quadtree:
https://github.com/murgo/libgdx-quadtree/blob/master/core/src/com/innerlogic/quadtreedemo/collision/QuadTreeNode.java

How can i solve the issue, since i try to update the quadtree once a second, but it causing the flickering issue.
Offline VaTTeRGeR
« Reply #29 - Posted 2018-01-20 22:51:08 »

Here's your problem:
1  
new Timer().scheduleAtFixedRate(...


Using an asynchronous timer f**ks around with the rest of your game logic. Do you know when this is getting executed? Yeeea...nope... The timer might call this function at any time and then it modifies the quad-tree, etc. Maybe even while you are rendering or fetching objects from the tree.

Also, do you really think this will actually remove lag? If updating every frame causes stutter, so will updating every 20 frames. It will just be "lag every second" vs "lag every frame", it's still not fixed, just reduced. If you want to remove lag, you must split the work between frames or between threads.
Pages: [1] 2
  ignore  |  Print  
 
 

 
EgonOlsen (543 views)
2018-06-10 19:43:48

EgonOlsen (647 views)
2018-06-10 19:43:44

EgonOlsen (444 views)
2018-06-10 19:43:20

DesertCoockie (789 views)
2018-05-13 18:23:11

nelsongames (1023 views)
2018-04-24 18:15:36

nelsongames (1057 views)
2018-04-24 18:14:32

ivj94 (1636 views)
2018-03-24 14:47:39

ivj94 (561 views)
2018-03-24 14:46:31

ivj94 (1442 views)
2018-03-24 14:43:53

Solater (566 views)
2018-03-17 05:04:08
Java Gaming Resources
by philfrei
2017-12-05 19:38:37

Java Gaming Resources
by philfrei
2017-12-05 19:37:39

Java Gaming Resources
by philfrei
2017-12-05 19:36:10

Java Gaming Resources
by philfrei
2017-12-05 19:33:10

List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05
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!