1

穴居人が岩を投げているゲームを作成しており、クリックすると岩が出現します。最初の 5 つほどは正常に動作し、その後、岩が画面から消えるまで待機し、その後再びスポーンできるようになります。クリックするたびにそれらを生成したいと思います。

前もって感謝します

コード:

 package com.russell.raphael.birds;

import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

@SuppressWarnings("serial")

public class Start extends JFrame {

    ImageIcon landImage, manImage, skyImage, RockPileImage, RockImage;
    JLabel skylbl, manlbl, landlbl, rockPilelbl;
    Bird[] birds = new Bird[10];
    Rock[] rocks = new Rock[10000];

    public static MouseListener throwrock;

    public static void main(String[] args){

        new Start();

    }

    public Start() {

        setVisible(true);

        initComp();
        setSize(1000, 1100);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setTitle("Not the Birds!!!");
        setIconImage(Toolkit.getDefaultToolkit().getImage(Start.class.getResource("/com/russell/raphael/images/Icon.png")));

    }

    private void initComp() {

        throwrock = new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int eventX = 0, eventY = 0, sourceX = 420, sourceY = 840;
                int rise = 0, run = 0;

                try {
                    JLabel source = (JLabel) e.getSource();

                    eventX = (source.getLocation().x) + (e.getX());
                    eventY = (source.getLocation().y) + (e.getY());
                    rise = Math.abs(eventY - sourceY);
                    run = eventX - sourceX;


                    nextRock().start(rise, run);

                } catch (Exception ex) {

                    ex.printStackTrace();
                }

            }

        };

        setResizable(false);

        for(int counter =0; counter < rocks.length; counter++){

            rocks[counter] = new Rock();
            getContentPane().add(rocks[counter]);

        }

        landImage = new ImageIcon(
                Start.class.getResource("/com/russell/raphael/images/land.png"));
        manImage = new ImageIcon(
                Start.class.getResource("/com/russell/raphael/images/man.png"));
        skyImage = new ImageIcon(
                Start.class.getResource("/com/russell/raphael/images/sky.jpg"));
        RockPileImage = new ImageIcon(
                Start.class
                        .getResource("/com/russell/raphael/images/rockpile.png"));

        getContentPane().setLayout(null);

        skylbl = new JLabel(skyImage);
        skylbl.addMouseListener(throwrock);
        skylbl.setLocation(0, 0);
        skylbl.setSize(1010, 983);
        skylbl.setVisible(true);

        manlbl = new JLabel(manImage);
        manlbl.setSize(200, 300);
        manlbl.addMouseListener(throwrock);
        manlbl.setLocation(400, 700);

        landlbl = new JLabel(landImage);
        landlbl.setBounds(0, 725, 1000, 400);
        manlbl.addMouseListener(throwrock);

        rockPilelbl = new JLabel();
        rockPilelbl.setIcon(RockPileImage);
        rockPilelbl.setBounds(236, 782, 220, 174);
        getContentPane().add(rockPilelbl);
        manlbl.addMouseListener(throwrock);

        getContentPane().add(manlbl);
        getContentPane().add(landlbl);
        getContentPane().add(skylbl);

    }

    public Rock nextRock(){

        for(int counter = 0; counter < rocks.length; counter++){

            if(!rocks[counter].hasBeenUsed){

                return rocks[counter];

            }

        }
        return null;
    }
}

次の授業:

package com.russell.raphael.birds;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

    import javax.swing.ImageIcon;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.Timer;

    @SuppressWarnings("serial")
    public class Rock extends JLabel {

        Timer timer;

        Thread thread;

        boolean hasBeenUsed = false;

        public Rock() {

            super();

            setBounds(415, 840, 37, 35);
            setIcon(new ImageIcon(
                    Rock.class.getResource("/com/russell/raphael/images/Rock.png")));

            setVisible(true);
        }

        public void start(final int rise, final int run) {

            hasBeenUsed = true;

            thread = new Thread() {

                public void run() {

                    timer = new Timer(30, new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent ae) {

                            setBounds(getBounds().x + run / 20, getBounds().y
                                    + -rise / 20, getBounds().width,
                                    getBounds().height);

                            if (getBounds().x < 0 || getBounds().y < 0
                                    || getBounds().y > 1000) {

                                timer.stop();

                                hasBeenUsed = false;

                                setBounds(415, 840, 37, 35);

                                thread.stop();

                            }

                        }

                    });
                    timer.start();
                }
            };

            thread.start();

        }
    }
</code>
4

1 に答える 1

1

岩のプールを空にしてからそれらが消えるのを待つことに問題はありませんが、他にもたくさんの問題があります...

始めましょう...

nextRock().start(rise, run);

