我做了一个Swing简单的塔防游戏,我当我试图把许多小精灵(超过20个),在屏幕上遇到性能问题。
整场比赛发生在具有setIgnoreRepaint(真)的JPanel地方。 这里是方法的paintComponent(con是所述控制器):
public void paintComponent(Graphics g){
super.paintComponent(g);
//Draw grid
g.drawImage(background, 0, 0, null);
if (con != null){
//Draw towers
for (Tower t : con.getTowerList()){
t.paintTower(g);
}
//Draw targets
if (con.getTargets().size() != 0){
for (Target t : con.getTargets()){
t.paintTarget(g);
}
//Draw shots
for (Shot s : con.getShots()){
s.paintShot(g);
}
}
}
}
目标类的简单描绘在当前位置的BufferedImage。 该方法的getImage不创建一个新的BufferedImage,它只是返回它的控制器类的实例:
public void paintTarget(Graphics g){
g.drawImage(con.getImage("target"), getPosition().x - 20, getPosition().y - 20, null);
}
每个目标上运行一个Swing计时器来计算其位置。 这是它调用的ActionListener:
public void actionPerformed(ActionEvent e) {
if (!waypointReached()){
x += dx;
y += dy;
con.repaintArea((int)x - 25, (int)y - 25, 50, 50);
}
else{
moving = false;
mover.stop();
}
}
private boolean waypointReached(){
return Math.abs(x - currentWaypoint.x) <= speed && Math.abs(y - currentWaypoint.y) <= speed;
}
除此之外,重绘()将新塔时,才会调用。
我怎样才能提高性能?
每个目标上运行一个Swing计时器来计算其位置。 这是它调用的ActionListener:
这可能是你的问题 - 为每个目标/子弹(我假设?)负责跟踪的时候进行自我更新,并绘制自己听起来像相当多的工作。 更常见的方法是让沿线的一环
while (gameIsRunning) {
int timeElapsed = timeSinceLastUpdate();
for (GameEntity e : entities) {
e.update(timeElapsed);
}
render(); // or simply repaint in your case, I guess
Thread.sleep(???); // You don't want to do this on the main Swing (EDT) thread though
}
从本质上讲,对象进一步与链有责任跟踪所有的实体在你的游戏,告诉他们自我更新,并使它们。
我想可能是错在这里是你的整个游戏设定的逻辑(无犯罪意图),作为另一种回答说你有不同的定时器以每个实体运动的照顾,这是不好的。 我建议考虑看看一些游戏圈的例子,你调整到这一点,你会发现一个很大的可读性和性能改进了几个不错的链接:
http://www.java-gaming.org/index.php/topic,24220.0
http://www.cokeandcode.com/info/tut2d.html
http://entropyinteractive.com/2011/02/game-engine-design-the-game-loop/
我最初警惕过于许多定时器理论。 的实例javax.swing.Timer
使用“一个共享线程(由执行所述第一定时器对象创建)”。 几十个甚至分数是完全正常的,但通常数百开始变得迟缓。 根据周期和占空比, EventQueue
最终达到饱和。 我同意,你需要认真审视你的设计的人,但你可能要进行实验setCoalesce()
作为参考,这里是一个SSCCE ,你可能喜欢的轮廓。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
/**
* @see http://stackoverflow.com/a/11436660/230513
*/
public class TimerTest extends JPanel {
private static final int N = 25;
public TimerTest() {
super(new GridLayout(N, N));
for (int i = 0; i < N * N; i++) {
this.add(new TimedLabel());
}
}
private static class TimedLabel extends JLabel {
private static final Random r = new Random();
public TimedLabel() {
super("000", JLabel.CENTER);
// period 100 to 1000 ms; frequency 1 to 10 Hz.
Timer timer = new Timer(r.nextInt(900) + 100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TimedLabel.this.setText(next());
}
});
timer.setCoalesce(true);
timer.start();
}
private String next() {
return String.valueOf(r.nextInt(900) + 100);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
private void display() {
JFrame f = new JFrame("TimerTet");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(this));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TimerTest().display();
}
});
}
}
尝试使用一个定时器的所有目标。
如果你有20个目标,那么你也将有20个定时器同时运行(想想1000的目标?)。 有一些费用,最重要的是他们每个人在做类似的工作 - 来计算位置 - 你不必分割。 我想这是一个简单的任务,它不会带你眨眼,甚至跑步20倍。
如果我得到了点,你想要做的就是试图在同一时间改变所有目标的位置是什么。 您可以在一个线程中改变所有的人都在一个单一的运行方法实现这一目标。