Java Slick: Adding to subclasses of StateBasedGame and scaling up the display...

Just getting properly started with game development in Java with Slick, after a few small games with C++ and working with Java a bit in college. It’s going fine so far but a few small things are confusing me…

  1. It seems a class deriving from BasicGameState has to implement certain methods such as:
    public void render( GameContainer arg0, StateBasedGame arg1, Graphics arg2 )throws SlickException

That’s fine, but what if you have something like:

public class PlatformGame extends StateBasedGame
{
public static final int SCREEN_WIDTH = 320;
}

And you’d like to be able to access that variable in the game’s various states?

You have to implement render etc. with StateBasedGame, so then how might I access something particular to my derived class from within the methods of a class deriving from BasicGameState?
I know I COULD cast a StateBasedGame into a PlatformGame, but that seems pretty sloppy, then I dunno.

Maybe I’m missing something obvious here. It’s been a while since I coded properly at all in fact.

  1. The main reason I need to ask question 1 is because I want to make a game in fairly low resolution but then scale it up so that things are actually discernible on the screen.

Right now I’m messing around with 320x200 and scaling it up by 2.

What I want to know is: what is a proper way to do that? Is there a fairly standard way of setting that up in Slick? I have it working in a basic way now but I’m afraid that maybe it may require more careful attention than is necessary.

Right now my PlatformGame class (extending from StateBasedGame) has the following fields:

public static final int WIN_RES_WIDTH = 320;
public static final int WIN_RES_HEIGHT = 200;
public static final float WIN_RES_SCALE = 2.0f;

public static final int WIN_WIDTH = ( int ) ( WIN_RES_WIDTH * WIN_RES_SCALE );
public static final int WIN_HEIGHT = ( int ) ( WIN_RES_HEIGHT * WIN_RES_SCALE );

My main then has:

AppGameContainer app = new AppGameContainer( new PlatformGame() );

app.setDisplayMode( WIN_WIDTH, WIN_HEIGHT, false );

So that sets up a window that’s twice the resolution I want.

Then to actually draw something, I access the resolution scaling value and alter the coordinates appropriately such as in this code I’m using to draw map tiles:

draw( x / TILE_SIZE * TILE_SIZE * PlatformGame.WIN_RES_SCALE,
				y / TILE_SIZE * TILE_SIZE * PlatformGame.WIN_RES_SCALE,
				x / TILE_SIZE * TILE_SIZE * PlatformGame.WIN_RES_SCALE + TILE_SIZE * PlatformGame.WIN_RES_SCALE,
				y / TILE_SIZE * TILE_SIZE * PlatformGame.WIN_RES_SCALE + TILE_SIZE * PlatformGame.WIN_RES_SCALE,
				spriteSheetX * TILE_SIZE,
				spriteSheetY * TILE_SIZE, spriteSheetX * TILE_SIZE + TILE_SIZE,
				spriteSheetY * TILE_SIZE + TILE_SIZE );

The last 3 arguments are what part of the sprite sheet to draw and of course irrelevant here, but you can see the first 4 arguments are a bit of a convoluted mess.

That’s going to cause serious confusion and bugginess down the line if I leave it like that.

So, how should I scale my graphics up? There must be a relatively painless way that keeps the scaling code all in one or very few places. There must be a fairly standard solution I imagine.

  1. Also, I see you can draw images using the Image class’ own draw() method, but also there appears to be a list of identical functions in the Graphics class called drawImage(). What’s the difference between those? Are there situations where you’d need to use one way over the other? Does Image.draw() just use the methods of the AppGameContainer’s Graphics object implicitly?

Firstly, Slick doesn’t use Java2D so this thread should be moved. :wink:

  1. Since the variable is public and static, it would be accessed like so from any other class:
int width = PlatformGame.SCREEN_WIDTH;

For non-static variables, a common technique is to pass your own subclass of StateBasedGame to the GameState constructor (or, better yet, a “GameContext”-type interface that only implements necessary functions) so that states can access “global” resources/settings/etc.

  1. Setting the resolution of AppGameContainer in Slick will change the size of the display window (for windowed mode). Ideally, scaling should be done in the game itself – note that your images will look somewhat blurry if you simply render them at a larger size. You could use GL_NEAREST for filtering (in slick; Image.FILTER_NEAREST), which might be a stylistic choice. You would then decide on a window/app resolution (or let the user decide) and scale to it accordingly.

If you are scaling the entire screen, you might rather utilize the Graphics.scale/pushTransform/popTransform methods so that you don’t need to also scale each sprite individually to the screen resolution.

You can also look into Slick’s ScalableGame (and ScalableTest) for resolution-independent rendering.

  1. Graphics.drawImage will simply call Image.draw method. The only difference is that using the graphics methods ensures that the graphics is “enabled.” This becomes important if you plan to use multiple graphics contexts; i.e. image graphics (offscreen rendering). In general, it’s better to use the Graphics methods unless you are sure that the right graphics context is already “enabled” (by another render call, such as clear, drawRect, setColor, etc). You can be extra sure by doing this before any draw calls with multiple graphics contexts:
//changes graphics context
Graphics newGraphics = image.getGraphics();

//ensures that new graphics context is properly enabled
Graphics.setCurrent(newGraphics);

//since we ensured context is ensured, we don't need to use Graphics.drawImage
myImage.draw(. . .);

//disable the new graphics
newGraphics.flush();

It’s a little tricky – generally users don’t need to worry about this or call setCurrent() themselves. Really the only time I’ve needed to do this is in exceptional cases when calling Font.drawString or Image.drawImage on a new graphics context (i.e. offscreen buffer), or using my own GL calls.

Oh right, crap, sorry. I misinterpreted the forum description as being for 2D Java graphics programming in general. Oops :stuck_out_tongue:

I see… that kinda makes sense.

Cool… it seems to be working nicely now.

Provided I haven’t done anything that might be problematic for some reason…

I can scale everything properly just by changing a single float and the map tiles (which is about all I’m rendering ATM) don’t know anything about the scaling but all seem to scale and line up properly. Yay.

Right now my PlatformGame class has:


public static final int WIN_RES_WIDTH = 320;
public static final int WIN_RES_HEIGHT = 200;
public static final float WIN_RES_SCALE = 2.0f;
	
public static final int WIN_WIDTH = ( int ) ( WIN_RES_WIDTH * WIN_RES_SCALE );
public static final int WIN_HEIGHT = ( int ) ( WIN_RES_HEIGHT * WIN_RES_SCALE );

...

public static void main( String[] args ) throws SlickException
{
	AppGameContainer app = new AppGameContainer( new PlatformGame() );

	[b]app.setDisplayMode( WIN_WIDTH, WIN_HEIGHT, false );[/b]

	app.start();
}

Everything look fine there?

One more thing… I was able to put the application into full screen no problem, but it was always ended up being aligned to the top left of the screen, which looks a bit weird. How do you make it display in the centre of the screen? I did some searching and some looking at method etc. but I couldn’t find anything.

Thanks for the help.

EDIT: Another thing is… how can I put an Image in a StateBasedGame and load it? StateBasedGame’s init function is final so it seems I can’t override then and that makes it seem impossible to actually load an Image that way… it’s just I want to put my image with all of the game’s graphics in some accessible place.