简体   繁体   English

JFrame,留下矩形的痕迹

[英]JFrame, leaves trail of rectangle

i'm trying to create a game. 我正在尝试创建一个游戏。 And almost everytime I move, it's leaving a trail 几乎每次我移动时,都会留下痕迹

Code: 码:

package lt.mchackers.gametest.main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;

import lt.mchackers.gametest.handlers.InputHandler;

/** 
 * Main class for the game 
 */ 
public class Main extends JFrame 
{
        private static final long serialVersionUID = -828018325337767157L;
        boolean isRunning = true; 
        int fps = 30; 
        int windowWidth = 320; 
        int windowHeight = 320;
        int speed;

        BufferedImage backBuffer; 
        Insets insets; 
        InputHandler input; 

        int x = 0;
        int y = 0;
        int xa = 0;
        int ya = 0;
        Coordinates coords = new Coordinates(0, 0);

        public static void main(String[] args) 
        {       Main game = new Main(); 
                game.run(); 
                System.exit(0); 
        } 

        /** 
         * This method starts the game and runs it in a loop 
         */ 
        public void run() 
        { 
                initialize(); 

                while(isRunning) 
                { 

                        long time = System.currentTimeMillis(); 

                        update(); 
                        draw(); 

                        //  delay for each frame  -   time it took for one frame 
                        time = (1000 / fps) - (System.currentTimeMillis() - time); 

                        if (time > 0) 
                        { 
                                try 
                                { 
                                        Thread.sleep(time); 
                                } 
                                catch(Exception e){} 
                        } 
                } 

                setVisible(false); 
        } 

