Visual Studio C# テトリス のnextBlockの表示

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
MONO

Visual Studio C# テトリス のnextBlockの表示

#1

投稿記事 by MONO » 12年前

コード:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;

namespace tetris_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            image = Image.FromFile("tetrisBlock3 198 22.bmp");
            PutStartPos();
        }


        Image image;
        const int nColor = 9;
        const int width = 10;
        const int height = 20;
        readonly Point start_pos = new Point(4, 1);
        int[,] screen = new int[width, height];
        Block block;
        Point pos;
        int rot;

        int score = 0;


        const int fall_cycle = 10;
        int fall_cnt = 0;
        bool rot_stop;


        class Block
        {
            public Point[,] sq;     // sq[i, j]は回転パターンiのj個目の四角の位置
            public int color;       // 黒、水、黄、青、赤、橙、緑、紫
            public Block(Point[] sq, int n, int color)
            { // nは回転パターンの数
                this.sq = new Point[n, 4];
                for (int i = 0; i < n; ++i)
                {
                    for (int j = 0; j < 4; ++j) this.sq[i, j] = sq[j];
                    for (int j = 0; j < 4; ++j) sq[j] = RotateSq(sq[j]);
                }
                this.color = color;
            }
            private Point RotateSq(Point sq) { return new Point(sq.Y, -sq.X); }
        }

        readonly Block[] blocks = new Block[] { 
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(2, 0) }, 2, 7),   // I
            new Block(new Point[] { new Point(0, -1), new Point(1, -1), new Point(0, 0), new Point(1, 0) }, 1, 2),  // 四角
            new Block(new Point[] { new Point(-1, -1), new Point(-1, 0), new Point(0, 0), new Point(1, 0) }, 4, 5), // J
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(0, 1), new Point(1, 1) }, 2, 1),   // Z
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(1, -1) }, 4, 6),  // L
            new Block(new Point[] { new Point(-1, 1), new Point(0, 1), new Point(0, 0), new Point(1, 0) }, 2, 4),   // S
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(0, -1) }, 4, 3),  // T
        };

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            const int length = 22;
            var srcRect = new Rectangle[nColor];
            var destRect = new Rectangle[width, height];
            for (int i = 0; i < nColor; ++i) srcRect[i] = new Rectangle(i * length, 0, length, length);
            for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i) destRect[i, j] = new Rectangle(i * length, j * length, length, length);
            for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i) e.Graphics.DrawImage(image, destRect[i, j], srcRect[screen[i, j]], GraphicsUnit.Pixel);

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Point next_pos;
            int next_rot;
            GetNextPosRot(out next_pos, out next_rot);
            ReviseScreen(next_pos, next_rot);
        }


        void GetNextPosRot(out Point next_pos, out int next_rot)
        {
            next_pos = new Point(pos.X, pos.Y);
            next_rot = rot;
            if ((fall_cnt = (fall_cnt + 1) % fall_cycle) == 0) next_pos.Y += 1;    // 自然落下
            else if (Keyboard.IsKeyDown(Key.Up)) { if (!rot_stop) next_rot = (next_rot + 1) % block.sq.GetLength(0); }
            else if (Keyboard.IsKeyDown(Key.Down)) next_pos.Y += 1;
            else if (Keyboard.IsKeyDown(Key.Right)) next_pos.X += 1;
            else if (Keyboard.IsKeyDown(Key.Left)) next_pos.X -= 1;
            // 連続して回らないようにする
            if (Keyboard.IsKeyDown(Key.Up)) rot_stop = true;
            else rot_stop = false;
        }

        void ReviseScreen(Point next_pos, int next_rot)
        {
            Point[] sqs, next_sqs;
            GetSqs(block, pos, rot, out sqs);
            PutSqs(sqs, 0);
            if (GetSqs(block, next_pos, next_rot, out next_sqs))
            {
                PutSqs(next_sqs, block.color);
                pos = next_pos;
                rot = next_rot;
            }
            else
            {
                PutSqs(sqs, block.color);
                if (next_pos.Y == pos.Y + 1)
                {
                    DeleteLine();

                    label1.Text = Convert.ToString(score);

      
                    PutStartPos();
                    if (!GetSqs(block, pos, rot, out sqs))
                    {
                        PutSqs(sqs, block.color);
                        GameOver();
                    }
                }
            }
            Invalidate();
        }

        private void PutStartPos()
        {
            pos = start_pos;
            block = blocks[(new Random()).Next(0, blocks.Length)];
            rot = (new Random()).Next(0, block.sq.GetLength(0));
        }

        private bool GetSqs(Block block, Point pos, int rot, out Point[] sqs)
        {
            bool overlap = false;
            sqs = new Point[block.sq.GetLength(1)];
            for (int i = 0; i < sqs.Length; ++i)
            {
                var p = new Point(pos.X + block.sq[rot, i].X, pos.Y + block.sq[rot, i].Y);
                overlap |= p.X < 0 || p.X >= screen.GetLength(0) || p.Y < 0 || p.Y >= screen.GetLength(1) || screen[p.X, p.Y] != 0;
                sqs[i] = p;
            }
            return !overlap;
        }

        private void PutSqs(Point[] sqs, int color)
        {
            foreach (var sq in sqs) screen[sq.X, sq.Y] = color;
        }

        private void GameOver()
        {
            for (int i = 0; i < width; ++i) for (int j = 0; j < height; ++j) if (screen[i, j] != 0) screen[i, j] = 8;
            timer1.Enabled = false;
        }

        int DeleteLine()
        {
            int sum = 0;
            var delCount = 0;

            for (int j = 0; j < height; ++j)
            {

                bool delete = true;

                for (int i = 0; i < width; ++i)
                    if (screen[i, j] == 0) 
                        delete = false;


                if (delete)
                {
                    for (int k = j; k >= 1; --k)
                        for (int i = 0; i < width; ++i)
                            screen[i, k] = screen[i, k - 1];

                    delCount++;

                }
                                            
            }
            if (delCount == 4)
                sum = 1200;

            if (delCount == 3)
                sum = 300;

            if (delCount == 2)
                sum = 100;

            if (delCount == 1)
                sum = 40;

            score = score + sum;

            return score;

        }

    }
}


VIsual Studio C# でのテトリス作成において、右上の方に、次に落ちてくるブロックの表示をしたいと考えています。
自分で試行錯誤やってみたのですが、なかなかうまくいきません。
ちょっとしたアドバイスでも良いので教えて頂けると幸いです。よろしくお願いします。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#2

投稿記事 by みけCAT » 12年前

1. 「今落ちてくるブロックの変数(=block)」の他に「次に落とすブロックの変数」も作る。
2. ゲーム開始時に、「今落ちてくるブロックの変数」と「次に落とすブロックの変数」にブロックを乱数で代入する。
3. 「次に落とすブロックの変数」に格納されたブロックをNEXT欄に表示する。
4. 今落ちているブロックが落ちきったら、「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し、
 「次に落とすブロックの変数」にブロックを乱数で代入する。
5. 次のブロック(この時点で「今落ちてくるブロックの変数」に格納されているブロック)を落とす処理を始める。
6. 3に戻る。

このような流れでできると思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#3

投稿記事 by MONO » 12年前

ご指摘のように作成しているのですが、
3. 「次に落とすブロックの変数」に格納されたブロックをNEXT欄に表示する。
が、うまくできません。PictureBoxを用いて試してみましたが、e.Graphics.DrawImageではエラーをはいてしまいました。
どのようにすれば、NEXT欄に表示することができるでしょうか?

