C#でドミノエディタ(ドラッグ元のドミノの向きを変える)


アニメ『Re:CREATORS(レクリエイターズ)』
人が創造したはずのアニメの世界の住人が現実世界に現れて、てんやわんやになるってアニメっぽいです。
最近Re:から始まるタイトルをよく目にしますが、Re:って、~についてという意味だったと記憶してますが、そんなことはどうでもよく、Re:がつくとなんかかっこいい気がします。

ではドミノエディタの続きです。今回は描いた線に合わせて、このように斜めのドミノを自動で配置してみます。

考えなしに、プログラミングをしてますので、ぐっちゃぐちゃです。少しだけリファクタリングします。
まずは一番ひどい場所から。

  new private void DragEnter(object sender, DragEventArgs e){
    Matrix b = (Matrix)sender;

    string x_y = (string)e.Data.GetData(typeof(String));
    char[] delim={','};
    string[] pos=x_y.Split(delim,StringSplitOptions.None);
    if((int.Parse(pos[0]) == b.x) && (int.Parse(pos[1]) != b.y) ){
        b.Image = Image.FromFile(basedir + img[1]);
    }else if((int.Parse(pos[1]) == b.y) && (int.Parse(pos[0]) != b.x) ){
        b.Image = Image.FromFile(basedir + img[2]);
    }

    e.Data.SetData(""+b.x + "," + b.y);
  }  

