1

この奇妙な問題が発生していますが、何が原因なのかわかりません。問題がない場合もあります。私が推測しているのは、これは Java メモリの問題か、ある種のスレッドの問題であるということです。

を持っているShipと、船が撃ちBulletsますSpaceキーを押し続けると、船が弾丸を撃ちます。弾丸を 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){
        }
    }
}

アクション完了:

package JGame.Actions;

import javax.swing.AbstractAction;

public class Action {
    protected boolean actionComplete = false;
    protected AbstractAction complete;

    public void actionComplete(){
        complete.actionPerformed(null);
    }
}

私のコードmoveToYでは、非常に単純な呼び出しですが、Bullets異なる速度で移動する場合もあれば (間違った場合)、同じ速度で移動する場合もあります (右)。弾丸が動くと、1〜2秒間減速してから、正しい速度に戻ることがあることに言及することが役立つかどうかはわかりません.

編集:メインスレッド

以下は、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){
    }
}
4

3 に答える 3

5

多数の同時実行スレッド (弾丸の移動によるもの) があり、各スレッドが正確にmoveAmountミリ秒後にウェイクアップすることを期待していると思います。スレッド スケジューラでは、各スレッドが一度に 1 つずつ実行されるため、このような保証はありません。そのため、不具合が発生する可能性があります。

もう 1 つの問題は、イベント ディスパッチ スレッドから Swing コンポーネントの変更を実行しているように見えることです。これは、Swing のスレッド化ポリシーによって明らかに禁止されています。

于 2012-12-25T18:15:24.297 に答える
1

コードを変更する最も重要なことは、時間をモデル化しないことThread.sleepです。ミリ秒ごとに実行するようにスケジュールするSwing Timerを使用するmoveAmountと、おまけとして、コードはイベント ディスパッチ スレッドで実行されます。

于 2012-12-25T18:23:21.597 に答える