JLabel 和 JLayeredPane - 如何在另一个图像上显示图像?

2022-01-24 00:00:00 java jlabel jpanel jframe jlayeredpane

我尝试用java创建一个小游戏,但我遇到了麻烦.

当我绘制地图时,如果不覆盖正方形的标题集,我将无法显示字符.

我的目标是能够在同一个方格上显示多张图片(比如草、人物和树的标题集),所以我必须处理图片的透明度(这不是问题)和层(这是问题所在).

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

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

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

import javax.swing.JFrame;导入 javax.swing.ImageIcon;导入 javax.swing.JLabel;导入 javax.swing.SwingUtilities;公共类窗口扩展线程{私有静态 JFrame 窗口 = new JFrame("game");公共无效运行(){地图地图=新地图();字符 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();字符.start();}私有静态无效重载()抛出异常{SwingUtilities.updateComponentTreeUI(window);}私有静态类 Map 扩展 Thread{私人 int numberSquareX = Settings.sizeX/20 + 1;私人 int numberSquareY = Settings.sizeY/20 + 1;私有 JLabel square[][] = new JLabel[numberSquareX][numberSquareY];公共无效运行(){for (int x = 0, y = 0; y 

我已经找到了这个主题:

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

JLayeredPane 层 = new JLayeredPane();图层.add(tilesetsUnderCharacter, 0);//第 0 层图层.add(字符,1);//第 1 层图层.add(tilesetsOnCharacter, 2);//第 2 层frame.setContentPane(层);

代码示例:

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  x * tilesetX - characters[0].getSizeX() - characters[0].getMovementSpeed() - 1)退出=真;字符渲染[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]))){字符[0].left();字符[0].setScaleX(-3);if (allowExitLeft && characters[0].getX() <= 0)退出=真;字符渲染[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() + 字符[0].getSizeX())/tilesetX]))){如果(!跳转){字符[0].up();字符[0].setScaleY(-3);if (allowExitUp && characters[0].getY() <= 0)退出=真;字符渲染[0] = true;}else if (!jumped && !falling){跳转当前持续时间 = 跳转持续时间;跳=真;}否则 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])){字符[0].up();字符[0].setScaleY(-3);if (allowExitUp && characters[0].getY() <= 0)退出=真;字符渲染[0] = true;}}别的{跳=假;}}if ((((down && !jumped) || (重力 && !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]))){字符[0].down();字符[0].setScaleY(5);if (allowExitDown && characters[0].getY() > y * tilesetY - characters[0].getSizeY() - characters[0].getMovementSpeed())退出=真;如果(跳转)下降=真;字符渲染[0] = true;}否则如果(跳转)下降=假;}私人无效渲染(){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(), 字符[i].getSizeY());字符渲染[i] = false;}}}

屏幕截图:

我还发现了一个名为 Slick2D 的库,它与 TiledMapEditor 一起使用:

  • http://slick.ninjacave.com/

  • http://www.mapeditor.org/

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

如何使用 Slick2D 和 TiledMapEditor:Slick2D + Tiled 无法加载地图

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

I try to create a little game in java but I'm in trouble.

When I draw a map, I'm not able to display the characters without overwrite the titlesets of the squares.

My goal is to be able to display many pictures on the same square (like the titleset of the grass, the character and a tree), so I have to deal with the transparency of my pictures (this is not the problem) and the layer (it is the problem).

So how can I display an image on another image?

How can I explain to java that I need to display this image on or under another image?

This is my source code. I don't know is that can help you. Your help can be really helpfull for me if you give me a clue or a function who is able to manage the layers. That is useless to rewrite all the code for me x) This program is not complete, I use it only for test my program right now. I know that he refresh two times the map so he overwrite the square of the character (and he have many others littles glitchs), but that is not the purpose of my question. I try to done my game by step!

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;
        }
    }
}

I have already find this subjects: How to use JLayered Pane to display an image on top of another image? and this one Best practice for creating a composite image output for Java Swing but they haven't really help me...

I continue to search the answer. If I find it, I will come back for post it here.

解决方案

Solved.

Thanks to MadProgrammer for his comments.

Render the title map to a BufferedImage, either in it's entirety or based on the available viewable area, which ever is more efficient. Paint this to the screen, then paint your character on top it – MadProgrammer

In 15+ years of professional Java/Swing development, I've never found a need to use SwingUtilities.updateComponentTreeUI(window);, instead, simply call repaint on the component which is responsible for renderer the output, I'm pretty sure, you'll find this more efficient. – MadProgrammer

Swing is also a single threaded environment AND is not thread safe, you should NOT be update the UI from outside of the context of the Event Dispatching Thread, as this will setup a race condition and could result in unwanted and difficult to resolve graphical issues. – MadProgrammer

Hint. JLabel is a descendent of Container, which means it can contain other components ;) – MadProgrammer

Thanks a lot MadProgrammer! So I have replace SwingUtilities.updateComponentTreeUI(window) by window.repaint(). You had right for the Thread safe, my map had some bugs but I wasn't able to find where they was from. And what about the BufferedImage? If I create two BufferedImage, the last one can be automatically on the top of the first one? Or I just want to render the title map to a BufferedImage (so I am limited by 2 layers)? – Celine

It will depend on what it is you want to achieve. Using BufferedImages gives you complete control over the placement of the images and yes, one can be rendered over the other, painting is like a artists canvas, as you add things to it, they are added on top of what is already there, BUT, you might find it easier to add a JLabel to another JLabel - just remember, JLabel doesn't have a layout manager by default – MadProgrammer

Code example:

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();
    }
}

Screen capture:

1

Another solution is to use 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);

Code example:

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;
        }
    }
}

Screen Capture:

Edit: I also found a library called Slick2D who work with TiledMapEditor:

  • http://slick.ninjacave.com/

  • http://www.mapeditor.org/

How to setup Slick2D: How to install Slick2d?

How to use Slick2D and TiledMapEditor: Slick2D + Tiled cant load map

Where started: https://thejavablog.wordpress.com/2008/06/08/using-slick-2d-to-write-a-game/

相关文章