워리어 콤보 모작 개발일지

워리어콤보 모작 개발일지 - 03 [Block][연습]

다모아 2023. 9. 14. 15:01

참고

https://ninezmk2.blogspot.com/2019/11/block.html

 

3. 블럭(Block) 추가하기

유니티 3매치 퍼즐 게임 개발 과정을 공유하는 블로그입니다.

ninezmk2.blogspot.com


BlockConfig

Block

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Block
{
    private BlockType m_BlockType;
    public BlockType type
    {
        get { return m_BlockType; }
        set { m_BlockType = value; }
    }

    protected BlockBreed m_Breed;
    public BlockBreed breed
    {
        get { return m_Breed; }
        set
        {
            this.m_Breed = value;
            if(this.m_BlockBehaviour != null)
            {
                this.m_BlockBehaviour.UpdateView(true);
            }
        }
    }

    protected BlockBehaviour m_BlockBehaviour;
    public BlockBehaviour blockBehaviour
    {
        get { return m_BlockBehaviour; }
        set
        {
            this.m_BlockBehaviour = value;
            this.m_BlockBehaviour.SetBlock(this);
        }
    }

    public Block(BlockType blockType)
    {
        this.m_BlockType = blockType;
    }

    public Block InstantiateBlockObj(GameObject blockPrefab, Transform containerObj)
    {
        if(this.IsValidate() == false)
        {
            return null;
        }

        GameObject newObj = GameObject.Instantiate(blockPrefab, new Vector3(0, 0, 0), Quaternion.identity);

        newObj.transform.parent = containerObj;

        this.blockBehaviour = newObj.transform.GetComponent<BlockBehaviour>();

        return this;
    }

    public bool IsValidate()
    {
        return this.type != BlockType.EMPTY;
    }

    public void Move(float x, float y)
    {
        this.blockBehaviour.transform.position = new Vector3(x, y);
    }
}

 

BlockFactory

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class BlockFactory
{
    public static Block SpawnBlock(BlockType blockType)
    {
        Block block = new Block(blockType);

        if(blockType == BlockType.BASIC)
        {
            block.breed = (BlockBreed)Random.Range(0, 6);
        }
        else if(blockType == BlockType.EMPTY)
        {
            block.breed = BlockBreed.NA;
        }

        return block;
    }
}

 

BlockDefine

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//Block Enum 
public enum BlockType
{
    EMPTY = 0,
    BASIC = 1,
}

public enum BlockBreed
{
    NA = -1,
    BREED_0 = 0,
    BREED_1 = 1,
    BREED_2 = 2,
    BREED_3 = 3,
    BREED_4 = 4,
    BREED_5 = 5,
}

 

BlockBehaviour

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BlockBehaviour : MonoBehaviour
{
    Block m_Block;
    SpriteRenderer m_SpriteRenderer;

    [SerializeField]
    private BlockConfig m_BlockConfig;
    // Start is called before the first frame update
    private void Start()
    {
        this.m_SpriteRenderer = GetComponent<SpriteRenderer>();

        this.UpdateView(false);
    }

    public void SetBlock(Block block)
    {
        this.m_Block = block;
    }

    public void UpdateView(bool bValueChanged)
    {
        if (this.m_Block.type == BlockType.EMPTY)
        {
            this.m_SpriteRenderer.sprite = null;
        }
        else if(this.m_Block.type == BlockType.BASIC)
        {
            this.m_SpriteRenderer.sprite = this.m_BlockConfig.basicBlockSprites[(int)this.m_Block.breed];
        }
    }
}

 

