프로젝트/테트리스 만들기

[.NET C# 프로젝트] 테트리스 만들기 – Part 4(Final). 꽉 찬 라인 지우기, 종료 체크

언제나휴일 2020. 4. 17. 11:59
반응형

 

 

 

[C# 프로젝트] 테트리스 만들기 – Part 4(Final). 꽉 찬 줄 지우기, Ending – 언제나 휴일

 안녕하세요. 언제나 휴일에 언휴예요.  이번 강의에서는 꽉 찬 라인을 지우는 기능과 종료 조건을 체크하는 부분을 구현합니다.  Store 메서드에 라인이 꽉 찼는지 확인하는 메서드를 호출합니다. 이 때 주의할 점은 라인 체크는 아래부터 한다는 것입니다. 벽돌이 4X4공간에 배치하므로 벽돌이 있는 좌표에서 3칸 더 있다는 것을 고려하세요.  internal void Store(int bn, int turn, int x, int y) { for (int x

ehpub.co.kr

테트리스 마무리.zip
0.07MB
테트리스 만들기- 벽돌 모양에 따라 색상 변화.zip
0.04MB

소스 코드

 

GameRule.cs

namespace 도형_이동
{
    class GameRule
    {
        internal const int B_WIDTH = 30;
        internal const int B_HEIGHT = 30;
        internal const int BX = 12;
        internal const int BY = 20;
        internal const int SX = 4;
        internal const int SY = 0;
    }
}

BlockValue.cs

namespace 도형_이동
{
    static class BlockValue
    {
        static public readonly int[,,,] bvals = new int[7, 4, 4, 4]
        {
            {
#region 벽돌1
                {
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 1, 1, 1, 1 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 1, 1, 1, 1 },
                    { 0, 0, 0, 0 }
                }
            },
            #endregion 벽돌1
#region 벽돌2
            {
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                }
            },
            #endregion 벽돌2
#region 벽돌3
            {
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 1 },
                    { 0, 1, 1, 1 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 1 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 1 },
                    { 0, 1, 0, 0 }
                }
            },
            #endregion 벽돌3
#region 벽돌4
            {
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 1, 1 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 1 },
                    { 0, 0, 0, 1 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 1, 1, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 0, 0 },
                    { 0, 1, 1, 1 },
                    { 0, 0, 0, 0 }
                }
            },
            #endregion 벽돌4
#region 벽돌5
            {
                {
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 1 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 1 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 1, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 1, 0 },
                    { 0, 1, 1, 1 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                }
            },
            #endregion 벽돌5
#region 벽돌6
            {
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 1, 1 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 1 },
                    { 0, 0, 1, 1 },
                    { 0, 0, 1, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 1, 1 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 1 },
                    { 0, 0, 1, 1 },
                    { 0, 0, 1, 0 }
                }
            },
#endregion 벽돌6
#region 벽돌7
            {
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 1, 1 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 1 },
                    { 0, 0, 0, 1 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 1, 1 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 1, 1 },
                    { 0, 0, 0, 1 }
                }
            }
#endregion 벽돌7
        };
    }
}


Diagram.cs

using System;

namespace 도형_이동
{
    internal class Diagram
    {        
        internal int X
        {
            get;
            private set;
        }
        internal int Y
        {
            get;
            private set;
        }
        internal int Turn
        {
            get;
            private set;
        }
        internal int BlockNum
        {
            get;
            private set;
        }
        internal Diagram()
        {
            Reset();
        }
        internal void Reset()
        {
            Random rand = new Random();
            X = GameRule.SX;
            Y = GameRule.SY;
            Turn = rand.Next()%4;
            BlockNum = rand.Next() % 7;
        }
        internal void MoveLeft()
        {
            X--;
        }
        internal void MoveRight()
        {
            X++;
        }
        internal void MoveDown()
        {
            Y++;
        }
        internal void MoveTurn()
        {
            Turn = (Turn + 1) % 4;
        }
    }
}

Board.cs

