Unity3D俄罗斯方块

2019-12-07  本文已影响0人  莫忘初心_倒霉熊

游戏展示

截屏2019-12-07下午10.11.49.png 截屏2019-12-07下午10.10.02.png

游戏整体结构

游戏整体结构 整体资源和代码

源码下载地址

俄罗斯方块地址:https://github.com/BackkomCoder/GameSet.git

代码讲解

GameMgr.cs用于整体游戏的控制。

using UnityEngine;

/// <summary>
/// 游戏管理
/// </summary>
public class GameMgr : MonoBehaviour
{
    public static GameMgr _instance;

    /// <summary>
    /// 方块预设
    /// </summary>
    public Item[] items;

    /// <summary>
    /// 游戏是否暂停
    /// </summary>
    private bool isPause = false;
    /// <summary>
    /// 当前的方块
    /// </summary>
    private Item currentItem;
    /// <summary>
    /// 分数
    /// </summary>
    private int score = 0;

    private void Awake()
    {
        _instance = this;
    }
    private void Update()
    {
        if (isPause)
            return;
        if (currentItem == null)
            //生成方块
            SpawnItem();
    }

    /// <summary>
    /// 开始游戏
    /// </summary>
    public void StartGame()
    {
        isPause = false;
        if (currentItem != null)
        {
            currentItem.Resume();
        }
    }
    /// <summary>
    /// 暂停游戏
    /// </summary>
    public void PauseGame()
    {
        isPause = true;
        if (currentItem != null)
        {
            currentItem.Pause();
        }
    }
    /// <summary>
    /// 当前方块落下完成
    /// </summary>
    public void FallDownComplete()
    {
        currentItem = null;
        //删除无用的方块父物体
        foreach (Transform t in transform)
        {
            if (t.childCount <= 1)
            {
                Destroy(t.gameObject);
            }
        }
        //方块下落完成后,检查游戏是否结束
        if (MapData._instance.IsGameOver())
        {
            PauseGame();
            UIMgr._instance.ShowGameOver();
        }
    }
    /// <summary>
    /// 删除当前方块
    /// </summary>
    public void DeleteCurrentItem()
    {
        if (currentItem != null)
        {
            Destroy(currentItem.gameObject);
            currentItem = null;
        }
    }
    /// <summary>
    /// 增加分数
    /// </summary>
    /// <param name="score">分数</param>
    public void AddScore(int score)
    {
        this.score += score;
        UIMgr._instance.ShowScore(this.score);
    }
    /// <summary>
    /// 设置分数
    /// </summary>
    /// <param name="score">分数</param>
    public void SetScore(int score)
    {
        this.score = score;
        UIMgr._instance.ShowScore(this.score);
    }

    /// <summary>
    /// 生成方块
    /// </summary>
    private void SpawnItem()
    {
        int index = Random.Range(0, items.Length);
        Item item = Instantiate(items[index]);
        item.transform.SetParent(transform);
        currentItem = item;
    }
}

MapData.cs为游戏核心逻辑,地图数据管理。

using UnityEngine;

/// <summary>
/// 地图数据
/// </summary>
public class MapData : MonoBehaviour
{
    public static MapData _instance;

    /// <summary>
    /// 方块正常下落的行数,大于20行,则表示游戏结束
    /// </summary>
    public const int NORMAL_ROWS = 20;
    /// <summary>
    /// 最大行数
    /// </summary>
    public const int MAX_ROWS = 24;
    /// <summary>
    /// 最大列数
    /// </summary>
    public const int MAX_COLUMNS = 10;
    /// <summary>
    /// 地图数据
    /// </summary>
    private Transform[,] map = new Transform[MAX_COLUMNS, MAX_ROWS];

    private void Awake()
    {
        _instance = this;
    }

