JLabel和JLayeredPane – 如何在另一张图像上显示图像?

我尝试在java中创建一个小游戏,但我遇到了麻烦。

当我绘制地图时,我无法在不覆盖正方形的标题集的情况下显示字符。

我的目标是能够在同一个方块上显示许多图片(如草的标题集,角色和树),所以我必须处理我的图片的透明度(这不是问题)和图层(这是问题)。

那么如何在另一张图像上显示图像呢?

如何向java解释我需要在另一个图像上或下面显示此图像?

这是我的源代码。 我不知道是不是可以帮到你。 如果你给我一个能够管理图层的线索或function,你的帮助对我来说真的很有帮助。 对我来说重写所有代码没用.x)这个程序不完整,我只用它来测试我的程序。 我知道他刷了两次地图,所以他覆盖了角色的方格(他还有很多其他的小故障),但这不是我问题的目的。 我尝试一步一步完成我的游戏!

import javax.swing.JFrame; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.SwingUtilities; public class Window extends Thread { private static JFrame window = new JFrame("game"); public void run() { Map map = new Map(); Characters characters = new Characters(); window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); window.setSize(Settings.sizeX, Settings.sizeY); window.setLocationRelativeTo(null); window.setResizable(false); window.setVisible(true); map.start(); characters.start(); } private static void reload() throws Exception { SwingUtilities.updateComponentTreeUI(window); } private static class Map extends Thread { private int numberSquareX = Settings.sizeX / 20 + 1; private int numberSquareY = Settings.sizeY / 20 + 1; private JLabel square[][] = new JLabel[numberSquareX][numberSquareY]; public void run() { for (int x = 0, y = 0; y < numberSquareY; x++) { square[x][y] = new JLabel(new ImageIcon("grass_1.png")); square[x][y].setBounds(x * 20, y * 20, 20, 20); window.add(square[x][y]); if (x == numberSquareX - 1) { y++; x = -1; } } square[numberSquareX - 1][numberSquareY - 1] = new JLabel(new ImageIcon("grass_1.png")); square[numberSquareX - 1][numberSquareY - 1].setBounds(numberSquareX * 20, numberSquareY * 20, 20, 20); window.add(square[numberSquareX - 1][numberSquareY - 1]); try { reload(); } catch (Exception e) { } return; } } private class Characters extends Thread { private JLabel square[][] = new JLabel[1][1]; public void run() { square[0][0] = new JLabel(new ImageIcon("character_1.png")); square[0][0].setBounds(Test.posX, Test.posX, 20, 20); window.add(square[0][0]); try { reload(); } catch (Exception e) { } return; } } } 

我已经找到了这个主题: 如何使用JLayered Pane在另一个图像上显示图像? 这是为Java Swing创建合成图像输出的最佳实践,但它们并没有真正帮助我…

我继续搜索答案。 如果我找到它,我会回来发布它。

解决了。

感谢MadProgrammer的评论。

将标题映射渲染为BufferedImage,无论是整体还是基于可用的可视区域,这都是更高效的。 将其绘制到屏幕上,然后在角色上绘制你的角色 – MadProgrammer

在15年以上的专业Java / Swing开发中,我从未发现需要使用SwingUtilities.updateComponentTreeUI(window);而是简单地在负责渲染器输出的组件上调用repaint,我很确定,你会发现这更有效率。 – MadProgrammer

Swing也是一个单线程环境并且不是线程安全的,您不应该从事件调度线程的上下文之外更新UI,因为这将设置竞争条件并可能导致不必要且难以解决的图形问题。 – MadProgrammer

暗示。 JLabel是Container的后代,这意味着它可以包含其他组件;) – MadProgrammer

非常感谢MadProgrammer! 所以我用window.repaint()替换了SwingUtilities.updateComponentTreeUI(window)。 你有正确的线程安全,我的地图有一些错误,但我无法找到它们的来源。 那么BufferedImage呢? 如果我创建两个BufferedImage,最后一个可以自动在第一个上面吗? 或者我只想将标题映射渲染为BufferedImage(所以我受限于2层)? – 席琳

这取决于你想要达到的目标。 使用BufferedImages可以完全控制图像的位置,是的,一个可以渲染到另一个,绘画就像一个艺术家canvas,当你添加东西时,它们被添加到已经存在的东西上,但是,你可能会发现将JLabel添加到另一个JLabel更容易 – 只记得,JLabel默认没有布局管理器 – MadProgrammer

代码示例:

 import javax.swing.JFrame; import javax.swing.ImageIcon; import javax.swing.JLabel; public class Window extends Thread { private static JFrame window = new JFrame("game"); private int numberSquareX = Settings.sizeX / 20 + 1; private int numberSquareY = Settings.sizeY / 20 + 1; private JLabel titlesetLayer1[][] = new JLabel[numberSquareX][numberSquareY]; private JLabel titlesetLayer2[] = new JLabel[1]; private JLabel titlesetLayer3[] = new JLabel[1]; private JLabel titlesetLayer4[] = new JLabel[0]; private JLabel titlesetLayer5[] = new JLabel[0]; private JLabel characters[] = new JLabel[2]; public void run() { window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); window.setSize(Settings.sizeX, Settings.sizeY); window.setLocationRelativeTo(null); window.setResizable(false); // draw layer5 (on the layer4) // draw layer4 (on the layer3) // draw layer3 (on the characters) titlesetLayer3[0] = new JLabel(new ImageIcon("tree_1.png")); titlesetLayer3[0].setBounds(130, 120, 126, 160); window.add(titlesetLayer3[0]); // draw the charaters characters[1] = new JLabel(new ImageIcon("character_1.png")); characters[1].setBounds(600, 500, 100, 100); window.add(characters[1]); characters[0] = new JLabel(new ImageIcon("character_1.png")); characters[0].setBounds(100, 100, 100, 100); window.add(characters[0]); // draw layer2 (under the characters) titlesetLayer2[0] = new JLabel(new ImageIcon("tree_1.png")); titlesetLayer2[0].setBounds(570, 400, 126, 160); window.add(titlesetLayer2[0]); // draw layer1 (under the layer2) for (int x = 0, y = 0; y < numberSquareY; x++) { titlesetLayer1[x][y] = new JLabel(new ImageIcon("grass_1.png")); titlesetLayer1[x][y].setBounds(x * 20, y * 20, 20, 20); window.add(titlesetLayer1[x][y]); if (x == numberSquareX - 1) { y++; x = -1; } } titlesetLayer1[numberSquareX - 1][numberSquareY - 1] = new JLabel(new ImageIcon("grass_1.png")); titlesetLayer1[numberSquareX - 1][numberSquareY - 1].setBounds(numberSquareX * 20, numberSquareY * 20, 20, 20); window.add(titlesetLayer1[numberSquareX - 1][numberSquareY - 1]); window.setVisible(true); // window.repaint(); } } 

屏幕截图:

例 1

另一种解决方案是使用JLayeredPane!

 JLayeredPane layers = new JLayeredPane(); layers.add(tilesetsUnderCharacter, 0); // Layer 0 layers.add(character, 1); // Layer 1 layers.add(tilesetsOnCharacter, 2); // Layer 2 frame.setContentPane(layers); 

代码示例:

 private void init() { frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); frame.setSize(Settings.getX(), Settings.getY()); frame.setResizable(false); frame.setLocationRelativeTo(null); for (int i = 0; i < y ; i++) { for (int j = 0; j < x; j++) { for (int k = 0; k < tilesetsOnCharactersSize; k++) { tilesetsOnCharacters[i][j][k] = new javax.swing.JLabel(new javax.swing.ImageIcon(Resources.getTileset(Maps.getMapTileset(mapNumber, 1, k, i, j)))); tilesetsOnCharacters[i][j][k].setBounds(j * tilesetX, i * tilesetY, tilesetX, tilesetY); map.add(tilesetsOnCharacters[i][j][k], 4); } for (int k = 0; k < tilesetsUnderCharactersSize; k++) { tilesetsUnderCharacters[i][j][k] = new javax.swing.JLabel(new javax.swing.ImageIcon(Resources.getTileset(Maps.getMapTileset(mapNumber, 0, k, i, j)))); tilesetsUnderCharacters[i][j][k].setBounds(j * tilesetX, i * tilesetY, tilesetX, tilesetY); map.add(tilesetsUnderCharacters[i][j][k], 0); } for (int k = 0; k < mapAttributeSize; k++) { if (Maps.getMapTileset(mapNumber, 2, k, i, j) == 1) { blocked[i][j] = true; } } } } for (int i = 0; i < charactersNumber; i++) { characters[i] = new Character(0, 0, 64, 64, 0, 0, 0, 0, 5); tilesetsCharacters[i] = new javax.swing.JLabel(new javax.swing.ImageIcon(Characters.getCharacter(characters[i].getCharacterSkin(), characters[i].getDirection()))); tilesetsCharacters[i].setBounds(characters[i].getX(), characters[i].getY(), characters[i].getSizeX(), characters[i].getSizeY()); map.add(tilesetsCharacters[i], 1); charactersRender[i] = false; } frame.addKeyListener(new java.awt.event.KeyAdapter() { @Override public void keyTyped(java.awt.event.KeyEvent keyEvent) { } @Override public void keyPressed(java.awt.event.KeyEvent keyEvent) { if((keyEventInt = keyEvent.getKeyCode()) == java.awt.event.KeyEvent.VK_F) { right = true; } else if(keyEventInt == java.awt.event.KeyEvent.VK_S) { left = true; } else if(keyEventInt == java.awt.event.KeyEvent.VK_E) { up = true; } else if(keyEventInt == java.awt.event.KeyEvent.VK_D) { down = true; } } @Override public void keyReleased(java.awt.event.KeyEvent keyEvent) { if((keyEventInt = keyEvent.getKeyCode()) == java.awt.event.KeyEvent.VK_F) { right = false; } else if(keyEventInt == java.awt.event.KeyEvent.VK_S) { left = false; } else if(keyEventInt == java.awt.event.KeyEvent.VK_E) { up = false; } else if(keyEventInt == java.awt.event.KeyEvent.VK_D) { down = false; } } }); frame.setContentPane(map); frame.setVisible(true); } private void update() { if (exit && characters[0].getX() < x * tilesetX - characters[0].getSizeX() - characters[0].getMovementSpeed() && characters[0].getX() > 0 && characters[0].getY() > 0 && characters[0].getY() < y * tilesetY - characters[0].getSizeY() - characters[0].getMovementSpeed()) { exit = false; } if (right && (exit || (characters[0].getX() < x * tilesetX - characters[0].getSizeX() - characters[0].getMovementSpeed() && !blocked[characters[0].getY() / tilesetY][(characters[0].getX() + characters[0].getSizeX() + characters[0].getMovementSpeed()) / tilesetX] && !blocked[(characters[0].getY() + characters[0].getSizeY()) / tilesetY][(characters[0].getX() + characters[0].getSizeX() + characters[0].getMovementSpeed()) / tilesetX]))) { characters[0].right(); characters[0].setScaleX(5); if (allowExitRight && characters[0].getX() > x * tilesetX - characters[0].getSizeX() - characters[0].getMovementSpeed() - 1) exit = true; charactersRender[0] = true; } if (left && (exit || (characters[0].getX() > 0 && !blocked[characters[0].getY() / tilesetY][(characters[0].getX() - characters[0].getMovementSpeed()) / tilesetX] && !blocked[(characters[0].getY() + characters[0].getSizeY()) / tilesetY][(characters[0].getX() - characters[0].getMovementSpeed()) / tilesetX]))) { characters[0].left(); characters[0].setScaleX(-3); if (allowExitLeft && characters[0].getX() <= 0) exit = true; charactersRender[0] = true; } if (jumped || up && (exit || (characters[0].getY() > 0 && !blocked[(characters[0].getY() - characters[0].getMovementSpeed()) / tilesetY][characters[0].getX() / tilesetX] && !blocked[(characters[0].getY() - characters[0].getMovementSpeed()) / tilesetY][(characters[0].getX() + characters[0].getSizeX()) / tilesetX]))) { if (!jump) { characters[0].up(); characters[0].setScaleY(-3); if (allowExitUp && characters[0].getY() <= 0) exit = true; charactersRender[0] = true; } else if (!jumped && !falling) { jumpCurrentDuration = jumpDuration; jumped = true; } else if (--jumpCurrentDuration > 0) { if (exit || (characters[0].getY() > 0 && !blocked[(characters[0].getY() - characters[0].getMovementSpeed()) / tilesetY][characters[0].getX() / tilesetX] && !blocked[(characters[0].getY() - characters[0].getMovementSpeed()) / tilesetY][(characters[0].getX() + characters[0].getSizeX()) / tilesetX])) { characters[0].up(); characters[0].setScaleY(-3); if (allowExitUp && characters[0].getY() <= 0) exit = true; charactersRender[0] = true; } } else { jumped = false; } } if (((down && !jumped) || (gravity && !jumped)) && (exit || (characters[0].getY() < y * tilesetY - characters[0].getSizeY() - characters[0].getMovementSpeed() && !blocked[(characters[0].getY() + characters[0].getSizeY() + characters[0].getMovementSpeed()) / tilesetX][characters[0].getX() / tilesetX] && !blocked[(characters[0].getY() + characters[0].getSizeY() + characters[0].getMovementSpeed()) / tilesetY][(characters[0].getX() + characters[0].getSizeX()) / tilesetX]))) { characters[0].down(); characters[0].setScaleY(5); if (allowExitDown && characters[0].getY() > y * tilesetY - characters[0].getSizeY() - characters[0].getMovementSpeed()) exit = true; if (jump) falling = true; charactersRender[0] = true; } else if (jump) falling = false; } private void render() { for (int i = 0; i < charactersNumber; i++) { if (charactersRender[i]) { tilesetsCharacters[i].setIcon(new javax.swing.ImageIcon(Characters.getCharacter(characters[i].getCharacterSkin(), characters[i].getDirection()))); tilesetsCharacters[i].setBounds(characters[i].getX() + characters[i].getScaleX(), characters[i].getY() + characters[i].getScaleY(), characters[i].getSizeX(), characters[i].getSizeY()); charactersRender[i] = false; } } } 

屏幕截图:

的JLayeredPane

编辑:我还找到了一个名为Slick2D的库,它使用TiledMapEditor:

如何设置Slick2D: 如何安装Slick2d?

如何使用Slick2D和TiledMapEditor: Slick2D + Tiled cant加载图

哪里开始: https : //thejavablog.wordpress.com/2008/06/08/using-slick-2d-to-write-a-game/