書き換えた箇所を示します。

コード:

        public Form1()
        {
            InitializeComponent();
            image = Image.FromFile("tetrisBlock3 198 22.bmp");
            GameStart();

        }

        Block block;
        Block second_block

   //ゲーム開始時に「今落ちてくるブロックの変数」と「次に落とすブロックの変数」にブロックを代入
        private void GameStart()
        { 
            PutStartPos();
            SubSecond_Block();
        }

   //最初に落とすブロックの変数に乱数でブロックを代入
        private void PutStartPos()
        {
            pos = start_pos;
            block = blocks[(new Random()).Next(0, blocks.Length)];
            rot = (new Random()).Next(0, block.sq.GetLength(0));
        }

   //次に落とすブロックの変数に乱数でブロックを代入
        private void SubSecond_Block()
        {
            second_block = blocks[(new Random()).Next(0, blocks.Length)];
        }


アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#4

投稿記事 by みけCAT » 12年前

今行っている表示システムを拡張します。
今のフィールドの表示欄を横に伸ばし(ゲームのフィールド自体は伸ばさない)、
横にできたスペースに現状のブロック表示システム(GetSqs→PutSqs)でブロックを描画します。
MONO さんが書きました:PictureBoxを用いて試してみましたが、e.Graphics.DrawImageではエラーをはいてしまいました。
これに相当しそうなコードが見当たらないので、これはよくわからないです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#5

投稿記事 by MONO » 12年前

アドバイスの意味は分かるのですが、やはりどうしても 3. 「次に落とすブロックの変数」に格納されたブロックをNEXT欄に表示する だけができません。

たぶんですが、他の1,2,4,5,6はできていると思います。

具体的にブロック表示システムでのブロックの描画の手順を教えてもらえないでしょうか。よろしくお願いします。

コード:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;

namespace tetris_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            image = Image.FromFile("tetrisBlock3 198 22.bmp");
            GameStart();

        }


        Image image;
        const int nColor = 9;
        const int width = 10;
        const int height = 20;

        readonly Point start_pos = new Point(4, 1);


        int[,] screen = new int[width, height];

        Block block;

        Block second_block;


        Point pos;

        int rot;

        int score = 0;


        const int fall_cycle = 10;
        int fall_cnt = 0;
        bool rot_stop;


        class Block
        {
            public Point[,] sq;  // sq[i, j]は回転パターンiのj個目の四角の位置



            public int color;       // 黒、水、黄、青、赤、橙、緑、紫
            public Block(Point[] sq, int n, int color)
            { // nは回転パターンの数
                this.sq = new Point[n, 4];
                for (int i = 0; i < n; ++i)
                {
                    for (int j = 0; j < 4; ++j)
                        this.sq[i, j] = sq[j];
                    for (int j = 0; j < 4; ++j)
                        sq[j] = RotateSq(sq[j]);
                }
                this.color = color;
            }
            private Point RotateSq(Point sq) { return new Point(sq.Y, -sq.X); }
        }

        readonly Block[] blocks = new Block[] { 
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(2, 0) }, 2, 7),   // I
            new Block(new Point[] { new Point(0, -1), new Point(1, -1), new Point(0, 0), new Point(1, 0) }, 1, 2),  // 四角
            new Block(new Point[] { new Point(-1, -1), new Point(-1, 0), new Point(0, 0), new Point(1, 0) }, 4, 5), // J
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(0, 1), new Point(1, 1) }, 2, 1),   // Z
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(1, -1) }, 4, 6),  // L
            new Block(new Point[] { new Point(-1, 1), new Point(0, 1), new Point(0, 0), new Point(1, 0) }, 2, 4),   // S
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(0, -1) }, 4, 3),  // T
        };






        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            const int length = 22;
            var srcRect = new Rectangle[nColor];
            var destRect = new Rectangle[width, height];



            for (int i = 0; i < nColor; ++i)
                srcRect[i] = new Rectangle(i * length, 0, length, length);

                for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                    destRect[i, j] = new Rectangle(i * length, j * length, length, length);

                    for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                        e.Graphics.DrawImage(image, destRect[i, j], srcRect[screen[i, j]], GraphicsUnit.Pixel);


        }



        private void timer1_Tick(object sender, EventArgs e)
        {
            Point next_pos;
            int next_rot;
            GetNextPosRot(out next_pos, out next_rot);
            ReviseScreen(next_pos, next_rot);
        }


        void GetNextPosRot(out Point next_pos, out int next_rot)
        {
            next_pos = new Point(pos.X, pos.Y);
            next_rot = rot;
            if ((fall_cnt = (fall_cnt + 1) % fall_cycle) == 0) next_pos.Y += 1;    // 自然落下
            else if (Keyboard.IsKeyDown(Key.Up)) { if (!rot_stop) next_rot = (next_rot + 1) % block.sq.GetLength(0); }
            else if (Keyboard.IsKeyDown(Key.Down)) next_pos.Y += 1;
            else if (Keyboard.IsKeyDown(Key.Right)) next_pos.X += 1;
            else if (Keyboard.IsKeyDown(Key.Left)) next_pos.X -= 1;
            // 連続して回らないようにする
            if (Keyboard.IsKeyDown(Key.Up)) rot_stop = true;
            else rot_stop = false;
        }

        void ReviseScreen(Point next_pos, int next_rot)
        {
            Point[] sqs, next_sqs;
            GetSqs(block, pos, rot, out sqs);

            PutSqs(sqs, 0);
            if (GetSqs(block, next_pos, next_rot, out next_sqs))
            {
                PutSqs(next_sqs, block.color);
                pos = next_pos;
                rot = next_rot;
            }
            else
            {
                PutSqs(sqs, block.color);

                
                if (next_pos.Y == pos.Y + 1)
                {
                    substitution();

                    DeleteLine();

                    label1.Text = Convert.ToString(score);

                    PutStartPos();


                    //最初の位置にブロックが置けなかったら
                    if (!GetSqs(block, pos, rot, out sqs))
                    {
                        PutSqs(sqs, block.color);
                        GameOver();
                    }
                }
            }
            Invalidate();
        }



        //ゲームを始める
        private void GameStart() {
            PutStartPos();
            PutSecondPos();
        
        }

        //最初のブロックの変数に乱数を代入
        private void PutStartPos()
        {
            pos = start_pos;
            block = blocks[(new Random()).Next(0, blocks.Length)];
            rot = (new Random()).Next(0, block.sq.GetLength(0));
        }

        //2番目のブロックの変数に乱数を代入
        private void PutSecondPos()
        {
            second_block = blocks[(new Random()).Next(0, blocks.Length)];
            rot = (new Random()).Next(0, second_block.sq.GetLength(0));
        }

        //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
        private void substitution() {

            block = second_block;

            second_block = blocks[(new Random()).Next(0, blocks.Length)];
            rot = (new Random()).Next(0, second_block.sq.GetLength(0));

        
        }




        private bool GetSqs(Block block, Point pos, int rot, out Point[] sqs)
        {
            bool overlap = false;
            sqs = new Point[block.sq.GetLength(1)];

            for (int i = 0; i < sqs.Length; ++i)
            {
                var p = new Point(pos.X + block.sq[rot, i].X, pos.Y + block.sq[rot, i].Y);
                overlap |= p.X < 0 || p.X >= screen.GetLength(0) || p.Y < 0 || p.Y >= screen.GetLength(1) || screen[p.X, p.Y] != 0;
                sqs[i] = p;
            }

            return !overlap;
        }


        private void PutSqs(Point[] sqs, int color)
        {
            foreach (var sq in sqs) screen[sq.X, sq.Y] = color;
        }
   }
}


アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#6

投稿記事 by みけCAT » 12年前

170行目の下(ReviseScreenのInvalidate();の上)に以下の5行を追加すれば、
ブロックの落下開始地点に次のブロックが表示されるかもしれません。(未検証です)

コード:

{
	Point[] nextBlock_sqs;
	GetSqs(second_block,start_pos,rot,out nextBlock_sqs);
	PutSqs(nextBlock_sqs,second_block.color);
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#7

投稿記事 by MONO » 12年前

5行の追加により、ブロックの落下開始地点に次のブロックが表示されました。
しかし、今落ちているブロックを回転させると、次のブロックも回転してしまいます(落下はしません)。

また、次のブロックの位置を落下開始地点から、右上(screen配列10×20マスの外)に移動することができません。

自分で試してみたのは、今ある start_pos の他に second_pos というものをつくり、次のブロックの表示する位置を変更しました。
しかし、テトリスの画面(10×20のマス内)にしか表示することができません。
どのようにすれば右上の方(10×20マス外)へ次のブロックを表示できるでしょうか?

変更したソースコードを以下に示します。

コード:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;

namespace tetris_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            image = Image.FromFile("tetrisBlock3 198 22.bmp");
            GameStart();

        }


        Image image;
        const int nColor = 9;
        const int width = 10;
        const int height = 20;


        
        readonly Point start_pos = new Point(4, 1);

        //次のブロックを置く位置
        readonly Point second_pos = new Point(6,16);


        int[,] screen = new int[width, height];




        Block block;

        Block second_block;

        Point pos;

        int rot;

        int score = 0;


        const int fall_cycle = 10;
        int fall_cnt = 0;
        bool rot_stop;


        class Block
        {
            public Point[,] sq;  // sq[i, j]は回転パターンiのj個目の四角の位置



            public int color;       // 黒、水、黄、青、赤、橙、緑、紫
            public Block(Point[] sq, int n, int color)
            { // nは回転パターンの数
                this.sq = new Point[n, 4];
                for (int i = 0; i < n; ++i)
                {
                    for (int j = 0; j < 4; ++j)
                        this.sq[i, j] = sq[j];
                    for (int j = 0; j < 4; ++j)
                        sq[j] = RotateSq(sq[j]);
                }
                this.color = color;
            }
            private Point RotateSq(Point sq) { return new Point(sq.Y, -sq.X); }
        }

        readonly Block[] blocks = new Block[] { 
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(2, 0) }, 2, 7),   // I
            new Block(new Point[] { new Point(0, -1), new Point(1, -1), new Point(0, 0), new Point(1, 0) }, 1, 2),  // 四角
            new Block(new Point[] { new Point(-1, -1), new Point(-1, 0), new Point(0, 0), new Point(1, 0) }, 4, 5), // J
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(0, 1), new Point(1, 1) }, 2, 1),   // Z
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(1, -1) }, 4, 6),  // L
            new Block(new Point[] { new Point(-1, 1), new Point(0, 1), new Point(0, 0), new Point(1, 0) }, 2, 4),   // S
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(0, -1) }, 4, 3),  // T
        };






        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            const int length = 22;
            var srcRect = new Rectangle[nColor];
            var destRect = new Rectangle[width, height];



            for (int i = 0; i < nColor; ++i)
                srcRect[i] = new Rectangle(i * length, 0, length, length);

                for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                    destRect[i, j] = new Rectangle(i * length, j * length, length, length);

                    for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                        e.Graphics.DrawImage(image, destRect[i, j], srcRect[screen[i, j]], GraphicsUnit.Pixel);

        }



        private void timer1_Tick(object sender, EventArgs e)
        {
            Point next_pos;
            int next_rot;
            GetNextPosRot(out next_pos, out next_rot);
            ReviseScreen(next_pos, next_rot);
        }


        void GetNextPosRot(out Point next_pos, out int next_rot)
        {
            next_pos = new Point(pos.X, pos.Y);
            next_rot = rot;
            if ((fall_cnt = (fall_cnt + 1) % fall_cycle) == 0) next_pos.Y += 1;    // 自然落下
            else if (Keyboard.IsKeyDown(Key.Up)) { if (!rot_stop) next_rot = (next_rot + 1) % block.sq.GetLength(0); }
            else if (Keyboard.IsKeyDown(Key.Down)) next_pos.Y += 1;
            else if (Keyboard.IsKeyDown(Key.Right)) next_pos.X += 1;
            else if (Keyboard.IsKeyDown(Key.Left)) next_pos.X -= 1;
            // 連続して回らないようにする
            if (Keyboard.IsKeyDown(Key.Up)) rot_stop = true;
            else rot_stop = false;
        }

        void ReviseScreen(Point next_pos, int next_rot)
        {
            Point[] sqs, next_sqs;
            GetSqs(block, pos, rot, out sqs);

            PutSqs(sqs, 0);
            if (GetSqs(block, next_pos, next_rot, out next_sqs))
            {
                PutSqs(next_sqs, block.color);
                pos = next_pos;
                rot = next_rot;
            }
            else
            {
                PutSqs(sqs, block.color);


                if (next_pos.Y == pos.Y + 1)
                {
                    substitution();

                    DeleteLine();

                    label1.Text = Convert.ToString(score);

                    PutStartPos();


                    //最初の位置にブロックが置けなかったら
                    if (!GetSqs(block, pos, rot, out sqs))
                    {
                        PutSqs(sqs, block.color);
                        GameOver();
                    }
                }
            }
     
     //追加した5行
            second_blockshow();

            Invalidate();
        }



        //ゲームを始める
        private void GameStart() {
            PutStartPos();
            PutSecondPos();
        
        }

        //最初のブロックの変数に乱数を代入
        private void PutStartPos()
        {
            pos = start_pos;
            block = blocks[(new Random()).Next(0, blocks.Length)];
            rot = (new Random()).Next(0, block.sq.GetLength(0));
        }

        //2番目のブロックの変数に乱数を代入
        private void PutSecondPos()
        {
            second_block = blocks[(new Random()).Next(0, blocks.Length)];
        }

        //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
        private void substitution() {

            block = second_block ;
            second_block = blocks[(new Random()).Next(0, blocks.Length)];    
        }

        //次のブロックを表示する 追加した5行
        private void second_blockshow() {           
            Point[] nextBlock_sqs;
            GetSqs(second_block, second_pos, rot, out nextBlock_sqs);
            PutSqs(nextBlock_sqs, second_block.color);
        }





        private bool GetSqs(Block block, Point pos, int rot, out Point[] sqs)
        {
            bool overlap = false;
            sqs = new Point[block.sq.GetLength(1)];

            for (int i = 0; i < sqs.Length; ++i)
            {
                var p = new Point(pos.X + block.sq[rot, i].X, pos.Y + block.sq[rot, i].Y);
                overlap |= p.X < 0 || p.X >= screen.GetLength(0) || p.Y < 0 || p.Y >= screen.GetLength(1) || screen[p.X, p.Y] != 0;
                sqs[i] = p;
            }

            return !overlap;
        }

        private void PutSqs(Point[] sqs, int color)
        {
            foreach (var sq in sqs) screen[sq.X, sq.Y] = color;
        }
   }
}


アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#8

投稿記事 by みけCAT » 12年前

widthの値を大きくすれば、描画領域が右に広がるので「テトリスの画面」の外にブロックを表示できるはずです。
NEXT表示が回転しないようにするには、217行目を

コード:

            GetSqs(second_block, second_pos, 0, out nextBlock_sqs);
としてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#9

投稿記事 by MONO » 12年前

返信ありがとうございます。

widthの値を大きくするという方法ですが、テトリスの画面が横に広がってしまいます。
つまり width = 15 というようにすると、テトリスのマスが15×20マスになってしまいます。

回転の問題は解決しました、ありがとうございます。

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#10

投稿記事 by MONO » 12年前

やはりなかなかうまく次のブロックを表示することができません。
ちょっとしたことでもいいので、アドバイス等いただければ幸いです。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#11

投稿記事 by みけCAT » 12年前

1. 新たにテトリスのフィールドの幅と高さを示すwidth2、height2という変数をwidthやheightと同じあたりに作ります。
2. width、heightに表示領域の幅と高さをそれぞれ格納し、width2、height2にフィールドの幅と高さを格納します。
3. No: 7のコードの233行目を以下のように書き換えます。

コード:

                overlap |= p.X < 0 || p.X >= width2 || p.Y < 0 || p.Y >= height2 || screen[p.X, p.Y] != 0;
仕様をよく理解していない上、実行もしていないので間違っているかもしれませんが、これでどうでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#12

投稿記事 by MONO » 12年前

返信ありがとうございます。
試してみましたが、 追加情報:インデックスが配列の境界外です。 というエラーがでてしまいました。

仕様を説明したいのですが、以下のURLの動画を見ながら作成していて、すべて自分で作成しているわけではないので、うまく仕様を説明することができません。
申し訳ありません。

http://www.nicovideo.jp/watch/sm17983957

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#13

投稿記事 by みけCAT » 12年前

修正後のコードを提示できますか?
width>=width2 かつ height>=height2となるようにしてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#14

投稿記事 by MONO » 12年前

次のブロックを表示する領域を作ることはできました。
しかし、うまく代入できていないのか、今落ちてくるブロックと同じブロックがNEXT欄に表示されてしまいます。
また、再描画もうまくできていなくて、NEXT欄に次のブロック、次のブロックと、上から塗りつぶされる形で描画され続けてしまいます。

どのようにすれば、うまく代入でき、NEXT欄を切り替えながら表示できるでしょうか?

以下にソースコードを提示します。

コード:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;

namespace tetris_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            image = Image.FromFile("tetrisBlock4 198 22.bmp");
            GameStart();

        }


        Image image;
        const int nColor = 9;

    //新しく作成したNEXT欄を表示できる領域
         const int width2 = 10;
         const int height2 = 20;

         const int width = 16;
         const int height = 20;

        
        readonly Point start_pos = new Point(4, 1);

        //次のブロックを置く位置
        readonly Point second_pos = new Point(12,5);


        int[,] screen = new int[width, height];




        Block block;

        Block second_block;

        Point pos;

        int rot;

        int score = 0;


        const int fall_cycle = 10;
        int fall_cnt = 0;
        bool rot_stop;


        class Block
        {
            public Point[,] sq;  // sq[i, j]は回転パターンiのj個目の四角の位置



            public int color;       // 黒、水、黄、青、赤、橙、緑、紫
            public Block(Point[] sq, int n, int color)
            { // nは回転パターンの数
                this.sq = new Point[n, 4];
                for (int i = 0; i < n; ++i)
                {
                    for (int j = 0; j < 4; ++j)
                        this.sq[i, j] = sq[j];
                    for (int j = 0; j < 4; ++j)
                        sq[j] = RotateSq(sq[j]);
                }
                this.color = color;
            }
            private Point RotateSq(Point sq) { return new Point(sq.Y, -sq.X); }
        }

        readonly Block[] blocks = new Block[] { 
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(2, 0) }, 2, 7),   // I
            new Block(new Point[] { new Point(0, -1), new Point(1, -1), new Point(0, 0), new Point(1, 0) }, 1, 2),  // 四角
            new Block(new Point[] { new Point(-1, -1), new Point(-1, 0), new Point(0, 0), new Point(1, 0) }, 4, 5), // J
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(0, 1), new Point(1, 1) }, 2, 1),   // Z
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(1, -1) }, 4, 6),  // L
            new Block(new Point[] { new Point(-1, 1), new Point(0, 1), new Point(0, 0), new Point(1, 0) }, 2, 4),   // S
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(0, -1) }, 4, 3),  // T
        };






        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            const int length = 22;
            var srcRect = new Rectangle[nColor];
            var destRect = new Rectangle[width, height];



            for (int i = 0; i < nColor; ++i)
                srcRect[i] = new Rectangle(i * length, 0, length, length);

                for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                    destRect[i, j] = new Rectangle(i * length, j * length, length, length);

                    for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                        e.Graphics.DrawImage(image, destRect[i, j], srcRect[screen[i, j]], GraphicsUnit.Pixel);

        }



        private void timer1_Tick(object sender, EventArgs e)
        {
            Point next_pos;
            int next_rot;
            GetNextPosRot(out next_pos, out next_rot);
            ReviseScreen(next_pos, next_rot);
        }


        void GetNextPosRot(out Point next_pos, out int next_rot)
        {
            next_pos = new Point(pos.X, pos.Y);
            next_rot = rot;
            if ((fall_cnt = (fall_cnt + 1) % fall_cycle) == 0) next_pos.Y += 1;    // 自然落下
            else if (Keyboard.IsKeyDown(Key.Up)) { if (!rot_stop) next_rot = (next_rot + 1) % block.sq.GetLength(0); }
            else if (Keyboard.IsKeyDown(Key.Down)) next_pos.Y += 1;
            else if (Keyboard.IsKeyDown(Key.Right)) next_pos.X += 1;
            else if (Keyboard.IsKeyDown(Key.Left)) next_pos.X -= 1;
            // 連続して回らないようにする
            if (Keyboard.IsKeyDown(Key.Up)) rot_stop = true;
            else rot_stop = false;
        }

        void ReviseScreen(Point next_pos, int next_rot)
        {
            Point[] sqs, next_sqs;
            GetSqs(block, pos, rot, out sqs);

            PutSqs(sqs, 0);
            if (GetSqs(block, next_pos, next_rot, out next_sqs))
            {
                PutSqs(next_sqs, block.color);
                pos = next_pos;
                rot = next_rot;
            }
            else
            {
                PutSqs(sqs, block.color);

                //もしブロックが下まで落ちきったら
                if (next_pos.Y == pos.Y + 1)
                {

                    //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
                    substitution();

                    //一列揃っていたら消す
                    DeleteLine();

                    //スコアを表示する
                    label1.Text = Convert.ToString(score);

                    //最初の位置にブロックを置く
                    PutStartPos();


                    //最初の位置にブロックが置けなかったら
                    if (!GetSqs(block, pos, rot, out sqs))
                    {
                        PutSqs(sqs, block.color);
                        GameOver();
                    }

                    
                }
               
            }

      //次のブロックを表示する
            second_blockshow();
            

            Invalidate();
        }



        //ゲームを始める
        private void GameStart() {
            PutStartPos();
            PutSecondPos();
        
        }

        //最初のブロックの変数に乱数を代入
        private void PutStartPos()
        {
            pos = start_pos;
            block = blocks[(new Random()).Next(0, blocks.Length)];
            rot = (new Random()).Next(0, block.sq.GetLength(0));
        }

        //2番目のブロックの変数に乱数を代入
        private void PutSecondPos()
        {
            second_block = blocks[(new Random()).Next(0, blocks.Length)];
            rot = (new Random()).Next(0, block.sq.GetLength(0));
        }

        //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
        private void substitution() {

            block = second_block;
            second_block = blocks[(new Random()).Next(0, blocks.Length)];    
        }

        //次のブロックを表示する
        private void second_blockshow() {           
            Point[] second_block_sqs;
            GetSqs(second_block, second_pos, 0, out second_block_sqs);
            PutSqs(second_block_sqs, second_block.color);
        }





        private bool GetSqs(Block block, Point pos, int rot, out Point[] sqs)
        {
            bool overlap = false;
            sqs = new Point[block.sq.GetLength(1)];

            for (int i = 0; i < sqs.Length; ++i)
            {
                var p = new Point(pos.X + block.sq[rot, i].X, pos.Y + block.sq[rot, i].Y);
                overlap |= p.X < 0 || p.X >= width2 || p.Y < 0 || p.Y >= height2 || screen[p.X, p.Y] != 0;
                sqs[i] = p;
            }

            return !overlap;
        }





        private void PutSqs(Point[] sqs, int color)
        {
            foreach (var sq in sqs) screen[sq.X, sq.Y] = color;
        }


        private void GameOver()
        {
            for (int i = 0; i < width; ++i)
                for (int j = 0; j < height; ++j)
                    if (screen[i, j] != 0) screen[i, j] = 8;
                        timer1.Enabled = false;


        }




        int DeleteLine()
        {
            int sum = 0;
            var delCount = 0;

            for (int j = 0; j < height2; ++j)
            {

                bool delete = true;

                for (int i = 0; i < width2; ++i)
                    if (screen[i, j] == 0) 
                        delete = false;


                if (delete)
                {
                    for (int k = j; k >= 1; --k)
                        for (int i = 0; i < width2; ++i)
                            screen[i, k] = screen[i, k - 1];

                    delCount++;

                }
                                            
            }
            if (delCount == 4)
                sum = 1200;

            if (delCount == 3)
                sum = 300;

            if (delCount == 2)
                sum = 100;
            
            if (delCount == 1)
                sum = 40;

            score = score + sum;

            return score;

        }

    }
}


MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#15

投稿記事 by MONO » 12年前

どなたかちょっとしたことでもいいので知恵をお借りしたいです。
よろしくお願いします。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#16

投稿記事 by みけCAT » 12年前

とりあえず、ブロックが重なって描かれる問題については、230行目と231行目の間に以下の3行を追加することで治ったようです。

コード:

for(int i=width2;i<width;i++) {
    for (int j = 0; j < height; j++) screen[i, j] = 0;
}
(フィールドの右側全体を黒で塗りつぶしています)

正しいブロックが表示されない問題は検討中です。
オフトピック
Microsoft.csharpが見つからないと文句を言われる、キー操作が効かない、画像が適当という問題はありますが、
いちおうこちらでも動作確認できるようになりました。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#17

投稿記事 by MONO » 12年前

ありがとうございます。
重なってブロックが表示される問題、解決しました。

しかし、やはりまだ今落ちてくるブロックと同じブロックがNEXT欄にも表示されてしまいます。

コード:


        //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
        private void substitution() {

            block = second_block;
            second_block = blocks[(new Random()).Next(0, blocks.Length)]; 

        }

これではうまく代入できていないのでしょうか?

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#18

投稿記事 by みけCAT » 12年前

まず、以下の操作を行ってください。
1. 46行目に

コード:

Random rnd;
という行を加える。
2. 20行目と21行目の間に

コード:

rnd = new Random();
という行を加える。
3. コード中の(new Random())を全てrndに置換する。(2.で加えた場所は置換しない、念のため)
4. 実行する
すると、落ちてくるブロックとNEXT欄のブロックが、それぞれ別々に変化するはずです。ここからわかることは、
・せっかくsubstitution関数でblockにsecond_blockを代入しても、次のPutStartPosで上書きされてしまう。
・これまではRandamクラスのオブジェクトをほぼ同時に作成していたため、おそらく同じ乱数系列が使用され、同じ値が出た。
 そのため、「落ちてくるブロックとNEXT欄のブロックが同じ」という現象が観測された。
ということです。
したがって、以下の3個の関数を、それぞれ下記のように書き換えるといいと思います。

コード:

//ゲームを始める
private void GameStart()
{
    PutSecondPos();
    substitution();
    PutStartPos();

}

//最初のブロックの位置を代入
private void PutStartPos()
{
    pos = start_pos;
    rot = rnd.Next(0, block.sq.GetLength(0));
}

