0

I'm working on a 2D sidescrolling game in Java. All of the blocks and enemies rendered are 32x32px. When I try to make too big levels, the game won't be able to handle them, which will make it lag extremely much. So what I'm trying to do to fix this problem is to make only the blocks visible by the camera render, and only the blocks visible by camera + 200-300px run their tick methods. That would probably make the game lag less.

The code:

All of the typed of objects have an own class which extends a class called GameObject, which gives them all of the methods they need (tick method, render, collision etc). In a class called Handler, GameObject is made into a LinkedList, like this:

public LinkedList<GameObject> object = new LinkedList<GameObject>();

Everything inside that LinkedList is runned like this...

public void tick()
    for(int i = 0; i < object.size(); i++){
             GameObject tempObject = object.get(i);

             tempObject.tick(object);    

             if(tempObject.getId() == ID.MovingBlock){
                 velX_MB = tempObject.velX;
                 velY_MB = tempObject.velY;
             }
         }
}

...and rendered like this:

public void render(Graphics g){
     for(int i = 0; i < object.size(); i++){
         GameObject tempObject = object.get(i);

         tempObject.render(g); 
     }
 }

I've tried rendering only the blocks inside the camera by doing something like this:

private GameObject player;

    for(int i = 0; i < object.size(); i++){   //searching through GameObject LinkedList 
             if(object.get(i).getId() == ID.Player){ //if found player
                 player = object.get(i);
             }        
         }

After that, I checked if the blocks were close enough to the player to be rendered inside the render method, and if they were, I rendered them, like this:

public void render(Graphics g){

     for(int i = 0; i < object.size(); i++){
         GameObject tempObject = object.get(i);

         if(tempObject.getX() <= player.getX() + Game.xsize + 200 && tempObject.getX() >= player.getX() - Game.xsize - 200){ //this row got error
            tempObject.render(g);  
         }

     }
 }

But this didn't work, it gave me a NullPointerException error, pointing to the row marked in the previously shown code. The full error message:

Exception in thread "Thread-12" java.lang.NullPointerException
at game.main.Handler.render(Handler.java:53)
at game.main.Game.render(Game.java:363)
at game.main.Game.run(Game.java:302)
at java.lang.Thread.run(Unknown Source)

And that was only the render method, but I guess it would be the same when running them instead.

Thank you for taking your time..

EDIT: I fixed the null error and added my old method in both tick() and render(), but it's still lagging extremely much.

