C#で2048ゲームのクローンを作る[その5]

今回は、予定通り盤面に表示させる駒(セル)を管理するクラスを作成します。
これまでのゲームルール作成は一旦置いておき、描画寄りのプログラムになります。

今回作るプログラムで、以下のような盤面の表示を行えるようにします。



CellScriptクラスの作成(概要)

まずは、セルを管理するCellScriptクラスを作成します。
大枠だけまず書くと、以下のような感じになります。
CellScript.cs

using System.Windows.Forms;
using System.Collections.Generic;
using System.Drawing;
using System;
 
class CellScript {
    /// <summary>セルの大きさ</summary>
    public const int CELL_SIZE = 50;
 
    /// <summary>セル間の隙間</summary>
    public const int CELL_PADDING = 4;
 
    private Panel pnlBoard;
    private Label lblCell;
 
    // コンストラクタ
    public CellScript( Panel pnlBoard, int cellValue, int x, int y ) {
        ...
    }
 
    // セルの位置を指定する
    public void setPosition(int x, int y) {
        ...
    }
 
    // セルに値をセットする
    public void setValue (int cellValue) {
        ...
    }
}



クラス定義を見てみると、まず、セルの大きさや隙間のサイズです。これはいろいろな所で必要となるので、定数にしておきます。

/// <summary>セルの大きさ</summary>
public const int CELL_SIZE = 50;
 
/// <summary>セル間の隙間</summary>
public const int CELL_PADDING = 4;



次に、内部的なメンバ変数として、駒を表現するためLabelと、駒を置く盤になるPanelオブジェクトを保持します。ここで出てくるLabelは、今回GUIの描画にWinFormを使用しているため、正確に書くとSystem.Windows.Forms.Labelクラスです。Panelも同様です。

private Panel pnlBoard;
private Label lblCell;



今回作るメソッドは、コンストラクタ、位置の移動、値のセットの3つです。将来的にはセルの状態管理やアニメーションを行う為にメソッドを増やすつもりですが、最低限これだけあれば表示は可能です。

// コンストラクタ
public CellScript( Panel pnlBoard, int cellValue, int x, int y );
 
// セルの位置を指定する
public void setPosition(int x, int y);
 
// セルに値をセットする
public void setValue (int cellValue);


それでは、これらのメソッドの中身を作っていきます。


CellScriptクラスの作成(詳細)

まずは、コンストラクタからです。今回作ったソースはこちらです。

//*********************************************************************
/// <summary> コンストラクタ
/// </summary>
/// <param name="value"></param>
/// <param name="x"></param>
/// <param name="y"></param>
//*********************************************************************
public CellScript( Panel pnlBoard, int cellValue, int x, int y ) {
    this.pnlBoard = pnlBoard;
    _createLabel();
    setPosition( x, y );
    setValue( cellValue );
}


行っていることはシンプルで、GUIパーツであるラベルオブジェクトを生成し、値・位置を初期化しているだけです。


次に、コンストラクタから呼び出される_createLabel()を見てみます。

//*********************************************************************
/// <summary> セルのラベルを作成する
/// </summary>
//*********************************************************************
private void _createLabel() {
    if (pnlBoard == null) {
        return;
    }
 
    lblCell = new System.Windows.Forms.Label();
 
    lblCell.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
    lblCell.Location = new System.Drawing.Point(0, 0);
    lblCell.Name = "cellLabel";
    lblCell.Size = new System.Drawing.Size(CELL_SIZE, CELL_SIZE);
    lblCell.Text = "";
    lblCell.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
 
    pnlBoard.Controls.Add(this.lblCell);
    lblCell.BringToFront();
}


ここではWinFormのコントロールを自動生成しています。
このコードの作り方は、別の記事で説明しています。
LabelなどGUIコントロールの動的生成コードを一瞬で作る方法

メソッドの最後でpnlBoard.Controls.Add()としているので、作ったLabelはパネルの上に作成されます。


_createLabel()でlblCellにLabelオブジェクトを作成したら、次は場所の指定です。
LabelオブジェクトはLocationプロパティで場所を指定できるため、セルの大きさとセル間の隙間を考慮して、セルを置く左上の座標を求めています。

