본문 바로가기
프로그래밍/콘솔프로젝트

BrickGame <최종>

by SUGI_ 2023. 7. 13.

 

namespace BrickGameFinal
{
    internal class BALLDATA
    {
        public int nReady;
        public int nDirect;
        public int nX, nY;
    }
}
namespace BrickGameFinal
{
    internal class Ball
    {
        BALLDATA m_tBall = new BALLDATA();

        //C# 공의 방향 배열 정의
        int[,] g_WallCollision = new int[4, 6]
        { 
            {  3 , 2,-1,-1,-1, 4},
            { -1 ,-1,-1,-1, 2, 1},
            { -1 , 5, 4,-1,-1,-1},
            { -1 ,-1, 1, 0, 5,-1},
        };

        Bar m_pBar;
        Block m_pBlock;

        //바 클래스도 가져와야 할 거 같다. 값만 가져온다.
        public void SetBar(Bar bar) { m_pBar = bar; }
        //벽돌 클래스도 가져와야 할 거 같다. ref로 가져와서 값을 변환해줄 수 있다.
        //참조해야한다 블럭의 Life값을 설정해주기 위해서 
        public void SetBlock(ref Block pBlock) { m_pBlock = pBlock; }

        //그려줄 함수
        public void ScreenWall()
        {
            Program.gotoxy(0, 0);
            Console.Write("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓");
            Program.gotoxy(0, 1);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 2);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 3);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 4);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 5);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 6);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 7);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 8);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 9);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 10);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 11);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 12);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 13);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 14);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 15);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 16);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 17);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 18);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 19);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 20);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 21);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 22);
            Console.Write("┃                                                                             ┃");
            Program.gotoxy(0, 23);
            Console.Write("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛");
        }

        //충돌 처리
        public int Collision(int x, int y)
        {
            // 벽충돌
            if (y == 0)
            {
                m_tBall.nDirect = g_WallCollision[0, m_tBall.nDirect];
                return 1; //공의 방향이 바뀌면 1을 리턴  
            }

            if (x == 1)
            {
                m_tBall.nDirect = g_WallCollision[1, m_tBall.nDirect];
                return 1;
            }

            if (x == 77)
            {
                m_tBall.nDirect = g_WallCollision[2, m_tBall.nDirect];
                return 1;
            }

            if (y == 23)
            {
                m_tBall.nDirect = g_WallCollision[3, m_tBall.nDirect];
                return 1;
            }

            // Bar충돌처리 ->바 윗면 아랫면 체크 Y + 1(아래충돌) Y - 1 (윗충돌)
            if(x >= m_pBar.m_tBar.nX[0] && x <= m_pBar.m_tBar.nX[2] + 1 && y == (m_pBar.m_tBar.nY)) // 바위 충돌
            {
                //공의 방향 정의
                if (m_tBall.nDirect == 1)
                    m_tBall.nDirect = 2;
                else if (m_tBall.nDirect == 2)
                    m_tBall.nDirect = 1;
                else if (m_tBall.nDirect == 5)
                    m_tBall.nDirect = 4;
                else if (m_tBall.nDirect == 4)
                    m_tBall.nDirect = 5;

                //방향이 바뀐다
                return 1;
            }
            
            // 위충돌
            if (x >= m_pBar.m_tBar.nX[0] && x <= m_pBar.m_tBar.nX[2] + 1 && y == (m_pBar.m_tBar.nY +1)) // 바위 충돌
            {
                if (m_tBall.nDirect == 1)
                    m_tBall.nDirect = 2;
                else if (m_tBall.nDirect == 2)
                    m_tBall.nDirect = 1;
                else if (m_tBall.nDirect == 5)
                    m_tBall.nDirect = 4;
                else if (m_tBall.nDirect == 4)
                    m_tBall.nDirect = 5;

                //방향이 바뀐다
                return 1;
            }

            //벽돌 충돌
            for(int i = 0; i < 20; i++)
            {
                if (m_pBlock.tBlock[i].nLife == 1) //살아있을때
                {
                    if(x >= m_pBlock.tBlock[i].nX && x <= m_pBlock.tBlock[i].nX+1 && y == m_pBlock.tBlock[i].nY) //충돌 하면
                    {
                        if (m_tBall.nDirect == 1)
                            m_tBall.nDirect = 2;
                        else if (m_tBall.nDirect == 2)
                            m_tBall.nDirect = 1;
                        else if (m_tBall.nDirect == 5)
                            m_tBall.nDirect = 4;
                        else if (m_tBall.nDirect == 4)
                            m_tBall.nDirect = 5;

                        //벽돌은 숨겨야 한다.
                        m_pBlock.tBlock[i].nLife = 0;

                        //방향이 바뀐다
                        return 1;
                    }
                }

                if (m_pBlock.tBlock[i].nLife == 1) //살아있을때
                {
                    if (x >= m_pBlock.tBlock[i].nX && x <= m_pBlock.tBlock[i].nX + 1 && y == m_pBlock.tBlock[i].nY+1) //충돌 하면
                    {
                        if (m_tBall.nDirect == 1)
                            m_tBall.nDirect = 2;
                        else if (m_tBall.nDirect == 2)
                            m_tBall.nDirect = 1;
                        else if (m_tBall.nDirect == 5)
                            m_tBall.nDirect = 4;
                        else if (m_tBall.nDirect == 4)
                            m_tBall.nDirect = 5;

                        //벽돌은 숨겨야 한다.
                        m_pBlock.tBlock[i].nLife = 0;

                        //방향이 바뀐다
                        return 1;
                    }
                }
            }

            return 0; 
        }

        //볼 데이터 값
        public BALLDATA GetBall() { return m_tBall; }
        //바에서 움직이는 값
        public void SetX(int x) { m_tBall.nX += x; }
        public void SetY(int y) { m_tBall.nY += y; }
        //볼 데이터 넣기
        public void SetBall(BALLDATA tBall) { m_tBall = tBall; }
        //레디 할 것인지.
        public void SetReady(int Ready) { m_tBall.nReady = Ready; }
       
        public void Initialize()
        {
            // 이동을 위한
            m_tBall.nReady = 0; //공안움직임 1 움직임 0
            m_tBall.nDirect = 1;

            m_tBall.nX = 30;
            m_tBall.nY = 10;

            //커서 안보이게 하기
            Console.CursorVisible = false;
        }

        public void Progress() 
        {

            if (m_tBall.nReady == 0)
            {
                //공의 방향에따른 스위치문
                switch (m_tBall.nDirect)
                {
                    case 0: //위
                        if (Collision(m_tBall.nX, m_tBall.nY - 1) == 0)
                            m_tBall.nY--;
                        break;
                    case 1:  //오른쪽 위
                        if (Collision(m_tBall.nX + 1, m_tBall.nY - 1) == 0)
                        {
                            m_tBall.nX++;
                            m_tBall.nY--;
                        }
                        break;
                    case 2: //오른쪽 아래
                        if (Collision(m_tBall.nX + 1, m_tBall.nY + 1) == 0)
                        {
                            m_tBall.nX++;
                            m_tBall.nY++;
                        }
                        break;
                    case 3: //아래
                        if (Collision(m_tBall.nX, m_tBall.nY + 1) == 0)
                            m_tBall.nY++;
                        break;
                    case 4: //왼쪽 아래
                        if (Collision(m_tBall.nX - 1, m_tBall.nY + 1) == 0)
                        {
                            m_tBall.nX--;
                            m_tBall.nY++;
                        }
                        break;
                    case 5://왼쪽 위
                        if (Collision(m_tBall.nX - 1, m_tBall.nY - 1) == 0)
                        {
                            m_tBall.nX--;
                            m_tBall.nY--;
                        }
                        break;
                }
            }
        }

        public void Render() 
        {
            ScreenWall();

            Program.gotoxy(m_tBall.nX, m_tBall.nY);
            Console.Write("●");
        }

        public void Releas()
        {

        }
    }
}
namespace BrickGameFinal
{
    internal class BARDATA
    {
        public int[] nX = new int[3];
        public int nY;
    }
}
namespace BrickGameFinal
{
    internal class Bar
    {
        //퍼블릭으로 변경 바와 공의 충돌 처리를 위해
        public BARDATA m_tBar = new BARDATA();
        
        int m_nCatch; //공을 잡았는지 체크

        const int LEFTKEY = 75; //상수로 만들어준다. 변수에 값 대입 x
        const int RIGHTKEY = 77; //상수로 만들어준다. 변수에 값 대입 x

        public void Initialize()
        {
            m_nCatch = 0;

            m_tBar.nY = 18;
            m_tBar.nX[0] = 12;
            m_tBar.nX[1] = 14;
            m_tBar.nX[2] = 16;
        }

        //공의 객체를 가지고와서 잡았는지 판단 및 움직임도 줘야함
        //ref로 인자값 전달 참조 
        public void Progress(ref Ball pBall)
        {
            int nKey = 0;

            if (Console.KeyAvailable)
            {
                nKey = Program._getch(); // 키 눌림 값

                switch (nKey)
                {
                    case LEFTKEY: //왼쪽
                        m_tBar.nX[0]--;
                        m_tBar.nX[1]--;
                        m_tBar.nX[2]--;

                        if (pBall.GetBall().nReady == 1 && m_nCatch == 1)
                        {
                            //공이 잡힌상태
                            pBall.SetX(-1); //공왼쪽으로 움직이게 값주기
                        }
                        break;

                    case RIGHTKEY: //오른쪽
                        m_tBar.nX[0]++;
                        m_tBar.nX[1]++;
                        m_tBar.nX[2]++;

                        if (pBall.GetBall().nReady == 1 && m_nCatch == 1)
                        {
                            //공이 잡힌상태
                            pBall.SetX(1); //공 오른쪽으로 움직이게 값주기
                        }
                        break;

                    case 'a':
                        pBall.SetReady(0);
                        //초기화 -> 떠나보내기로 변경
                        /*BALLDATA tBall = new BALLDATA();
                        tBall.nReady = 0;
                        tBall.nX = 20;
                        tBall.nY = 1;
                        pBall.SetBall(tBall);
                        m_nCatch = 0;*/
                        break;
                    case 's':
                        if (pBall.GetBall().nX >= m_tBar.nX[0] && pBall.GetBall().nX <= m_tBar.nX[2] + 1 && pBall.GetBall().nY == (m_tBar.nY - 1))
                        {
                            pBall.SetReady(1);
                            m_nCatch = 1;
                        }
                        break;
                }
            }
        }

