我正在尝试学习Graphics2D库,同时构建2D汽车游戏,平台游戏等小型游戏......今天我决定制作一个基于太空的游戏,并在你需要的空间中进行虚拟游戏明星。所以我决定使用fillOval()
绘制小圆圈,这将产生夜空效果。但是,每当我尝试移动星星或任何其他物体时,旧框架就会停留在那里并且一层又一层地绘制。我认为dipose()
方法就够了......但似乎不是这样。
我有什么方法可以解决这个问题?
以下是我运行代码时的预览。
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};
}
在我尝试在绘制星星和船之前添加背景图像g.drawImage(this.bg,0,0,Config.WINDOW_WH[0], Config.WINDOW_WH[1], null);
后,它不会再发生了。但我想知道这是一个修复,还是一个不好的做法,以避免未清除帧。
答案 0 :(得分:0)
但是,每当我试图移动星星或任何其他物体时,旧框架就会停留在那里并且一层又一层地被绘制。
是的,这就是绘画的作用。将Graphics
上下文视为物理画布。每次在其上绘画时,您都会向其添加更多内容。 API不会为您清除它。
这样做的好处是,如果您正在执行添加绘画过程,您可能不希望在每次传递时刷新它,但在您的情况下,您每次都必须清除它。
我认为dipose()方法就够了......但它似乎不是
不,dispose
释放上下文可能持有的所有内部资源,释放内存。话虽如此,您不应该处理您创建的上下文,因为它可能会阻止将来的操作被应用。
如果您查看example中的tutorials,则会清楚地显示Graphics
背景已为每个框架明确/准备......
Graphics g = bufferStrategy.getDrawGraphics();
if (!bufferStrategy.contentsLost()) {
g.setColor(COLORS[i]);
g.fillRect(0,0,bounds.width, bounds.height);
bufferStrategy.show();
g.dispose();
}
我还建议您查看JavaDocs中提供基本循环操作的示例