将 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 进行大量比较。然后你应该简单地渲染这个“虚拟”视图或模型的状态
更新了非常基本的示例
这是一个基本示例,它使用GridLayout
和setComponentZOrder
移动到面板周围的组件...没有碰撞检测,“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 的游戏)的主要内容,如果未能解决你的问题,请参考以下文章
添加到 BorderLayout 时,无法在 JPanel 中左对齐 JLabel