ILikeJava
  • 29
  • 6
  • Incidental note: `object.get(i)` in a `LinkedList` is a superexpensive operation. If you're going to iterate on a `LinkedList`, use its own iterator. Never ever do `for(int i = 0; i < object.size(); i++) tempObject = object.get(i);` See [java - iterating a linked list](https://stackoverflow.com/questions/4767615/java-iterating-a-linked-list) – Amadan Aug 13 '18 at 06:05
  • Is this better? `Iterator Iterator = object.iterator(); while (Iterator.hasNext()) { //I have no idea how to write this part }` – ILikeJava Aug 13 '18 at 06:18
  • Indubitably better. (Note that there is a newer syntactic sugar for it - "enhanced for loop" - that is easier on the eyes: `for (GameObject gameObject : objectList)`, but from Java's perspective it doesn't really matter if you use `Iterator` directly or indirectly, same thing happens.) – Amadan Aug 13 '18 at 06:18
  • If you really want to use the explicit iterator, `Iterator objectListIterator = objectList.iterator(); while (objectListIterator.hasNext()) { GameObject gameObject = objectListIterator.next(); ... }` – Amadan Aug 13 '18 at 06:21
  • Thank you, I'll fix that! I guess it won't stop the lag completely, but at least reduce it... – ILikeJava Aug 13 '18 at 06:23
  • I'm also subtly letting you know that giving your `LinkedList` the name `object` ensures you will get lost in your code a month from now. :P Proper naming of things is one of the hardest things in programming, but well worth the time. (Now I changed my mind and wish I'd've written `gameObjects` as the list name. Such is life.) – Amadan Aug 13 '18 at 06:24
  • Also, precalculate everything that you can. I doubt that during your game's lifecycle you have several different game objects that are your player; so searching for the player each tick is inefficient; just keep `GameObject player` as a property of the game or something, so you don't need to search it each time. Similarly, your player's coordinates probably don't change during the tick (except possibly on player object's tick, but even so you probably don't want to evaluate first half of game objects on the former position and second half on next); so do `x = player.getX()` before the loop. – Amadan Aug 13 '18 at 06:29
  • This question is not a duplicate of 218384 @OP: You probably compared Integer/String IDs with "==". Your player is returned null. Try to compare with .equals(...). Would like to give a more elaborate answer, but this box is limited. – TreffnonX Aug 13 '18 at 06:44
  • 1
    @TreffnonX The OP needs to pin down exactly what is null in that line first. The linked duplicate is appropriate for that. When they do that, if they still have a question as to why that thing is null, they can then edit to provide a [mcve] that demonstrates the issue. Until then, it's just a guess as to what the specific issue is. – Mike M. Aug 13 '18 at 06:53
  • @MikeM. While true that the question could be more precise, if the null pointer had been followed further, it is sufficiently accurate to be answered. Only the "player" object can be null at this point, and the reason for this must be a "=="-comparison further up the code. Sure, the question could be more focused, if OP had more experience, but this platform is not just for professionals, is it :)? – TreffnonX Aug 13 '18 at 06:59
  • @TreffnonX I disagree that it's "sufficiently accurate to be answered". I'm not sure how you're coming to the conclusion that only `player` can be null there, but that's really not true. `Game` is nowhere declared or assigned in the given code, any of those getters could be returning a null value, etc. Anyway, it's a moot point now, as the OP has apparently solved their NPE. – Mike M. Aug 13 '18 at 07:14
  • Sorry for being unclear, it's the player which is null, but I've fixed that problem. Unfortunately, the game still lags, which should mean my rendering-a-part method isn't correct made. But I wouldn't see this as a dublicated question. – ILikeJava Aug 13 '18 at 07:17
  • @MikeM. You are right that it's mute, but you are incorrect in that any object can return null. NullPointers are only thrown on nullary access, not on passing null as argument. The strack trace clearly shows the line as being the one highlighted, so it needed to be an access in that line. Game is a Class, not an object, so it cannot be null. It it could not be resolved, he'd received a different error. and tempObject can't be null because then the null pointer would have been thrown earlier. It had to be "player" and OP confirmend this. – TreffnonX Aug 13 '18 at 07:55
  • @ILikeJava You need to work a lot on your code. You access your Lists in very inefficient ways, which is probably the reason your game runs slow. – TreffnonX Aug 13 '18 at 07:57
  • @TreffnonX I don't know what you mean by "passing null as argument", as there are no method arguments on that line, and I certainly didn't refer to any. Also, we don't know for sure that the getters are returning primitives – and I'm not just talking about `tempObject` – so a null from any of those would've thrown an NPE. Furthermore, you're assuming that `Game` is the `game.main.Game` class there. That's why I pointed out that it's not really specified anywhere in the given code, so we can't be sure what it is. Anyway, I wasn't saying that you were wrong; only that you couldn't be certain. – Mike M. Aug 13 '18 at 08:18
  • @TreffnonX @Amadan I changed my way to access lists to an Enchanced for loop, but when I clear levels and add new objects and all that stuff, I get `java.util.ConcurrentModificationException` error. Is there any way to avoid this? – ILikeJava Aug 14 '18 at 14:23
  • ConcurrentModificationExceptions are thrown, if a Collection is modified, while being iterated over. This is a common beginner's mistake. You should really consider not modifying your collections that often. Try to either work with arrays, or pick a more viable data structure for your objective. I personally would use a matrix-array (MapObject[][] = ...) and then you can access the MapObjects directly, depending on the coordinates you want to render. This is, however not perfect either, but it is a lot faster than the list approach. – TreffnonX Aug 14 '18 at 15:03

0 Answers0