        public void Render()
        {
            for (int i = 0; i < 3; i++)
            {
                Program.gotoxy(m_tBar.nX[i], m_tBar.nY);
                Console.Write("▥");
            }
        }

        public void Release()
        {

        }
    }
}
namespace BrickGameFinal
{
    internal class BLOCKDATA
    {
        public int nLife;
        public int nX, nY;
    }
}
namespace BrickGameFinal
{
    internal class Block
    {
        //벽돌이 여러개 -> 충돌 처리를 위해 public 으로 변경
        public BLOCKDATA[] tBlock = new BLOCKDATA[50]; //배열

        public Block() //생성자
        {
            //벽돌초기화
            for (int i = 0; i < tBlock.Length; i++)
            {
                tBlock[i] = new BLOCKDATA();
                tBlock[i].nLife = 0;
                tBlock[i].nX = 0;
                tBlock[i].nY = 0;
            }
        }

        //Search함수 주어진 좌표가 현재 설정된 블록 배열 중에 중복된 것이 있는지를
        //검색해주는 함수이다.
        //현재 최대 블록 50개 설정가능
        //매번 50개의 블록을 전부 검색할 필요없이 스테이지마다 할당된 블록
        //안에서만 검색
        //Search함수는 첫번째 인자의 nEnd변수는 블로그이 범위가 된다.
        //이 함수는 SetBlock함수에서 호출이 된다.