    #region 公共方法
    /// <summary>
    /// 方块当前位置是否合法
    /// </summary>
    /// <param name="t">方块的父物体</param>
    /// <returns>位置是否合法</returns>
    public bool IsValidPosition(Transform t)
    {
        foreach (Transform child in t)
        {
            if (!child.CompareTag("Item"))
                continue;
            int x = Mathf.RoundToInt(child.position.x);
            int y = Mathf.RoundToInt(child.position.y);
            //是否在地图内
            if (IsInsideMap(new Vector2(x, y)) == false)
                return false;
            //当前地图位置是否为空
            if (map[x, y] != null)
                return false;
        }
        return true;
    }
    /// <summary>
    /// 方块停止下落后,将方块保存地图中
    /// </summary>
    /// <param name="t">方块的父物</param>
    public void PlaceItem(Transform t)
    {
        foreach (Transform child in t)
        {
            if (!child.CompareTag("Item"))
                continue;
            int x = Mathf.RoundToInt(child.position.x);
            int y = Mathf.RoundToInt(child.position.y);
            map[x, y] = child;
        }
        //检测是否有满行的
        CheckMapRowFull();
    }
    /// <summary>
    /// 游戏是否结束
    /// </summary>
    /// <returns>是否结束</returns>
    public bool IsGameOver()
    {
        for (int i = NORMAL_ROWS; i < MAX_ROWS; I++)
        {
            for (int j = 0; j < MAX_COLUMNS; j++)
            {
                if (map[j, i] != null)
                {
                    return true;
                }
            }
        }
        return false;
    }
    /// <summary>
    /// 清空地图
    /// </summary>
    public void ClearMap()
    {
        for (int i = 0; i < MAX_COLUMNS; I++)
        {
            for (int j = 0; j < MAX_ROWS; j++)
            {
                if (map[i, j] != null)
                {
                    Destroy(map[i, j].gameObject);
                    map[i, j] = null;
                }
            }
        }
    }
    #endregion

    #region 私有方法
    /// <summary>
    /// 当前位置是否在地图内
    /// </summary>
    /// <param name="pos">位置</param>
    /// <returns>是否在地图内</returns>
    private bool IsInsideMap(Vector2 pos)
    {
        return pos.x >= 0 && pos.x < MAX_COLUMNS && pos.y >= 0;
    }
    /// <summary>
    /// 检查地图是否要消除行
    /// </summary>
    private void CheckMapRowFull()
    {
        for (int i = 0; i < MAX_ROWS; I++)
        {
            //检查每一行是否满
            bool isFull = CheckIsRowFull(i);
            if (isFull)
            {
                //增加分数
                GameMgr._instance.AddScore(100);
                //删除满行
                DeleteRow(i);
                //满行以上的方块下落
                MoveDownRowAbove(i + 1);
                I--;
            }
        }
    }
    /// <summary>
    /// 检查行是否满
    /// </summary>
    /// <param name="row">行</param>
    /// <returns>是否行满</returns>
    private bool CheckIsRowFull(int row)
    {
        for (int i = 0; i < MAX_COLUMNS; I++)
        {
            if (map[i, row] == null)
                return false;
        }
        return true;
    }
    /// <summary>
    /// 删除行
    /// </summary>
    /// <param name="row">行</param>
    private void DeleteRow(int row)
    {
        for (int i = 0; i < MAX_COLUMNS; I++)
        {
            Destroy(map[i, row].gameObject);
            map[i, row] = null;
        }
    }
    /// <summary>
    /// 满行以上的方块下落
    /// </summary>
    /// <param name="row">行</param>
    private void MoveDownRowAbove(int row)
    {
        for (int i = row; i < MAX_ROWS; I++)
        {
            MoveDownRow(i);
        }
    }
    /// <summary>
    /// 满行,以上的某一行方块下落
    /// </summary>
    /// <param name="row">行</param>
    private void MoveDownRow(int row)
    {
        for (int i = 0; i < MAX_COLUMNS; I++)
        {
            if (map[i, row] != null)
            {
                map[i, row - 1] = map[i, row];
                map[i, row] = null;
                map[i, row - 1].position += new Vector3(0, -1, 0);
            }
        }
    }
    #endregion
}

Item.cs 控制每一个方块的逻辑。

using UnityEngine;

/// <summary>
/// 每一个方块的控制
/// </summary>
public class Item : MonoBehaviour
{
    /// <summary>
    /// 是否暂停
    /// </summary>
    private bool isPause = false;
    /// <summary>
    /// 下落计时器
    /// </summary>
    private float timer = 0;
    /// <summary>
    /// 下落间隔
    /// </summary>
    private float intervalTime = 0.5f;
    /// <summary>
    /// 旋转点
    /// </summary>
    private Transform pivot;

    private void Start()
    {
        pivot = transform.Find("Pivot");
    }
    private void Update()
    {
        if (isPause)
            return;
        timer += Time.deltaTime;
        if (timer > intervalTime)
        {
            timer = 0;
            //下落
            Fall();
        }
        //方块控制
        InputCtrl();
    }

