Swing MapPanel更新图形

时间:2015-07-07 15:55:18

标签: java swing animation jpanel

尝试使用图形地图概述创建面板。地图概览显示完整地图的10x10平铺(因此始终只有某个区域)。这导致有100个MapTile对象,每个对象代表MapPanel类中的一个tile。每个MapTile都包含一个Field对象,它当前正在显示。一个字段对象可以保存很多数据,比如它是否被阻塞,哪个人站在字段上,字段类型等等(可能的类型是草,泥土,石头等)。

每当有什么变化我需要更新MapPanel以便它显示实际情况而不是我用它实例化的那个。这是我目前失败的地方。

这是我到目前为止所做的:

public class MapTile extends JPanel {
    private BufferedImage backgroundImage;
    private BufferedImage fighterImage;
    private Field field;

    stuff...

    public MapTile(Field field) throws MidWarGeneralException {
        loadBackgroundImage(field.getType());
        if(field.isOccupied()) {
            loadFighterImage(field.getFighter().getTeam());
        }
        setToolTip(field);
        this.field = field;
    }

    private void setToolTip(Field field) {
        if(field.isOccupied()) {
            setToolTipText(field.getX() + "/" + field.getY() + "\n"
                    + "used by: " + field.getFighter().getName() + "(Team: " + field.getFighter().getTeam().getName()
                    + ")\n" + "Type: " + field.getType().getName());
        }
        else {
            setToolTipText(field.getX() + "/" + field.getY() + "\n" +
                    "Type: " + field.getType().getName());
        }
    }

    private void loadBackgroundImage(TileType type) {
        stuff...
    }

    private void loadFighterImage(Team team) {
       stuff ...
    }

    public void update(Field field) {
        this.field = field;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);
        Graphics2D g2d = (Graphics2D) graphics;
        g2d.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
        if(fighterImage != null) {
            g2d.drawImage(fighterImage, 0, 0, getWidth(), getHeight(), this);
        }
    }
}

load()函数只会根据当前字段对象的当前数据加载适当的图像。我想要的是:MapTile对象总是有一个背景(grass.png,stone.png等),如果该字段被一个人占用,它将以团队的颜色绘制person.jpg。到目前为止,这确实有效,但是我无法更新视图。

视图需要在以下时间更新:

  1. 我们改变渲染区域(地图也可以是例如200x200,但我们总是只渲染它的10x10区域。所以我们可以在每个方向“行走”并渲染地图的不同区域)
  2. 移动的人(只需更新旧字段和新字段)
  3. 一个人死亡(只是更新旧字段)
  4. 这是我的MapPanel类:

    public class MapPanel extends JPanel {
        private Map map;
        private int currentX;
        private int currentY;
        private List<MapTile> tiles;
    
        public MapPanel(Map map) {
            this.map = map;
            this.currentX = 0;
            this.currentY = 0;
            this.tiles = new ArrayList<>();
    
            init();
        }
    
        private int[] calcRenderArea() {
            currentX = (currentX > map.getWidth()) ? map.getWidth() : currentX;
            currentY = (currentY > map.getHeight()) ? map.getHeight() : currentY;
    
            int difX = map.getWidth() - currentX;
            int difY = map.getHeight() - currentY;
    
            currentX = (difX < 10) ? currentX - (10 - difX) : currentX;
            currentX = (difY < 10) ? currentY - (10 - difY) : currentY;
    
            return new int[]{currentX, currentY};
        }
    
        private void render() {
            int[] offsets = calcRenderArea();
            int tileCounter = 0;
            for(int x = offsets[0]; x < 10; x++) {
                for(int y = offsets[1]; y < 10; y++, tileCounter++) {
                    tiles.get(tileCounter).update(map.getField(x + offsets[0], y + offsets[1]));
                }
            }
        }
    
        private void init() {
            setLayout(new GridLayout(10, 10));
            for(int i = 0; i < 10; i++) {
                for(int j = 0; j < 10; j++) {
                    MapTile tile = new MapTile(map.getField(i, j));
                    tile.setBorder(BorderFactory.createLineBorder(GUIConfig.BORDER_COLOR));
                    add(tile);
                    tiles.add(tile);
                }
            }
        }
    
        public void toLeft() {
            currentX -= 1;
            update();
        }
    
        public void toRight() {
            currentX += 1;
            update();
        }
    
        public void toTop() {
            currentY -= 1;
            update();
        }
    
        public void toBottom() {
            currentY += 1;
            update();
        }
    
        public void update() {
            // Todo :fix the map panel updating
            render();
        }
    }
    

    所以我到目前为止搜索了很多,发现了一些关于JPanel中几张图片的帖子但没有关于如何更新它们的帖子......我试过这样默认的repaint();这不起作用。有人有什么想法吗?谢谢!

1 个答案:

答案 0 :(得分:2)

看起来您需要改进MapTile的update(Field field)方法,以便它从Field对象中提取所有信息,类似于构造函数。

即,

    public final void update(Field field) {
        // this.field = field;
        loadBackgroundImage(field.getType());
        if(field.isOccupied()) {
            loadFighterImage(field.getFighter().getTeam());
        }
        setToolTip(field);
        this.field = field;
        repaint();
    }

    public MapTile(Field field) throws MidWarGeneralException {
        updateField(field);
    }

但是作为一个&#34;的一面&#34;推荐,一个不会解决原始问题但可能有助于解决未来问题的建议,我建议您将程序结构更改为更多MVC(模型 - 视图 - 控制)类型结构,并拥有您的视图 - 上面的GUI,监听模型的更改(程序的逻辑部分),并在发生更改时自行更新。