将 jLabel 移动到 jPanel 中的不同位置(类似 Pacman 的游戏)

Posted

技术标签:

【中文标题】将 jLabel 移动到 jPanel 中的不同位置(类似 Pacman 的游戏)【英文标题】:Moving jLabel to a different place in the jPanel (Pacman like game) 【发布时间】:2014-01-28 16:58:42 【问题描述】:

我正在制作一个像吃豆人这样的游戏,到目前为止我只是从网格开始。我启动了网格,但我需要弄清楚如何将某些东西移动到网格中的不同位置,以便当用户单击或我的幽灵移动时,它会显示在屏幕上。我如何让它动起来?我尝试了很多不同的方法,但没有一个对我有用。

import java.awt.*;

import javax.swing.*;
import javax.swing.border.BevelBorder;


public class GUI 

public static void main(String[] args) 
    final JFrame f = new JFrame("Frame Test");
    GridLayout Layout = new GridLayout(50,50);

    JPanel panel = new JPanel(new GridLayout(50, 50, 1, 1));

    //Not sure if I need this or not?
    //panel.setLayout(new GridBagLayout());

    //first set of black
    for (int i = 0; i < 1000; i++) 
        JLabel a = new JLabel(new ImageIcon("black-square.jpg"), JLabel.CENTER);
        panel.add(a);

    

    //adds pacman
    JLabel b = new JLabel(new ImageIcon("pacman.png"), JLabel.CENTER);
    panel.add(b);

    //next set of black
    for (int i = 0; i < 1000; i++) 
        JLabel c = new JLabel(new ImageIcon("black-square.jpg"), JLabel.CENTER);
        panel.add(c);
    


   //do the thing 
    f.setContentPane(panel);
    f.setSize(1000, 1000);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);



【问题讨论】:

【参考方案1】:

首先查看Concurrency in Swing 和How to Use Swing Timers

您将遇到的下一个问题是容器处于LayoutManager 的控制之下。虽然可以使用它来实现移动,但它会是块状的,因为每个组件都会跳跃单元格。

如果你想要平滑移动,你将不得不设计自己的布局逻辑,这可能非常复杂。

不过,您的目标应该是保持游戏的“虚拟”视图。这可以让您知道迷宫的形状和角色的位置,而无需与 UI 进行大量比较。然后你应该简单地渲染这个“虚拟”视图或模型的状态

更新了非常基本的示例

这是一个基本示例,它使用GridLayoutsetComponentZOrder 移动到面板周围的组件...没有碰撞检测,“AI”很可怜...

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class PacMan101 

    public static void main(String[] args) 
        new PacMan101();
    

    public PacMan101() 
        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 MazePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            
        );
    

    public class MazePane extends JPanel 

        private JLabel pacMan;
        private JLabel ghost;

        public MazePane() 
            pacMan = new JLabel(new ImageIcon(getClass().getResource("/PacMan.png")));
            ghost = new JLabel(new ImageIcon(getClass().getResource("/Ghost.png")));

            setLayout(new GridLayout(8, 8));
            add(pacMan);

            for (int index = 1; index < (8 * 8) - 1; index++) 
                add(new JPanel() 

                    @Override
                    public Dimension getPreferredSize() 
                        return new Dimension(32, 32);
                    

                );
            

            add(ghost);

            Timer timer = new Timer(500, new ActionListener() 
                @Override
                public void actionPerformed(ActionEvent e) 
                    move(pacMan);
                    move(ghost);
                    revalidate();
                    repaint();
                

                protected void move(Component obj) 
                    int order = getComponentZOrder(obj);
                    int row = order / 8;
                    int col = order - (row * 8);

                    boolean moved = false;
                    while (!moved) 
                        int direction = (int) (Math.round(Math.random() * 3));
                        int nextRow = row;
                        int nextCol = col;
                        switch (direction) 
                            case 0:
                                nextRow--;
                                break;
                            case 1:
                                nextCol++;
                                break;
                            case 2:
                                nextRow++;
                                break;
                            case 3:
                                nextCol--;
                                break;
                        

                        if (nextRow >= 0 && nextRow < 8 && nextCol >= 0 && nextCol < 8) 
                            row = nextRow;
                            col = nextCol;
                            moved = true;
                        
                    

                    order = (row * 8) + col;
                    setComponentZOrder(obj, order);

                
            );
            timer.start();
        

    


【讨论】:

这是一个类项目,所以它不需要平滑,但我正在寻找类似 label.set(x,y);有什么办法吗? 是的,但是根据您的示例,它不起作用,因为附加标签的容器受布局管理器的控制。您可以考虑使用setComponentZOrder,这将改变组件的布局顺序,但您需要将 x/y 位置转换为线性值 好的。我愿意改变布局。 (今天刚开始,我有一两个星期的时间来做这个)那么通过做另一种类型的 GUI 会更容易吗?老师根本没有教 GUI 的东西,但如果你想要满分的话,他会把它作为我们期末成绩的一部分。 更改布局管理器会给您带来同样的问题。一个更简单的解决方案是取消布局管理器并手动计算对象的位置,但这并不容易并且会引发更多问题。另一种解决方案是直接进行绘画,但同样不容易,还会带来更多问题......【参考方案2】:

在网格中的每个位置放置标签可能更简单,然后在你的生物移动时更改与每个标签相关的图标。见Add and remove an icon on a JLabel

【讨论】:

我刚读到,我把它删除了,但它没有指定位置,它是一个标签。另外,我没有办法设置它,因为如果我做了 .add() 它会添加到最后。我该怎么做? 我的想法是,您创建一个标签引用的二维数组,并在将它们添加到网格布局时将它们添加到数组中,因此当您想要更改特定位置的图标时现场,您从数组中获取标签并调用setIcon(image)setIcon(null) 来设置或清除图像。另外:在 Swing 线程中进行这些调用很重要。 (如果您不是在摇摆计时器中执行此操作,请参阅 SwingUtilities.invokeLater 或 .invokeAndWait())

以上是关于将 jLabel 移动到 jPanel 中的不同位置(类似 Pacman 的游戏)的主要内容,如果未能解决你的问题,请参考以下文章

如何将 JLabel 对齐到 JPanel 的左侧?

添加到 BorderLayout 时,无法在 JPanel 中左对齐 JLabel

将 JLabel 中的文本右对齐

如何在已动态添加的JLabel的JPanel中getLocation()?

只能添加JLabel背景或JPanel背景

如何将 JLabel 中的图标(拖放)移动到另一个 JLabel 而不是复制它?