    /// <summary>
    /// 下落
    /// </summary>
    private void Fall()
    {
        Vector3 pos = transform.position;
        pos.y -= 1;
        transform.position = pos;
        //位置不合法,回复到上一个位置,并暂停下落,将方块保存到地图中
        if (MapData._instance.IsValidPosition(transform) == false)
        {
            pos.y += 1;
            transform.position = pos;
            isPause = true;
            //将方块保存到地图中
            MapData._instance.PlaceItem(transform);
            //当前方块完成下落
            GameMgr._instance.FallDownComplete();
        }
    }
    /// <summary>
    /// 输入控制
    /// </summary>
    void InputCtrl()
    {
        float h = 0;
        //左
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            h = -1;
        }
        //右
        else if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            h = 1;
        }
        //旋转
        else if (Input.GetKeyDown(KeyCode.UpArrow))
        {
            transform.RotateAround(pivot.position, Vector3.forward, -90);
            //位置是否合法检测
            if (MapData._instance.IsValidPosition(transform) == false)
            {
                transform.RotateAround(pivot.position, Vector3.forward, 90);
            }
        }
        //下落
        else if (Input.GetKey(KeyCode.DownArrow))
        {
            intervalTime = 0.1f;
        }
        else
        {
            intervalTime = 0.5f;
        }
        if (h != 0)
        {

            Vector3 pos = transform.position;
            pos.x += h;
            transform.position = pos;
            //位置是否合法检测
            if (MapData._instance.IsValidPosition(transform) == false)
            {
                pos.x -= h;
                transform.position = pos;
            }
        }
    }
    /// <summary>
    /// 暂停
    /// </summary>
    public void Pause()
    {
        isPause = true;
    }
    /// <summary>
    /// 继续
    /// </summary>
    public void Resume()
    {
        isPause = false;
    }

}

UIMgr.cs 用于UI管理。

using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// UI管理
/// </summary>
public class UIMgr : MonoBehaviour
{
    public static UIMgr _instance;
    /// <summary>
    /// 开始按钮
    /// </summary>
    private Button btnStart;
    /// <summary>
    /// 暂停按钮
    /// </summary>
    private Button btnPause;
    /// <summary>
    /// 重新开始按钮
    /// </summary>
    private Button btnRestart;
    /// <summary>
    /// 分数
    /// </summary>
    private Text textScore;
    /// <summary>
    /// 游戏结束
    /// </summary>
    private Text textGameOver;

    private void Awake()
    {
        _instance = this;
    }

    void Start()
    {
        textGameOver = transform.Find("GameOverText").GetComponent<Text>();
        textScore = transform.Find("ScoreText").GetComponent<Text>();
        btnStart = transform.Find("StartBtn").GetComponent<Button>();
        btnPause = transform.Find("PauseBtn").GetComponent<Button>();
        btnRestart = transform.Find("RestartBtn").GetComponent<Button>();
        //开始游戏
        btnStart.onClick.AddListener(() =>
        {
            if (MapData._instance.IsGameOver())
            {
                return;
            }
            GameMgr._instance.StartGame();
            btnStart.gameObject.SetActive(false);
            btnPause.gameObject.SetActive(true);
        });
        //暂停游戏
        btnPause.onClick.AddListener(() =>
        {
            if (MapData._instance.IsGameOver())
            {
                return;
            }   
            GameMgr._instance.PauseGame();
            btnStart.gameObject.SetActive(true);
            btnPause.gameObject.SetActive(false);
        });
        //重新游戏
        btnRestart.onClick.AddListener(() =>
        {
            btnStart.gameObject.SetActive(false);
            btnPause.gameObject.SetActive(true);
            textGameOver.gameObject.SetActive(false);
            //删除当前方块
            GameMgr._instance.DeleteCurrentItem();
            //清空地图
            MapData._instance.ClearMap();
            //重置分数
            GameMgr._instance.SetScore(0);
            //重新游戏
            GameMgr._instance.StartGame();
        });
    }
    /// <summary>
    /// 展示分数
    /// </summary>
    /// <param name="score">分数</param>
    public void ShowScore(int score)
    {
        textScore.text = score.ToString();
    }
    /// <summary>
    /// 游戏结束
    /// </summary>
    public void ShowGameOver()
    {
        textGameOver.gameObject.SetActive(true);
    }
}

结束语

大学的时候就想着要做个俄罗斯方块,现在终于完成了(哈哈,真是汗颜💧)
有什么问题,下方评论区随时联系我哦!
喜欢的话,点个关注支持一下!!!

上一篇下一篇

猜你喜欢

热点阅读