Making game less laggy

I am working on a simple game (I’m a beginner) in which the player jumps up platforms. Currently, there is only one screen and a level creator. The way it works right now, I mean only the basics of creating levels, is in a grid you select certain boxes, in which an object called platformerBoxes is placed. The position is then saved in an array in a .txt file once the changes have been saved. There are no hitboxes or players or anything yet. However, the game is very laggy right now. The grid is 34 * 20, and with only 50 boxes the game lags at 1920 x 1080. Are there any systematic changes I should make? Is there a better approach on a theoretical level? Thanks

1 Like

It would help to see code

In suspicion is that you save the txt throughout and not only once

1 Like

Maybe my wording was a bit misleading. Only if you enter the level creator and save configs, does it get saved. The data from the text file gets loaded in setup(), and you can go directly to the game without editing the level, so unless I’m mistaken the data technically should only load once. My code is spread out over multiple tabs, however I could send the whole thing as a .rar. Could the issue just be too many objects on screen?

In theory yes. How much are there?

Also important: load images only once in setup (). Use resize() for images only in setup. Use the command image() only with 3 parameters, not 5 parameters (otherwise he is doing a resize every time prior to posting the image).

You mentioned a grid. When your grid encompasses the whole screen and each cell is small, this would take time. It would be faster to have a background image and have a list of platforms with its length. Much faster I guess.

Chrisir


This is how the game looks in level creator. The grid is just lines, and whenever your mouse is within two lines using modulo a box object is placed. The res. is 1920 * 1080, and currently everything in it (like moving an ellipse on the mouse position) runs at <10 frames. On the actual game screen however, the boxes are still there but without the grid. I guess it could be too many objects being constantly refreshed (in an enhanced for loop out of an arrayList), but I need it for hitboxes later on.

1 Like

Instead of looping the entire grid you could make a list of the indexes of the cell’s grid that are not black and only loop over them

Maybe I’m misunderstanding, but the black boxes aren’t objects. They are just the space between the lines, and the red/blue boxes are objects in an array list.

Edit: The coordinates of each box are saved in an array, which is then stored in a text file - this list gets loaded in setup() and modified in the editing stage, but in the final (very laggy) screen, there’s still lag even though the array as well as text file stay the same.

1 Like

Do you use a nested for loop to loop over all cells in the grid?

I draw the grid with a nested for loop and then determine which square the mouse is in via modulo, and if the mouse clicked an object is added to an arrayList and “spawned” there - in the game state, the grid is no longer being drawn. I will narrow down my code and post it here later so you see what I’m doing. Thanks for the help so far and if you have any ideas to clean up my code I would greatly appreciate it!

//simple version of code without tabs

//to make new level, delete boxes.txt and put null in the first line

float[] xC = new float[35];       //has all x line coordinates
float[] xY = new float[20];       //has all y line coordinates
ArrayList<platformerBoxes> boxes;     //stores boxes
boolean hitBoxes, gameState, removeOne = true;
int boxPlaceDelay = millis();      //delay between placing boxes so you dont place 10 a second
int time1 = millis();
int counter = 0;
String[] boxsaver = new String[1400];   //saves positions of placed boxes in array
int mov = 0; 
String[] noteLines;        //reads box coordinates from .txt
boolean nextGameState;
boolean editorState;
int platformerStateSwitcher;

void setup() {
  size(1920, 1080);
  //platformer
  boxes = new ArrayList<platformerBoxes>();    
  noteLines = loadStrings("boxes.txt");          //loads Box coordinates
}

void draw() {
  background(0);
  switch(platformerStateSwitcher) {
  default:
    drawPlatBoxes();
    break;

  case 1:
    platLevelEditor();
    break;

  case 2:
    platformerGameState();
    break;
  }
}


void drawPlatBoxes() {
  for (int row = 1; row != noteLines.length && row < boxsaver.length && noteLines[row] != null; row++) {      //saves the read text file to box array so it can be placed, stops if the text files starts reading null
    boxsaver[row] = noteLines[row];
  }

  rectMode(CORNER);
  for (int d = 1; d < noteLines.length - 1 && d < boxsaver.length - 1; d++) {
    boxes.add(new platformerBoxes(int(boxsaver[d]), int(boxsaver[d + 1])));    //creates objects
    d++;                                                                  //makes sure rectangles dont reuse coordinated
  }
  for (int l = boxes.size() - 1; l > 0; l--) {      //Shows objects
    platformerBoxes gg = boxes.get(l);
    gg.show();
  }

  //Lines
  platformerGrid();     //grid drawn
  textSize(20);
  fill(255, 255, 0);
  textAlign(CORNER);
  text("Press K to create new level design (It will overwrite current if saved!)", 60, 40);
  text("Press T to Start Game (not implemented fully!)", 60, 80);


  if (key == 'k') {
    platformerStateSwitcher = 1;
  }
  if (key == 't') {
    platformerStateSwitcher = 2;
  }
}


