初心者向けの純粋なJavaのゲーム、初心者向け

私は初心者のJavaプログラマーであり、私の道は何千人も旅をしました。







最初に最も正しい本の長く苦痛な選択が来て、それからそれから転載されたプログラムリストの仕事に対する最初の熱意が来ます。 その後、成長するクールさとプロ意識の意識。 自分で何かを書き込もうとしているときに、自分の取るに足りないものの落とし穴に落ちる。 そして長い道のり。



私の場合、最も正しい本は2巻の「Java。 「ケイホルストマンとゲイリーコーネルによって執筆され、Javaの世界への扉を開いた最初の本は、ジェイコブファイン、「子供、親、祖父、祖母のためのJavaプログラミング」です。」



私の頭ではなく、スマートブックのページに頑なに留まろうとしていた、ばらまこうとする知識を統合するために、私は簡単なゲームを書くことにしました。 主なタスクは、サードパーティのライブラリを使用せずに記述することでした。



一般的なアイデア(私のものではなく、Chain Rxnフラッシュゲームから取ったもの)


長方形の競技場では、レベルに応じて、壁に反射するさまざまな速度で、それに沿って着用されるいくつかのボールが表示されます。 プレーヤーは競技場でマウスカーソルを押します。押した時点でボールが成長し、所定の半径まで増加します。 一定時間後、残りのボールは、衝突した場合、停止し、サイズが大きくなり、さらに小さくなり、消えます。



各レベルの特定の目標は、「ノックアウト」するボールの数です。







実装。


まず、GameConstantsインターフェースが作成され、そこにすべての主要な定数が配置されました。 すべてのクラスについて、GameConstantsの実装が指定されました:



GameConstantsインターフェース
public interface GameConstants { public final int DEFAULT_WIDTH = 600;//   public final int DEFAULT_HEIGHT = 300; //   public final int DELAY = 8; //  «»  public final int BASERADIUS=5; //   public final int LIFETIME=1300; // «»  public final int MAXRADIUS=25; //   public final int STARTQNTBALLS=10; //     }
      
      







次に、Ballクラスが作成されました。 このクラスの各オブジェクトには、x軸とy軸に沿った独自の座標セット、dx変数とdy変数があり、単位時間あたりの座標の増分(実際には速度)、半径と半径の増分の値、および色と一意の識別子が記録されます。 識別子は、後で衝突を追跡するときに役立ちます。



各ボールには、現在の状態を特徴付けるinAction変数もあります。つまり、0-衝突前、1-衝突と成長、2-寿命とサイズの縮小です。



別のタイマーがクラスに追加されました。その目的は、ボールの「寿命」の時間を、最大サイズに達した瞬間から追跡することです。 上記のインターフェース(LIFETIME)で指定された時間が経過すると、サイズの増分は負になり、サイズがゼロになるとオブジェクトが削除されます。



ボールクラス
 public class Ball implements GameConstants { private int inAction; //   private int x; //   x  y private int y; private int dx; //   x  y private int dy; private int radius; // private int dRadius; //  private Color color; // private static int count; public final int id=count++; //  ()  private static int score; //  private Timer gameTimer; private TimerTask gameTimerTask; //     // Ball Ball(int x, int y, int dx, int dy, int radius, Color color, int inAction, int dRadius){ this.x=x; this.y=y; this.dx=dx; this.dy=dy; this.radius=radius; this.color=color; this.inAction=inAction; this.dRadius=dRadius; gameTimer = new Timer(); } //     public Ellipse2D getShape(){ return new Ellipse2D.Double(x-radius, y-radius, radius*2, radius*2); } //    : public void moveBall(BallComponent ballComponent){ x+=dx; y+=dy; radius+=dRadius; if(x<=0+radius){ x=radius; dx=-dx; } if (x>=DEFAULT_WIDTH-radius){ x=DEFAULT_WIDTH-radius; dx=-dx; } if(y<=0+radius){ y=radius; dy=-dy; } if (y>=DEFAULT_HEIGHT-radius){ y=DEFAULT_HEIGHT-radius; dy=-dy; } for(Ball ballVer: ballComponent.listBall){ // -        Ball, //  ,    «» , //  (ballVer),        //       (    id) if(inAction==0) if((Math.sqrt(Math.pow(x-ballVer.x,2)+Math.pow(y-ballVer.y,2)))<=radius+ballVer.radius && id!=ballVer.id && (ballVer.inAction==1 || ballVer.inAction==2)) { ballComponent.score++; ballComponent.totalScore++; dx=dy=0; inAction=1; ballComponent.setBackground(ballComponent.getBackground().brighter()); } if(inAction==1){ dRadius=1; if (radius>=MAXRADIUS){ inAction=2; dRadius=0; // ,     ,     gameTimerTask = new gameTimerTask(this); gameTimer.schedule(gameTimerTask, LIFETIME); } } //    -      if(inAction==2 && radius<=0){ ballComponent.listBall.remove(this); }}} //,    LIFETIME,     : class gameTimerTask extends TimerTask{ private Ball ballTimer; public gameTimerTask(Ball ball) { // TODO Auto-generated constructor stub this.ballTimer = ball; } public void run() { // TODO Auto-generated method stub ballTimer.dRadius=-1; } } }
      
      







moveBall関数では、ボールの位置とそのサイズが追跡されます。 これを行うには、速度値を座標に追加します。これは、以下のBallGameクラスでランダムな値として設定され、その増分はベース半径の値(ゼロに設定)に追加されます。

