将图像移动到新位置后删除图像

时间:2013-11-29 20:25:35

标签: java animation user-interface sprite

我正在制作游戏小行星。一切功能都正常,但最初我将背景颜色设置为黑色,并在Canvas上移动的形状表示对象。我已经将背景更改为Image,我正在努力更改要由图像表示的对象。

但是,无论背景如何,我都无法在新位置重新绘制图像。在将每个对象移动到每个新位置后,您可以看到它们的路径。我一直专注于射击射击,我注意到如果我在屏幕周围射击,背景会刷新,但它几乎完全是随机的。如果有人能指导我朝着正确的方向前进,那就太棒了!我已经阅读了几个文档,教科书,并观看了几个视频,试图理解。

package comets;


import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import javax.sound.sampled.*;
import javax.swing.*;

import java.util.*;
import java.io.*;
import java.net.URL;

// This class is primarily responsible for organizing the game of Comets
public class CometsMain extends JPanel implements KeyListener 
{



    // GUI Data
    private JFrame frame; // The window itself
    private JPanel playArea;  // The area where the game takes place



    private final int playWidth = 500; // The width of the play area (in pixels)
    private final int playHeight = 500; // The height of the play area (in pixels)

    // Game Data
    private SpaceObject spaceObject;
    private Ship ship; // The ship in play
    private Shot s = new Shot(0, 0, 0, 0);
    private LargeComet large = new LargeComet(0, 0, 0, 0);
    private MediumComet medium = new MediumComet(0, 0, 0, 0);
    private SmallComet small = new SmallComet(0, 0, 0, 0);
    private Vector<Shot> shots; // The shots fired by the player
    private Vector<Comet> comets; // The comets floating around

    private boolean shipDead; // Whether or not the ship has been blown up
    private long shipTimeOfDeath; // The time at which the ship blew up

    // Keyboard data
    // Indicates whether the player is currently holding the accelerate, turn
    // left, or turn right buttons, respectively
    private boolean accelerateHeld = false;
    private boolean turnLeftHeld = false;
    private boolean turnRightHeld = false;
    private boolean slowDownHeld = false;

    // Indicates whether the player struck the fire key
    private boolean firing = false;


    // Create Images 
    private Image background; // background image
    private BufferedImage spaceShip = null;
    private BufferedImage largeComet = null;
    private BufferedImage mediumComet = null;
    private BufferedImage smallComet = null;
    private BufferedImage bullet = null;
    private int type = AlphaComposite.SRC_OVER;
    private float alpha = 0;










    // Set up the game and play!
    public CometsMain()
    {





        // Get everything set up
        configureGUI();
        configureGameData();



        // Display the window so play can begin
        frame.setVisible(true);

        //Use double buffering
        frame.createBufferStrategy(2);

        //play music
        playMusic();

        // Start the gameplay
        playGame();






    }

