3

我正在开发一个 Java 项目来模拟直升机在框架中的飞行。直升机使用箭头键在屏幕上移动。我希望直升机能够无限移动,即当直升机到达画面边缘时,背景应该向相反的方向移动,以产生无尽地形的效果。

这是我到目前为止的代码:

import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.io.IOException;

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

public class MainFrame extends JFrame
{
    private static int FRAME_WIDTH = 800;
    private static int FRAME_HEIGHT = 500;

    public MainFrame()
    {
        add(new AnotherBackground(FRAME_WIDTH, FRAME_HEIGHT));
        setTitle("Helicopter Background Test");
        setSize(FRAME_WIDTH,FRAME_HEIGHT);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

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

class AnotherBackground extends JPanel
{
private BufferedImage heliImage = null;
private BufferedImage backImage = null;

private int heliX = 0;
private int heliY = 0;

private int backX = 0;
private int backY = 0;

private int frameWidth = 0;
private int frameHeight = 0;

private int backWidth = 0;
private int backHeight = 0;

public AnotherBackground(int fWidth, int fHeight)
{
    frameWidth = fWidth;
    frameHeight = fHeight;

    this.setFocusable(true);
    this.addKeyListener(new HeliListener());

    try
    {
        heliImage = ImageIO.read(new URL("http://imageshack.us/a/img7/2133/helicopter2f.png"));
        // 2.7 Meg Crap that is a humungous image!  Substitute dummy.
        backImage = new BufferedImage(1918,1200,BufferedImage.TYPE_INT_RGB);
    }

    catch(IOException ex)
    {
        System.out.println("Problem durinng loading heli image");
    }

    backWidth = backImage.getWidth();
    backHeight = backImage.getHeight();

    HeliPainter l = new HeliPainter();
    new Thread(l).start();
}

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

    g.drawImage(backImage, backX, backY, null);
    g.drawImage(heliImage, heliX, heliY, null);

}

class HeliListener extends KeyAdapter
{
    @Override
    public void keyPressed(KeyEvent e)
    {
        System.out.println(heliX + " " + heliY + " " + backX + " " + backY);

        if (e.getKeyCode() == KeyEvent.VK_LEFT)
        {
            if(heliX > 0)
            {
                heliX -= 5;
            }

            else
            {
                backX += 5;
            }
        }

        else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
        {
            if(heliX < frameWidth)
            {
                heliX += 5;
            }

            else
            {
                backX -= 5;
            }
        }

        else if (e.getKeyCode() == KeyEvent.VK_UP)
        {
            if(heliY > 0)
            {
                heliY -= 5;
            }

            else
            {
                backY += 5;
            }
        }

        else if (e.getKeyCode() == KeyEvent.VK_DOWN)
        {
            if(heliY < frameHeight)
            {
                heliY += 5;
            }

            else
            {
                backY -= 5;
            }
        }
    }
}

class HeliPainter implements Runnable
{
    @Override
    public void run()
    {
        try
        {
            while(true)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        repaint();
                    }
                });

                Thread.sleep(1);
            }
        }

        catch(InterruptedException ex)
        {
            System.out.println("Problem putting thread to sleep");
        }
    }
}
}

现在代码中有两个图像。一个是小型直升机,另一个是大型(2.7 兆)背景。他们在这里:

如何连续显示BG?

4

2 回答 2

5

看看这个以更可预测的方式运行的源,还包括对斩波器图像(动画)的一个很好的调整。;)

带 BG 的滚动车辆

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.io.IOException;

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

public class MainFrame
{
    public MainFrame()
    {
        JFrame f = new JFrame("Helicopter Background Test");
        f.add(new AnotherBackground());
        //setTitle("Helicopter Background Test");  Redundant..
        // Set a preferred size for the content area and pack() the frame instead!
        // setSize(FRAME_WIDTH,FRAME_HEIGHT);
        // setLocationRelativeTo(null); Better to..
        f.setLocationByPlatform(true);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack(); // Size the GUI - VERY MPORTANT!
        f.setVisible(true);
    }

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

class AnotherBackground extends JPanel
{
    private static int PREFERRED_WIDTH = 400;
    private static int PREFERRED_HEIGHT = 200;

    private BufferedImage heliImage = null;
    private BufferedImage heliLeftImage = null;
    private BufferedImage heliRightImage = null;
    private BufferedImage backImage = null; //getFlippedImage(


    private int heliX = 0;
    private int heliY = 0;

    private int backX = 0;
    private int backY = 0;

    private int frameWidth = 0;
    private int frameHeight = 0;

    private int backWidth = 0;
    private int backHeight = 0;

    public AnotherBackground()
    {
        frameWidth = PREFERRED_WIDTH;
        frameHeight = PREFERRED_HEIGHT;

        this.setFocusable(true);
        this.addKeyListener(new HeliListener());

        try
        {
            heliLeftImage = ImageIO.read(
                new URL("http://imageshack.us/a/img7/2133/helicopter2f.png"));
            heliRightImage = getFlippedImage(heliLeftImage);
            heliImage = heliLeftImage;
            // 2.7 Meg Crap that is an humungous image!  Substitute dummy.
            backImage = getTileImage(250);
            //ImageIO.read(
            //  new URL("http://i.stack.imgur.com/T5uTa.png"));

            backWidth = backImage.getWidth();
            backHeight = backImage.getHeight();

            //HeliPainter l = new HeliPainter();  //  see mention of repaint()
            //new Thread(l).start();
        } catch(IOException ex) {
            // THERE IS NO POINT CONTINUING AFTER THIS POINT!
            // unless it is to pop an option pane error message..
            System.err.println("Problem during loading heli image");
            ex.printStackTrace();
        }

    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT);
    }

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

        int normalizeX = (heliRealX-heliX)%backImage.getWidth();
        int normalizeY = (heliRealY-heliY)%backImage.getHeight();
        int timesRepeatX = (getWidth()/backImage.getWidth())+2;
        int timesRepeatY = (getHeight()/backImage.getHeight())+2;

        for (int xx=-1; xx<timesRepeatX; xx++) {
            for (int yy=-1; yy<timesRepeatY; yy++) {
                g.drawImage(
                    backImage,
                    (xx*backImage.getWidth())-normalizeX,
                    (yy*backImage.getHeight())-normalizeY,
                    this);  // A JPanel IS AN ImageObserver!
                g.drawImage(heliImage, heliX, heliY, this);
            }
        }
        g.setColor(Color.BLACK);
    }

    private int heliRealX = 0;
    private int heliRealY = 0;

    class HeliListener extends KeyAdapter
    {
        @Override
        public void keyPressed(KeyEvent e)
        {
            int pad = 5;
            if (e.getKeyCode() == KeyEvent.VK_LEFT)
            {
                if(heliX > 0)
                {
                    heliX -= 5;
                }
                else
                {
                    backX += 5;
                }
                heliRealX-=5;
                heliImage = heliLeftImage;
            }
            else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
            {
                // correct for image size + padding
                if(heliX+heliImage.getWidth()+pad < getWidth())
                {
                    heliX += 5;
                }
                else
                {
                    backX -= 5;
                }
                heliRealX+=5;
                heliImage = heliRightImage;
            }

            else if (e.getKeyCode() == KeyEvent.VK_UP)
            {
                if(heliY > 0)
                {
                    heliY -= 5;
                }
                else
                {
                    backY += 5;
                }
                heliRealY-=5;
            }

            else if (e.getKeyCode() == KeyEvent.VK_DOWN)
            {
                // correct for image size + padding
                if(heliY+heliImage.getHeight()+pad < getHeight())
                {
                    heliY += 5;
                }
                else
                {
                    backY -= 5;
                }
                heliRealY+=5;
            }
            repaint(); // Replaces need for threads for this simple demo!
        }
    }

    public BufferedImage getFlippedImage(BufferedImage original) {
        BufferedImage bi = new BufferedImage(
            original.getWidth(),
            original.getHeight(),
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bi.createGraphics();

        AffineTransform at = AffineTransform.getTranslateInstance(bi.getWidth(),1d);
        at.concatenate(AffineTransform.getScaleInstance(-1d,1d));
        g.setTransform(at);
        g.drawImage(original,0,0,this);

        g.dispose();
        return bi;
    }

    public BufferedImage getTileImage(int s) {
        BufferedImage bi = new BufferedImage(s,s,BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bi.createGraphics();

        GradientPaint gp1 = new GradientPaint(
            (float)0,(float)s/4, Color.YELLOW,
            (float)s/4,0f, Color.GREEN,
            true);
        g.setPaint(gp1);
        g.fillRect(0,0,s,s);

        int trans = 165;
        GradientPaint gp2 = new GradientPaint(
            (float)s/2,(float)s/2, new Color(255,0,0,trans),
            0f,(float)s/2, new Color(255,255,255,trans),
            true);
        g.setPaint(gp2);
        g.fillRect(0,0,s,s);

        g.dispose();
        return bi;
    }
}
于 2013-04-22T05:48:46.483 回答
4

这是一个非常简单的例子(你只能在一个方向上移动)。基本思想是有一种prepareView方法负责根据可用的可视区域生成世界视图。如果视图试图查看地图之外的区域,则地图的标题会弥补它。

在此处输入图像描述

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class InfiniteBackground {

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

    public InfiniteBackground() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        protected static final int DELTA = 5;
        private BufferedImage terrian;
        private BufferedImage heli;
        private Point pov;
        private Point heliPoint;
        private BufferedImage view;

        public TestPane() {
            pov = new Point();
            heliPoint = new Point();
            try {
                terrian = ImageIO.read(getClass().getResource("/terrain_map.jpg"));
                heli = ImageIO.read(getClass().getResource("/helicopter2f.png"));

                pov.x = terrian.getWidth() - getPreferredSize().width;
                pov.y = ((terrian.getHeight() - getPreferredSize().height) / 2);

                heliPoint.x = getPreferredSize().width / 2;
                heliPoint.y = getPreferredSize().height / 2;

                prepareView();

                InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
                ActionMap am = getActionMap();

                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "goLeft");
                am.put("goLeft", new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        heliPoint.x -= DELTA;
                        if (heliPoint.x - (heli.getWidth() / 2) < 0) {
                            heliPoint.x = (heli.getWidth() / 2);
                            prepareView();
                            pov.x -= DELTA;
                        }
                        repaint();
                    }
                });

            } catch (IOException ex) {
                ex.printStackTrace();
            }

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 200);
        }

        protected void prepareView() {
            if (getWidth() > 0 && getHeight() > 0) {
                view = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
                Graphics2D g2d = view.createGraphics();
                if (pov.x < 0) {
                    pov.x = terrian.getWidth();
                }
                g2d.drawImage(terrian, -pov.x, -pov.y, this);
                if (pov.x + getWidth() > terrian.getWidth()) {
                    g2d.drawImage(terrian, -pov.x + terrian.getWidth(), -pov.y, this);
                }
                g2d.dispose();
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (terrian != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                if (view == null) {
                    prepareView();
                }
                g2d.drawImage(view, 0, 0, this);
                g2d.drawImage(heli, heliPoint.x - (heli.getWidth() / 2), heliPoint.y - (heli.getHeight() / 2), this);
                g2d.dispose();
            }
        }
    }
}
于 2013-04-22T02:55:05.963 回答