        public int Search(int nEnd, int nX, int nY)
        {
            for (int i = 0; i < nEnd; i++)
            {
                if (tBlock[i].nY == nY) //Y좌표가 같고
                {
                    if (tBlock[i].nX == nX || (tBlock[i].nX + 1) == 1) //특수문자여서
                        return 1; //같으면 1을 반환 
                }
            }
            return 0; //같지 않으면 0을 반환
        }

        //범위 안에서 블록의 중복 검사를 하는 이유
        public void SetBlock(int nBlockCount)
        {
            int nX, nY;

            Random r = new Random();

            for (int i = 0; i < nBlockCount; i++)
            {
                tBlock[i].nLife = 1;

                while (true) //중복찾기
                {
                    nX = r.Next(2, 66); //2~65범위 안에서
                    nY = r.Next(2, 16); //2~15범위 안에서

                    if (Search(i, nX, nY) == 0)
                    {
                        //중복이 아님
                        tBlock[i].nX = nX;
                        tBlock[i].nY = nY;
                        break; //한개를 만들고 for문 탈출
                    }
                }
            }
        }

        //필요 함수들
        public void Initialize()
        {
            SetBlock(20);
        }

        public void Progress()
        {

        }

        public void Render()
        {
            for (int i = 0; i < 20; i++)
            {
                if (tBlock[i].nLife == 1) //살아있는 벽돌만 그리기
                {
                    Console.SetCursorPosition(tBlock[i].nX, tBlock[i].nY);
                    Console.Write("■");
                }
            }
        }

        public void Release()
        {

        }
    }
}
namespace BrickGameFinal
{
    internal class GameManager
    {
        Ball m_pBall = null;
        Block m_pBlock = null;
        Bar m_pBar = null;

        //초기화
        public void Initialize() 
        {  
            //하나만 생성하고 싶음
            if(m_pBall == null)
            {
                m_pBall = new Ball();
                m_pBall.Initialize();
            }

            //바
            if(m_pBlock == null)
            {
                m_pBlock = new Block();
                m_pBlock.Initialize();
            }

            //벽돌
            if(m_pBar == null)
            {
                m_pBar = new Bar();
                m_pBar.Initialize();
            }

            //볼에서 바와 벽돌을 사용해야할 거 같다. -> 이제 충돌처리를 할 수 있는 상태임
            m_pBall.SetBar(m_pBar);
            m_pBall.SetBlock(ref m_pBlock);
        }

        public void Progress()
        {
            m_pBall.Progress();
            m_pBar.Progress(ref m_pBall);
            m_pBlock.Progress();
        }

        public void Render()
        {
            //지우고 전체를 그려줌
            Console.Clear();
            m_pBall.Render();
            m_pBar.Render();
            m_pBlock.Render();
        }

        //c#자체에 있는 함수인가봄. 나중에 바꿔주던지 해야함.
        public void Release()
        {
            m_pBall.Releas();
            m_pBar.Release();
            m_pBlock.Release();
        }
    }
}
namespace BrickGameFinal
{
    internal class Program
    {
        [DllImport("msvcrt.dll")]
        public static extern int _getch();  //c언어 함수 가져옴

        public static void gotoxy(int x, int y)
        {
            Console.SetCursorPosition(x, y);
        }

        static void Main(string[] args)
        {
            GameManager gm = new GameManager();

            //초기화
            gm.Initialize();

            //현재시간
            int Curr = Environment.TickCount;
            while(true)
            {
                if(Curr + 50 < Environment.TickCount)
                {
                    Curr = Environment.TickCount;

                    gm.Progress();
                    gm.Render();
                }
            }
            gm.Release();
        }
    }
}
728x90

'프로그래밍 > 콘솔프로젝트' 카테고리의 다른 글

공 튕기기  (0) 2023.07.12
벽돌 중복없이 만들기  (0) 2023.07.12
Ball Bar로 잡기  (0) 2023.07.11
공의 이동  (0) 2023.07.11
공 벽 튕기기  (0) 2023.07.11