所以我的目标是从框架的右侧连续出现物体流,并在它们到达框架的左侧后将其消失/删除。我将有一个球对象/图像,它将是静止的但似乎向前移动并跳过我想要创建的矩形对象。我希望在用户“幸存”一段时间后停止创建对象。
基本上我的问题是如何加载我的JFrame,然后在运行时继续绘制对象。这样做一段时间,不断地绘画和移除物体。
答案 0 :(得分:3)
好的,所以这是非常基本的例子......
基本上,它有两个List
,一个是"池"可用对象和另一个是当前屏幕上对象的List
。
目的是减少需要创建的新对象的数量,而是保留主循环可以从中抽取的可用对象池。如果池是空的并且需要新对象,它将被创建,但是一旦它离开屏幕,它将被替换为池,假设我们需要它。
此示例为您提供动态更改活动对象数(25-10,000)的功能。系统将尝试将它在两个列表中管理的总对象数量平衡到这个确切的数量。如果您不断更改活动对象的数量,您可以考虑允许池具有"软糖"因素,但我会留给你。
还有一个增长率因子,这意味着当你增加活动对象的数量时,在主循环的每个循环上,它将增加可用对象的数量,这有助于减少滞后的可能性可能会因创建9,000个新对象而产生;)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
GamePane gamePane = new GamePane();
JSlider slider = new JSlider(25, 10000);
add(gamePane);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
gamePane.setActiveEntityCount(slider.getValue());
}
});
slider.setValue(25);
}
}
public class GamePane extends JPanel {
private List<MovableEntity> poolOfEntities;
private List<MovableEntity> activeEntities;
private int activeCount;
private int growthRate = 100;
public GamePane() {
poolOfEntities = new ArrayList<>(25);
activeEntities = new ArrayList<>(25);
setFont(getFont().deriveFont(Font.BOLD, 48f));
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Iterator<MovableEntity> it = activeEntities.iterator();
while (it.hasNext()) {
MovableEntity entity = it.next();
if (entity.update(getWidth(), getHeight())) {
it.remove();
// This drop objects if the total number of objects exceeds the activeCount
if (poolOfEntities.size() + activeEntities.size() < activeCount) {
poolOfEntities.add(entity);
}
}
}
for (int growth = 0; growth < growthRate && activeEntities.size() < activeCount; growth++) {
MovableEntity entity = null;
if (poolOfEntities.isEmpty()) {
entity = createNewEntity();
} else {
entity = poolOfEntities.remove(0);
}
activeEntities.add(entity);
}
repaint();
}
});
timer.start();
}
protected MovableEntity createNewEntity() {
int width = getWidth();
int height = getHeight();
if (width == 0) {
width = getPreferredSize().width;
} else if (height == 0) {
height = getPreferredSize().height;
}
return new ShapeEntity(width, height);
}
public void setActiveEntityCount(int count) {
if (count != activeCount) {
activeCount = count;
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Iterator<MovableEntity> it = activeEntities.iterator();
while (it.hasNext()) {
MovableEntity entity = it.next();
entity.paint(g2d);
}
String text = Integer.toString(activeEntities.size());
FontMetrics fm = g2d.getFontMetrics();
int x = getWidth() - fm.stringWidth(text);
int y = (getHeight() - fm.getHeight() )+ fm.getAscent();
g2d.setColor(Color.WHITE);
g2d.drawString(text, x, y);
g2d.dispose();
}
}
public interface Entity {
public void paint(Graphics2D g);
}
public interface MovableEntity extends Entity {
public boolean update(int width, int height);
}
public static class ShapeEntity implements MovableEntity {
protected static final Color COLORS[] = {Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE, Color.YELLOW};
protected static final Random RND = new Random();
private Rectangle bounds;
private final Color color = COLORS[RND.nextInt(COLORS.length)];
private int xDelta;
public ShapeEntity(int width, int height) {
reset(width, height);
}
protected void reset(int width, int height) {
bounds = new Rectangle();
bounds.width = 5 + RND.nextInt(25);
bounds.height = 5 + RND.nextInt(25);
bounds.x = -bounds.width; // offscreen
bounds.y = RND.nextInt(height - bounds.height);
xDelta = 1 + RND.nextInt(8);
}
@Override
public boolean update(int width, int height) {
boolean reset = false;
bounds.x += xDelta;
if (bounds.x > width) {
reset(width, height);
reset = true;
}
return reset;
}
@Override
public void paint(Graphics2D g) {
g.setColor(color);
g.fill(bounds);
}
}
}
如果您想知道,我已经测试过设置增长率为500,最大活动数为100,000而没有太多问题;)