Reputation: 1165
I'm trying to learn Graphics2D library while building small games such as 2D car games, platformer games and so on... Today I decided to make a space-based game and obvoiusly in space you need stars. So I decided to use fillOval()
to draw small circles which would give the effect of night-sky. BUT, whenever I try to move the stars or any other object, the older frames just stay there and a bunch of layers are drawn one after another. I thought that dipose()
method would be enough... but it seems like it aint.
What options do I have to fix this problem?
Here's a preview of what it looks like when i run the code.
package asteroids;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
public class Main extends Canvas implements KeyListener {
private boolean gameOver;
private BufferStrategy backBuffer;
private Dimension dimension = new Dimension(Config.WINDOW_WH[0], Config.WINDOW_WH[1]);
private List<Star> stars = new ArrayList<Star>();
private HashMap<Integer,Boolean> keyDownMap = new HashMap<Integer, Boolean>();
private Ship ship;
public Main() {
// Initialize Window
initWindow();
addKeyListener(this);
this.createBufferStrategy(2);
backBuffer = this.getBufferStrategy();
// init variables
gameOver = false;
// Generating stars
generateStars();
// Init spaceship
ship = new Ship(25,36,"ship.png");
// Init loop
gameLoop();
}
public void initWindow(){
JFrame window = new JFrame("Asteroids");
setPreferredSize(dimension);
window.add(this);
window.pack();
window.setResizable(false);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBackground(new Color(54, 71, 99));
window.requestFocus();
}
public void update() {
if(keyDownMap.containsKey(KeyEvent.VK_ESCAPE)){
gameOver = false;
System.exit(0);
}
/*for(Star s: stars) {
s.update(keyDownMap);
}*/
this.ship.update(keyDownMap);
}
public void render(){
Graphics2D g = (Graphics2D) backBuffer.getDrawGraphics();
// Stars
for(Star s: stars) {
g.fillOval(s.posx - (s.width/2), s.posy - (s.height/2), s.width, s.height);
}
// Spaceship
g.drawImage(
this.ship.getImage(),
this.ship.posx, this.ship.posy,
this.ship.width, this.ship.height, null);
g.dispose();
backBuffer.show();
}
public void generateStars() {
for(int i = 0;i < 20;i++) {
int starX = new Random().nextInt(Config.WINDOW_WH[0]-10)+5;
int starY = new Random().nextInt(Config.WINDOW_WH[1]-10)+5;
stars.add(new Star(starX, starY));
}
}
public void gameLoop(){
while(!gameOver){
update();
render();
try{ Thread.sleep(20);}catch(Exception e){};
}
}
public static void main(String[] args) {
new Main();
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
keyDownMap.put(e.getKeyCode(), true);
}
@Override
public void keyReleased(KeyEvent e) {
keyDownMap.remove(e.getKeyCode());
}
}
package asteroids;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.util.HashMap;
import java.util.Random;
public class Star {
int width, height;
int posx, posy;
/** CONSTRUCTOR **/
public Star(int x, int y) {
int rand = new Random().nextInt(Config.STAR_SIZES.length);
width = Config.STAR_SIZES[rand];
height = Config.STAR_SIZES[rand];
posx = x;
posy = y;
}
public void update(HashMap keyDownMap) {
if(keyDownMap.containsKey(KeyEvent.VK_LEFT))
this.posx += 1;
if(keyDownMap.containsKey(KeyEvent.VK_RIGHT))
this.posx -= 1;
if(keyDownMap.containsKey(KeyEvent.VK_UP))
this.posy += 1;
if(keyDownMap.containsKey(KeyEvent.VK_DOWN))
this.posy -= 1;
}
}
package asteroids;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import javax.swing.ImageIcon;
public class Ship {
public int posx, posy;
public int width, height;
private Image image;
public Ship(int w, int h, String img) {
this.posx = Config.WINDOW_WH[0]/2;
this.posy = Config.WINDOW_WH[1]/2;
this.width = w;
this.height = h;
this.image = new ImageIcon(getClass().getResource("/"+img)).getImage();
}
public Image getImage() {
return this.image;
}
public void setPosx(int x) {posx = x;}
public void setPosy(int y) {posy = y;}
public void setImg(Image img) {
this.image = img;
}
public void update(HashMap keyDownMap) {
if(keyDownMap.containsKey(KeyEvent.VK_LEFT))
this.posx += 1;
if(keyDownMap.containsKey(KeyEvent.VK_RIGHT))
this.posx -= 1;
if(keyDownMap.containsKey(KeyEvent.VK_UP))
this.posy += 1;
if(keyDownMap.containsKey(KeyEvent.VK_DOWN))
this.posy -= 1;
}
}
import java.awt.Color;
public class Config {
// MAIN CANVAS SETTINGS
public static int[] WINDOW_WH = {500, 500};
public static String WINDOW_BG_IMG = "";
public static Color WINDOW_BG_CLR = new Color(40, 42, 45);
// OBJECT SETTINGS
public static int[] STAR_SIZES = {10,5,8,3,7};
}
After I tried to add a background image g.drawImage(this.bg,0,0,Config.WINDOW_WH[0], Config.WINDOW_WH[1], null);
before drawing stars and the ship, it doesn't happen anymore. But im wondering if this is a fix or just a bad practice for avoiding the un-cleared frames.
Upvotes: 0
Views: 1127
Reputation: 347214
BUT, whenever I try to move the stars or any other object, the older frames just stay there and a bunch of layers are drawn one after another.
Yes, that's how painting works. Think of the Graphics
context like a physical canvas. Each time you paint on it, you are adding more more content to it. The API won't clear it for you.
There advantages to this, if you're performing an additive painting process, you may not wish to refresh it on each pass, but in your case, you're going to have to clear it each time.
I thought that dipose() method would be enough... but it seems like it aint
No, dispose
releases any internal resources the context might be holding, freeing up memory. Having said that, you shouldn't dispose of a context you did create, as it can prevent future operations from been applied.
If you take a look at the example from the tutorials it clear shows the Graphics
context been clear/prepared for each frame...
Graphics g = bufferStrategy.getDrawGraphics();
if (!bufferStrategy.contentsLost()) {
g.setColor(COLORS[i]);
g.fillRect(0,0,bounds.width, bounds.height);
bufferStrategy.show();
g.dispose();
}
I would also recommend having a look at the example in the JavaDocs which presents a basic loop operation
Upvotes: 1