//2番目のブロックの変数に乱数を代入
private void PutSecondPos()
{
    second_block = blocks[rnd.Next(0, blocks.Length)];
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#19

投稿記事 by MONO » 12年前

ありがとうございます。NEXTブロックの表示はうまくいっているみたいなのですが、途中で 「追加情報:インデックスが配列の境界外です。」 と表示されてしまいます。
また、起動を押しても 「追加情報:インデックスが配列の境界外です。」 と表示されることもあります。
これはscreen配列に問題があるのでしょうか?

コード:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;

namespace tetris_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            image = Image.FromFile("tetrisBlock4 198 22.bmp");
            rnd = new Random();
            GameStart();

        }


        Image image;
        const int nColor = 9;

        //テトリスの画面の領域
         const int width2 = 10;
         const int height2 = 20;

        //画面全体の領域
         const int width = 18;
         const int height = 20;

        //最初のブロックを置く位置
        readonly Point start_pos = new Point(4, 1);

        //次のブロックを置く位置
        readonly Point second_pos = new Point(13,5);


        int[,] screen = new int[width, height];


        Random rnd;

        Block block;

        Block second_block;

        Point pos;

        int rot;

        int score = 0;


        const int fall_cycle = 10;
        int fall_cnt = 0;
        bool rot_stop;


        class Block
        {
            public Point[,] sq;  // sq[i, j]は回転パターンiのj個目の四角の位置



            public int color;       // 黒、水、黄、青、赤、橙、緑、紫
            public Block(Point[] sq, int n, int color)
            { // nは回転パターンの数
                this.sq = new Point[n, 4];
                for (int i = 0; i < n; ++i)
                {
                    for (int j = 0; j < 4; ++j)
                        this.sq[i, j] = sq[j];
                    for (int j = 0; j < 4; ++j)
                        sq[j] = RotateSq(sq[j]);
                }
                this.color = color;
            }
            private Point RotateSq(Point sq) { return new Point(sq.Y, -sq.X); }
        }

        readonly Block[] blocks = new Block[] { 
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(2, 0) }, 2, 7),   // I
            new Block(new Point[] { new Point(0, -1), new Point(1, -1), new Point(0, 0), new Point(1, 0) }, 1, 2),  // 四角
            new Block(new Point[] { new Point(-1, -1), new Point(-1, 0), new Point(0, 0), new Point(1, 0) }, 4, 5), // J
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(0, 1), new Point(1, 1) }, 2, 1),   // Z
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(1, -1) }, 4, 6),  // L
            new Block(new Point[] { new Point(-1, 1), new Point(0, 1), new Point(0, 0), new Point(1, 0) }, 2, 4),   // S
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(0, -1) }, 4, 3),  // T
        };


        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            const int length = 22;
            var srcRect = new Rectangle[nColor];
            var destRect = new Rectangle[width, height];


            for (int i = 0; i < nColor; ++i)
                srcRect[i] = new Rectangle(i * length, 0, length, length);

                for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                    destRect[i, j] = new Rectangle(i * length, j * length, length, length);

                    for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                        e.Graphics.DrawImage(image, destRect[i, j], srcRect[screen[i, j]], GraphicsUnit.Pixel);

        }



        private void timer1_Tick(object sender, EventArgs e)
        {
            Point next_pos;
            int next_rot;
            GetNextPosRot(out next_pos, out next_rot);
            ReviseScreen(next_pos, next_rot);
        }


        void GetNextPosRot(out Point next_pos, out int next_rot)
        {
            next_pos = new Point(pos.X, pos.Y);
            next_rot = rot;
            if ((fall_cnt = (fall_cnt + 1) % fall_cycle) == 0) next_pos.Y += 1;    // 自然落下
            else if (Keyboard.IsKeyDown(Key.Up)) { if (!rot_stop) next_rot = (next_rot + 1) % block.sq.GetLength(0); }
            else if (Keyboard.IsKeyDown(Key.Down)) next_pos.Y += 1;
            else if (Keyboard.IsKeyDown(Key.Right)) next_pos.X += 1;
            else if (Keyboard.IsKeyDown(Key.Left)) next_pos.X -= 1;


            // 連続して回らないようにするためのif文
            if (Keyboard.IsKeyDown(Key.Up)) rot_stop = true;
            else rot_stop = false;
        }

        void ReviseScreen(Point next_pos, int next_rot)
        {
            Point[] sqs, next_sqs;
            GetSqs(block, pos, rot, out sqs);

            PutSqs(sqs, 0);
            if (GetSqs(block, next_pos, next_rot, out next_sqs))
            {
                PutSqs(next_sqs, block.color);
                pos = next_pos;
                rot = next_rot;
            }
            else
            {
                PutSqs(sqs, block.color);

                //もしブロックが下まで落ちきったら
                if (next_pos.Y == pos.Y + 1)
                {

                    //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
                    substitution();

                    //一列揃っていたら消す
                    DeleteLine();


                    //スコアを表示する
                    label1.Text = Convert.ToString(score);

                    //最初の位置にネクスト欄に表示したブロックを置く
                    PutStartPos();



                    //最初の位置にブロックが置けなかったら
                    if (!GetSqs(block, pos, rot, out sqs))
                    {
                        PutSqs(sqs, block.color);
                        GameOver();

                    }


                }

            }

            second_blockshow();

            Invalidate();
        }




        //ゲームを始める
        private void GameStart()
        {
            PutSecondPos();
            substitution();
            PutStartPos();
 
        }
 
        //最初のブロックの位置を代入
        private void PutStartPos()
        {
            pos = start_pos;
            rot = rnd.Next(0, block.sq.GetLength(0));
        }
 
        //2番目のブロックの変数に乱数を代入
        private void PutSecondPos()
        {
            second_block = blocks[rnd.Next(0, blocks.Length)];
        }

        //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
        private void substitution() {

            block = second_block;
            second_block = blocks[(new Random()).Next(0, blocks.Length)]; 

        }


        //次のブロックを表示する
        private void second_blockshow() {           
            Point[] second_block_sqs;

            for (int i = width2; i < width; i++)
            {
                for (int j = 0; j < height; j++) screen[i, j] = 0;
            }

            GetSqs(second_block, second_pos, 0, out second_block_sqs);
            PutSqs(second_block_sqs, second_block.color);
        }





        private bool GetSqs(Block block, Point pos, int rot, out Point[] sqs)
        {
            bool overlap = false;
            sqs = new Point[block.sq.GetLength(1)];

            for (int i = 0; i < sqs.Length; ++i)
            {
                var p = new Point(pos.X + block.sq[rot, i].X, pos.Y + block.sq[rot, i].Y);
                overlap |= p.X < 0 || p.X >= width2 || p.Y < 0 || p.Y >= height2 || screen[p.X, p.Y] != 0;
                sqs[i] = p;
            }

            return !overlap;
        }





        private void PutSqs(Point[] sqs, int color)
        {
            foreach (var sq in sqs) screen[sq.X, sq.Y] = color;
        }


        private void GameOver()
        {
            for (int i = 0; i < width; ++i)
                for (int j = 0; j < height; ++j)
                    if (screen[i, j] != 0) screen[i, j] = 8;
                        timer1.Enabled = false;


        }




        int DeleteLine()
        {
            int sum = 0;
            var delCount = 0;

            for (int j = 0; j < height2; ++j)
            {

                bool delete = true;

                for (int i = 0; i < width2; ++i)
                    if (screen[i, j] == 0) 
                        delete = false;


                if (delete)
                {
                    for (int k = j; k >= 1; --k)
                        for (int i = 0; i < width2; ++i)
                            screen[i, k] = screen[i, k - 1];

                    delCount++;

                }
                                            
            }
            if (delCount == 4)
                sum = 1200;

            if (delCount == 3)
                sum = 300;

            if (delCount == 2)
                sum = 100;
            
            if (delCount == 1)
                sum = 40;

            score = score + sum;

            return score;

        }


    }
}


アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#20

投稿記事 by みけCAT » 12年前

PutSqs関数を以下のものにしてみてください。

コード:

