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
It would help to see code
In suspicion is that you save the txt throughout and not only once
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.
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.
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;
}
}
}
}
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
No, I don’t think so
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…