[Slick2D] Why the F is it so slow? [SOLVED]

I am recreating my previous project https://github.com/GNecro1/TROTMGRO, it was java2D no libs nothing, pure java. Now i am using Slick2D and it is crap. In Java2D i was creating a world 128x128 tiles(300+ FPS), now i am creating (in Slick2D) a world 32x32 tiles (9 FPS). So wtf is wrong?
How I do the rendering:


 // Only 1 chunk, rendering
public void render(GameContainer c, StateBasedGame game, Graphics g) throws SlickException {
	for (int i = 0; i < tile.length; i++) {
		for (int j = 0; j < tile[0].length; j++) {
			tile[i][j].render(c, game, g);
		}
	}
}
// tile rendering

public void render(GameContainer c, StateBasedGame game, Graphics g) throws SlickException {
	img.draw(x, y,2);
}


And how i did it in Java2D :


// world
public void render(Graphics2D g) {
	for (int i = 0; i < tiles.length; i++) {
		for (int j = 0; j < tiles[0].length; j++) {
			tiles[i][j].render(g);
		}
	}
}
//tile

public void render(Graphics2D g) {
	g.drawImage(RL.grass, x, y, width, height, null);
}


So anyone care to explain?

Slick is an outdated library, however that is not the issue here.

Are you positive it is this block of code that is the problem and not something else ? Try cutting the tile count right down or even just draw one to see if it is still slow.

I did i draw one tile and it still slows down… when i dont draw tiles the FPS goes to 60 (target FPS 60) and when i draw one it goes to 57 FPS

Maybe you are reading images from disk every time you draw?

Retro Pixel Castles is written with Slick2D I believe and it seems to work pretty nicely :stuck_out_tongue:

Nope that is not the problem i checked that first when i saw the FPS.

You need to post more of your slick code, not enough to isolate the problem from the above snippet.

Here you go the whole project https://www.mediafire.com/?9h7o6mmy97919di

I suspect you’re not using the start() end() of the tileset use, if you don’t then every time you use an image it’ll start a new geometry underneath which will be very costly.

Cheers,

Kev

When i use start() and end() my game brakes… ? It does not show the player (Animation) and it only shows some of the sprites…

You’d need to render the tiles in one block, then render the players in a separate block. If you want to swap to a different sprite set (say the player) mid tile render you’d need to end() and start() around it. However, this would break the efficiency of the OpenGL rendering under neath.

There used to be a bunch of samples showing how tile rendering would work, are they not there any more?

Cheers,

Kev

I dont think so…

I don’t know much about slick but I’m pretty sure it’s more efficient when you batch the renders

^ no doubt this. RPC would scream if I tried to render my tile map without using .start(), .end() and .drawEmbedded().

Assuming all your tiles are on a single sprite sheet, you can simply just do this:


public void render(GameContainer c, StateBasedGame game, Graphics g) throws SlickException {
   referenceToYourTileSpriteSheet.startUse();
   for (int i = 0; i < tile.length; i++) {
      for (int j = 0; j < tile[0].length; j++) {
         tile[i][j].render(c, game, g);
      }
   }
   referenceToYourTileSpriteSheet.endUse();
}


public void render(GameContainer c, StateBasedGame game, Graphics g) throws SlickException {
   img.drawEmbedded(x, y);
}

Slick is actually quite fast when you use it correctly, Retro-Pixel Castles renders about 36,000 tiles and 1,000 entities on screen all at once (including lighting and particles) at 60FPS, and like trollwarrior1 said, it uses slick. :stuck_out_tongue:

EDIT: Goofed on the render code, all fixed now.

Thx it runs very fast! <3

Good rule with slick I’ve learned, use sprite sheets whenever possible, and try your best to render everything on that sheet you use all at once if you can. For example, render your entire map with startUse() endUse() and drawEmbedded(), then render your entities on top of that, then the shadows/lighting/particles/whatever else using the same start/end/drawEmbedded combo. But try to keep each batch of things you want to render on a single sprite sheet. There’s fancier ways to do it even faster, but there’s a point where optimizing is just going to get silly. Unless you’re trying to push LWJGL and Slick’s limits you should be fine just grouping sprite sheets together and rendering everything related to them all in one go.

