java - 未绘制 JPanel
问题描述
我正在开发一个垂直滚动游戏,我正在使用一个线程每 2 秒生成新的敌人。每个敌人都是 JPanel 中的一个图像。出于某种原因,生成的敌人没有出现在 JFrame 中,但它们存在。当玩家与其中一个敌人发生碰撞时,所有的敌人都会出现。这是代码:
private void checkCollision() {
for(AlienShip as : enemies) {
if(player.getBounds().intersects(as.getBounds()))
player.setVisible(false);
}
}
private void setAlien() {
alien = new AlienShip();
add(alien);
enemies.add(alien);
System.out.println("Enemies: " + enemies.size());
}
public Thread alienGenerator() {
for(int i = 0; i < 3; i++) { // these are being drawn
setAlien();
}
return new Thread(new Runnable() {
@Override
public void run() {
int sleepTime = 2000;
while(true) {
try {
Thread.sleep(sleepTime);
} catch(InterruptedException e) {
System.out.println(e);
}
setAlien(); //these aren't
}
}
});
}
private void gameLoop() {
alienGenerator().start();
mainTimer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
repaint();
checkCollision();
}
});
mainTimer.start();
}
解决方案
似乎你做的时候就该死,如果你不做就该死。就我而言,您在之前的帖子中放置的代码是足够的,事实上,它仍然缺乏(没有 PlayerShip 类)。这篇文章中的代码示例更不公平。尽管如此......
在开始之前,我只想让您知道,我个人会以不同的方式处理此任务,并且此处提供的微不足道的帮助将完全基于您在本文和以前的帖子中已经提供的代码。
您在创建时没有看到您的外星飞船显示在游戏板上的原因是您没有重新验证板面板。由于您现在拥有您的代码,这可以在添加外星飞船的Board.setAlien()方法中完成。直接在代码行下:
alien = new AlienShip();
add(alien);
enemies.add(alien);
添加代码行:revalidate();
,因此代码如下所示:
alien = new AlienShip();
add(alien);
enemies.add(alien);
revalidate();
你的外星飞船现在应该会显示出来。
旁注:
当任何外星飞船真正到达游戏板底部时会发生什么?作为建议,让他们重新生成到游戏板的顶部(为您服务)。这可以在AlienShip.scrollShip()方法中通过检查 Alien Ship 是否已到达棋盘底部来完成,例如:
public void scrollShip() {
if (getY() + 1 > this.getParent().getHeight()) {
setY(0 - PANEL_HEIGHT);
}
else {
setY(getY() + 1);
}
}
在我看来,PANEL_HEIGHT是使用错误的字段名称。我认为使用ALIEN_SHIP_WIDTH和ALIEN_SHIP_HEIGHT 之类的东西会更合适。变量panelX和panelY相同,可以是alienShipX和alienShipY。深思熟虑。
正如您在上面的代码中看到的,当前游戏板的高度是通过轮询游戏板的getHeight()方法获得的this.getParent().getHeight()
:这使您可以随时更改游戏板的大小,并且外星飞船将在向下滚动时知道当前边界的位置。所有这一切都意味着setResizable(false); 在游戏的 JFrame 窗口的主类中完成的属性设置现在可以调整大小setResizable(true);
:
您还会注意到,当外星飞船在游戏板顶部重新生成时,它实际上不在现场,并且在向下移动时会流入视野。我认为这是向游戏领域的更顺畅的过渡,而不仅仅是突然出现。这是通过setY(0 - PANEL_HEIGHT);
上面的代码行完成的。事实上,即使在游戏最初开始时,您的外星飞船也应该以这种方式流入游戏区域,这可以通过将panelY变量初始化为AlienShip.initAlienShip()方法来完成。panelY = -PANEL_HEIGHT;
现在这将我带到PANEL_WIDTH和PANEL_HEIGHT字段的初始化。这些值似乎很大(分别为 224 和 250)。当然,您可能出于碰撞测试等目的设置了这些尺寸,但我认为 64 x 35 的图像尺寸很可能就足够了:
此图像应该是具有透明背景的 PNG 图像,这样就不需要setBackground(Color.BLUE);
位于AlienShip.initAlienShip()方法中的代码行。
AlienShip.getX ()和AlienShip.getY()方法应该被覆盖:
@Override
public int getX() { ... }
@Override
public int getY() { ... }
我认为将 AlienShip 类扩展到 JLabel 会比 JPanel 更好。对 JPanel 来说似乎有点矫枉过正:
public class AlienShip extends JLabel { ... }
将背景图像添加到游戏板可以为游戏添加 pizazz。这可以通过将以下代码添加到Board.paintComponent()方法来实现:
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
ImageIcon imgIcon = new ImageIcon("images/StarBackground.png");
Image img = imgIcon.getImage();
g.drawImage(img, 0, 0, this.getSize().width, this.getSize().height, this);
}
可以在此处获取图像。
这应该让你坚持一段时间。用不了多久,这将是外星人的混乱。
推荐阅读
- google-sheets - 如果单元格 <> 单元格在上方,则条件格式
- architecture - 将单体服务拆分为多个服务
- expo - 如何让 expo 连接到具有非本地主机 IP 地址的 Android 模拟器?
- php - 任务计划程序不起作用,(未执行 php 脚本)Windows 7
- c# - 如何使用 for 循环拆分 DataTable 行?
- html - 我的 div 子级不包含在父级 div 中
- java - infinity double 操作导致 infinity java/android studio
- javascript - react-query:仅在状态变量更改时重新获取查询
- javascript - JavaScript:对 ArrayBuffer 内存进行分区的最有效和最高效的方法
- vue.js - 如何在 laravel 路由文件中返回 vuejs 视图