Advertisement

Turn-based strategy - Graphic performance issue

Started by January 16, 2017 05:01 PM
7 comments, last by Rach3 7 years, 10 months ago
Hi,
I am developing a turn-based strategy game in JavaFX and I'm having performance issues when loading 60+ PNG images (each image min 300 x 300px) that represent provinces. The idea behind map generation is to use a static overall map shape and the shape of its provinces. But each province would be represented by one of four images, representing a different terrain type. Thus each time a player would start a new game the map would be changed. Also, during gameplay, province images would be changed to represent seasons change.
So, my initial idea was to have at least 60 provinces (preferably up to 100) where each province would have 4 type images and 4 seasonal images. I know ... A LOT of images.
The problem I'm having is when I load more than 50 images, zooming, scrolling, and button responsiveness starts to lag on iMac. On Windows laptop, I get serious lag even with less than 30 images.
I've searched a lot on the internet on how to approach the programming of an image-based world map, but without success. All I could find is either hex approach or HOI or EU style approach. For now, I would like to stick with my idea of using images, so if anyone can help me solve this performance issue I would be much grateful. Or, if anyone has another idea of ho can I generate a dynamic world with provinces that can graphically change.
Also, I would like to program this myself without using game engines like Unity.
The thing is I don't really have a much understanding of how each image and it's size affects memory usage, so I'm basically doing a trial&error approach. And right now I'm stuck on "errors".
Sincere thanks for all your goodwill and help!
Rach

Just to clarify things, is "loading" the problem (ie transfering images from disk to memory), or "displaying" (showing the images at the right spot at the screen)?

I assume now you mean the latter.

First thing to check is memory use. If the garbage collector runs, do you get a lot of free memory again?

Java will try very hard to stay within its memory limit, and if you are near the upper bound, it runs the GC very aggressively, which takes loads of CPU time (which kills performance quite effectively).

Simplest solution for this problem is to give the JVM more memory. (Could also be a test, does the problem go away with more memory?)

Depending on your Java version this may not be relevant any more, iirc Java 8 allocates memory as needed, but not sure about that. You should probably check what the documentation of your Java version says about memory.

When you say you display 50 images, that means for each province 1 image, right?

I assume you load them all in memory before displaying them, you don't want to load them each time again :)

You don't paint images that are not shown (ie fall outside the viewport)?

Not sure if this makes things much better, usually paint code is very efficient in clipping stuff.

To understand how images affect performance, you can load less province images, and simply display the same one multiple times. It will look horrible, but that's alright, you are debugging a performance problem, looks are non-relevant. (Do keep a copy of the working version of course :) )

Another experiment you can do is to see what happens if you paint less images (but bigger ones). Make one big image for your whole world, and display that.

To make the test it a bit realistic, make an image in some editor of the world size, and random fill it with province images. It doesn't have to look good yet, the only thing you should try is whether displaying a part of 1 image works or not. If it works, then start worrying about making it look properly with all the provinces at the right spot. If it doesn't work, you have that knowledge without wasting time on making a nice big world map that is useless, as the solution doesn't work.

(I suggested to fill the world image with random provinces, since you need to get a size of the image that is approximately what you will get when you do it properly. You could also eg fill the entire world with 1 colour and display that, but that image is likely to be much smaller (in memory usage) than the real map you'd get with real province image data, and that extra memory for the real map may be the difference between working and not working.)

Advertisement

Many games show thousands of images onscreen and manage to render them 30 or 60 times a second - so you know it should be possible. Do you have access to a profiler, to find out exactly what the slow part of your game is? Measuring is usually better than guessing.

Thanks for your help!

My apologies for not being clear enough in my question. I will try to clarify:

Yes, each image is one province. I am loading images into an ArrayList and then also all ImageViews to ArrayList, which I then loop to display images on StackPane. I also use cache interfaces like setCacheHint(CacheHint.SPEED).

For zooming and scrolling, I use ScaleTransition and TranslateTransition.

Initial screen loading is not an issue. When I zoom in or out, or scroll is where things slow down. Also, button hovering effect starts to have a lag even if I don't use scrolling or zooming.

I have tried with:

- one image (jpg) 7865 × 5208 - no problem!

- one image and 90 ImageViews - no problem!

- less images and 90 ImageView - no problem! (but I can't use this approach since each province has a unique shape)

- 40 400x500 images - noticed a little lag

- 60 300x200 images - bigger lag (especially on laptop)

- 100 30x30 images - lag on laptop (if I would use this approach I could use several images for one province but would require hundreds of images)

- tried various sizes of images, from 2kb to 250kb (it doesn't seem to make any big difference as opposed to varying image number)

- tried with 8 bit and 32 bit images, tried with one color images and almost entirely transparent images. When it comes to (px) bigger images + more images I start to see lag.

I am using Java 8 (111).

@Kylotan: I am sure that what I am after (displaying, zooming and scrolling 100 400x400 images) should be possible. What I don't know yet, if it is possible with JavaFX and my programming skills.

So far I haven't used a profiler but will try with Java VisualVM.

I much appreciate any further help!

Rach

It wasn't clear to me from your description, but do you always have all 16 province version (4 terrain * 4 seasons) loaded?

If so, you could at least drop that to just 4 province versions quite easily, if you choose + load the terrain upon new game.

You implied these don't change during gameplay, so you don't need to have them taking up any memory if not in use.

Another potential change is to not load all seasons. Especially if loading is async, you can just always have the current + next season loaded, and unload the 2 others.

---

EDIT: Another alternative would be to merge a lot of these images into 1 images, and just draw parts of the images -- if the problem is related to multiple files for some reason. Like a spritesheet or similar.

Hello to all my stalkers.

No, only images that are actually used will be loaded.

I mentioned this, just to demonstrate why I believe using images is the only way I can do this (using irregular province shapes).

I am sorry for the confusion.

Thank you!

Advertisement

which I then loop to display images on StackPane

I looked up what StackPane does, and it scares me:

StackPane lays out its children in a back-to-front stack.
The z-order of the children is defined by the order of the children list with the 0th child being the bottom and last child on top. If a border and/or padding have been set, the children will be layed out within those insets.


Why do you have a Z order between images? Doing layout for 100 or so children, yeah, that could cost time. "layout" is usually some complicated constraint driven computation that explodes in cpu time when you add more children.

I would expect you can use something like "Canvas", ie http://docs.oracle.com/javafx/2/api/javafx/scene/canvas/Canvas.html
Just an area to paint on, and you blit all images onto it.

The GraphicsContext http://docs.oracle.com/javafx/2/api/javafx/scene/canvas/GraphicsContext.html seems to have scaling, so that might work.

I didn't consider StackPane's own layering.

Changing to canvas seems promising!

Will try.

Many thanks!!

Solved!

I couldn't use Canvas since I couldn't use event filters on each image, so I used Pane with ImageViews. I also moved Pane's cache hint before adding the actual images.

Now it works great!

Thanks to all for the help, especially Alberth. You nailed it!

Thanks again!

Rach

This topic is closed to new replies.

Advertisement