private void PutSqs(Point[] sqs, int color)
{
    foreach (var sq in sqs)
    {
        if(sq.X>=0 && sq.X<width && sq.Y>=0 && sq.Y<height)screen[sq.X, sq.Y] = color;
    }
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#21

投稿記事 by MONO » 12年前

変更しました。
途中で急に上の方でブロックが詰まってしまい、ゲームが終わってしまいます。

コード:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;

namespace tetris_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            image = Image.FromFile("tetrisBlock4 198 22.bmp");
            rnd = new Random();
            GameStart();

        }


        Image image;
        const int nColor = 9;

        //テトリスの画面の領域
         const int width2 = 10;
         const int height2 = 20;

        //画面全体の領域
         const int width = 18;
         const int height = 20;

        //最初のブロックを置く位置
        readonly Point start_pos = new Point(4, 1);

        //次のブロックを置く位置
        readonly Point second_pos = new Point(13,5);


        int[,] screen = new int[width, height];


        Random rnd;

        Block block;

        Block second_block;

        Point pos;

        int rot;

        int score = 0;


        const int fall_cycle = 10;
        int fall_cnt = 0;
        bool rot_stop;


        class Block
        {
            public Point[,] sq;  // sq[i, j]は回転パターンiのj個目の四角の位置



            public int color;       // 黒、水、黄、青、赤、橙、緑、紫
            public Block(Point[] sq, int n, int color)
            { // nは回転パターンの数
                this.sq = new Point[n, 4];
                for (int i = 0; i < n; ++i)
                {
                    for (int j = 0; j < 4; ++j)
                        this.sq[i, j] = sq[j];
                    for (int j = 0; j < 4; ++j)
                        sq[j] = RotateSq(sq[j]);
                }
                this.color = color;
            }
            private Point RotateSq(Point sq) { return new Point(sq.Y, -sq.X); }
        }

        readonly Block[] blocks = new Block[] { 
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(2, 0) }, 2, 7),   // I
            new Block(new Point[] { new Point(0, -1), new Point(1, -1), new Point(0, 0), new Point(1, 0) }, 1, 2),  // 四角
            new Block(new Point[] { new Point(-1, -1), new Point(-1, 0), new Point(0, 0), new Point(1, 0) }, 4, 5), // J
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(0, 1), new Point(1, 1) }, 2, 1),   // Z
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(1, -1) }, 4, 6),  // L
            new Block(new Point[] { new Point(-1, 1), new Point(0, 1), new Point(0, 0), new Point(1, 0) }, 2, 4),   // S
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(0, -1) }, 4, 3),  // T
        };


        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            const int length = 22;
            var srcRect = new Rectangle[nColor];
            var destRect = new Rectangle[width, height];


            for (int i = 0; i < nColor; ++i)
                srcRect[i] = new Rectangle(i * length, 0, length, length);

                for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                    destRect[i, j] = new Rectangle(i * length, j * length, length, length);

                    for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                        e.Graphics.DrawImage(image, destRect[i, j], srcRect[screen[i, j]], GraphicsUnit.Pixel);

        }



        private void timer1_Tick(object sender, EventArgs e)
        {
            Point next_pos;
            int next_rot;
            GetNextPosRot(out next_pos, out next_rot);
            ReviseScreen(next_pos, next_rot);
        }


        void GetNextPosRot(out Point next_pos, out int next_rot)
        {
            next_pos = new Point(pos.X, pos.Y);
            next_rot = rot;
            if ((fall_cnt = (fall_cnt + 1) % fall_cycle) == 0) next_pos.Y += 1;    // 自然落下
            else if (Keyboard.IsKeyDown(Key.Up)) { if (!rot_stop) next_rot = (next_rot + 1) % block.sq.GetLength(0); }
            else if (Keyboard.IsKeyDown(Key.Down)) next_pos.Y += 1;
            else if (Keyboard.IsKeyDown(Key.Right)) next_pos.X += 1;
            else if (Keyboard.IsKeyDown(Key.Left)) next_pos.X -= 1;


            // 連続して回らないようにするためのif文
            if (Keyboard.IsKeyDown(Key.Up)) rot_stop = true;
            else rot_stop = false;
        }

        void ReviseScreen(Point next_pos, int next_rot)
        {
            Point[] sqs, next_sqs;
            GetSqs(block, pos, rot, out sqs);

            PutSqs(sqs, 0);
            if (GetSqs(block, next_pos, next_rot, out next_sqs))
            {
                PutSqs(next_sqs, block.color);
                pos = next_pos;
                rot = next_rot;
            }
            else
            {
                PutSqs(sqs, block.color);

                //もしブロックが下まで落ちきったら
                if (next_pos.Y == pos.Y + 1)
                {

                    //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
                    substitution();

                    //一列揃っていたら消す
                    DeleteLine();


                    //スコアを表示する
                    label1.Text = Convert.ToString(score);

                    //最初の位置にたブロックを置く
                    PutStartPos();



                    //最初の位置にブロックが置けなかったら
                    if (!GetSqs(block, pos, rot, out sqs))
                    {
                        PutSqs(sqs, block.color);
                        GameOver();

                    }


                }

            }

            second_blockshow();

            Invalidate();
        }




        //ゲームを始める
        private void GameStart()
        {
            PutSecondPos();
            substitution();
            PutStartPos();
 
        }
 
        //最初のブロックの位置を代入
        private void PutStartPos()
        {
            pos = start_pos;
            rot = rnd.Next(0, block.sq.GetLength(0));
        }
 
        //2番目のブロックの変数に乱数を代入
        private void PutSecondPos()
        {
            second_block = blocks[rnd.Next(0, blocks.Length)];
        }

        //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
        private void substitution() {

            block = second_block;
            second_block = blocks[(new Random()).Next(0, blocks.Length)]; 

        }


        //次のブロックを表示する
        private void second_blockshow() {           
            Point[] second_block_sqs;

            for (int i = width2; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                    screen[i, j] = 0;
            }

            GetSqs(second_block, second_pos, 0, out second_block_sqs);
            PutSqs(second_block_sqs, second_block.color);
        }





        private bool GetSqs(Block block, Point pos, int rot, out Point[] sqs)
        {
            bool overlap = false;
            sqs = new Point[block.sq.GetLength(1)];

            for (int i = 0; i < sqs.Length; ++i)
            {
                var p = new Point(pos.X + block.sq[rot, i].X, pos.Y + block.sq[rot, i].Y);
                overlap |= p.X < 0 || p.X >= width2 || p.Y < 0 || p.Y >= height2 || screen[p.X, p.Y] != 0;
                sqs[i] = p;
            }

            return !overlap;
        }





        private void PutSqs(Point[] sqs, int color)
        {
            foreach (var sq in sqs)
            {
                if (sq.X >= 0 && sq.X < width && sq.Y >= 0 && sq.Y < height) screen[sq.X, sq.Y] = color;
            }
        }


        private void GameOver()
        {
            for (int i = 0; i < width; ++i)
                for (int j = 0; j < height; ++j)
                    if (screen[i, j] != 0) screen[i, j] = 8;
                        timer1.Enabled = false;


        }




        int DeleteLine()
        {
            int sum = 0;
            var delCount = 0;

            for (int j = 0; j < height2; ++j)
            {

                bool delete = true;

                for (int i = 0; i < width2; ++i)
                    if (screen[i, j] == 0) 
                        delete = false;


                if (delete)
                {
                    for (int k = j; k >= 1; --k)
                        for (int i = 0; i < width2; ++i)
                            screen[i, k] = screen[i, k - 1];

                    delCount++;

                }
                                            
            }
            if (delCount == 4)
                sum = 1200;

            if (delCount == 3)
                sum = 300;

            if (delCount == 2)
                sum = 100;
            
            if (delCount == 1)
                sum = 40;

            score = score + sum;

            return score;

        }


    }
}



アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: Visual Studio C# テトリス のnextBlockの表示

#22

投稿記事 by みけCAT » 12年前

一部のブロックの形に対して、スタート位置が上過ぎるのだと思います。
スタート位置を1~2段下にずらしてみてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

MONO

Re: Visual Studio C# テトリス のnextBlockの表示

#23

投稿記事 by MONO » 12年前

ありがとうございます。
無事nextBlockの表示を行うことが出来ました。
みけCATさん、最後まで質問に答えていただき本当にありがとうございます。感謝します。

いかに完成のソースコードを示します。


コード:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;