nullこれにより、オブジェクトが返される可能性があり、NullPointerException

Thread前に述べたように、ミックスする必要はありませんTimer

public class Rock extends JLabel {

    Timer timer;
    private volatile boolean hasBeenUsed = false;

    public Rock() {
        super();
        setIcon(new ImageIcon(Rock.class.getResource("/Rock.png")));
        setBounds(415, 840, getPreferredSize().width, getPreferredSize().height);
        setVisible(false);
    }

    public void start(final int rise, final int run) {
        hasBeenUsed = true;
        setVisible(true);
        timer = new Timer(30, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                setBounds(getBounds().x + run / 20, getBounds().y
                                + -rise / 20, getBounds().width,
                                getBounds().height);

                if (getBounds().x < 0 || getBounds().y < 0
                                || getBounds().y > 1000) {
                    timer.stop();
                    hasBeenUsed = false;
                    setBounds(415, 840, getPreferredSize().width, getPreferredSize().height);
                }
            }
        });
        timer.start();
    }
}

あなたの岩のプールには 10,000 個の岩が含まれています!! この山を使い果たすのに十分な速さでクリックできるとは思えません。

テスト用に 2 か 3 のように減らしてみてください...

サイドノート

これは非常に高価な通話です...

public Rock nextRock() {
    for (int counter = 0; counter < rocks.length; counter++) {
        if (!rocks[counter].hasBeenUsed) {
            return rocks[counter];
        }
    }
    return null;
}

空中に 9, 999 個の岩がある場合、現在利用できないすべての岩を反復処理する必要があるため、最後の岩に到達するまでにかなりの時間がかかります。

すべての岩を に追加する方が簡単かもしれませんjava.util.List(これを rockPile と呼びましょう)。石が投げられたら、このリストをチェックして、利用可能な石があるかどうかを確認し、そうでない場合は戻り、そうでない場合は、リストから最初の石を削除して「飛行中」リストに配置します。これにより、岩の山をチェックするのが速くなります ( のようなものを使用するList#isEmptyList#get(0)、はるかに高速になります)。

ロックが再び「使用可能」になったら、「飛行中」リストから削除して、rockPileリストに戻します。

Timerこれは、リストを繰り返し処理し、そのinFlight位置を更新する責任を負うものに到達する可能性があることも意味します...

リストを使用した更新

基本的に、必要なすべての情報を維持し、関係者間で共有できるある種の「マネージャー」が必要です...

public class RockManager {

    private List<Rock> rockPile;
    private List<Rock> inFlight;
    public static final int MAX_ROCKS = 2;

    public RockManager() {
        rockPile = new ArrayList<Rock>(MAX_ROCKS);
        inFlight = new ArrayList<Rock>(MAX_ROCKS);
        for (int index = 0; index < MAX_ROCKS; index++) {
            rockPile.add(new Rock(this));
        }
    }

    public Rock[] getRocksOnPile() {
        return rockPile.toArray(new Rock[rockPile.size()]);
    }

    public Rock[] getRocksInFlight() {
        return inFlight.toArray(new Rock[inFlight.size()]);
    }

    public Rock pickRockOfPile() {
        Rock rock = null;
        if (!rockPile.isEmpty()) {
            rock = rockPile.remove(0);
            inFlight.add(rock);
        }
        return rock;
    }

    public void putRockBackOnPile(Rock rock) {
        if (inFlight.contains(rock)) {
            inFlight.remove(rock);
            rockPile.add(rock);
        }
    }
}

NB: 技術的には、おそらく「必要」inFlightではありませんが、飛行中でない岩を山に追加できないようにするためのトラップとして使用しています ;)。これにより、一意の参照のみがリスト内に含まれるようになりSetます...rockPile

次に、インスタンス フィールドをクラスに追加しましRockManagerStart

クラスのinitCompメソッドではStart、岩の作成方法を変更する必要があります...

だから、代わりに

for(int counter =0; counter < rocks.length; counter++){
    rocks[counter] = new Rock();
    getContentPane().add(rocks[counter]);
}

あなたは今持っているでしょう...

rockManager = new RockManager();
for (Rock rock : rockManager.getRocksOnPile()) {
    getContentPane().add(rock);
}

あなたのnextRock方法は...

public Rock nextRock() {
    return rockManager.pickRockOfPile();
}

そして最後に、Rockクラスには への参照が必要ですRockManager。基本的に、コンストラクターを介して参照を渡します...

private RockManager manager;

public Rock(RockManager manager) {
    super();
    this.manager = manager;

次に、岩が競技場を離れたら、RockManager...を介して山に戻すことができます。

manager.putRockBackOnPile(Rock.this);
于 2012-11-04T03:24:19.897 に答える