e.Data.GetDataで取得する文字列は、ドラッグ元のButtonの座標が入っていますが、わざわざ文字列にしなくても、Buttonオブジェクトをそのまま渡していまえばよいです。
このように修正することにしました。

  new private void DragEnter(object sender, DragEventArgs e){
    Matrix now = (Matrix)sender;
    Matrix last = (Matrix)e.Data.GetData(typeof(Matrix));

    if((last.x == now.x) && (last.y != now.y) ){
        now.Image = Image.FromFile(basedir + img[1]);
    }else if( (last.y == now.y) && (last.x != now.x) ){
        now.Image = Image.FromFile(basedir + img[2]);
    }
    e.Data.SetData((Matrix)now);

次に画像を設定するこのようなソースですが、

        now.Image = Image.FromFile(basedir + img[1]);

やってることは画像の設定ですが、もう少しオブジェクト指向っぽく考えると、ドミノを置いていることになります。
Matrixのクラスにドミノ設定を組み込んでしまいましょう。

        now.SetDominoUp2Down();

こんな風に書き換えました。当然クラスが変更になります。

Matrixは、シンプルなButtonの派生でしたが、

  class Matrix : Button{
    public int state = 0;
    public int x;
    public int y;
  }

このようになりました。

class Matrix : Button{
  public int state = 0;
  public int x;
  public int y;
  public int dx;
  public int dy;
  string basedir="c:\\Users\\takk\\Desktop\\img\\";
  public void SetDominoUp2Down(){
      Image = Image.FromFile(basedir + "domino-tate.png");
      state = 1;
  }
  public void SetDominoLeft2Right(){
      Image = Image.FromFile(basedir + "domino-yoko.png");
      state = 2;
  }
  public void SetDominoDown2Left(){
      Image = Image.FromFile(basedir + "domino-cv1.png");
      state = 3;
  }
  public void SetDominoDown2Right(){
      Image = Image.FromFile(basedir + "domino-cv2.png");
      state = 4;
  }
  public void SetDominoUp2Right(){
      Image = Image.FromFile(basedir + "domino-cv3.png");
      state = 5;
  }
  public void SetDominoUp2Left(){
      Image = Image.FromFile(basedir + "domino-cv4.png");
      state = 6;
  }
}

ボタンの中にファイル名が埋め込まれているのが、むしろ改悪な感じではありますが、とりあえずこんな形で修正を進めます。

最後に、ドラッグ方向が変わった時に、ドミノの方向を変える処理を埋め込みます。
DragEnterメソッドの最後に追加します。

    if(last.state == 0){
      if((now.x == last.x) && (now.y != last.y)){
          last.SetDominoUp2Down();
      }else if((now.y == last.y) && (now.x != last.x)){
          last.SetDominoLeft2Right();
      }
    }else if(last.state != now.state){
	if((last.dx ==  1) && (last.y < now.y)) last.SetDominoDown2Left();
	if((last.dx ==  1) && (last.y > now.y)) last.SetDominoUp2Left();
	if((last.dx == -1) && (last.y < now.y)) last.SetDominoDown2Right();
	if((last.dx == -1) && (last.y > now.y)) last.SetDominoUp2Right();

	if((last.dy ==  1) && (last.x < now.x)) last.SetDominoUp2Right();
	if((last.dy ==  1) && (last.x > now.x)) last.SetDominoUp2Left();
	if((last.dy == -1) && (last.x < now.x)) last.SetDominoDown2Right();
	if((last.dy == -1) && (last.x > now.x)) last.SetDominoDown2Left();
    }

    if(last.x < now.x){ now.dx= 1; }
    if(last.x > now.x){ now.dx=-1; }
    if(last.y > now.y){ now.dy=-1; }
    if(last.y < now.y){ now.dy= 1; }

last.state が0のときは、ドラッグの起点を表してますので、縦か横かだけの判定にしています。
last.stateとnow.stateが違うときは、ドラッグ方向が変わってますので、ドラッグ元のドミノの配置を斜めにします。
最後のnow.dxやnow.dyへの1または-1の代入は、ドラッグの方向を覚えておくための処理です。

まだ直し甲斐のあるソースではありますが、修正後の全ソースです。

using System;
using System.Drawing;
using System.Windows.Forms;

class Matrix : Button{
  public int state = 0;
  public int x;
  public int y;
  public int dx;
  public int dy;
  string basedir="c:\\Users\\takk\\Desktop\\img\\";
  public void SetDominoUp2Down(){
      Image = Image.FromFile(basedir + "domino-tate.png");
      state = 1;
  }
  public void SetDominoLeft2Right(){
      Image = Image.FromFile(basedir + "domino-yoko.png");
      state = 2;
  }
  public void SetDominoDown2Left(){
      Image = Image.FromFile(basedir + "domino-cv1.png");
      state = 3;
  }
  public void SetDominoDown2Right(){
      Image = Image.FromFile(basedir + "domino-cv2.png");
      state = 4;
  }
  public void SetDominoUp2Right(){
      Image = Image.FromFile(basedir + "domino-cv3.png");
      state = 5;
  }
  public void SetDominoUp2Left(){
      Image = Image.FromFile(basedir + "domino-cv4.png");
      state = 6;
  }
}

class Test : Form{
  const int xlen=20;
  const int ylen=16;
  const int bsize=44;

  Matrix[,] mat = new Matrix[xlen,ylen];

  Test(){
    this.Size = new Size((bsize+1)*xlen,(bsize+1)*ylen);
    for(int x=0;x<xlen;x++){
      for(int y=0;y<ylen;y++){
        mat[x,y] = new Matrix();
        mat[x,y].x = x;
        mat[x,y].y = y;
        mat[x,y].Parent = this;
        mat[x,y].Location = new Point(bsize*x,bsize*y);
        mat[x,y].Size = new Size(bsize,bsize);
        mat[x,y].AllowDrop = true;
        mat[x,y].MouseDown += MouseDown;
        mat[x,y].DragEnter += DragEnter;
      }
    }
  }

  new private void MouseDown(object sender, MouseEventArgs e){
    Matrix b = (Matrix)sender;
    b.DoDragDrop((Matrix)sender, DragDropEffects.Copy | DragDropEffects.Move);
  }  

  new private void DragEnter(object sender, DragEventArgs e){
    Matrix now = (Matrix)sender;
    Matrix last = (Matrix)e.Data.GetData(typeof(Matrix));

    if((last.x == now.x) && (last.y != now.y) ){
        now.SetDominoUp2Down();
    }else if( (last.y == now.y) && (last.x != now.x) ){
        now.SetDominoLeft2Right();
    }

    e.Data.SetData((Matrix)now);

    if(last.state == 0){
      if((now.x == last.x) && (now.y != last.y)){
          last.SetDominoUp2Down();
      }else if((now.y == last.y) && (now.x != last.x)){
          last.SetDominoLeft2Right();
      }
    }else if(last.state != now.state){
	if((last.dx ==  1) && (last.y < now.y)) last.SetDominoDown2Left();
	if((last.dx ==  1) && (last.y > now.y)) last.SetDominoUp2Left();
	if((last.dx == -1) && (last.y < now.y)) last.SetDominoDown2Right();
	if((last.dx == -1) && (last.y > now.y)) last.SetDominoUp2Right();

	if((last.dy ==  1) && (last.x < now.x)) last.SetDominoUp2Right();
	if((last.dy ==  1) && (last.x > now.x)) last.SetDominoUp2Left();
	if((last.dy == -1) && (last.x < now.x)) last.SetDominoDown2Right();
	if((last.dy == -1) && (last.x > now.x)) last.SetDominoDown2Left();
    }

    if(last.x < now.x){ now.dx= 1; }
    if(last.x > now.x){ now.dx=-1; }
    if(last.y > now.y){ now.dy=-1; }
    if(last.y < now.y){ now.dy= 1; }
  }  

  [STAThread]
  public static void Main(){
    Application.Run(new Test());
  }
}

これでペンタブで、自由に描いてドミノ配置できるようになりました。

マトリクスを増やして、試し描きしてみました。

ペンタブですらすらドミノが配置できます。
しかし描いてから、セーブ機能を追加していないことに気が付きました。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA