java - 立即更改图像

标签 java image swing replace jpanel

我目前正在尝试学习一些关于游戏编程的知识。 我给自己一个播放器类扩展了我自己编写的 Sprite 类。 现在我想知道如何在运行游戏的过程中更改玩家对象的图像。想象一艘宇宙飞船,当按下右箭头键时,它应该是一个不同的图像,向右倾斜。 现在我正在尝试这样做: 当按下按钮时(例如空格)setImage(新图像) 但是现在,当我调用此方法时,我的图像就消失了,而新图像不会出现?

有什么想法吗? 我的主类代码:

    public class Game extends JPanel implements Runnable{
    private static final long serialVersionUID = 1L;

    public boolean isRunning;

    public static final int WIDTH = 320;
    public static final int HEIGHT = 240;
    public static final int SCALE = 2;

    private Player player;

    public Game() {
        addKeyListener(new TAdapter());
        setFocusable(true);
        requestFocus();
        start();
    }

    public void start() {
        isRunning = true;
        new Thread(this).start();
    }

    public void stop() {
        isRunning = false;
    }

    public void run() {
        init();
        while(isRunning) {

            update();
            repaint();

            try {
                Thread.sleep(5);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void init() {
        player = new Player("/ship_blue", WIDTH - 32/2, 400);
    }

    public void update() {
        player.update();
    }

    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D)g;

        drawPlayer(g2d);
    }

    public void drawPlayer(Graphics2D g2d) {
        if(player.isVisible)g2d.drawImage(player.getImage(),(int) player.getX(), (int) player.getY(), null);
    }

    public static void main(String[] args) {
        Game gameComponent = new Game();
        Dimension size = new Dimension(WIDTH*SCALE, HEIGHT*SCALE);

        JFrame frame = new JFrame("Invaders");
        frame.setVisible(true);
        frame.setSize(size);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.add(gameComponent);
    }

    public class TAdapter extends KeyAdapter{
        public void keyPressed(KeyEvent e) {
            player.keyPressed(e);
        }

        public void keyReleased(KeyEvent e) {
            player.keyReleased(e);
        }
    }
}

这是主类,现在是播放器类,我试图在其中的 onPress() 方法中更改图像:

    public class Player extends Sprite{

    private double glideSpeed = .125;
    private int fixY;
    private int xDirection = 0;
    private int yDirection = 1;

    public Player(String source, int x, int y) {
        this.x = x;
        this.y = y;
        ImageIcon ii = new ImageIcon(this.getClass().getResource(source));
        setImage(ii.getImage());
        setTileSize(ii.getIconWidth());
        setSpeed(0.2);
        fixY = y;
    }

    public void update() {
        x += xDirection * 1.4;
        glide(10);
    }

    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();

        if(key == KeyEvent.VK_RIGHT) {
            xDirection = 1;
        }
        if(key == KeyEvent.VK_LEFT) {
            xDirection = -1;
        }
        if(key == KeyEvent.VK_SPACE) {
            ImageIcon ii2 = new ImageIcon("/player_blue_negativ");
            setImage(ii2.getImage()); //<-----Here I am trying to change the image
        }
    }

    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();

        if(key == KeyEvent.VK_RIGHT || key == KeyEvent.VK_LEFT) {
            xDirection = 0;
        }
    }

    public void glide(int span) {
        y += yDirection * glideSpeed;
        if(y - fixY > span || fixY - y > span) {
            yDirection = -yDirection;
        }
    }
}

为了完成这里的所有内容,我的 sprite 类:

    public class Sprite {

    protected double x;
    protected double y;
    protected int tileSize;
    protected double speed;
    protected Image img;
    protected boolean isVisible;

    public Sprite() {
        isVisible = true;
    }

    public double getSpeed() {
        return speed;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }

    public int getTileSize() {
        return tileSize;
    }

    public Image getImage() {
        return img;
    }

    public boolean getVisible() {
        return isVisible;
    }

    public void setSpeed(double speed) {
        this.speed = speed;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }

    public void setTileSize(int tileSize) {
        this.tileSize = tileSize;
    }

    public void setImage(Image img) {
        this.img = img;
    }

    public void die() {
        isVisible = false;
    }
}

最佳答案

if(key == KeyEvent.VK_SPACE) {
    ImageIcon ii2 = new ImageIcon("/player_blue_negativ");

这是一个基本问题。所有图像都应该在事件发生之前加载和缓存。事件发生时,使用缓存的图像,GUI 应立即呈现。

作为mentioned by @camickr , ImageIcon 的使用也巧妙地从 URL 转换为 String(假定代表 文件 路径)。坚持使用从 getResource(..) 获得的 URL

ImageObserver 上。

如果使用 ImageObserver 绘制图像,观察者将被通知异步加载的图像更新。所有组件(例如 JPanel)都实现了 ImageObserver,所以..

g2d.drawImage(player.getImage(),(int) player.getX(), (int) player.getY(), null);

应该是:

g2d.drawImage(player.getImage(),(int) player.getX(), (int) player.getY(), this);

释放 EDT!

class Game extends JPanel implements Runnable ..

Thread.sleep(5);

不要阻塞 EDT(事件调度线程)——当发生这种情况时,GUI 将“卡住”。 也不要尝试从除 EDT 之外的任何东西更新 GUI。

不是在 Runnable 中调用 Thread.sleep(n),而是实现一个 Swing Timer 用于重复任务或一个 SwingWorker 用于长时间运行的任务。参见 Concurrency in Swing了解更多详情。

对 Swing 组件使用 paintComponent(Graphics)!

public void paint(Graphics g) {

应该是:

@Override
public void paintComponent(Graphics g) {

关于java - 立即更改图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18291088/

相关文章:

java - 在单链表上写add方法哪种方式比较好

java - 尝试在方法中访问三角形数组时出现空指针异常

java - 如何查找哪个字段导致不可序列化异常

html - 以较小的尺寸查看时,高质量的主图会变得模糊

java - 使用 JPanels 列表制作表格(使用百分比大小列)

java - Jbutton 带填充的隐形边框

java - 如何让JButton事件修改JFrame(this)

java - 线程和观察者模式。我怎样才能让一个线程通知所有其他线程并执行某个方法/事物?

python PIL : color index to RGB

java - JPanel 不显示图像?