i have several scenes thore are canvas clases, 1 canvas per level, the first screen ( or scene ) its loaded and i have no problem, the canvas level class accepts an instance of a JFrame, to remove al components and after that, stop the main level, instanciate the new one and add it, but i have an error, and i do know what to do, and besides im not sure im doing the correct thing,
can someone tell me how can i make to swap between levels?
the canvas is the room or the entire screen ( or level, wheatever ),
canvas has:
player
enemies
gameloop
update and render method
keyboardListener
so that class ( Canvas ) is the entire screen, i would like to change levels removing the actual canvas and creating a new canvas, with new background, initialice players and enemies, again and start the gameloop,but now im looking for a new way to make it, i mean, i need the best aproach to change between levels…
You want to separate your game logic from rendering. The game loop should not be tightly bound to a canvas, neither should your list of entities. Refactor your code so that you could theoretically change your rendering backend without having to modify your game logic, or that you could change your list of entities without needing to change the canvas.
Create a Canvas object. It’s up to you if you want to put your Gameloop in the same class or not, but to make things easier let’s assume you do.
Next up is creating the render and update method in your canvas object (and again, for the sake of ease I’ll put these in the Canvas object). Now when you want to render for example a set of squares that is part of your level, you can create a Level object that contains the data for that set of squares. Each time you want to draw this specific level you can call the render method within that level, which renders all the squares you need.
This way you’ll end up with something like this:
public class Game extends Canvas implements Runnable {
private boolean running;
private Thread mainThread;
// your current level that contains all the level data you want to render:
private Level currentLevel;
public Game() { }
public void start() {
if (running)
return;
mainThread = new Thread(this);
mainThread.start();
}
public void stop() {
if (!running)
return;
try {
mainThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
// example gameloop. DO NOT USE!
while (running) {
update(0);
render();
}
}
public void update(int delta) {
// update logic here.
level.update(delta);
}
public void render() {
BufferStrategy bfs = getBufferStrategy();
if (bfs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bfs.getDrawGraphics();
g.clear();
currentLevel.render(g);
g.dispose();
bfs.show();
}
}
public class Level {
private List<Rectangle> squaresToDraw;
public Level(int width, int height) {
for (int i = 0; i < 10; i++) {
squaresToDraw.add(new Rectangle(i * 10, i * 10, 10, 10));
}
}
public void update(int delta) {
// update stuff.
}
public void render(Graphics g) {
for (int i = 0; i < squaresToDraw.size(); i++) {
g.fillRectangle(squaresToDraw.get(i));
}
}
}
//render lvl 1
// render player
// render enemies of lvl 1
break;
case 2:
//render lvl 2
// render player
// render enemies of lvl 2
break;
.
.
.
//more lvls
}//
then when i want to change lvl i need to set to null my “enemy pool” and instanciate again the enemies for new lvl, and make the same for the update method, i mean, check colisions with the new enemies and the player, its that so?
You might not want to do that. Assume you have 250 levels. That would mean that you get a massive switch statement. Let’s say you have 3 things to do (render level, render player, render entities) for every level. You’d get 750 lines of code (minimum) to run through. It would be very inconvenient to do so.
A better way of doing it would be making an abstract class for a Level, in which you define the basic methods and fields for a level. Then you make a class which inherits Level, and you fill that in with specific details for your actual level. That’s the level you render in the gameloop defined above.
It would look something like this:
public abstract class Level {
protected int x, y;
protected int width, height;
protected List<Tile> tiles;
public Level(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void initialize() {
tiles = new ArrayList<Tile>();
}
public void update(int delta) {
// update stuff here.
}
public void render(Graphics g) {
g.fillRect(x, y, width, height);
}
}
public class SpawnLevel extends Level {
private int uniqueX, uniqueY;
private int uniqueWidth, uniqueHeight;
public SpawnLevel(int x, int y, int width, int height) {
super(x, y, width, height);
}
// Let's assume the render method of SpawnLevel does something special, we can override the
// render method from the super class and add some unique rendering stuff to it.
public void render(Graphics g) {
super.render(g);
g.fillRect(uniqueX, uniqueY, uniqueWidth, uniqueHeight);
}
}
You might want to look into design patterns. Here’s a good book on it:
you are right, thats will become troublesome in the near future,
i think i understand your code, a leve with all his logic inside is own functions, i only need to call those functions in the methods of the container class, in this case the screen
so, to clarify:
screen extends canvas{
.
.
.
public void render(Graphics g)
{
currentLevel.render(g);
}//