namespace 도형_이동
{
    class Board
    {
        internal static Board GameBoard
        {
            get;
            private set;
        }
        static Board()
        {
            GameBoard = new Board();
        }
        Board()
        {
        }
        int[,] board = new int[GameRule.BX, GameRule.BY];
        internal int this[int x,int y]
        {
            get
            {
                return board[x, y];
            }
        }
        internal bool MoveEnable(int bn,int tn,int x,int y)
        {
            for(int xx=0;xx<4;xx++)
            {
                for(int yy=0;yy<4;yy++)
                {
                    if(BlockValue.bvals[bn,tn,xx,yy]!=0)
                    {
                        if(board[x+xx,y+yy]!=0)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        internal void Store(int bn, int turn, int x, int y)
        {
            for (int xx = 0; xx < 4; xx++)
            {
                for(int yy = 0; yy<4;yy++)
                {
                    if(((x+xx)>=0)&&(x+xx<GameRule.BX)&&(y+yy>=0)&&(y+yy<GameRule.BY))
                    {
                        board[x + xx, y + yy] += BlockValue.bvals[bn, turn, xx, yy];
                    }
                }
            }
            CheckLines(y+3);
        }

        private void CheckLines(int y)
        {
            int yy = 0;
            for(yy=0;(yy<4);yy++)
            {
                if(y-yy<GameRule.BY)
                {                    
                    if (CheckLine(y - yy))
                    {
                        ClearLine(y - yy);
                        y++;
                    }
                }                
            }
        }

        private void ClearLine(int y)
        {
            for (; y > 0; y--)
            {
                for (int xx = 0; xx < GameRule.BX; xx++)
                {
                    board[xx, y] = board[xx, y - 1];
                }
            }
        }

        private bool CheckLine(int y)
        {
            for(int xx= 0; xx<GameRule.BX;xx++)
            {
                if(board[xx,y]==0)
                {
                    return false;
                }
            }
            return true;
        }

        internal void ClearBoard()
        {
            for(int xx=0;xx<GameRule.BX;xx++)
            {
                for(int yy=0;yy<GameRule.BY;yy++)
                {
                    board[xx, yy] = 0;
                }
            }
        }
    }
}

Game.cs

using System.Drawing;

namespace 도형_이동
{
    class Game
    {
        Diagram now;
        Board gboard = Board.GameBoard;
        internal Point NowPosition
        {
            get
            {
                return new Point(now.X, now.Y);
            }
        }
        internal int BlockNum
        {
            get
            {
                return now.BlockNum;
            }
        }
        internal int Turn
        {
            get
            {
                return now.Turn;
            }
        }

        internal static Game Singleton
        {
            get;
            private set;
        }
        internal int this[int x,int y]
        {
            get
            {
                return gboard[x, y];
            }
        }
        static Game()
        {
            Singleton = new Game();
        }
        Game()
        {
            now = new Diagram();
        }
        internal bool MoveLeft()
        {               
            for(int xx=0;xx<4;xx++)
            {
                for(int yy=0;yy<4;yy++)
                {
                    if(BlockValue.bvals[now.BlockNum,Turn, xx,yy]!=0)
                    {
                        if (now.X + xx <= 0)
                        {
                            return false;
                        }
                    }
                }
            }

            if (gboard.MoveEnable(now.BlockNum, Turn, now.X - 1, now.Y))
            {
                now.MoveLeft();
                return true;
            }
            return false;
        }

        internal bool MoveRight()
        {
            for (int xx = 0; xx < 4; xx++)
            {
                for (int yy = 0; yy < 4; yy++)
                {
                    if (BlockValue.bvals[now.BlockNum, Turn, xx, yy] != 0)
                    {
                        if ((now.X + xx+1) >= GameRule.BX)
                        {
                            return false;
                        }
                    }
                }
            }
            if (gboard.MoveEnable(now.BlockNum, Turn, now.X + 1, now.Y))
            {
                now.MoveRight();
                return true;
            }
            return false;
        }

        internal bool MoveDown()
        {
            for (int xx = 0; xx < 4; xx++)
            {
                for (int yy = 0; yy < 4; yy++)
                {
                    if (BlockValue.bvals[now.BlockNum, Turn, xx, yy] != 0)
                    {
                        if ((now.Y + yy + 1) >=GameRule.BY)
                        {
                            gboard.Store(now.BlockNum, Turn, now.X, now.Y);
                            return false;
                        }
                    }
                }
            }
            if (gboard.MoveEnable(now.BlockNum, Turn, now.X, now.Y + 1))
            {
                now.MoveDown();
                return true;
            }
            gboard.Store(now.BlockNum, Turn, now.X, now.Y);
            return false;
        }

        internal bool MoveTurn()
        {
            for (int xx = 0; xx < 4; xx++)
            {
                for (int yy = 0; yy < 4; yy++)
                {
                    if (BlockValue.bvals[now.BlockNum, (Turn+1)%4, xx, yy] != 0)
                    {
                        if (((now.X + xx) < 0)|| ((now.X + xx) >= GameRule.BX)||((now.Y+yy)>=GameRule.BY))
                        {
                            return false;
                        }
                    }
                }
            }
            if (gboard.MoveEnable(now.BlockNum, (Turn + 1) % 4, now.X, now.Y))
            {
                now.MoveTurn();
                return true;
            }
            return false;
        }

        internal bool Next()
        {
            now.Reset();
            return gboard.MoveEnable(now.BlockNum, Turn, now.X, now.Y);
        }

        internal void ReStart()
        {
            gboard.ClearBoard();
        }
    }
}

Form1.cs

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

namespace 도형_이동
{
    public partial class Form1 : Form
    {
        Game game;
        int bx;
        int by;
        int bwidth;
        int bheight;
        public Form1()
        {
            InitializeComponent();            
        }
        private void Form1_Load(object sender, EventArgs e)
        {            
            game = Game.Singleton;
            bx = GameRule.BX;
            by = GameRule.BY;
            bwidth = GameRule.B_WIDTH;
            bheight = GameRule.B_HEIGHT;
            this.SetClientSizeCore(GameRule.BX * GameRule.B_WIDTH, GameRule.BY * GameRule.B_HEIGHT);
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            DoubleBuffered = true;
            DrawGraduation(e.Graphics);
            DrawDiagram(e.Graphics);
            DrawBoard(e.Graphics);
        }

        private void DrawBoard(Graphics graphics)
        {
            for(int xx=0;xx<bx;xx++)
            {
                for(int yy=0; yy<by;yy++)
                {
                    if(game[xx,yy]!=0)
                    {
                        Rectangle now_rt = new Rectangle(xx * bwidth + 2, yy * bheight + 2, bwidth - 4, bheight - 4);
                        graphics.DrawRectangle(Pens.Green, now_rt);
                        graphics.FillRectangle(Brushes.Red, now_rt);
                    }
                }
            }
        }

        private void DrawDiagram(Graphics graphics)
        {
            Pen dpen = new Pen(Color.Red, 4);
            Point now = game.NowPosition;
            int bn = game.BlockNum;
            int tn = game.Turn;
            for(int xx=0;xx<4;xx++)
            {
                for(int yy=0;yy<4;yy++)
                {
                    if(BlockValue.bvals[bn,tn,xx,yy]!=0)
                    {
                        Rectangle now_rt = new Rectangle((now.X+xx) * bwidth + 2, (now.Y+yy) * bheight + 2, bwidth - 4, bheight - 4);
                        graphics.DrawRectangle(dpen, now_rt);
                    }
                }
            }
        }

        private void DrawGraduation(Graphics graphics)
        {
            DrawHorizons(graphics);
            DrawVerticals(graphics);
        }

        private void DrawVerticals(Graphics graphics)
        {
            Point st = new Point();
            Point et = new Point();
            
            for (int cx = 0; cx < bx; cx++)
            {
                st.X = cx * bwidth;
                st.Y = 0;
                et.X = st.X;
                et.Y = by * bheight;

                graphics.DrawLine(Pens.Purple, st, et);
            }
        }

        private void DrawHorizons(Graphics graphics)
        {
            Point st = new Point();
            Point et = new Point();

            for (int cy = 0; cy < by; cy++)
            {
                st.X = 0;
                st.Y = cy * bheight;
                et.X = bx * bwidth;
                et.Y = cy * bheight;

                graphics.DrawLine(Pens.Green, st, et);
            }
        }



        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch(e.KeyCode)
            {
                case Keys.Right: MoveRight(); return;
                case Keys.Left: MoveLeft(); return;
                case Keys.Space: MoveSSDown();return;
                case Keys.Up: MoveTurn();return;
                case Keys.Down: MoveDown(); return;
            }
        }

        private void MoveSSDown()
        {
            while (game.MoveDown())
            {
                Region rg = MakeRegion(0, -1);
                Invalidate(rg);
            }
            EndingCheck();    
        }

        private void MoveTurn()
        {
            if(game.MoveTurn())
            {
                Region rg = MakeRegion();
                Invalidate(rg);
            }
        }

        private void MoveDown()
        {
            if(game.MoveDown())
            {
                Region rg = MakeRegion(0, -1);
                Invalidate(rg);
            }
            else
            {
                EndingCheck();
            }
        }

        private void EndingCheck()
        {
            if (game.Next())
            {
                Invalidate();
            }
            else
            {
                timer_down.Enabled = false;

                if (DialogResult.Yes == MessageBox.Show("계속 하실건가요?", "계속 진행 확인 창", MessageBoxButtons.YesNo))
                {
                    game.ReStart();
                    timer_down.Enabled = true;
                    Invalidate();
                }
                else
                {
                    this.Close();
                }
            }
        }

        private void MoveLeft()
        {
            if (game.MoveLeft())
            {
                Region rg = MakeRegion(1, 0);
                Invalidate(rg);
            }
        }

        private Region MakeRegion(int cx, int cy)
        {
            Point now = game.NowPosition;

            int bn = game.BlockNum;
            int tn = game.Turn;
            Region region = new Region();
            for (int xx = 0; xx < 4; xx++)
            {
                for (int yy = 0; yy < 4; yy++)
                {
                    if (BlockValue.bvals[bn, tn, xx, yy] != 0)
                    {
                        Rectangle rect1 = new Rectangle((now.X + xx) * bwidth + 2, (now.Y + yy) * bheight + 2, bwidth - 4, bheight - 4);
                        Rectangle rect2 = new Rectangle((now.X + cx+xx) * bwidth, (now.Y + cy+yy) * bheight, bwidth, bheight);
                        Region rg1 = new Region(rect1);
                        Region rg2 = new Region(rect2);
                        region.Union(rg1);
                        region.Union(rg2);
                    }
                }
            }
            return region;
        }
        private Region MakeRegion()
        {
            Point now = game.NowPosition;
            int bn = game.BlockNum;
            int tn = game.Turn;
            int oldtn = (tn + 3) % 4;
            Region region = new Region();
            for (int xx = 0; xx < 4; xx++)
            {
                for (int yy = 0; yy < 4; yy++)
                {
                    if (BlockValue.bvals[bn, tn, xx, yy] != 0)
                    {
                        Rectangle rect1 = new Rectangle((now.X + xx) * bwidth + 2, (now.Y + yy) * bheight + 2, bwidth - 4, bheight - 4);
                        Region rg1 = new Region(rect1);
                        region.Union(rg1);                        
                    }
                    if (BlockValue.bvals[bn, oldtn, xx, yy] != 0)
                    {
                        Rectangle rect1 = new Rectangle((now.X + xx) * bwidth + 2, (now.Y + yy) * bheight + 2, bwidth - 4, bheight - 4);
                        Region rg1 = new Region(rect1);
                        region.Union(rg1);
                    }
                }
            }
            return region;
        }
        private void MoveRight()
        {
            if (game.MoveRight())
            {
                Region rg = MakeRegion(-1, 0);
                Invalidate(rg);
            }
        }

        private void timer_down_Tick(object sender, EventArgs e)
        {
            MoveDown();
        }
    }
}
반응형