    private void playMusic(){

        try {

            URL url = this.getClass().getClassLoader().getResource("BackgroundMusic.wav");
            AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);

            Clip clip = AudioSystem.getClip();

            clip.open(audioIn);

            clip.start();
            clip.loop(5);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Set up the initial positions of all space objects
    private void configureGameData()
    {
        // Configure the play area size
        SpaceObject.playfieldWidth = playWidth;
        SpaceObject.playfieldHeight = playHeight;

        // Create the ship
        ship = new Ship(playWidth/2, playHeight/2, 0, 0);

        // Create the shot vector (initially, there shouldn't be any shots on the screen)
        shots = new Vector<Shot>();

        // Read the comets from comets.cfg
        comets = new Vector<Comet>();

        try
        {
            Scanner fin = new Scanner(new File("comets.cfg"));

            // Loop through each line of the file to read a comet
            while(fin.hasNext())
            {
                String cometType = fin.next();
                double xpos = fin.nextDouble();
                double ypos = fin.nextDouble();
                double xvel = fin.nextDouble();
                double yvel = fin.nextDouble();

                if(cometType.equals("Large"))
                    comets.add(new LargeComet(xpos, ypos, xvel, yvel));
                else if(cometType.equals("Medium")){
                    comets.add(new MediumComet(xpos, ypos, xvel, yvel));
                }
                else 
                    comets.add(new SmallComet(xpos, ypos, xvel, yvel));
            }
        }
        // If the file could not be read correctly for whatever reason, abort
        // the program
        catch(FileNotFoundException e)
        {
            System.err.println("Unable to locate comets.cfg");
            System.exit(0);
        }
        catch(Exception e)
        {
            System.err.println("comets.cfg is not in a proper format");
            System.exit(0);
        }
    }

    // Set up the game window
    private void configureGUI()
    {
        // Load Images & Icons
        // Background Image
        try {
            background = ImageIO.read(this.getClass().getClassLoader().getResource("galaxy.jpg"));
        } catch (IOException e) {
        }

        // Space Ship Image
        try {
            spaceShip = ImageIO.read(this.getClass().getClassLoader().getResource("ship.png"));
        } catch (IOException e) {
        }

        // Large Comet Image
        try {
            largeComet = ImageIO.read(this.getClass().getClassLoader().getResource("largecomet.png"));
        } catch (IOException e) {
        }

        // Medium Comet Image
        try {
            mediumComet = ImageIO.read(this.getClass().getClassLoader().getResource("mediumcomet.png"));
        } catch (IOException e) {
        }

        // Medium Comet Image
        try {
            smallComet = ImageIO.read(this.getClass().getClassLoader().getResource("smallcomet.png"));
        } catch (IOException e) {
        }

        // bullet Image
        try {
            bullet = ImageIO.read(this.getClass().getClassLoader().getResource("bullet.png"));
        } catch (IOException e) {
        }





        // Create the window object
        frame = new JFrame("Comets");
        frame.setSize(playWidth+20, playHeight+35);
        frame.setResizable(false);


        // The program should end when the window is closed
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);



        frame.setSize(playWidth, playHeight);
        // Set the window's layout manager
        frame.setLayout(new FlowLayout());



        // Create background
        JLabel bgLabel = new JLabel( new ImageIcon(background.getScaledInstance(playWidth, playHeight, 0) ) );
        bgLabel.setSize(playWidth, playHeight);
        frame.setContentPane(bgLabel);
        frame.pack();



        // Create the play area
        playArea = new JPanel();
        playArea.setSize(playWidth, playHeight);
        playArea.setFocusable(false);
        playArea.setOpaque(false);
        frame.add(playArea);






        // Make the frame listen to keystrokes
        frame.addKeyListener(this);


    }


    // The main game loop. This method coordinates everything that happens in
    // the game
    private void playGame()
    {


        while(true)
        {
            // Measure the current time in an effort to keep up a consistent
            // frame rate
            long time = System.currentTimeMillis();

            // If the ship has been dead for more than 3 seconds, revive it
            if(shipDead && shipTimeOfDeath + 3000 < time)
            {
                shipDead = false;
                ship = new Ship(playWidth/2, playHeight/2, 0, 0);
            }

            // Process game events, move all the objects floating around,
            // and update the display
            if(!shipDead)
            handleKeyEntries();
            handleCollisions();
            moveSpaceObjects();

            // Sleep until it's time to draw the next frame 
            // (i.e. 32 ms after this frame started processing)
            try
            {
                long delay = Math.max(0, 32-(System.currentTimeMillis()-time));

                Thread.sleep(delay);
            }
            catch(InterruptedException e)
            {
            }

        }
    }

    // Deal with objects hitting each other
    private void handleCollisions()
    {
        // Anything that is destroyed should be erased, so get ready
        // to erase stuff
        Graphics g = playArea.getGraphics();
        Graphics2D g2d = (Graphics2D) g;
        g2d.setComposite(AlphaComposite.getInstance(type, alpha));

        // Deal with shots blowing up comets
        for(int i = 0; i < shots.size(); i++)
        {
            Shot s = shots.elementAt(i);
            for(int j = 0; j < comets.size(); j++)
            {
                Comet c = comets.elementAt(j);

                // If a shot has hit a comet, destroy both the shot and comet
                if(s.overlapping(c))
                {

                    // Erase the bullet
                    shots.remove(i);
                    i--;
                    repaint((int)shots.elementAt(i).getXPosition(), (int)shots.elementAt(i).getYPosition(), (int)(2*shots.elementAt(i).getRadius()), (int)(2*shots.elementAt(i).getRadius()));

                    // If the comet was actually destroyed, replace the comet
                    // with the new comets it spawned (if any)
                    Vector<Comet> newComets = c.explode();

                    if(newComets != null)
                    {

                        paintComponent(g);
                        comets.remove(j);
                        j--;
                        comets.addAll(newComets);
                    }
                    break;
                }
            }
        }

        // Deal with comets blowing up the ship
        if(!shipDead)
        {
            for(Comet c : comets)
            {
                // If the ship hit a comet, kill the ship and mark down the time 
                if(c.overlapping(ship))
                {
                    shipTimeOfDeath = System.currentTimeMillis();
                    shipDead = true;
                    spaceObject=ship;
                    paintComponent(g);
                }
            }
        }
    }

