0

私はsscceを作成していましたが、ここに投稿するにはコードが多すぎたので、セクションを投稿します。フォローしていただければ幸いです。

だから、私はこのクラスを持っていShipます、クラス内にはこれがあります:

チャンク1:

keyboard.keyPress("SPACE", new Runnable(){

    @Override
    public void run(){
        Laser laser = new Laser(
                new Sprite("/media/images/laser.png"),
                sscce.Ship.this.room);
        sscce.Ship.this.room.addGameObjectAt(
                laser,
                sscce.Ship.this.getX() + (sscce.Ship.this.getWidth() / 2) - 3,
                sscce.Ship.this.getY());
    }
});

Spaceキーを押すとオブジェクトが作成さLaserれ、ゲームに追加されます。このオブジェクトはゲーム内に保存されArrayList、メインのゲームループの画面に描画されます。このループは。をループしますArrayList

Laserは非常に単純なクラスで、次のようになります。

チャンク2:

package JGame.GameObject;

import JGame.Room.Room;

public class Laser extends GameObject{

    public Laser(Sprite sprite, Room room){
        super(sprite, room);
        move.moveToY(0 - this.getHeight(), 5, new Runnable(){
            @Override
            public void run(){
                Laser.this.destroy.destroyGameObject();
            }
        });
    }
}

したがって、チャンク1はチャンク2を作成し、それを配列リストに追加します。これはすべてうまく機能し、ダンディです!

チャンク3:

public void moveToY(int y, int speed, Runnable complete){
    this.obj.moveEndY = y;
    this.obj.moveAmountY = speed;
    this.complete = complete;
    this.obj.needsToMoveY = true;
}

これにより、新しく作成されたに移動アクションが追加されLaserます。次に、オブジェクトを垂直方向に移動します(チャンク2で定義され、メインのゲームループ内で実行されます)。

この次の部分はゲームを中断することです。中断とは、すべてが停止することを意味します(イベントリスナー、動きなど)。

チャンク2から、「moveToYが目的地に到達したら、ランナブルコードを実行する」と言い、ランナブルコードは、を使用してレーザーを破壊するように指示しますdestroyGameObject()。デストリーは次のようになり、すべてのゲームオブジェクトコンストラクター(など)で初期化されLaserますShip

チャンク4:

package JGame.Actions;

import JGame.GameObject.GameObject;
import JGame.Room.Room;

public class DestroyAction extends Action{
    GameObject obj;
    Room room;
    public DestroyAction(Room room, GameObject obj){
        this.room = room;
        this.obj = obj;
    }

    public void destroyGameObject(){
        room.removeGameObject(this.obj);
    }
}

チャンク4は、部屋に「このオブジェクトをリストから削除する必要があります」と伝えるだけです。

チャンク5:

public class Room extends JPanel implements Runnable{

    ArrayList<GameObject> gameObjects = new ArrayList<>();

    public void run(){
        try{
            while(true){
                // Do Event Listeners
                // Move objects along Y axis
                for(GameObject go : gameObjects){
                    if(go.needsToMoveY){
                        int objY = go.getY();
                        if(objY > go.moveEndY){
                            go.setY(objY - go.moveAmountY);
                        }else if(objY < go.moveEndY){
                            go.setY(objY + go.moveAmountY);
                        }else{
                            go.needsToMoveY = false;
                            // Executes Runnable parameter from moveToY()
                            go.move.actionComplete();
                        }
                    }
                }
                this.repaint();
                Thread.sleep(roomSpeed);
            }
        }catch(Exception e){
        }
    }

    public void removeGameObject(GameObject go){
        gameObjects.remove(go);
        System.gc();
    }
}

したがって、最後にここチャンク5では、これは多くのコードが削除されたメインループですが、移動する必要があるかどうかをテストします。移動した場合は、moveToY()を介してRunnableとして渡されたactionComplete()を実行します。 。さて、このRunnableは、オブジェクトがその場所に到達したら削除すると言います。そして、Runnable 1回以内にコードを実行すると、すべてが停止します。動きが止まります。したがって、2つ以上のレーザーが発射された場合、それらは上向きに移動する必要がありますが、それらはその位置で停止し、移動しません。キーボードボタンが機能しなくなるため、移動する矢印がShip反応しなくなり、船を上/下/左/右にナビゲートできるようになります。これは、Runnableが最初にトリガーされたポイントの最後の位置にあります。

それで...なぜすべてが止まるのですか?Runnableにあったオブジェクトを削除したいだけです。

4

1 に答える 1

1

コード編成に深刻な問題があります。gameObjectsリストをRoom直接(メソッド内でremoveGameObject)変更すると同時に、イテレータを使用して(メソッド内でrun)リストを変更しています。これにより、イテレータは(例外をスローする場合のように)文句を言います。runメインメソッドの例外をキャッチし、黙って無視していることに注意してください。そのような例外を決して捨てないでください—何かがうまくいかないとき、それらはあなたに教えてくれます。

リストをトラバースするイテレータがない場合にのみリストからオブジェクトを削除するように、コードを編成する必要があります。これを行うには、オブジェクトに削除のマークを付けてから、ゲームループの別のステップでオブジェクトを削除する方法を作成します。

于 2012-12-26T20:23:34.603 に答える