  x+=dx; y+=dy; radius+=dRadius;
      
      





BallComponentクラスはJPanelを継承し、競技場を直接描画する役割を果たし、Ballタイプのオブジェクトが配置され、スコアが維持されるリストを作成します。 オブジェクトの存続期間が過ぎると、リストから削除されます。



BallComponentクラス
 public class BallComponent extends JPanel implements GameConstants { List<Ball> listBall = new CopyOnWriteArrayList<>(); boolean startClick; public int score=0; public int totalScore=0; //  Ball   public void addBall(Ball b){ listBall.add(b); } public void paintComponent(Graphics g){ super.paintComponent(g); Graphics2D g2d = (Graphics2D)g; for(Ball ball: listBall){ g2d.setColor(ball.getColor()); g2d.fill(ball.getShape()); } } public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }}
      
      







さらに、HorstmannとCornellの教育的な例の最良の伝統では、メインのBallGameクラスが作成され、そこからBallGameFrame()クラスが呼び出されました。



BallGameクラス
 public class BallGame implements GameConstants { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame ballFrame = new BallGameFrame(); ballFrame.setVisible(true); }}); }}
      
      







JFrameを継承するBallGameFrameクラスは、競技場の外部シェルを作成します。つまり、要素を配置し、マウスイベントリスナーを処理し、情報メッセージを出力します。 また、マウスをクリックすると呼び出されるstartGame()関数も含まれます。 この関数は、無限のゲームループが回転するストリームを起動します。