    // Check which keys have been pressed and respond accordingly
    private void handleKeyEntries()
    {
        // Ship movement keys
        if(accelerateHeld)
            ship.accelerate();

        if(slowDownHeld)
            ship.slowDown();

        // Shooting the cannon
        if(firing)
        {
            firing = false;
            shots.add(ship.fire());
        }


    }

    // Deal with moving all the objects that are floating around
    private void moveSpaceObjects()
    {
        Graphics g = playArea.getGraphics();


        // Handle the movements of all objects in the field
        if(!shipDead)
        updateShip(g);
        updateShots(g);
        updateComets(g);        
    }

    // Move all comets and draw them to the screen
    private void updateComets(Graphics g)
    {


        for(Comet c : comets)
        {
            spaceObject=c;
            paintComponent(g);

            // Move the comet to its new position
            c.move();


            paintComponent(g);

        }
    }


    // Move all shots and draw them to the screen
    private void updateShots(Graphics g)
    {

        for(int i = 0; i < shots.size(); i++)
        {
            Shot s = shots.elementAt(i);

            // Erase the shot at its old position
            paintComponent(g);


            // Move the shot to its new position
            s.move();

            // Remove the shot if it's too old
            if(s.getAge() > 180)
            {
                shots.remove(i);
                i--;
            }
            // Otherwise, draw it at its new position
            else
            {
                moveImage(g, s, (int)s.getXPosition(), (int)s.getYPosition());
                paintComponent(g);
            }       
        }
    }


    // Moves the ship and draws it at its new position
    private void updateShip(Graphics g)
    {
        // Erase the ship at its old position
        paintComponent(g);

        // Ship rotation must be handled between erasing the ship at its old position
        // and drawing it at its new position so that artifacts aren't left on the screen
        if(turnLeftHeld)
            ship.rotateLeft();
        if(turnRightHeld)
            ship.rotateRight();
        ship.move();

        // Draw the ship at its new position
        moveImage(g, ship, (int)ship.getXPosition(), (int)ship.getYPosition());
        paintComponent(g);
    }

    // Draws this ship s to the specified graphics context
    private void drawShip(Graphics g, Ship s)
    {




        Graphics2D ship = (Graphics2D) spaceShip.getGraphics();

        double x = Math.sin(s.getAngle());
        double y = Math.cos(s.getAngle());


        AffineTransform transformsave = AffineTransform.getRotateInstance(x, y, spaceShip.getWidth()/2, spaceShip.getHeight()/2);
        AffineTransformOp transform = new AffineTransformOp( transformsave, AffineTransformOp.TYPE_BILINEAR );


        // Figure out where the ship should be drawn
        int xCenter = (int)s.getXPosition();
        int yCenter = (int)s.getYPosition();



        // Draw the ship body
        g.drawImage(transform.filter(spaceShip, null), xCenter-10, yCenter-20, null);
        ship.setTransform(transformsave);


    }

    public void setSpaceObject(SpaceObject s){
        spaceObject=s;
    }

    public SpaceObject getSpaceObject(){
        return spaceObject;
    }

    @Override
    protected void paintComponent( Graphics g ){
        super.paintComponent(g);

        spaceObject=getSpaceObject();
        int radius = (int)s.getRadius();
        int xCenter = (int)s.getXPosition();
        int yCenter = (int)s.getYPosition();

        // Draw the object
        if(spaceObject==s)
            g.drawImage( bullet, xCenter-radius, yCenter-radius, this );
        else if(spaceObject==large)
            g.drawImage( largeComet, xCenter-radius, yCenter-radius, this );
        else if(spaceObject==medium)
            g.drawImage( mediumComet, xCenter-radius, yCenter-radius, this );
        else if(spaceObject==small)
            g.drawImage( smallComet, xCenter-radius, yCenter-radius, this );
        else if(spaceObject==ship)
            drawShip(g, ship);



    }

    public void moveImage(Graphics g, SpaceObject s, int x, int y){
        int radius = (int)s.getRadius();
        int xCenter=0, yCenter=0;



        if(xCenter!=x || yCenter!=y){

            xCenter= (int)s.getXPosition();
            yCenter = (int)s.getYPosition();
            repaint(xCenter, yCenter, radius*2, radius*2);
        }


    }



