我是java新手,一直在做一个小型生态系统项目。整个游戏的主网格由一个名为grid[][]的二维数组表示。生物的列表是种群[][]。为了简单起见,我只使用一种生物进行测试。
我正在做一个运动,它的工作原理如下:
- 将生物体所在位置的网格上的贴图更改为生物体下方的贴图
- 改变生物体的位置
- 记录生物体下的瓷砖
- 将tile替换为生物体的id
当移动时,有时生物体会复制自己,只在这一秒出现,下一秒就消失了。我已经努力找了2天了,还是找不到他们为什么这样做。
下面是重要的代码:
package ecosystem.Window;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.Random;
public class Game extends Canvas implements Runnable{
public boolean running=false;
public int fps;
public Thread thread;
public Random rand=new Random();
public int tile=33;
public final int WATER=-2;
public final int TREES=-1;
public final int GROUND=0;
public final int PREY=1;
public final int PREDATOR=2;
public final int X=0;
public final int Y=1;
public final int UNDERSQUARE=2;
public int[][]grid=new int[16][16];
public int[][]population=new int[10][3];
public synchronized void start(){
if(running)
return;
running=true;
thread=new Thread(this);
thread.start();
}
public static void main(String[] args){
new Window(640,480,"Ecosystem",new Game());
}
public void init(){
int row=0;
int column=0;
int r;
while(row<15){
if(column>=15){
row+=1;
column=0;
}else{
column+=1;
}
r=rand.nextInt(4);
grid[column][row]=(r-3);
}
for(int i=0;i<2;i++){
population[i][X]=rand.nextInt(16);
population[i][Y]=rand.nextInt(16);
population[i][UNDERSQUARE]=GROUND;
grid[population[i][X]][population[i][Y]]=PREY;
}
}
public void run(){
init();
this.requestFocus();
System.out.println(" ");
long lastTime = System.nanoTime();
double amountOfTicks = 10000000000.0;
int frames=0;
double ns = 8000000000000000000.0 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int updates = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
updates++;
delta--;
render();
}
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
fps=frames;
frames = 0;
updates = 0;
}
}
}
private void tick() {
System.out.println("Tick");
grid[population[1][X]][population[1][Y]]=population[1][UNDERSQUARE];
population[1][X]--;
population[1][UNDERSQUARE]=grid[population[1][X]][population[1][Y]];
grid[population[1][X]][population[1][Y]]=PREY;
}
private void render() {
int column=0;
int row=0;
BufferStrategy bs = this.getBufferStrategy();
if(bs==null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.darkGray);
g.fillRect(0, 0, 700, 900);
g.setColor(Color.black);
g.fillRect(0, 0, 494, 496);
//GRID//
while(row<15){
if(column>=15){
row+=1;
column=0;
}else{
column+=1;
}
if(grid[column][row]==WATER){
g.setColor(Color.blue);
}
if(grid[column][row]==TREES){
g.setColor(Color.green);
}
if(grid[column][row]==GROUND){
g.setColor(Color.orange);
}
if(grid[column][row]==PREY){
g.setColor(Color.red);
}
if(grid[column][row]==PREDATOR){
g.setColor(Color.YELLOW);
}
g.fillRect(column*tile-(tile+1), row*tile, (tile-1), (tile-1));
}
//CONTROL PANEL//
/////////////////
/////////////////
g.dispose();
bs.show();
//System.out.println("");
}
}
你直接从另一个线程访问AWT对象(例如,通过从你的线程调用render()
,或this
的任何其他Canvas
方法)。您只能从事件分派线程访问这些对象。如果你不这样做,所有的赌注都结束了;这很容易破坏你的渲染输出。EDT的链接描述是这样说的:
忽略此规则的程序可能在大多数情况下正常运行,但会发生不可预测的错误,难以重现。
你需要做一些改变。你有几个选择。
最简单的选择可能是在线程中使用SwingUtilities.invokeAndWait()
,使用调用render()
的Runnable
。您可以使用invokeLater()
,但是您必须特别注意确保您正在同步访问数据。尽管如此,你还必须检查你的代码,并确保你没有从其他线程调用任何的Canvas
方法(例如this.requestFocus()
是一个no-go)。
其他选项包括重新设计你的代码,使GUI自己渲染,例如通过计时器,并主动查询当前状态从你的线程;而不是让线程控制呈现,让GUI从线程中提取状态。这有时会变得很复杂,特别是当你想要模拟帧和GUI更新之间的1:1对应时。
一般来说,让你的类扩展Canvas
,但也有你的线程实现有一个坏的组合;因为一般来说,Canvas
方法都不能安全地从另一个线程调用。你应该考虑将模拟逻辑与GUI分离(即不要将游戏逻辑放在Canvas
中);这样做还有很多潜在的好处。