Java 代码有时可以工作,但其他代码不能工作(内存或线程问题)
我有一个奇怪的问题,我不知道是什么原因造成的。有时,问题甚至不存在。据我猜测,这是一个Java内存问题或某种线程问题 我有一艘Java 代码有时可以工作,但其他代码不能工作(内存或线程问题),java,multithreading,swing,Java,Multithreading,Swing,我有一个奇怪的问题,我不知道是什么原因造成的。有时,问题甚至不存在。据我猜测,这是一个Java内存问题或某种线程问题 我有一艘飞船,飞船射出子弹如果我按下空格键,飞船就会射出子弹。我让子弹每200毫秒发射一次。有时他们射门很好,移动速度也一样!其他时候,它们以不同的速度射击。这是什么原因造成的 package JGame.Actions; import JGame.GameObject.GameObject; import javax.swing.AbstractAction; public
飞船
,飞船射出子弹
如果我按下空格键,飞船就会射出子弹。我让子弹每200毫秒发射一次。有时他们射门很好,移动速度也一样!其他时候,它们以不同的速度射击。这是什么原因造成的
package JGame.Actions;
import JGame.GameObject.GameObject;
import javax.swing.AbstractAction;
public class MoveAction extends Action implements Runnable{
protected GameObject obj;
protected int endX = 0, endY = 0;
protected int moveAmount = 0;
protected Thread thread;
public void moveToY(GameObject obj, int y, int amount, AbstractAction complete){
this.obj = obj;
this.endY = y;
this.moveAmount = amount;
this.complete = complete;
thread = new Thread(this);
thread.start();
}
public void run(){
try{
boolean run = true;
while(run){
int objY = obj.getY();
if(objY > this.endY){
obj.setY(obj.getY() - 1);
}else if(objY < this.endY){
obj.setY(obj.getY() + 1);
}else{
run = false;
this.actionComplete();
}
thread.sleep(moveAmount);
}
}catch(Exception e){
}
}
}
在我的代码中,我调用moveToY
这是一个非常简单的调用,但有时子弹
以不同的速度移动(错误),而其他子弹则以相同的速度移动(正确)。我不知道这是否有助于提到,当子弹移动时,有时它们会减速一两秒钟,然后再加速到正确的速度
编辑:主线程
下面是我使用paintComponent的主要线程
@Override
public void run(){
try{
while(true){
// Check for key press events
Iterator actions = KeyboardMap.map.entrySet().iterator();
while(actions.hasNext()){
Map.Entry ap = (Map.Entry)actions.next();
Mapping mp = (Mapping)ap.getValue();
if(mp.pressed){
mp.run();
}
}
// Check for click mouse events
Iterator actions2 = MouseMap.map.entrySet().iterator();
while(actions2.hasNext()){
Map.Entry ap = (Map.Entry)actions2.next();
Mapping mp = (Mapping)ap.getValue();
if(mp.pressed){
mp.run();
}
}
for(GameObject go : gameObjects){
if(!go.getLeaveScreen()){
int goWidth = go.getWidth();
int goHeight = go.getHeight();
int goX = go.getX();
int goY = go.getY();
int gameWidth = Game.width;
int gameHeight = Game.height;
if(goX + goWidth >= gameWidth){
go.setX(gameWidth - goWidth);
}
if(goX <= 0){
go.setX(0);
}
if(goY + goHeight >= gameHeight){
go.setY(gameHeight - goHeight);
}
if(goY <= 0){
go.setY(0);
}
}
}
this.repaint();
Thread.sleep(roomSpeed);
}
}catch(Exception e){
}
}
public void paintComponent(Graphics g){
try{
g.drawImage(bg, 0, 0, this);
for(int i = 0; i < gameObjects.size(); i++){
GameObject go = gameObjects.get(i);
g.drawImage(go.getSprite(), go.getX(), go.getY(), this);
}
}catch(Exception e){
}
}
@覆盖
公开募捐{
试一试{
while(true){
//检查按键事件
迭代器操作=KeyboardMap.map.entrySet().Iterator();
while(actions.hasNext()){
Map.Entry ap=(Map.Entry)actions.next();
映射mp=(映射)ap.getValue();
如果(按mp键){
mp.run();
}
}
//检查单击鼠标事件
迭代器动作2=MouseMap.map.entrySet().Iterator();
while(actions2.hasNext()){
Map.Entry ap=(Map.Entry)actions2.next();
映射mp=(映射)ap.getValue();
如果(按mp键){
mp.run();
}
}
用于(游戏对象转到:游戏对象){
如果(!go.getLeaveScreen()){
int goWidth=go.getWidth();
int goHeight=go.getHeight();
int goX=go.getX();
int goY=go.getY();
int gameWidth=Game.width;
int gameHeight=Game.height;
如果(goX+goWidth>=gameWidth){
go.setX(gameWidth-goWidth);
}
如果(goX=游戏高度){
go.setY(游戏高度-goHeight);
}
如果(goY好吧,我猜您有大量并发线程在运行(一个通过移动bullet),并且您希望每个线程在moveAmount
毫秒后醒来。您不能有这样的保证,因为线程调度程序允许每个线程一次运行一段时间,因此您可能会出现故障
另一个问题是,您似乎在事件分派线程之外对Swing组件执行修改,这显然是被禁止的。好吧,我猜您有大量并发线程正在运行(一个是通过移动bullet),并且您希望每个线程在moveAmount
毫秒后完全唤醒。您不能有这样的保证,因为线程调度程序允许每个线程一次运行一段时间,因此您可能会出现故障
另一个问题是,您似乎在事件调度线程之外执行对Swing组件的修改,这显然是被禁止的。告知您自己多线程的使用情况以及如何正确制作游戏的处理结构。
对于您的案例来说,最重要的信息是:您应该只使用一个线程来处理/移动所有子弹,然后进行渲染。了解多个线程的用法以及如何正确制作游戏的处理结构。
对于您的案例,最重要的信息是:您应该只使用一个线程来处理/移动所有项目符号,然后进行渲染。代码中最重要的更改是不要使用线程对时间建模。睡眠
。使用摆动计时器,您将计划执行每个移动量milliseconds,作为奖励,代码在事件调度线程上执行,您无需付出任何努力。代码中最重要的更改是不要使用线程对时间建模。睡眠
。使用摆动计时器,您将计划每隔moveAmount
毫秒执行一次另外,代码是在事件调度线程上执行的,您无需付出任何努力。+1对于JBNizet,我建议重新构建您的游戏循环以更新实体移动等,这样您就不必通过其他线程执行此操作,因此单个线程将处理屏幕上所有实体的移动等。请参阅此固定时间步长的游戏循环示例:完全正确。一个循环来控制所有实体。+1到JBNizet,我建议重新构建游戏循环来更新实体移动等,这样你就不必通过其他线程来完成这项工作,因此一个线程将处理屏幕上所有实体的移动等。请参阅此固定时间步游戏循环示例:完全正确。一个循环来控制所有实体。具体取决于游戏对象是,即如果它是JComponent,EDT将应用,如果不是,即OP使用扩展的矩形/形状类,则不需要Swing timer,因为更改形状/矩形的坐标不会修改任何Swing UI组件。无论是否需要EDT,这仍然是所有其他原因的解决方法。如果没有Swing组件正在使用我认为执行不必要的代码(不修改Swing组件的代码)在EDT中,a是不正确的,它应该被很好地使用,因为你没有考虑到,通过这种方法,有一个全新的资源需要管理——而且是浪费,如果所涉及的计算不会给EDT带来真正的负担。根据游戏对象是什么,例如,如果它是JComponent,EDT将被应用,如果不是,例如,OP使用扩展的矩形/形状类t韩秋千
@Override
public void run(){
try{
while(true){
// Check for key press events
Iterator actions = KeyboardMap.map.entrySet().iterator();
while(actions.hasNext()){
Map.Entry ap = (Map.Entry)actions.next();
Mapping mp = (Mapping)ap.getValue();
if(mp.pressed){
mp.run();
}
}
// Check for click mouse events
Iterator actions2 = MouseMap.map.entrySet().iterator();
while(actions2.hasNext()){
Map.Entry ap = (Map.Entry)actions2.next();
Mapping mp = (Mapping)ap.getValue();
if(mp.pressed){
mp.run();
}
}
for(GameObject go : gameObjects){
if(!go.getLeaveScreen()){
int goWidth = go.getWidth();
int goHeight = go.getHeight();
int goX = go.getX();
int goY = go.getY();
int gameWidth = Game.width;
int gameHeight = Game.height;
if(goX + goWidth >= gameWidth){
go.setX(gameWidth - goWidth);
}
if(goX <= 0){
go.setX(0);
}
if(goY + goHeight >= gameHeight){
go.setY(gameHeight - goHeight);
}
if(goY <= 0){
go.setY(0);
}
}
}
this.repaint();
Thread.sleep(roomSpeed);
}
}catch(Exception e){
}
}
public void paintComponent(Graphics g){
try{
g.drawImage(bg, 0, 0, this);
for(int i = 0; i < gameObjects.size(); i++){
GameObject go = gameObjects.get(i);
g.drawImage(go.getSprite(), go.getX(), go.getY(), this);
}
}catch(Exception e){
}
}