    // Deals with keyboard keys being pressed
    public void keyPressed(KeyEvent key)
    {
        // Mark down which important keys have been pressed
        if(key.getKeyCode() == KeyEvent.VK_UP)
            this.accelerateHeld = true;
        if(key.getKeyCode() == KeyEvent.VK_LEFT)
            this.turnLeftHeld = true;
        if(key.getKeyCode() == KeyEvent.VK_RIGHT)
            this.turnRightHeld = true;
        if(key.getKeyCode() == KeyEvent.VK_SPACE)
            this.firing = true;
        //ADD DOWN TO SLOW DOWN SHIP!!!
        if(key.getKeyCode() == KeyEvent.VK_DOWN)
            this.slowDownHeld = true;
    }

    // Deals with keyboard keys being released
    public void keyReleased(KeyEvent key)
    {
        // Mark down which important keys are no longer being pressed
        if(key.getKeyCode() == KeyEvent.VK_UP)
            this.accelerateHeld = false;
        if(key.getKeyCode() == KeyEvent.VK_LEFT)
            this.turnLeftHeld = false;
        if(key.getKeyCode() == KeyEvent.VK_RIGHT)
            this.turnRightHeld = false;
        //ADD DOWN TO SLOW DOWN SHIP!!!
        if(key.getKeyCode() == KeyEvent.VK_DOWN)
            this.slowDownHeld = false;
    }

    // This method is not actually used, but is required by the KeyListener interface
    public void keyTyped(KeyEvent arg0)
    {
    }





    public static void main(String[] args)
    {



        // A GUI program begins by creating an instance of the GUI
        // object. The program is event driven from that point on.
        new CometsMain();



    }

}

3 个答案:

答案 0 :(得分:2)

请勿使用getGraphics。这个问题,只是它是上次绘制的一个快照。

这就像拿一张纸并反复在它上面画画一样,它真的很快就会变得非常混乱。

getGraphics也可以返回null

在Swing中,绘画是由RepaintManager控制的,它决定了什么时候应该画什么。

您应该遵循的基本概念是......

  • 更新游戏模型的状态
  • 更新游戏模型视图
  • 将视图渲染到屏幕

这可以通过几种不同的方式实现,但首先,如果要对UI进行更新,则应覆盖从{{1}这样的扩展的组件的paintComponent方法。 }。

调用时,请调用JComponent,这将自动准备super.paintComponent上下文进行绘画。

更新视图......

你可以......

  • 在后台线程中,更新游戏模型并请求重新绘制视图
  • 在视图的Graphics方法中,重新绘制模型

这是一种相对简单的方法,但如果控制得不好,可以使视图和模型不同步。您还需要确保在更新视图时不更改模型...

或者,你可以......

  • 创建两个(或更多)paintComponent
  • 在后台主题中,更新游戏模型
  • 在后台线程中,更新“offscreen”缓冲区以表示当前游戏模型状态
  • 切换缓冲的图像(将“屏幕外”缓冲区移动到“活动屏幕”,将“活动屏幕”移动到“屏幕外”)
  • 请求更新视图
  • 在视图的BufferedImages方法中,只需绘制“活动屏幕”
  • 即可

这是一个更复杂的过程,需要您确保缓冲区的大小与视图相同,但这意味着模型可以独立于视图重新绘制进行更新。在绘制视图时,仍然存在更改“关闭”和“活动”屏幕缓冲区的危险。

您可以通过使用某种队列稍微提升此过程,您可以在其中放置paintComponent可以用于渲染(通过将它们从队列中弹出)并让“视图”再次将它们推回一旦它渲染它......

或者这些的一些组合,您可以锁定“活动”和“关闭”屏幕缓冲区的切换,以确保没有绘制“活动”缓冲区。

请查看Performing Custom PaintingPainting in AWT and Swing了解详情

例如......

答案 1 :(得分:0)

现代图形应用程序使用以下方法:

对于每一帧重复这些步骤

  1. 擦除屏幕
  2. 绘制背景
  3. 按正确顺序绘制对象
  4. 做其他事情
  5. 使用这种方法,您不需要跟踪对象的先前位置,这可能非常棘手,因为对象可能会重叠。

    当然,由于性能不足,这会导致闪烁。存在各种防止此问题的算法,请查看此Documentation和此Question

答案 2 :(得分:0)

每次使用 getContentPane().repaint() 时都可以使用 repaint()