StageBuilder

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StageBuilder
{
    private int m_nStage;

    public StageBuilder(int nStage)
    {
        this.m_nStage = nStage;
    }

    public Stage ComposeStage(int row, int col)
    {
        Stage stage = new Stage(this, row, col);

        //Cell, Block 초기 값 생성
        for (int nRow = 0; nRow < row; nRow++)
        {
            for (int nCol = 0; nCol < col; nCol++)
            {
                stage.blocks[nRow, nCol] = SpawnBlockForStage(nRow, nCol);
                stage.cells[nRow, nCol] = SpawnCellForStage(nRow, nCol);
            }
        }

        return stage;
    }

    private Block SpawnBlockForStage(int nRow, int nCol)
    {
        return nRow == nCol ? SpawnEmptyBlock() : SpawnBlock();
    }

    public Block SpawnBlock()
    {
        return BlockFactory.SpawnBlock(BlockType.BASIC);
    }

    public Block SpawnEmptyBlock()
    {
        Block newBlock = BlockFactory.SpawnBlock(BlockType.EMPTY);

        return newBlock;
    }
    private Cell SpawnCellForStage(int nRow, int nCol)
    {
        return new Cell(nRow == nCol ? CellType.EMPTY : CellType.BASIC);
    }

    public static Stage BuildStage(int nStage, int row, int col)
    {
        StageBuilder stageBuilder = new StageBuilder(0);
        Stage stage = stageBuilder.ComposeStage(row, col);

        return stage;
    }
}

 

StageController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//현재 스테이지를 총괄하는 역할
public class StageController : MonoBehaviour
{
    //초기화 여부 상태 true or false
    private bool m_blnit;
    private Stage m_Stage;

    [SerializeField]
    private Transform m_Container;
    [SerializeField]
    private GameObject m_CellPrefab;
    [SerializeField]
    private GameObject m_BlockPrefab;

    void Start()
    {
        this.InitStage();    
    }

    //초기화스테이지
    void InitStage()
    {
        // m_blnit가 true라면 반환해라
        if (m_blnit)
            return;

        this.m_blnit = true;

        BuildStage();

        this.m_Stage.PrintAll();
    }

    //스테이지 빌드
    private void BuildStage()
    {
        //스테이지 row, col 보내줘서 스테이지 구성하기
        this.m_Stage = StageBuilder.BuildStage(nStage: 0, row: 7, col: 7);
        //Cell[프리팹], Block[프리팹], Container[위치] 가져와서 Stage로 넘겨주기
        this.m_Stage.ComposeStage(this.m_CellPrefab, this.m_BlockPrefab, this.m_Container);
    }
}

 

Stage

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//게임판의 크기를 저장할 Stage다.
public class Stage
{
    private Board m_Board;
    public int maxRow { get { return this.m_Board.maxRow; } }
    public int maxCol { get { return this.m_Board.maxCol; } }
    public Board board { get { return m_Board; } }

    private StageBuilder stageBuilder;

    public Block[,] blocks { get { return this.m_Board.blocks; } }
    public Cell[,] cells { get { return this.m_Board.cells; } }

    public Stage(StageBuilder stageBuilder, int nRow, int nCol)
    {
        this.stageBuilder = stageBuilder;

        this.m_Board = new Board(nRow, nCol);
    }

    //StageController에서 넘김 받은 cell, block, container 정보들 Board로 넘겨주기
    internal void ComposeStage(GameObject cellPrefab, GameObject blockPrefab, Transform container)
    {
        this.m_Board.ComposeStage(cellPrefab, blockPrefab, container);
    }

    public void PrintAll()
    {
        System.Text.StringBuilder strCells = new System.Text.StringBuilder();
        System.Text.StringBuilder strBlocks = new System.Text.StringBuilder();

        for (int nRow = maxRow - 1 ; nRow >= 0; nRow--)
        {
            for (int nCol = 0; nCol < maxCol; nCol++)
            {
                strCells.Append($"{cells[nRow, nCol].type}, ");
                strBlocks.Append($"{blocks[nRow, nCol].type}, ");
            }
            strCells.Append("\n");
            strBlocks.Append("\n");
        }
        Debug.Log(strCells.ToString());
        Debug.Log(strBlocks.ToString());
    }
}

 

Board

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//보드를 구성하는 데이터 저장소임.
public class Board
{
    private int m_nRow; //열
    private int m_nCol; //행

    public int maxRow { get { return m_nRow; } }
    public int maxCol { get { return m_nCol; } }

    //2중 배열의 Cell 생성 --> 보드구성
    private Cell[,] m_Cells;
    public Cell[,] cells { get { return m_Cells; } }

    //2중 배열의 Block 생성 --> 보드구성
    private Block[,] m_Blocks;
    public Block[,] blocks { get { return m_Blocks; } }