        /** 
         * This method will set up everything need for the game to run 
         */ 
        void initialize() 
        { 
                setTitle("Game Tutorial"); 
                setSize(windowWidth, windowHeight); 
                setResizable(false); 
                setDefaultCloseOperation(EXIT_ON_CLOSE); 
                setVisible(true); 

                insets = getInsets(); 
                setSize(insets.left + windowWidth + insets.right, 
                                insets.top + windowHeight + insets.bottom); 

                backBuffer = new BufferedImage(windowWidth, windowHeight, BufferedImage.TYPE_INT_RGB); 
                input = new InputHandler(this); 
                Graphics bbg = backBuffer.getGraphics(); 
                BufferedReader reader = null;
                try {
                    reader = new BufferedReader(new FileReader("map"));
                } catch (FileNotFoundException e1) {
                    e1.printStackTrace();
                }
                String line = null;
                try {
                    BufferedImage gray = ImageIO.read(new File("gray.png"));
                    BufferedImage black = ImageIO.read(new File("black.png"));
                    while ((line = reader.readLine()) != null) {
                        for(String s : line.split(""))
                        {
                            if (s.contains("*"))
                            {
                                bbg.drawImage(gray, xa-32, ya, null);
                            }
                            else if (s.contains("#"))
                            {
                                bbg.drawImage(black, xa-32, ya, null);
                            }
                            if (xa < 320)
                            {
                                xa += 32;
                            }
                            else
                            {
                                ya += 32;
                                xa = 0;
                            }
                            System.out.println(xa);
                            System.out.println(ya);
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

        } 

        /** 
         * This method will check for input, move things 
         * around and check for win conditions, etc 
         */ 
        void update() 
        { 
            if (input.isKeyDown(KeyEvent.VK_NUMPAD0))
            {
                speed -= 1;
            }
            if (input.isKeyDown(KeyEvent.VK_NUMPAD1))
            {
                speed += 1;
            }
            if (input.isKeyDown(KeyEvent.VK_RIGHT)) 
            { 
                coords.setCoords(coords.getX() + 32, coords.getY()); 
            } 
            if (input.isKeyDown(KeyEvent.VK_LEFT)) 
            { 
                coords.setCoords(coords.getX() - 32, coords.getY()); 
            } 
            if (input.isKeyDown(KeyEvent.VK_UP))
            {
                coords.setCoords(coords.getX(), coords.getY() - 32); 
            }
            if (input.isKeyDown(KeyEvent.VK_DOWN))
            {
                coords.setCoords(coords.getX(), coords.getY() + 32); 
            }
            //System.out.println(x);
            //System.out.println(y);
            //System.out.println(speed);
            if (coords.getY() < 0)
            {
                coords.setCoords(coords.getX(), 0);
            }
            if (coords.getX() < 0)
            {
                coords.setCoords(0, coords.getY());
            }
            if (coords.getX() > windowWidth - 32)
            {   
                coords.setCoords(windowWidth - 32, coords.getY());
            }
            if (coords.getY() > windowHeight - 32)
            {
                coords.setCoords(coords.getX(), windowHeight - 32); 
            //  y = windowHeight - 32;
            }

        } 

        /** 
         * This method will draw everything 
         */ 
        void draw() 
        {               
                Graphics g = getGraphics(); 
                //this.setBackground(Color.BLACK);
                //super.paintComponents(g);
                backBuffer.setRGB(x, y, Color.BLACK.getRGB());

                Graphics bbg = backBuffer.getGraphics(); 

                BufferedReader reader = null;
                try {
                    reader = new BufferedReader(new FileReader("map"));
                } catch (FileNotFoundException e1) {
                    e1.printStackTrace();
                }
                String line = null;
                try {
                    BufferedImage gray = ImageIO.read(new File("gray.png"));
                    BufferedImage black = ImageIO.read(new File("black.png"));
                    while ((line = reader.readLine()) != null) {
                        for(String s : line.split(""))
                        {
                            if (s.contains("*") && xa + 32!= coords.getX() && ya - 32 != coords.getY())
                            {
                                bbg.drawImage(gray, xa-32, ya, null);
                            }
                            else if (s.contains("#") && xa + 32 != coords.getX() && ya - 32 != coords.getY())
                            {
                                bbg.drawImage(black, xa-32, ya, null);
                            }
                            if (xa < 320)
                            {
                                xa += 32;
                            }
                            else
                            {
                                ya += 32;
                                xa = 0;
                            }
                            //System.out.println(xa);
                            //System.out.println(ya);
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                bbg.setColor(Color.WHITE); 

                xa = 0;
                ya = 0;
                System.out.println(coords.getX());
                bbg.setColor(Color.WHITE);
                bbg.fillRect(coords.getX(),coords.getY(), 32,32);  
                System.out.println(coords.getY());
                //bbg.setColor(Color.BLACK); 
                //bbg.drawOval(x, y, 20, 20); 


                g.drawImage(backBuffer, insets.left, insets.top, this); 
        } 
}

Thanks for help. 感谢帮助。

Check out my code from here , to get a hint as to how to paint stuff in a game loop properly. 这里查看我的代码,以获取有关如何正确绘制游戏循环中内容的提示。

Basically what you need to take care of is double buffering to prevent any flickering and also repainting the background so that you don't leave out any trail of rectangles. 基本上,您需要注意的是双重缓冲以防止任何闪烁,并重新绘制背景,以免留下矩形的痕迹。

You can also check out the Killer Game Programming in Java online book, which can help you learn the game programming concepts and their implementation. 您还可以查看《 Killer Game Programming in Java》在线书,它可以帮助您学习游戏编程概念及其实现。

The concept of double buffering is simple. 双缓冲的概念很简单。 Since painting on the screen takes more time than updating the states of the objects in the gameplay, we use two canvas to prevent any flickering issues which arise when objects are painted directly on the screen. 由于在屏幕上绘画比更新游戏中对象的状态花费更多的时间,因此我们使用两个画布来防止在将对象直接绘画在屏幕上时出现的任何闪烁问题。

When the object states are updated in the game loop, it is rendered in a background canvas. 在游戏循环中更新对象状态时,将在背景画布中对其进行渲染。 The background canvas is then copied to the screen which takes less time compared to painting directly on the screen. 然后将背景画布复制到屏幕上,与直接在屏幕上绘画相比,它花费的时间更少。 And while this copying is happening, the object states are updated again and they are rendered on the background canvas again, which is then copied to the screen. 在进行复制的同时,对象状态将再次更新,并再次在背景画布上呈现,然后将其复制到屏幕上。 Repeat this over and over, and you get the double buffering. 一遍又一遍地重复,您将获得双重缓冲。
Basically you keep a buffer of screen which is to be painted and your game renders objects in the buffer which is then copied to the screen. 基本上,您会保留要绘制的屏幕缓冲区,而游戏会在缓冲区中渲染对象,然后将其复制到屏幕上。

Here's a code which I think might help you understand the concept: 这是我认为可以帮助您理解概念的代码:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class GamePanel extends JPanel implements Runnable
{
  private static final long serialVersionUID = 6892533030374996243L;
  public static final int WIDTH = 800;
  public static final int HEIGHT = 600;

  private Thread animator;

  private volatile boolean running = false;
  private volatile boolean isGameOver = false;
  private volatile boolean isUserPaused = false;
  private volatile boolean isWindowPaused = false;

  private Graphics dbg;
  private Image dbImage = null;

  private static final int NO_DELAYS_PER_YIELD = 16;
  private static final int MAX_FRAME_SKIPS = 5;

  private static final Color backgroundColor = new Color(245, 245, 245);

  private static long fps = 30;
  private static long period = 1000000L * (long) 1000.0 / fps;

  private static volatile boolean isPainted = false;

  public GamePanel()
  {
    setBackground(backgroundColor);
    setPreferredSize(new Dimension(WIDTH, HEIGHT));

    setFocusable(true);
    requestFocus();
    readyForPause();

    // Add key listeners here...
  }

  public void addNotify()
  {
    super.addNotify();
    startGame();
  }

  void startGame()
  {
    if (animator == null || !running)
    {
      animator = new Thread(this);
      animator.start();
    }
  }

  void stopGame()
  {
    running = false;
  }

  private void readyForPause()
  {
    addKeyListener(new KeyAdapter()
    {
      public void keyPressed(KeyEvent e)
      {
        int keyCode = e.getKeyCode();
        if ((keyCode == KeyEvent.VK_ESCAPE) || (keyCode == KeyEvent.VK_Q)
            || (keyCode == KeyEvent.VK_END) || (keyCode == KeyEvent.VK_P)
            || ((keyCode == KeyEvent.VK_C) && e.isControlDown()))
        {
          if (!isUserPaused)
            setUserPaused(true);
          else
            setUserPaused(false);
        }
      }
    });
  }

  // This is the game loop. You can copy-paste it even in your own code if you want to.
  public void run()
  {
    long beforeTime, afterTime, timeDiff, sleepTime;
    long overSleepTime = 0L;
    int noDelays = 0;
    long excess = 0L;

    beforeTime = System.nanoTime();

    running = true;

    while (running)
    {
      requestFocus();
      gameUpdate();
      gameRender();
      paintScreen();

      afterTime = System.nanoTime();

      timeDiff = afterTime - beforeTime;
      sleepTime = (period - timeDiff) - overSleepTime;

      if (sleepTime > 0)
      {
        try
        {
          Thread.sleep(sleepTime / 1000000L);
        }
        catch (InterruptedException e)
        {
        }

        overSleepTime = (System.nanoTime() - afterTime - sleepTime);
      }
      else
      {
        excess -= sleepTime;
        overSleepTime = 0L;

        if (++noDelays >= NO_DELAYS_PER_YIELD)
        {
          Thread.yield();
          noDelays = 0;
        }
      }

      beforeTime = System.nanoTime();

      int skips = 0;

      while ((excess > period) && (skips < MAX_FRAME_SKIPS))
      {
        excess -= period;
        gameUpdate();
        skips++;
      }

      isPainted = true;
    }
    System.exit(0);
  }

  private void gameUpdate()
  {
    if (!isUserPaused && !isWindowPaused && !isGameOver)
    {
      // Update the state of your game objects here...
    }
  }

  private void gameRender()
  {
    if (dbImage == null)
    {
      dbImage = createImage(WIDTH, HEIGHT);
      if (dbImage == null)
      {
        System.out.println("Image is null.");
        return;
      }
      else
        dbg = dbImage.getGraphics();
    }

    dbg.setColor(backgroundColor);
    dbg.fillRect(0, 0, WIDTH, HEIGHT);

    // Render your game objects here....
    // like: xyzObject.draw(dbg);
    // or dbg.drawOval(...);

    if (isGameOver)
      gameOverMessage(dbg);
  }

  private void gameOverMessage(Graphics g)
  {
    // Paint a game over message here..
  }

  private void paintScreen()
  {
    Graphics g;

    try
    {
      g = this.getGraphics();
      if ((g != null) && (dbImage != null))
        g.drawImage(dbImage, 0, 0, null);
      Toolkit.getDefaultToolkit().sync();
      g.dispose();
    }
    catch (Exception e)
    {
      System.out.println("Graphics context error : " + e);
    }
  }

  public void setWindowPaused(boolean isPaused)
  {
    isWindowPaused = isPaused;
  }

  public void setUserPaused(boolean isPaused)
  {
    isUserPaused = isPaused;
  }
}

Then you can simply add your game panel to your JFrame like following: 然后,您可以简单地将游戏面板添加到JFrame中,如下所示:

import java.awt.GridBagLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

public class GameFrame extends JFrame
{
  private static final long serialVersionUID = -1624735497099558420L;
  private GameFrame gamePanel = new GamePanel();

  public GameFrame()
  {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setTitle("Game");

    addWindowListener(new FrameListener());

    getContentPane().setLayout(new GridBagLayout());
    getContentPane().add(gamePanel);

    pack();
    setLocationRelativeTo(null);
    setResizable(false);
    setVisible(true);
  }

  public class FrameListener extends WindowAdapter
  {
    public void windowActivated(WindowEvent we)
    {
      gamePanel.setWindowPaused(false);
    }

    public void windowDeactivated(WindowEvent we)
    {
      gamePanel.setWindowPaused(true);
    }

    public void windowDeiconified(WindowEvent we)
    {
      gamePanel.setWindowPaused(false);
    }

    public void windowIconified(WindowEvent we)
    {
      gamePanel.setWindowPaused(true);
    }

    public void windowClosing(WindowEvent we)
    {
      gamePanel.stopGame();
    }
  }

  public static void main(String args[])
  {
    new GameFrame();
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM