I am making a game where for the purpose of this question i have a a class that extends JFrame that adds a class that extends JPanel(GamePanel). in GamePanel i have a run method that has two functions update(); and repaint(); and then a Thread.sleep(20). The update function takes about 1-2ms. I have all my drawing stuff in paintComponent(Graphics g) which seems to correctly get called when i use repaint() since stuff shows up on screen.
My problem is that it is increeedibly laggy. When i didn't have Thread.sleep(20) it was unplayable with like 2fps. I read that this was because repaint() wasnt given enough time to finish or something so i added a delay before next loop. anything above or under 20ms seems to make it more laggy.
I've tried using graphics configuration stuff, double buffering and more but it stays laggy. On my home pc, which is an intel i5, quad core, 3.2GHz i'm only getting around 100fps, and on a school computer i get around 15fps (ok pc, like amd dual core i believe). The paintComponent loop is Super lightweight! just drawmap with offset depending on player position, then draw player in middle of screen! I am using a map that is 2000x2000, 0.8mb. Tried switching to 1000x1000 0.4mb and no difference.
Here is the code:
#Override
public void paintComponent(Graphics g) {
//Rendering settings and stuff
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
//Draw map gameMap.gameMap is a bufferedImage
g2d.drawImage(gameMap.gameMap, gameMap.x, gameMap.y, null);
//Draw health bar
g2d.setColor(healthBarColor);
g2d.setComposite(alphaHealthBarBackground);
g2d.fillRect(100, 19, 200, 23);
g2d.setFont(font);
g2d.setComposite(alphaNormal);
g2d.setColor(healthBarColor);
g2d.drawString("HP: ", 20, 40);
g2d.fillRect(100, 19, player.health * 2, 23);
//Draw player player.playerImage is a BufferedImage
rotatePlayer.setToRotation(rotation, rotationAnchor.x, rotationAnchor.y);
rotatePlayer.translate(xResolution / 2, yResolution / 2);
g2d.drawImage(player.playerImage, rotatePlayer, this);
g2d.setColor(Color.white);
}
This results in 100fps on relatively awesome computer and 15fps on descent computer!
Not pretending to be ultimate solution, just some tips:
Make sure your buffered images are have same color model as default of GraphicsDevice on which they drawn. The method GraphicsConfiguration.createCompatibleImage could create such images.
If it is possible, try to split whole huge map to tiles and skip rendering off-screen (out of game view) parts.
It seems you use passive rendering, as you mentioned calling of repaint(). Event Dispatch Thread used for many things in Swing and AWT, and it can't guarantee acceptable timing for actively rendered games. Maybe it worth to redesign rendering part of game to use Active Rendering. Tutorial and example can be found here.
Well, for game development I donot think drawing a huge image in a Swing paintComponent is ever going to win any speed records. 100 FPS is still amazing (and about 40 FPS more than the refresh rate of most LCD displays).
For more speed it is essential that the drawing primitives you are using are accelerated. On your school PC's they may simply lack a decent graphics card that provides the 2D acceleration needed (how do these PC's feel doing normal 2D operations in say browsers and paint programs?)
You may want to look into a framework that uses OpenGL instead, like JOGL. Another option is to try out JavaFX 2 -- it may have a better rendering pipeline.
I am also developing a Java game and have done many things the same as you (extending JPanel and calling repaint()). One difference is that I am using a javax.swing.Timer to call an ActionPerformed(ActionEvent e) method to update my game every 5ms. At the end of the method it calls repaint() to do the rendering.
Also if you are using Graphics2D to do your rendering you can use RenderingHints to guide the computer on how you want your game to be rendered (Eg, speed or quality, stuff like that).
I haven't measured the FPS exactly but I get no lag on my Ubuntu 12.10 system and JUST a bit slower on Windows 8.
I apologize if my response isn't exactly what you wanted but this is what has worked for me so far without problems.
Related
I'm making an online multiplayer game (Nothing too complex, just a top-down tank shooting game) on a Java Canvas. You would think I'm here to ask about networking stuff, sockets, etc, but I'm much farther along than that, and I've come across something strange.
Basically, there are a few strings that I'm drawing on the canvas with a bold font. When I run it from NetBeans (Not building, just pressing F6/The green run button), the text shows up bold as it should. But, when I build the project, and run the JAR file, the text is not bold.
Note:
I tried updating Java, as I was quite a few updates behind. Didn't fix it.
Here is a code snippet to show that I am drawing the bold text correctly, but I don't know what else I would need to show for this kind of issue as the code can't be the problem.
g.setFont(new Font("TimesRoman", Font.BOLD, 50));
g.setColor(Color.red);
g.drawString("Connection Failed.", x, y);
TL;DR - Drawing bold text on canvas isn't bold when running JAR file, but is when running from NetBeans.
All help is appreciated. Thanks!
It looks like you might be creating a Font in your paint function. Given the paint function may be called several times per second, this can be a source inefficiency, and possibly resource starvation. Create your Font when you create your class, perhaps as a static resource, and then use the same font object in each paint call.
The Graphics object is allowed to take shortcuts when drawing objects, in the name of efficiency. This can include not bolding large fonts, not using anti-aliasing on diagonal lines, etc. Speed is king. Of course, you can tell the graphics engine you care more about appearance than speed, using Graphics2D.setRendingHint(...)
import static java.awt.RenderingHints.*;
void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRendingHint(KEY_RENDERING, VALUE_RENDERING_QUALITY);
g2d.setRendingHint(KEY_TEXT_ANTIALIAS, VALUE_TEXT_ANTIALIAS_ON);
You can set multiple hints at once with setRendingHints(Map hints).
Im trying to code a 2D pong game with java. The problem that i have is about fluidity. Im using images (As most of the 2D games do) for background and paddles and the ball. Created the game with the Actionlistener and attached it with a timer to the game. For now i just have this code in the game loop for collision.
#Override
public void actionPerformed(ActionEvent e) {
if (ball.y <= 0 || ball.y + ball.height + 35 > HEIGHT) { // Horizontal
// Walls
// collision
ballspeedY = -ballspeedY;
}
if (ball.x <= 0 || ball.x + ball.width + 5 >= WIDTH) { // Vertical Walls
// collision
ballspeedX = -ballspeedX;
}
ball.y += ballspeedY;
ball.x += ballspeedX;
renderer.repaint();
}
And this code for drawing
public void repaint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(backgroundImage, 0, 0, WIDTH, HEIGHT, null);
g2d.drawImage(ball.image, ball.x, ball.y, ball.width, ball.height, null);
g2d.drawImage(paddle.image, paddle.x, paddle.y, paddle.width, paddle.height, null);
}
The problem is, when i increase the ball's speed, it starts to move not smoothly. Ive done a research and tried to cancel drawing the background image. And the ball started to move a bit more smooth. The thing im confused about is, what if i have moving background or 100 balls or something else. Im doing something wrong and please someone tell me which way i should use to move these objects on the screen smoothly. The games which are using a lot bigger images or backgrounds or even 3D games move so fluidly but my simple pong game doesn't. What am i doing wrong?
SOLVED: The problem is just with this line:
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
This line cracks the animations fluidity. When i delete it, everthing runs pretty fast and smooth
I can't fully answer your question, because that is actually a complicated subject. There are multiple different aspects to talk about, but each of them is in itself studying material. I'll try to cover the basic ideas:
Multithreading
So first of all, your code is probably executed all sequential. Each time actionPerformed runs, it will call redraw at the end. Now, basically this will define your 'framerate'. So the more time consuming (more complex code) your actionPerformed is, the lower your framerate will get.
To counter this, one thread on it's own can take care to draw the actual state of the game.
Ball speed is not related to the framerate
I am not sure how to read your code. But from what I see, your ballspeed is an integer. Take in account the thing I wrote above. So in your current implementation ballspeed actually defines how far the ball moves per frame. That is a problem, because it would mean, that the game runs faster/slower depending on the complexity of actionPerformed. Even if I read your code wrong, this is a thing to consider.
One way to solve it, is to separate calculation and drawing with multiple threads like mentioned above. But you should probably also have a look at frame independent physics.
100 balls problem
If you would calculate the positions of all x balls in your actionPerformed method, your framerate becomes increasingly slower the bigger x gets. This, again, is because of the things above. But I guess at one point you have to do further optimizations, otherwise your recalculation process can't keep up. Though the number should be quite high - but this is where I lack experience.
Graphics2D is not OpenGL
I am not too familiar with how the Java Graphics2D works, but I have basic knowledge about OpenGL. For real games OpenGL is almost a must. Even webgames start to use WebGL (browser supported interface for similar functionality). This is where you actually use the graphics card for its capabilities. Especially for 3D games, but even for simple 2D games it is really the best for performance. By the way, smartphones games as well.
Covering that would be impossible here, so I just leave it as is. If you are interested in those things, you would need to learn them more in depth. I guess your next step would be to use a framerate independent calculation. I'm not sure about the multithreading stuff, because it usually comes along with a bunch of difficulties...
Hi I've been trying to get rid of my flickering on a JFrame app. Have searched around and seen that setDoubleBuffered(true) can be used for paintComponent of Jpanel, but not paint method of JFrame, nor applets.
Managed to diminish but not eliminate flickering by introducing the instructions this.createbufferstrategy(2) within paint method, and further reduced flickering with the instruction this.setignorerepaint(true) inside paint.
But I finally found an example of code that completely removes flickering and it works by drawing the static elements within the update function.
Tested fillRect within update in an applet and it works, but when copy pasted into a regular java application it does not work there within the jframe's update function.
Here's the code
Graphics graphics;
Image image;
public void update(Graphics g)
{
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
graphics = image.getGraphics(); }
graphics.setColor(Color.blue);
graphics.fillRect(0, 0, this.getWidth(), this.getHeight());
g.drawImage(image, 0, 0, this);//}
With an empty paint function this draws to the screen and fills it with blue in an applet, it also gets rid of flickering. But in a normal application of jframe it does nothing.
What needs to be done to allow either fillRect or drawImage to work from within update in a non applet regular application environment?
BTW, I'm a bit new to this if the graphics object is being modified itself by calling fillRect, how does that modify the image object? Because drawImage is necessary for the screen to turn blue.
PS I've tried not using both createbufferedstrategy and setignorerepaint, and nothing changes.
When using setIgnorePaint(true), its not allowing you to mess with the Graphics.
I'm guessing by the looks of your update(Graphics g) parameter, you call that within your paint method, using the paintMethod's graphic g to paint (inside paint method, you call update(g))
If you ignore paint, its not gonna allow you to use the paintComponent's Graphic parameter.
Post all code that includes graphics (Where you made your strategy, where you're calling this method, ect..)
The flickering is a pretty mainstream issue with the strategy, and I can't promise that I'll be able to fix it (my friend brought the problem up to me a while ago, but i didnt care enough to try and figure it out), but that should at least explain why your graphics aren't rendering
I am displaying an image in Swing. I am drawing on top of the image (a bunch of drawRect() calls) and refreshing the screen. The image is constant, but the objects drawn on top are not. Is there any way to avoid redrawing the image any time? Since the graphics card likely does the image display, is it safe to assume that the drawRect() calls are the bottleneck? I draw as many as 20,000 calls a frame (but usually no more than 3000).
Edit: It is indeed the rect calls that are slowing it down and it can be made considerably faster by removing the transparency channel. That being said, it would still be nice to speed it up and include the transparency. The code can't really get simpler, so I am hoping by doing something different it will help.
public void paintComponent(Graphics g) {
super.paintComponent(g) ;
//grid or walkers
g.drawImage(image, 0, 0, null);
for(Walker w : walkArray){
g.setColor(new Color(255,255-w.data[3], 0, w.data[2]));
g.drawRect(w.data[0], w.data[1], 1, 1);
}
}
This is out of context, but can you lookup the colors in a precomputed palette instead of creating an instance of a Color in every cycle? Maybe that could improve performance a little.
Edit: For example, a List<Integer> is used as an RGB lookup table here, and a Queue<Color> is used here.
I am making a game and I am trying to find the best way to implement Doublebuffering into it. Would anyone be able to show me how I could do it with my rendering code below?
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(p.getImage(), p.getX(),p.getY(),null);
//draw each ball object
for(int i=0;i<balls.size(); i++){
Ball tmp = (Ball) balls.get(i);
g2d.drawImage(tmp.getImage(), tmp.getX(),tmp.getY(),null);
}
//strings
g2d.drawString("Score: "+score,50,20);
}
Could someone please help?
If you're using Swing you just can use the built-in double buffering: http://java.sun.com/products/jfc/tsc/articles/painting/#db
In case you're implementing your own rendering, here are some hints:
Double Buffering basically means you have two draw buffers that you alternatingly write to while the other is displayed.
In your case, you might use an image to draw your game content to and then draw that image to the component. This should give you double buffering in a sense. You might use two images which you swap in order to reduce concurrent access, i.e. one would be the "front" buffer that is displayed and the other is the "back" buffer you draw to.
That said, I'd strongly recommend not to implement that yourself. Instead you should try and use one of the existing 2D libraries (like Swing) or 3D libraries (like OpenGL with JOGL or LWJGL as Java bindings - note that it doesn't have to be 3D with OpenGL). Alternatively you could also look for a game engine, there are plenty of them out there.