namespace tetris_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            image = Image.FromFile("tetrisBlock4 198 22.bmp");
            rnd = new Random();
            GameStart();

        }


        Image image;
        const int nColor = 9;

        //テトリスの画面の領域
         const int width2 = 10;
         const int height2 = 20;

        //画面全体の領域
         const int width = 18;
         const int height = 20;

        //最初のブロックを置く位置
        readonly Point start_pos = new Point(4, 2);

        //次のブロックを置く位置
        readonly Point second_pos = new Point(13,5);


        int[,] screen = new int[width, height];


        Random rnd;

        Block block;

        Block second_block;

        Point pos;

        int rot;

        int score = 0;


        const int fall_cycle = 10;
        int fall_cnt = 0;
        bool rot_stop;


        class Block
        {
            public Point[,] sq;  // sq[i, j]は回転パターンiのj個目の四角の位置



            public int color;       // 黒、水、黄、青、赤、橙、緑、紫
            public Block(Point[] sq, int n, int color)
            { // nは回転パターンの数
                this.sq = new Point[n, 4];
                for (int i = 0; i < n; ++i)
                {
                    for (int j = 0; j < 4; ++j)
                        this.sq[i, j] = sq[j];
                    for (int j = 0; j < 4; ++j)
                        sq[j] = RotateSq(sq[j]);
                }
                this.color = color;
            }
            private Point RotateSq(Point sq) { return new Point(sq.Y, -sq.X); }
        }

        readonly Block[] blocks = new Block[] { 
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(2, 0) }, 2, 7),   // I
            new Block(new Point[] { new Point(0, -1), new Point(1, -1), new Point(0, 0), new Point(1, 0) }, 1, 2),  // 四角
            new Block(new Point[] { new Point(-1, -1), new Point(-1, 0), new Point(0, 0), new Point(1, 0) }, 4, 5), // J
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(0, 1), new Point(1, 1) }, 2, 1),   // Z
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(1, -1) }, 4, 6),  // L
            new Block(new Point[] { new Point(-1, 1), new Point(0, 1), new Point(0, 0), new Point(1, 0) }, 2, 4),   // S
            new Block(new Point[] { new Point(-1, 0), new Point(0, 0), new Point(1, 0), new Point(0, -1) }, 4, 3),  // T
        };


        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            const int length = 22;
            var srcRect = new Rectangle[nColor];
            var destRect = new Rectangle[width, height];


            for (int i = 0; i < nColor; ++i)
                srcRect[i] = new Rectangle(i * length, 0, length, length);

                for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                    destRect[i, j] = new Rectangle(i * length, j * length, length, length);

                    for (int j = 0; j < height; ++j) for (int i = 0; i < width; ++i)
                        e.Graphics.DrawImage(image, destRect[i, j], srcRect[screen[i, j]], GraphicsUnit.Pixel);

        }



        private void timer1_Tick(object sender, EventArgs e)
        {
            Point next_pos;
            int next_rot;
            GetNextPosRot(out next_pos, out next_rot);
            ReviseScreen(next_pos, next_rot);
        }


        void GetNextPosRot(out Point next_pos, out int next_rot)
        {
            next_pos = new Point(pos.X, pos.Y);
            next_rot = rot;
            if ((fall_cnt = (fall_cnt + 1) % fall_cycle) == 0) next_pos.Y += 1;    // 自然落下
            else if (Keyboard.IsKeyDown(Key.Up)) { if (!rot_stop) next_rot = (next_rot + 1) % block.sq.GetLength(0); }
            else if (Keyboard.IsKeyDown(Key.Down)) next_pos.Y += 1;
            else if (Keyboard.IsKeyDown(Key.Right)) next_pos.X += 1;
            else if (Keyboard.IsKeyDown(Key.Left)) next_pos.X -= 1;


            // 連続して回らないようにするためのif文
            if (Keyboard.IsKeyDown(Key.Up)) rot_stop = true;
            else rot_stop = false;
        }

        void ReviseScreen(Point next_pos, int next_rot)
        {
            Point[] sqs, next_sqs;
            GetSqs(block, pos, rot, out sqs);

            PutSqs(sqs, 0);
            if (GetSqs(block, next_pos, next_rot, out next_sqs))
            {
                PutSqs(next_sqs, block.color);
                pos = next_pos;
                rot = next_rot;
            }
            else
            {
                PutSqs(sqs, block.color);

                //もしブロックが下まで落ちきったら
                if (next_pos.Y == pos.Y + 1)
                {

                    //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
                    substitution();

                    //一列揃っていたら消す
                    DeleteLine();


                    //スコアを表示する
                    label1.Text = Convert.ToString(score);

                    //最初の位置にたブロックを置く
                    PutStartPos();



                    //最初の位置にブロックが置けなかったら
                    if (!GetSqs(block, pos, rot, out sqs))
                    {
                        PutSqs(sqs, block.color);
                        GameOver();

                    }


                }

            }

            second_blockshow();

            Invalidate();
        }




        //ゲームを始める
        private void GameStart()
        {
            PutSecondPos();
            substitution();
            PutStartPos();
 
        }
 
        //最初のブロックの位置を代入
        private void PutStartPos()
        {
            pos = start_pos;
            rot = rnd.Next(0, block.sq.GetLength(0));
        }
 
        //2番目のブロックの変数に乱数を代入
        private void PutSecondPos()
        {
            second_block = blocks[rnd.Next(0, blocks.Length)];
        }

        //「今落ちてくるブロックの変数」に「次に落とすブロックの変数」の中身を代入し「次に落とすブロックの変数」にブロックを乱数で代入する
        private void substitution() {

            block = second_block;
            second_block = blocks[(new Random()).Next(0, blocks.Length)]; 

        }


        //次のブロックを表示する
        private void second_blockshow() {           
            Point[] second_block_sqs;

            for (int i = width2; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                    screen[i, j] = 0;
            }

            GetSqs(second_block, second_pos, 0, out second_block_sqs);
            PutSqs(second_block_sqs, second_block.color);
        }





        private bool GetSqs(Block block, Point pos, int rot, out Point[] sqs)
        {
            bool overlap = false;
            sqs = new Point[block.sq.GetLength(1)];

            for (int i = 0; i < sqs.Length; ++i)
            {
                var p = new Point(pos.X + block.sq[rot, i].X, pos.Y + block.sq[rot, i].Y);
                overlap |= p.X < 0 || p.X >= width2 || p.Y < 0 || p.Y >= height2 || screen[p.X, p.Y] != 0;
                sqs[i] = p;
            }

            return !overlap;
        }





        private void PutSqs(Point[] sqs, int color)
        {
            foreach (var sq in sqs)
            {
                if (sq.X >= 0 && sq.X < width && sq.Y >= 0 && sq.Y < height) screen[sq.X, sq.Y] = color;
            }
        }


        private void GameOver()
        {
            for (int i = 0; i < width; ++i)
                for (int j = 0; j < height; ++j)
                    if (screen[i, j] != 0) screen[i, j] = 8;
                        timer1.Enabled = false;


        }




        int DeleteLine()
        {
            int sum = 0;
            var delCount = 0;

            for (int j = 0; j < height2; ++j)
            {

                bool delete = true;

                for (int i = 0; i < width2; ++i)
                    if (screen[i, j] == 0) 
                        delete = false;


                if (delete)
                {
                    for (int k = j; k >= 1; --k)
                        for (int i = 0; i < width2; ++i)
                            screen[i, k] = screen[i, k - 1];

                    delCount++;

                }
                                            
            }
            if (delCount == 4)
                sum = 1200;

            if (delCount == 3)
                sum = 300;

            if (delCount == 2)
                sum = 100;
            
            if (delCount == 1)
                sum = 40;

            score = score + sum;

            return score;

        }


    }
}


本当にありがとうございました。


閉鎖

“C言語何でも質問掲示板” へ戻る