void platLevelEditor() {
  //mouse Collisions
  for (int i = 1; i < 35; i++) {             
    xC[i] = float(width)/float(34) * i;     
    for (int ii = 1; ii < 20; ii++) {
      xY[ii] = height/20 * ii;
      if (mouseY%xY[ii] < height/20 && xY[ii] >= mouseY * 0.5 && mouseX%xC[i] < width/34 && xC[i] > mouseX / 1.5) {   //modulo for getting coodinates that are withing a square range and then making sure it cant      
        fill(0, 255, 0);                                                                                              //apply to more than one (only ones really close to mouseX basically)
        rect(xC[i], xY[ii], float(width)/float(34), height/20);                                                                    


        //Place Boxes
        if (mousePressed && mouseButton == LEFT && millis() > boxPlaceDelay + 50) {                
          boxes.add(new platformerBoxes(int(xC[i]), int(xY[ii])));    
          mov++;
          boxsaver[mov] = str(xC[i]);       //adjusts array so it can be saved
          mov++;
          boxsaver[mov] = str(xY[ii]);
          boxPlaceDelay = millis();
        }

        //show placed Boxes
        for (int l = boxes.size() - 1; l > 0; l--) {
          platformerBoxes gg = boxes.get(l);
          gg.show();

          //Delete Boxes
          if (mousePressed && mouseButton == RIGHT && removeOne) {          //Deleted last boxes placed
            boxes.remove(boxes.size() - 1);
            mov--;
            boxsaver[mov] = str(0);   //Adjust array numbers so they dont still get saved
            mov--;
            boxsaver[mov] = str(0);
            removeOne = false;       //timer, so that not all boxes get instantly removed
            time1 = millis();
          }
        }
        if (keyPressed && key == 't') {        //saves configs, but only if the text file has been reset with "null" in line 1
          saveStrings("boxes.txt", boxsaver);
          platformerStateSwitcher = 2;
        }
        if (!removeOne && millis() > time1 + 100) {
          removeOne = true;
        }
      }
    }
  }
  //Lines
  platformerGrid();

  fill(255, 255, 0);
  text("Press Left Click to place Block", 60, 40);
  text("Press Right Click to remove last block", 60, 80);
  text("To save changes, delete boxes.txt, make a new version of it and put 'null' in the first line and save", 60, 130);
  text("Press T to save changes", 60, 170);
} 

void platformerGameState() {
  for (platformerBoxes gg : boxes) {
    gg.show();
  }
  fill(255);
  ellipse(mouseX, mouseY, 40, 40);
}

void platformerGrid() {           //draws lines
  stroke(255);
  for (int i = 0; i < 35; i++) {
    xC[i] = float(width)/float(34) * i;
    for (int ii = 0; ii < 20; ii++) {
      xY[ii] = height/20 * ii;
      line(xC[i], 0, xC[i], height);
      line(0, xY[ii], width, xY[ii]);
    }
  }
}






//class
class platformerBoxes {
  PVector location;
  PVector velocity;


  platformerBoxes(int _x, int _y) {
    location = new PVector(_x, _y);
    velocity = new PVector();
  }

  void shifting() {
    location.add(velocity);
  }

  void show() {
    //  println("buffering");
    noStroke();
    if (location.x > width/2) {
      fill(255, 0, 0);
    } else {
      fill(0, 0, 255);
    }
    rectMode(CORNER);
    hitboxes();
    rect(location.x, location.y, width/34, height/20);
  }

  void hitboxes() {
    for (platformerBoxes g : boxes) {
      if (mouseX > location.x && mouseX < location.x + width/34 && mouseY > location.y && mouseY < location.y + height/20) {
        hitBoxes= true;
      }
    }
  }
}
1 Like

in switch I wouldn’t use default as a regular statement.

Better say case 0: and use default: when platformerStateSwitcher has a wrong value.

default: 
// Error
println("Error "+ platformerStateSwitcher); 
break;

So your question is not concerning the editor but the speed in the actual game, right?
This is this function platformerGameState(), right?
This looks ok. How many boxes are there?

Thanks for the tip. Yes, I am concerned about the speed. The amount of boxes can go up to 700, if every square on the grid was filled, but currently there’s maybe 60 boxes, some red some blue. The lag is really visible since I made an ellipse on mouseX and mouseY, and theres a clear delay in its movement, when gameState() is running or in platLevelEditor() when the boxes are loaded in… Is there a possibility that because I used vectors for the location, it takes more resources to update in comparison to just using an x and y variable?

when you look at show() in your class you will find a call to hitboxes() which checks ALL boxes.
That’s not good because for each box you check ALL boxes. Remove the call of hitboxes() from show() and insted call hitboxes() from function platformerGameState() !!!


You can calculate and store these values: width/34, height/20 in the constructor of the class (store them as sizeX, sizeY).

And then:

rect(location.x, location.y, sizeX, sizeY);

Chrisir

Saves a little time maybe

2 Likes

No, I don’t think so

1 Like

Yes, thank you so much! The sizeX and sizeY helped a bit, but the hitboxes thing is great! Is it because I was essentially looping through all boxes twice, once in gameState() to show them and again in the class?

It was not only 2x every box but n*n every box because in show() (called from for loop over all boxes) you called hitboxes() with a for-loop over all boxes…

1 Like