Full Width Graphics Cause Major Lag - java

I'm creating a game with processing java. I optimized the game as much as I could making sure the image textures are very small, drawing only certain portions of the map, etc., and the game runs consistently at 60 FPS. However, when I want to draw an image across the entire screen, for an example, as a tinted overlay (as seen from the image below)
the FPS significantly decreases, going from 60 FPS to around 40 FPS. The same happens if I use a fullscreen graphic, like a rect(0, 0, width, height) the FPS will still decrease when the graphic is quite large, spanning the width of the entire screen. Literally something as simple as the code below causes lag.
PImage fullscreenImg;
void setup() {
size(displayWidth, displayHeight);
fullscreenImg = loadImage("img.png");
}
void draw() {
image(fullScreenImg, 0, 0, width, width);
}
Here's a video of the lag happening when a full width image is displayed (the FPS goes from ~30 to ~20): https://www.youtube.com/watch?v=bjKFIgb2fII
I've tried to solve this problem by using the get() function, or reducing the resolution of the image (which just causes the image to be more pixely), and none of it works; the FPS still stays at around 40. Is there any way to make an image that has a very wide width, in my case, covering the entire screen, without decreasing the FPS? Am I doing something wrong?
Thanks for any help!

Make sure you are not loading the image during the draw() method. All of your images should load in your setup() function, and should be stored in a variable (memory), before the main loop executes. Otherwise the image will have to be pulled from the disk every time the game loops, which takes much longer than pulling from memory.
Hopefully this helps, I would recommend posting code samples rather than screenshots of the game (although the game looks very nice), otherwise it is a bit hard to diagnose the issue.

Related

JavaFX - Game loop canvas high CPU usage

I'm working on a simple JavaFX 2D game and I encounter performance issues.
I am rendering my game into a canvas which is updated each frame.
But updating the canvas at 60 FPS strongly increases my CPU usage, and of course my GPU usage.
It doesn't come from big calculations because I tried with very basics manipulations in the canvas, as shown below, and the problem was still there.
Based on research I have made, I use a TimeLine to implement my game loop. It seems to be the best way to update the canvas at the frame rate I want :
private void initGameLoop()
{
final Duration oneFrameAmt = Duration.millis(1000/60);
final KeyFrame oneFrame = new KeyFrame(oneFrameAmt, actionEvent ->
{
gameView.getRenderer().render();
});
gameLoop = new Timeline();
gameLoop.setCycleCount(Animation.INDEFINITE);
gameLoop.getKeyFrames().add(oneFrame);
}
In this configuration I'm running my game loop at 60 FPS, and the changes are running on the FX application thread.
My render function is very simple :
public void render()
{
gc.clearRect(0, 0, 50, 50);
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, 50, 50);
}
gc is the graphicsContext2D of my canvas.
My canvas is scaling on my application's window size, but I'm simply redrawing a 50x50 black rectangle each frames, at 60 FPS my CPU usage increases by 8-10% on default window size, but on full screen my CPU usage increases by 25% to 30% which is insane.
The hardware acceleration is running, besides my CPU usage, my GPU usage is around 30%.
I can't just stop rendering the canvas when nothing happens in the game, because I need to render my animations.
And basically redraw only partials areas of the canvas doesn't change anything because my basic test (shown above) only redraw a 50x50 pixels rectangle on the upper left corner of the canvas, and it still uses 25%+ of the CPU.
All the examples of game loop or animations made with JavaFX that I have found on the web uses the same techniques, but every one I have tried so far have a high CPU usage.
My rendering is very smooth and fluid but the CPU usage is way to high for what it makes. I can't seem to find why doing so little takes so much on my CPU and GPU and can't find a solution on how to improve my game perfomances. From what I have found on my research, canvas seems to be the best way to render a game in JavaFX.
My questions are : Is there any way to improve performance using a canvas ? Should I be using the scene graph with multiple elements ? Or is there any solution that I have not think of yet ?
Thanks for your help !
Conceptionally JavaFX rendering always has a CPU and a GPU portion. In the CPU portion the geometry is prepared to be rendered and the GPU portion finally does the rendering. Canvas rendering is the slowest option because the API forces you to always create new objects in each frame when you want to change something which means that you always suffer from the slow CPU portion of the rendering. On the other hand scene graph rendering can be faster if the changes you apply to your scene are only translation transforms (which can be extended to rotations and scaling with the appropriate rendering hints) because then you suffer from the slow CPU portion only once but not in every frame. If you constantly have to change the geometry too, then you are lost with both approches and the only option is to go for 3D rendering (which is what I do) via a triangle mesh. The nice thing is that in JavaFX 3D rendering can be easily combined with 2D rendering to get the best of both worlds.

Expanding textures in libGDX