    private Transform m_Container;
    private GameObject m_CellPrefab;
    private GameObject m_BlockPrefab;
    //생성자
    public Board(int nRow, int nCol)
    {
        this.m_nRow = nRow;
        this.m_nCol = nCol;

        this.m_Cells = new Cell[nRow, nCol];
        this.m_Blocks = new Block[nRow, nCol];
    }

    //Stage에서 넘김받은 정보들 보드에 저장해두기 및 위치 
    internal void ComposeStage(GameObject cellPrefab, GameObject blockPrefab, Transform container)
    {
        this.m_BlockPrefab = blockPrefab;
        this.m_CellPrefab = cellPrefab;
        this.m_Container = container;

        float initX = CalcInitX(0.5f);
        float initY = CalcInitY(0.5f);
        for (int nRow = 0; nRow < m_nRow; nRow++)
        {
            for (int nCol = 0; nCol < m_nCol; nCol++)
            {
                if (m_Cells[nRow, nCol] != null)
                {
                    Cell cell = m_Cells[nRow, nCol].InstantiateCellObj(cellPrefab, container);
                    if (cell != null)
                    {
                        cell.Move(initX + nCol, initY + nRow);
                    }
                }

                if (this.m_Blocks[nRow, nCol] != null)
                {
                    Block block = m_Blocks[nRow, nCol].InstantiateBlockObj(blockPrefab, container);
                    if (block != null)
                    {
                        block.Move(initX + nCol, initY + nRow);
                    }
                }
                
                
                
            }
        }
    }

    public float CalcInitX(float offset)
    {
        return -m_nCol / 2.0f + offset;
    }

    public float CalcInitY(float offset)
    {
        return -m_nRow / 2.0f + offset;
    }
}

 

CellBehaviour

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CellBehaviour : MonoBehaviour
{
    Cell m_Cell;
    SpriteRenderer m_SpriteRenderer;

    private void Start()
    {
        this.m_SpriteRenderer = GetComponent<SpriteRenderer>();

        this.UpdateView(false);
    }

    //받아온 cell 저장해두기
    public void SetCell(Cell cell)
    {
        this.m_Cell = cell;
    }

    //EMPTY라면 sprite를 null로 바꾸라는 함수
    public void UpdateView(bool bValueChanged)
    {
        if (this.m_Cell.type == CellType.EMPTY)
        {
            this.m_SpriteRenderer.sprite = null;
        }
    }
}

 

Cell

using System.Collections;
using System.Collections.Generic;
using UnityEditor.U2D.Aseprite;
using UnityEngine;

//보드의 배경을 구성한다, 변하지 않는 데이터라 DataManager의 역할이랑 비슷하다고 본다
public class Cell
{
    protected CellType m_CellType;
    public CellType type
    {
        get { return m_CellType; }
        set { m_CellType = value; }
    }

    protected CellBehaviour m_CellBehaviour;
    public CellBehaviour cellBehaviour
    {
        get { return m_CellBehaviour; }
        set
        {
            m_CellBehaviour = value;
            m_CellBehaviour.SetCell(this);
        }
    }
    public Cell(CellType cellType)
    {
        this.m_CellType = cellType;
    }

    //Cell오브젝트 인스턴스화하기
    public Cell InstantiateCellObj(GameObject cellPrefab, Transform containerObj)
    {
        GameObject newObj = GameObject.Instantiate(cellPrefab, new Vector3(0, 0, 0), Quaternion.identity);

        newObj.transform.parent = containerObj;

        this.cellBehaviour = newObj.transform.GetComponent<CellBehaviour>();

        return this;
    }

    //위치지정
    public void Move(float x, float y)
    {
        this.cellBehaviour.transform.position = new Vector3(x, y);
    }
}

 

CellDefine

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//Cell Enum 역할인 것 같다.
public enum CellType
{
    EMPTY = 0, 
    BASIC = 1,
    FIXTURE = 2,
    JELLY = 3,
}

 

BlockConfig

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Bingle/Block Config", fileName = "BlockConfig.asset")]
public class BlockConfig : ScriptableObject
{
    public Sprite[] basicBlockSprites;
}