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);
}
}
结束语
大学的时候就想着要做个俄罗斯方块,现在终于完成了(哈哈,真是汗颜💧)
有什么问题,下方评论区随时联系我哦!
喜欢的话,点个赞或关注支持一下!!!