Another future optimization you’ll want to look at is render culling, I don’t know if you plan on having a movable map that’s larger than the screen, but in your current code you’re rendering the entire map, even if it’s off screen. You can get a huge performance boost on larger maps if you limit rendering to only what is actually visible to the player.

Yea i am doing that, one more problem i am using only one spritesheet for everything and how do i draw animation it only has draw? And when i draw it it goes to the 0,0 no matter what!

I solved it, i just get the image from the animation. YAy

@kevglass: just throwing it out there: if the slow path is too slow for basically anything (OP said: 32*32 tiles @ 9fps), then why expose this slow path to developers? Why not throw a YoureDoingItWrongException instead?

I know Slick2D is no longer supported by you, so it’s more of a question regarding why you made this decision a long time ago. :slight_smile: (when the slow path ran on ‘worse’ hardware, too)

While I can’t really speak for Kev obviously, I think it’s for simplicity’s sake. Any time you need to draw just one single image (Like a logo, or a single GUI button) you can just use .draw() and skip having to have startUse() and endUse() in your methods since they’re already inside the Image.draw() method.

For me, .draw() is used for larger images or places where optimizing would be totally pointless. My main menu’s GUI is all using .draw() for example, since there’s only actually 3 or 4 images total on the screen and all of them are on different sprite sheets (or single images) anyway. But things like entities, tiles, particles, shadows, etc, I use drawEmbedded().

There are also cases where you’re overlapping elements, like say drawing geometry, rendering an image, rendering some font, then some more geometry, and you just can’t use drawEmbedded easily.

If Slick was still supported, my advice would be to somehow notify people that .draw is the less efficient way of doing it, but I’m not sure how other than renaming it to drawOnlyOne() or something awkward.

If you don’t mind editing Slick itself, you can add drawEmbedded() support to Animation, it’s actually not that complicated. Honestly it’s just a ripoff of the regular draw() code, it just runs drawEmbedded when it’s all said and done.

Add this below line 380:

	/**
	 * Draw the animation to the screen without startUse() and endUse().
	 */
	public void drawEmbedded() {
		drawEmbedded(0,0);
	}

	/**
	 * Draw the animation at a specific location without startUse() and endUse().
	 * 
	 * @param x The x position to draw the animation at
	 * @param y The y position to draw the animation at
	 */
	public void drawEmbedded(float x,float y) {
		drawEmbedded(x,y,getWidth(),getHeight());
	}

	/**
	 * Draw the animation at a specific location without startUse() and endUse().
	 * 
	 * @param x The x position to draw the animation at
	 * @param y The y position to draw the animation at
	 * @param filter The filter to apply
	 */
	public void drawEmbedded(float x,float y, Color filter) {
		drawEmbedded(x,y,getWidth(),getHeight(), filter);
	}
	
	/**
	 * Draw the animation without startUse() and endUse().
	 * 
	 * @param x The x position to draw the animation at
	 * @param y The y position to draw the animation at
	 * @param width The width to draw the animation at
	 * @param height The height to draw the animation at
	 */
	public void drawEmbedded(float x,float y,float width,float height) {
		drawEmbedded(x,y,width,height,Color.white);
	}
	
	/**
	 * Draw the animation without startUse() and endUse().
	 * 
	 * @param x The x position to draw the animation at
	 * @param y The y position to draw the animation at
	 * @param width The width to draw the animation at
	 * @param height The height to draw the animation at
	 * @param col The colour filter to use
	 */
	public void drawEmbedded(float x,float y,float width, float height, Color col) {
		if (frames.size() == 0) {
			return;
		}
		
		if (autoUpdate) {
			long now = getTime();
			long delta = now - lastUpdate;
			if (firstUpdate) {
				delta = 0;
				firstUpdate = false;
			}
			lastUpdate = now;
			nextFrame(delta);
		}
		
		Frame frame = (Frame) frames.get(currentFrame);
		frame.image.drawEmbedded(x,y,x+width,y+height,0,0,width,height,col);
	}