//*********************************************************************
/// <summary> セルの位置を指定する
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
//*********************************************************************
public void setPosition(int x, int y) {
    if (lblCell == null) {
        return;
    }
 
    int dispPixelOffsetX = x*CELL_SIZE + (x+1)*CELL_PADDING;
    int dispPixelOffsetY = y*CELL_SIZE + (y+1)*CELL_PADDING;
 
    lblCell.Location = new System.Drawing.Point(dispPixelOffsetX, dispPixelOffsetY);
}




次に、値をセットするsetValue()メソッドと、そこから呼ばれるprivateメソッドを一度に見てみます。
基本的には、lblCell.Textで値をセットしておしまいなのですが、値によって色を変更するのと、桁数が増えると表示が折り返されてしまうので、桁数が増えるたびにフォントサイズを小さくして折り返されないようにする処理を入れています。

//*********************************************************************
/// <summary> セルに値をセットする
/// </summary>
/// <param name="cellValue"></param>
//*********************************************************************
public void setValue (int cellValue) {
    lblCell.Text = cellValue.ToString();
 
    // セルの値に応じた色/フォントをセットする
    lblCell.BackColor = _getCellColor( cellValue );
    lblCell.Font      = _getCellFont( cellValue );
}
 
//*********************************************************************
/// <summary> セルの値に応じた色を返す
/// </summary>
/// <param name="cellValue"></param>
/// <returns></returns>
//*********************************************************************
private Color _getCellColor( int cellValue ) {
    // セルの値を元に何番目かを求める 2:1番目, 4:2番目, 8:3番目, 16:4番目 ...
    int offset = (int)Math.Log(cellValue, 2 );
    offset = Math.Max( 0, offset);
 
    // 色を求める(番号が増えるほど青暗くするが、見づらいので0x60以下には暗くしない)
        int col = Math.Max( 60, 255 - offset*20 );
    return Color.FromArgb( 255, col, col, 0xff);
}
 
//*********************************************************************
/// <summary> セルの値に応じたフォントを返す
/// </summary>
/// <param name="cellValue"></param>
/// <returns></returns>
//*********************************************************************
private Font _getCellFont( int cellValue ) {
    // 数字の大きさに合わせてフォントサイズを切り替える
    float fontSize = 12;
    if (cellValue >= 1000) {
        fontSize = 10;
    }
    if (cellValue >= 10000) {
        fontSize = 8;
    }
    return new System.Drawing.Font("Meiryo UI", fontSize, 
                                    System.Drawing.FontStyle.Regular, 
                                    System.Drawing.GraphicsUnit.Point, 
                                    ((byte)(128)));
}



上記の処理で、CellScript.csは一旦完了です。


FormからCellScript.csを呼び出す

次は、Formから先ほど作成したCellScriptを実行します。
Formにパネル(pnlBase)を貼り付けた上で、下記のコードを実行します。

public partial class Form1 : Form {
    //*********************************************************************
    /// <summary> 画面表示時のハンドラ
    /// </summary>
    //*********************************************************************
    private void Form1_Load( object sender, EventArgs e ) {
 
        // 動作確認用のセルを生成する
        new CellScript( this.pnlBase,   64, 0, 0 );
        new CellScript( this.pnlBase,  256, 1, 0 );
        new CellScript( this.pnlBase, 1024, 2, 0 );
        new CellScript( this.pnlBase,65535, 3, 0 );
 
        new CellScript( this.pnlBase,    8, 0, 1 );
        new CellScript( this.pnlBase,    4, 1, 1 );
 
        new CellScript( this.pnlBase,    2, 3, 2 );
 
 
 
        // 盤面の大きさを調整する
        int boardSize     = CellScript.CELL_SIZE    * BoardManager.BOARD_SIZE +
                            CellScript.CELL_PADDING * (BoardManager.BOARD_SIZE+1) +
                            2;
        this.pnlBase.Size = new System.Drawing.Size(boardSize, boardSize);
    }
}



このコードを実行すると、最初にあった画像のような盤面が表示されます。
想定したとおり、数字によって色が変わっていたり、桁数によって文字の大きさが変わっていれば成功です。


これで基本的なセルの描画は完了しました。
次回も引き続きCellScriptを改良し、作ったセルを移動させるアニメーション処理を追加する予定です。

関連記事

コメントを残す

メールアドレスが公開されることはありません。