I'm using libgdx to make simple tile based game and everything seemed to be fine, until I added a rectangle, which follows mouse position. I figure out, that whenever I jump, rectangle (and other blocks too) expands probably by 1 px, until I let the spacebar. When I hit the spacebar again, it gets to normal size. I tried printing out rectangle width and height, but they didn't change, so problem is with rendering.
Everything allright
On this picture you can see game before jump.
Wider textures
Here is game after jump. You can also clearly see it on players head.
A little more detail. I don't use block2d. Tiles sizes are 8x8 scaled to 20x20. Using texturepacker without padding (problem occurs with padding anyway). I don't know which code to post, because I have no idea where the problem could be, so here is just simple block class. Any help would be much appreciated, thanks.
public class Block extends Sprite {
private int[] id = { 0, 0 };
public Rectangle rect;
private int textureSize = 8;
public Block(PlayScreen play,String texture, int x, int y, int[] id) {
super(play.getAtlas().findRegion("terrain"));
this.id = id;
rect = new Rectangle(x, y, ID.tileSize, ID.tileSize);
setRegion(id[0] * textureSize, id[1] * textureSize + 32, textureSize, textureSize);
setBounds(rect.x, rect.y, rect.width, rect.height);
}
public void render(SpriteBatch batch) {
draw(batch);
}
Welcome to libGDX!
TL;DR- there isn't enough of your code there to tell what the exact problem is, but my guess is that somewhere in your code you are confusing pixel-space with game-space.
A Matter of Perspective
When you first create a libGDX game that is 2D, it's really tempting to think that you are just painting pixels onto the screen. After all, your screen is measured in pixels, your window is measured in pixels, and your texture is measured in pixels.
However, if you start looking closer at the API, you'll find weird little things such as your camera and sprite positions and sizes being measured as floating point values instead of integers (Why floats? You can't have a fraction of a pixel!).
The reason the dimensions of your game object are different than how big they are drawn. It's really easy to understand this in a 3D world- when I am close to something, it is drawn really big on the screen. When I am far away, it is drawn really small. The actual size of the object doesn't change based on my distance from it, but the perceived size did. This tells us that we can't safely measure things in our game just based on how they're drawn- we have to measure based on their true size.
As a side note, while you may be using an Orthographic camera (i.e. one without perspective) and drawing 2D sprites, libGDX is really drawing a flat 3D object (a plane) behind the scenes.
Game Units
So how do we measure the "true size" of something? The answer is that we can measure it using whatever type of unit we want! We can say something is 3.5 meters long, or 42 bananas- whatever you want! For the sake of this conversation, I'm going to call these units "Game Units" (GU).
For your game, you might consider making each block one GU high and one GU wide (essentially measuring your game world in blocks). Your character can move in fractions of a block, but you measure speed in terms of "blocks per second." I can almost guarantee it will make your game logic a lot simpler.
But our textures are in pixels!
As you probably already know, your game uses three things to render: A viewport (the patch of the screen where your game can be painted), A Camera (think of it like a real camera- you change the position and size of the lens to change how much of your world is 'in view'), and your game objects (the things you may or may not want to draw, depending on whether they're visible to the camera).
Now let's look at how they're measured:
Viewport: This is a chunk of your screen (set to be the size of your game window), and as such is measured in pixels.
Camera: The Camera is interesting, because its size and position are measured in Game Units, not pixels. Since the viewport uses the Camera to know what to paint on the screen, it does contain the mapping of GU to pixel.
Game Object: This is measured in Game Units. It may have a texture measured in pixels, but that different than the "true size" of the game object.
Now libGDX defaults all of these sizes such that 1 GU == 1 Pixel, which misleads a lot of folks into thinking that everything is measured by pixels. Once you realize that this isn't really the case, there are some really cool implications.
Really Cool Implications
The first implication is that even if my screen size changes, my camera size can stay the same. For example, if I have a small 800x600 pixel screen, I can set my camera size to 40x30. This maintains a nice aspect ratio, and allows me to draw 40x30 blocks on the screen.
If the screen size changes (say to 1440x900), my game will still show 40x30 blocks on the screen. They may look a little stretched if the aspect ratio changes, but libGDX has special viewports that will counteract this for you. This makes it much easier to support your game on other monitors, other devices, or even just handling screen resizes.
The second cool implication is that you stop caring about texture sizes to a large degree. If you start telling libGDX "Hey, go draw this 32x32px sprite on this 1x1 GU object" instead of "Hey, go draw this 32x32px sprite" (notice the difference?) it means that changing texture sizes doesn't change how big the things on your screen are drawn, it changes how detailed they are. If you want to change how big they are drawn, you can change your camera size to 'zoom in.'
The third cool implication is that this makes your game logic a lot cleaner. For example you start thinking of speeds in "Game Units per second", not "Pixels per second". This means that changes in drawing size won't affect how fast things are in the game, and will save you a ton of bug-hunting further down the road. You also avoid a lot of the weird "My jump behaves differently when I resize the screen" bugs.
Summary
I hope this is helpful and makes sense. It's difficult to get your mind around it at first, but it will make your life a lot easier and your game a lot better in the long run. If you'd like a better example with pictures, I recommend that you read this article by one of the libGDX developers.

(Java) Graphics change resolution?

I'm drawing to a Canvas using Graphics through a BufferStrategy with lines such as
g.drawImage(bufferedImage, x, y, null);
I currently have this running undecorated in a JFrame, 1920x1080p as per the resolution of my laptop. I'm curious as to whether there is any way to alter the resolution of the Graphics rendered, particularly lowering resolution so as to increase efficiency/speed, or fitting to another differently sized screen. There are many objects being rendered with a camera and the game runs fairly well, but any usable alterations to the resolution would be useful as optional in my settings.
I've researched this and found no good answers. Thank you for your time.
(Resolution changes such as for printing.)
Best to use a drawImage with a smaller image, and scaled width and height.
Now, you could even render all in your own BufferedImage using a Graphics2D with BufferedImage.createGraphics and scale afterwards. Not so nice for text or printing.
Or use Graphics2D scaling:
For complex rendering:
g.scale(2.0, 2.0);
... // Draw smaller image
g.scale(0.5, 0.5);
As you might imagine this probably does not help in memory consumption, apart from needing smaller images. At one point all pixels of the image must be given in the devices color size. 256 colors gif, or 10KB jpg will not help.
The other way around, supporting high resolutions with tight memory also exists. There one might use tiled images, see ImageIO.
Important is to prepare the image outside the paintComponent/paint.
You might also go for device compatible bit maps if you make your own BufferedImage, but this seems circumstantial (GraphicsEnvironment).

Reversing an image about axis or draw a reversed one to use instead?

I am working on a java game which deals with a bunch of sprite sheets, and I was wondering whether I should have separate sprite sheets for left and right animations, or if I should just draw up the left sprites and reverse the image programatically for the right animations. Which one would be a better practice, and would either of them perform better? I was thinking of having the image flipping occur during Game init(). If I do go with direction flipping (saving a lot of time in photoshop), would this be a safe way to go:
playerAttackLeft = spriteSheet.crop(0, 0, 400, 400); //(x, y, width, height)
playerAttackRight = spriteSheet.crop(400, 0, -400, 400);
?
You should rotate the image and use it instead of getting new one.
When you read an image then it will take space for JVM to load it.
Here is an example when I did it on my computer.
I had an image of 100kb and when I loaded it in my class, It has taken approximately 1mb of space.
reading an image is costly process
And on the other hand if you will use rotated image it will not only save your space but also your time too (space and time complexity, both) because rotating image will take much less time then to read an external image.

Performance of rescaling and filtering images repeatedly with drawImage(...) and solutions

I am making a grid-based game that resizes its grid as the window size changes. I also may apply color filters for lighting effects in the future. I am concerned about the performance of this code, which draws to the screen an image in one of the grid squares.
public void drawSquares(Graphics g){
ListIterator<Viewport> iterator = vp.listIterator();
while(iterator.hasNext()){
Viewport v = (Viewport)iterator.next();
BufferedImage img = v.getSqView().getImage();
Rectangle b = v.getPixRect();
g.drawImage(img, b.x, b.y, b.width, b.height, v.getSqView().getBackground(), null);
}
return;
}
What this code does is get the image (stored in img) and get the pixel rectangle it needs to fit in (stored in b), then draw it in the space alloted via drawImage.
drawImage says that it scales images on the fly - which means that all images are being rescaled every frame. But the window is only resized rarely, so this must waste lots of processor time doing the same thing over and over again.
Now I saw this and decided that I would just update all the images upon resizing once, then store the result and be able to draw normally.
Like this:
public void resizeImage(int width, int height){
BufferedImage resized = new BufferedImage(width, height, img.getType());
Graphics2D g = resized.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, width, height, 0, 0, img.getWidth(), img.getHeight(), null);
g.dispose();
img = resized;
}
This doesn't work - I think it has something to do with img = resized. I just lose all the images with this code.
I have a few questions then.
What is the performance cost of repeatedly scaling with drawImage? Is it any different even if the window has not been resized in between frames?
How should I get the second code snippet to work? What is going wrong?
If I apply a lighting filter to a tile, will that eat up tons of processor time as well if I run it each frame? (Think 225 or so small images on a 800x800 or so display)
What is best practice for applying lighting filters? I am planning on overlaying on the whole map a pitch black filter, then exposing the areas around light sources.
Thanks for any help with this!
Resize the frame of this Grid to get a subjective feel for the latency. Use the approach shown here to measure the latency. Verify your findings in a profiler.
There's no reason you shouldn't be able to resize the elements of a List<Image> as you propose, but add() the resized instances to a new list as they are created.
What is the performance cost of repeatedly scaling with drawImage? Is
it any different even if the window has not been resized in between
frames?
You should always measure, but there is definitely a performance cost here, even if the window is not resized, because as the Javadoc says, there is no caching behind this drawImage method. The cost also depends on the frame rate.
How should I get the second code snippet to work? What is going wrong?
The second code snippet should be OK, I think the problem is somewhere else. Try reproducing the problem in a "small but complete" program, and post another question if you still see the problem.
If I apply a lighting filter to a tile, will that eat up tons of processor time as well if I run it each frame? (Think 225 or so small images on a 800x800 or so display)
You should always measure :)
What is best practice for applying lighting filters? I am planning on overlaying on the whole map a pitch black filter, then exposing the areas around light sources.
You can use an AlphaComposite for this.

Categories