BallGameFrameクラス
 class BallGameFrame extends JFrame implements GameConstants{ private int level=1; //  private int ballQnt; private BallComponent ballComponent; private MousePlayer mousePlayerListener; // public BallGameFrame() { ballQnt=STARTQNTBALLS; setTitle("BallGame"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); ballComponent = new BallComponent(); ballComponent.setBackground(Color.DARK_GRAY); mousePlayerListener = new MousePlayer(); add(ballComponent, BorderLayout.CENTER); final JPanel buttonPanel = new JPanel(); final JButton startButton = new JButton(" ."); buttonPanel.add(startButton); final JLabel scoreLabel = new JLabel(); buttonPanel.add(scoreLabel); startButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { ballComponent.addMouseListener(mousePlayerListener); ballComponent.addMouseMotionListener(mousePlayerListener); startButton.setVisible(false); ballComponent.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); startGame(scoreLabel, ballQnt); }}); add(buttonPanel, BorderLayout.SOUTH); pack(); } public void startGame(JLabel scoreLabel, int ballQnt){ Runnable r = new BallRunnable(ballComponent, scoreLabel, level, ballQnt); Thread t = new Thread(r); t.start(); } //   MousePlayer,     : class MousePlayer extends MouseAdapter{ public void mouseClicked(MouseEvent e) { //   Random random = new Random(); //  ,      //   (),   Ball ball = new Ball(e.getX(), e.getY(), 0, 0, BASERADIUS, new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)), 1, 1); ballComponent.startClick=true; ballComponent.addBall(ball); //  ,       ,        ballComponent.removeMouseListener(mousePlayerListener); ballComponent.removeMouseMotionListener(mousePlayerListener); ballComponent.setCursor(Cursor.getDefaultCursor()); }}}
      
      







メインアクションが実行されるBallRunnableクラス。



BallRunnableクラス
 class BallRunnable implements Runnable, GameConstants{ private BallComponent ballComponent; private JLabel scoreLabel; private int level, ballQnt; private MousePlayer mousePlayerListener; private int goal; public BallRunnable(final BallComponent ballComponent, JLabel scoreLabel, int level, int ballQnt) { this.ballComponent = ballComponent; this.scoreLabel = scoreLabel; this.level=level; this.ballQnt=ballQnt; this.goal=2; } class MousePlayer extends MouseAdapter{ public void mousePressed(MouseEvent e) { Random random = new Random(); Ball ball = new Ball(e.getX(), e.getY(), 0, 0, BASERADIUS, new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)), 1, 1); ballComponent.addBall(ball); ballComponent.startClick=true; ballComponent.removeMouseListener(mousePlayerListener); ballComponent.removeMouseMotionListener(mousePlayerListener); ballComponent.setCursor(Cursor.getDefaultCursor()); }} public void run(){ while(true){ try{ mousePlayerListener = new MousePlayer(); ballComponent.addMouseListener(mousePlayerListener); ballComponent.addMouseMotionListener(mousePlayerListener); //      ballComponent.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); //     int countInWork=1; //    //    //    for (int i=0;i<ballQnt; i++){ Random randomX = new Random(); Random randomY = new Random(); Ball ball = new Ball(randomX.nextInt(DEFAULT_WIDTH), randomY.nextInt(DEFAULT_HEIGHT), randomX.nextInt(2)+1, randomY.nextInt(2)+1, BASERADIUS, new Color(randomX.nextInt(255),randomX.nextInt(255),randomX.nextInt(255)), 0, 0); ballComponent.addBall(ball); } //     while (countInWork!=0){ countInWork=0; if(!ballComponent.startClick) { EventQueue.invokeLater(new Runnable() { public void run() { // TODO Auto-generated method stub scoreLabel.setText(":  "+ goal+"   "+ ballQnt); } } ); countInWork=1; } for(Ball ball: ballComponent.listBall){ if((ball.inAction()==1 || ball.inAction()==2)) countInWork++; //    ball.moveBall(ballComponent); ballComponent.repaint(); if(ballComponent.startClick){ //   EventQueue.invokeLater(new Runnable() { public void run() { scoreLabel.setText(": "+ level+",   "+ballComponent.score+"  "+ballQnt); }}); }} Thread.sleep(DELAY); } } catch (InterruptedException ex){ ex.printStackTrace(); } ballComponent.listBall.clear(); ballComponent.repaint(); //  if(ballComponent.score<goal) { EventQueue.invokeLater(new Runnable() { public void run() { scoreLabel.setText("   !"); } }); JOptionPane.showMessageDialog(ballComponent, "   . \n : "+ ballComponent.totalScore+".\n   ."); ballComponent.startClick=false; ballComponent.score=0; ballComponent.setBackground(Color.DARK_GRAY); } else{ EventQueue.invokeLater(new Runnable() { public void run() { scoreLabel.setText(" !!!"); } }); ballComponent.startClick=false; level++; ballQnt++; goal++; ballComponent.setBackground(Color.DARK_GRAY); ballComponent.score=0; JOptionPane.showMessageDialog(ballComponent, " "+level+".\n:  "+ goal+"   "+ ballQnt); }}}
      
      







メッセージは別のストリームで画面に表示されることに注意してください。 これについては、ホルストマンの第14章「マルチスレッド処理」および「ストリームとSwingライブラリ」セクションを参照してください。



各レベルで、ボールの総数と目標(ノックアウトする必要がある数)が増加します。 最初は、プレーヤーが最初に多くのボール(たとえば、10個中8個)を打たなければならないようにしましたが、これはテスターに​​とって退屈に見え、ゲームは中止されました。 そのため、難易度の不適格度を徐々に上げることにしました。



公式記録はレベル86です。 著者自身が最大レベル15まで行きました。



その後、休暇を取らせてください。 アドバイス、批判、サポートを楽しみにしています。



All Articles