機能要件: 2048 の基本インターフェイスは 2048 のゲーム機能を実現できます。
一般的なアイデア: Game と GameListener の 2 つのクラス。
Game はインターフェイスの実装とペイント メソッドの書き換えを担当します
GameListener はキーボードとマウスのイベントの処理を実装します。移動方法、加算方法、勝敗判定、乱数の出現などはキーボード監視方式で実装する必要があります。
実装分析: 2048 ゲームを実装するには、まず 2048 に何が含まれるかを検討する必要があります。
インターフェースの実装:
2048のゲームインターフェースは非常にシンプルで、いくつかの四角形と数字だけです。このようなインターフェースを実装するには、Java の描画機能を使用することが考えられます。具体的には、JFrame クラスが提供する Graphics オブジェクトを描画に使用します。 2048 インターフェイスは、大きな長方形の背景と、数字を含む多数の小さな正方形で構成されます。 Graphics オブジェクトの描画メソッドは、背景や小さな四角形の描画を実現できます。小さな正方形内の数字は、グラフィックスのdrawStringメソッドを使用して描画できます。描くときは色に注意してください。インターフェイスの実装に必要な主なクラスは、JFrame クラスです。
基本的なインターフェースの実装コードはいくつかのボタンなどだけで、特に言うことはありません。
private void initUI() { setTitle("2048"); setDefaultCloseOperation(3); setSize(600, 700); setLocationRelativeTo(null);this.setLayout(null);//添加分数jl2 = new JLabel("分数:0"); jl2.setFont(new Font("黑体", Font.BOLD, 30)); jl2.setBounds(20, 30, 200, 50);this.add(jl2);//添加开始按钮ImageIcon start=new ImageIcon("res/start.png");//开始游戏图标,随意替换就好startJB=new JButton(start); startJB.setBounds(280, 40, 120, 30); startJB.setFocusable(false); startJB.setBorderPainted(false);//设置按钮的边框为空startJB.setFocusPainted(false); startJB.setContentAreaFilled(false);//设置按钮的边框内填充颜色 //添加退一步按钮ImageIcon back=new ImageIcon("res/backicon.png");//游戏结束图标,随意替换就好backJB=new JButton(back); backJB.setBounds(430, 40, 120, 30); backJB.setFocusable(false); backJB.setBorderPainted(false); backJB.setFocusPainted(false); backJB.setContentAreaFilled(false); this.add(startJB);this.add(backJB); setVisible(true); GameListener gl = new GameListener(this, arry, jl2,startJB,backJB); addKeyListener(gl); startJB.addActionListener(gl); backJB.addActionListener(gl); }
正方形と数字の描画:
正方形と数字の描画も、JFrameキャンバスオブジェクトの長方形描画メソッドを使用して実装されます。
public void buffPaint(Graphics g) { Image image = createImage(600, 600); Graphics g2 = image.getGraphics(); g2.setColor(Color.LIGHT_GRAY); Graphics2D g2d = (Graphics2D) g2; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.fillRoundRect(0, 0, Draw2048.RD, Draw2048.RD, 20, 20); g2.setColor(Color.GRAY);for (int r = 0; r < arry.length; r++) {for (int c = 0; c < arry[r].length; c++) { g2.fillRect(20 + c * (Draw2048.D + Draw2048.space), 20 + r* (Draw2048.D + Draw2048.space), Draw2048.D, Draw2048.D); } }for (int r = 0; r < arry.length; r++) {for (int c = 0; c < arry[r].length; c++) {if (arry[r][c] != 0) { g2.setColor(255, 250, 240); g2.fillRect(20 + c * (Draw2048.D + Draw2048.space), 20 + r* (Draw2048.D + Draw2048.space), Draw2048.D, Draw2048.D); g2.setColor(new Color(0, 191, 255)); g2.setFont(new Font("楷体", Font.BOLD, Draw2048.FSIZE)); g2.drawString(arry[r][c] + "", 50 + c* (Draw2048.D + Draw2048.space), 90 + r* (Draw2048.D + Draw2048.space)); } } } g.drawImage(image, 50, 150, this); }
Draw2048是一个接口,里面定义了关于方格绘制的相关常量,D方格边长,space方格间间隔。RD背景大矩形的边长。使用接口的好处就是使得界面的更改(如改成5*5的格子)可以更加方便的实现,提高程序的扩展性。另外界面需要不断的更新,所以要调用paint方法不断的重绘。如果直接把这里的绘制写在paint方法中,不断的重绘会使得界面一直在闪烁。这里的解决方案就是使用图片缓冲,先在图片中绘制好,在把图片一次性绘制出来,这样就不会出现界面的闪烁问题了。
移動実装:
グリッドを移動させたい場合に考えられる方法は、アートボードの再描画を利用することです。正方形内の数値は 2 次元配列に格納されます。配列を移動するたびに配列の値を変更し、配列の値に基づいてデータをインターフェイスに描画するだけです。もちろん、ゲームをプレイするときは、思考に頼ってゲームを操作することはできません。つまり、キーボードという入力デバイスが必要です。したがって、キーボード監視をインターフェイスに追加する必要があります。ユーザーが異なるキーを押すと、異なる動作アルゴリズムが実装されます。リスニング クラスで対応する移動アルゴリズムを記述するときは、ループの使用法と終了 (特に Break ステートメントの使用法) を明確にする必要があることに注意してください。そうしないと、さまざまなバグが発生します。モバイル実装では keyListener クラスを使用する必要があります。
以下は上方向への動きの実装です。他の方向への動きも同様です。<span style="font-size: 16px"><span style="color: #0000ff"><span style="color: #339966">//向上移动的算法</span><br/>for</span> (<span style="color: #0000ff">int</span> r = 0; r < arry.length; r++<span style="color: #000000">) </span><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> c = 0; c < arry[r].length; c++<span style="color: #000000">) {</span><span style="color: #0000ff">if</span> (arry[r][c] > max)<span style="color: #008000">//</span><span style="color: #008000">找出数组最大值,用于判断玩家的方块是否达到2048</span>max =<span style="color: #000000"> arry[r][c];</span><span style="color: #0000ff">if</span> (arry[r][c] == 0<span style="color: #000000">) {</span><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> r1 = r + 1; r1 < arry[c].length; r1++<span style="color: #000000">) </span><span style="color: #0000ff">if</span> (arry[r1][c] != 0<span style="color: #000000">) { arry[r][c] </span>=<span style="color: #000000"> arry[r1][c]; arry[r1][c] </span>= 0<span style="color: #000000">; count</span>++<span style="color: #000000">;<span style="color: #339966">//判断是否发生移动,并且作为输赢判断的标准之一</span></span><span style="color: #0000ff">break</span><span style="color: #000000">; } } }</span>それぞれの値が 0 の場合、ループします。 、上に移動できます。値が配置されている列を走査し、0 ではない最初の値を見つけて、この値を移動します (つまり、2 つの数値の値を交換します)。移動後、内側のループを終了し、次の値のトラバースを続けます。
数値の加算:
独立したアルゴリズムを使用して配列を走査し、移動方向に隣接する 2 つの数値を加算し、1 つを 0 に設定します。ここでのアルゴリズムの実装は、移動アルゴリズムとよく似ていますが、ブレークとループの使用にも注意が必要です。もう 1 つの注意点は、数字を移動する前に数字の追加を完了する必要があることです。そうしないと、移動後の数字にスペースが入ってしまいます。
<span style="font-size: 16px"><span style="color: #0000ff"><span style="color: #339966">//向左的相加算法</span><br>for</span> (<span style="color: #0000ff">int</span> r = 0; r < arry.length; r++<span style="color: #000000">)</span><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> c = 0; c < arry[r].length; c++<span style="color: #000000">)</span><span style="color: #0000ff">if</span> (arry[r][c] != 0<span style="color: #000000">)</span><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> c1 = c + 1; c1 < arry[r].length; c1++<span style="color: #000000">)</span><span style="color: #0000ff">if</span> (arry[r][c] ==<span style="color: #000000"> arry[r][c1]) { arry[r][c] </span>*= 2<span style="color: #000000">; score </span>+=<span style="color: #000000"> arry[r][c]; arry[r][c1] </span>= 0<span style="color: #000000">; count</span>++<span style="color: #000000">;<span style="color: #339966">//判断是否发生相加,并作为输赢判断条件之一。</span></span><span style="color: #0000ff">break</span><span style="color: #000000">; } </span><span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (arry[r][c1] != 0<span style="color: #000000">) { </span><span style="color: #0000ff">break</span><span style="color: #000000">; }</span></span>も、この値が 0 でない場合は、行内で隣接する
の 2 つの隣接する値が異なる場合、 は最も内側のループも終了します。 2 つの Break ステートメントを使用すると、数値間のジャンプや加算が回避されます。 勝敗の判定:
2048 の勝ちの法則は、足した数が 2048 になることなので、配列の中に 2048 に等しい数があるかどうかを判断するだけで済みます。当選情報が出力されます。
2048年の負けルールは、インターフェースがいっぱいである(配列がいっぱいで、追加する移動番号がない)ことです。私の個人的な判断方法は、グローバル変数 count を加算して配列がいっぱいかどうかを判断することです。 count が 0 の場合、配列がいっぱいの場合は移動や加算ができないことを意味し、プレイヤーが負けたと判断できます。
乱数の出現:
乱数の出現条件は移動か加算なのでカウントで判定します。条件が成立すると、対応するアルゴリズムが呼び出されます。
以上がJavaバージョン2048で実装されたゲーム機能の例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。