最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Unity實(shí)現(xiàn)俄羅斯方塊

 更新時(shí)間:2020年06月22日 08:50:05   作者:兩水先木示  
這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)俄羅斯方塊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Unity實(shí)現(xiàn)俄羅斯方塊的具體代碼,供大家參考,具體內(nèi)容如下

一、使用SpriteRenderer作為小方塊圖片,創(chuàng)建7種由若干個(gè)小方塊圖片組成的方塊,如下圖:

Shape-1是一個(gè)空物體,其子物體Block、Block(1)、Block(2)、Block(3)是小方塊,Pivot是錨點(diǎn)(空物體),錨點(diǎn)用作于旋轉(zhuǎn)中心點(diǎn),方塊旋轉(zhuǎn)是以它為中心進(jìn)行旋轉(zhuǎn)的。旋轉(zhuǎn)方塊的代碼如下:

transform.RotateAround(pivot.position, Vector3.forward, -90);

二、通過(guò)測(cè)試劃分出一個(gè)俄羅斯方塊操作區(qū)域(游戲區(qū)域),在z軸相同 的xy平面上的 每個(gè)坐標(biāo)作為二維數(shù)組map的索引,如:map[1,0]保存(1,0,z)坐標(biāo)上的小方塊物體的Transform組件,游戲區(qū)域上x(chóng)是橫軸、y是縱軸,左下角的小方塊坐標(biāo)(0,0),右上角是的小方塊坐標(biāo)(x-1,y-1)。這樣,將游戲區(qū)域劃分成 一個(gè)map數(shù)組后,就可以管理全部小方塊,實(shí)現(xiàn)判斷整行滿并消除行,方塊是否可以下落一行,方塊是否可以變形,方塊是否可以水平移動(dòng)等功能,下面貼出相關(guān)代碼。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Model : MonoBehaviour
{
 public const int NORMAL_ROWS = 20;//最大行數(shù)(這個(gè)也是用于判斷游戲結(jié)束邏輯)
 public const int MAX_ROWS = 23;//最大行數(shù)+3(用于判斷游戲結(jié)束邏輯)
 public const int MAX_COLUMNS = 10;//最大列數(shù)
 private Transform[,] map = new Transform[MAX_COLUMNS, MAX_ROWS];//地圖數(shù)組map
 //下面這些不用管,是UI的一些參數(shù)
 private int score = 0;
 private int highScore = 0;
 private int numbersGame = 0;
 
 public int Score { get { return score; } }
 public int HighScore { get { return highScore; } }
 public int NumbersGame { get { return numbersGame; } }
 
 public bool isDataUpdate = false;
 
 private void Awake()
 {
 LoadData();
 }
 //檢查一個(gè)方塊(如Sharp-1)的位置是否合理,參數(shù)t是方塊的Transform
 public bool IsValidMapPosition(Transform t)
 {
 foreach (Transform child in t)
 {
 //子物體帶"Block"字符的標(biāo)簽tag都是"Block",它們就是小方塊
 if (child.tag != "Block") continue;
 //如果遍歷到的子物體是小方塊的話進(jìn)行下面的邏輯判斷
 Vector2 pos = child.position.Round();//Round是我擴(kuò)展的方法,==貼出來(lái).
 //若不在地圖范圍內(nèi),則不可用
 if (IsInsideMap(pos) == false) return false;
 //有其他圖形占用著,則不可用
 if (map[(int)pos.x, (int)pos.y] != null)
 {
 return false;//不可用
 }
 }
 return true;
 }
 //不在地圖范圍內(nèi)返回false,在返回true
 private bool IsInsideMap(Vector2 pos)
 {
 return pos.x >= 0 && pos.x < MAX_COLUMNS && pos.y >= 0;
 }
 /// <summary>
 /// 在方塊進(jìn)行檢查位置不合理后,會(huì)固定自身位置 放入map[,]保存小方塊Block的Transform組件
 /// </summary>
 /// <param name="t">shape的父物體transform</param>
 public bool PlaceShape(Transform t)
 {
 foreach (Transform child in t)
 {
 if (child.tag != "Block") continue;
 Vector2 pos = child.position.Round();
 map[(int)pos.x, (int)pos.y] = child;
 }
 //放進(jìn)map后需要檢查整張地圖是否需要消行
 return CheckMap();
 }
 /// <summary>
 /// 檢查地圖 是否需要消除行
 /// </summary>
 private bool CheckMap()
 {
 int count = 0;//消行數(shù)
 for (int i = 0; i < MAX_ROWS; i++)
 {
 //若第i行填滿小方塊
 if (CheckIsRowFull(i))
 {
 count++;
 DeleteRow(i);//消除第i行
 MoveDownRowsAbove(i + 1);//第i+1行及其上方的所有行向下移動(dòng)一行(從下到上移動(dòng))
 i--; //因?yàn)樯厦娴哪且恍幸呀?jīng)移動(dòng)下來(lái)了,這里將i--,目的是為了繼續(xù)檢查上面那一行是否滿,因?yàn)閒or會(huì)將i++,這樣就抵消了i++,讓i繼續(xù)保持原樣
 }
 }
 //下面不用管,是UI部分的邏輯
 if (count > 0)
 {
 score += count * 100;
 if(score>highScore)
 {
 highScore = score;
 }
 isDataUpdate = true;
 return true;
 }
 else
 {
 return false;
 }
 
 }
 //檢查第row行是否滿
 private bool CheckIsRowFull(int row)
 {
 for (int i = 0; i < MAX_COLUMNS; i++)
 {
 if (map[i, row] == null)
 {
 return false;
 }
 }
 return true;
 }
 private void DeleteRow(int row)
 {
 for (int i = 0; i < MAX_COLUMNS; i++)
 {
 Destroy(map[i, row].gameObject);
 map[i, row] = null;
 }
 }
 //將索引row行至最上面的行都往下移動(dòng)一行(從下開(kāi)始移動(dòng))
 public void MoveDownRowsAbove(int row)
 {
 for (int i = row; i < MAX_ROWS; i++)
 {
 MoveDownRow(i);
 }
 }
 //將row行 下移一行,處理了邏輯位置 和 物體位置
 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];//這里是邏輯上的移動(dòng)
 map[i, row] = null;
 map[i, row - 1].position += new Vector3(0, -1, 0);//物理上的移動(dòng)
 }
 }
 }
 //判斷游戲結(jié)束邏輯
 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)
 {
  numbersGame++;
  SaveData();
  return true;
 }
 }
 }
 return false;
 }
 public void Restart()
 {
 for(int i=0;i<MAX_COLUMNS;i++)
 {
 for(int j=0;j<MAX_ROWS;j++)
 {
 if(map[i,j])
 {
  Destroy(map[i, j].gameObject);
  map[i, j] = null;
 }
 }
 }
 score = 0;
 }
 private void LoadData()
 {
 highScore= PlayerPrefs.GetInt("HighScore", 0);
 numbersGame = PlayerPrefs.GetInt("NumbersGame",0);
 }
 private void SaveData()
 {
 PlayerPrefs.SetInt("HighScore", highScore);
 PlayerPrefs.SetInt("NumbersGame", numbersGame);
 }
 public void ClearData()
 {
 score = 0;
 highScore = 0;
 numbersGame = 0;
 SaveData();
 }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Shape : MonoBehaviour {
 
 private GameManager gameManager;
 private Ctrl ctrl;
 private bool isPause = false;
 private bool isSpeedUp = false;
 private float timer = 0;
 private float stepTime = 0.8f;//0.8s方塊下落一行
 private Transform pivot;//錨點(diǎn)(旋轉(zhuǎn)中心點(diǎn))
 private int multiple = 15; 
 
 private void Awake()
 {
 pivot = transform.Find("Pivot");
 }
 
 private void Update()
 {
 if (isPause) return;
 timer += Time.deltaTime;
 if(timer>stepTime)
 {
 timer = 0;
 Fall();
 }
 InputControl();
 }
 /// <summary>
 /// 方塊下落一行邏輯
 /// </summary>
 private void Fall()
 {
 //先嘗試將方塊下移一行
 Vector3 pos = transform.position;
 pos.y -= 1;
 transform.position = pos;
 //使用Model的方法檢查方塊位置是否合理,若不合理返回false進(jìn)入if
 if(ctrl.model.IsValidMapPosition(this.transform)==false)
 {
 pos.y += 1;//因?yàn)楫?dāng)前位置是不可用的,而上一個(gè)位置肯定是可用的,所以這里移動(dòng)回到上一個(gè)位置處
 transform.position = pos;
 isPause = true;//暫停當(dāng)前shape的下移
 bool isLineclear = ctrl.model.PlaceShape(this.transform);//使用Model的方法固定shape,即放入map數(shù)組保存小方塊信息,并且檢查地圖消除行
 if (isLineclear) ctrl.audioManager.PlayLineClear();//isLineclear是true代表消除行了,播放聲音
 gameManager.FallDown();//設(shè)置GameManager中的currentShape=null,這樣就會(huì)實(shí)例化下一個(gè)shape方塊,并且更新分?jǐn)?shù)UI
 return;
 }
 ctrl.audioManager.PlayDrop();//方塊固定的聲音
 }
 //輸入控制
 private void InputControl()
 {
 // if (isSpeedUp) return;
 float h=0;
 if(Input.GetKeyDown(KeyCode.LeftArrow))
 {
 h = -1;
 }
 else if(Input.GetKeyDown(KeyCode.RightArrow))
 {
 h = 1;
 }
 if(h!=0)
 {
 //這里和Fall下移邏輯處理手法一樣,不再闡述!
 Vector3 pos = transform.position;
 pos.x += h;
 transform.position = pos;
 if (ctrl.model.IsValidMapPosition(this.transform) == false)
 {
 pos.x -= h;
 transform.position = pos;
 }
 else
 {
 ctrl.audioManager.PlayControl();
 }
 }
 
 //按鍵盤(pán)↑對(duì)方塊進(jìn)行旋轉(zhuǎn)(即變形)
 if(Input.GetKeyDown(KeyCode.UpArrow))
 {
 //以pivot位置為旋轉(zhuǎn)中心,繞z軸旋轉(zhuǎn)-90°
 transform.RotateAround(pivot.position, Vector3.forward, -90);
 //旋轉(zhuǎn)后自然也要檢查下位置是否合理
 if (ctrl.model.IsValidMapPosition(this.transform) == false)
 {
 //不合理,旋轉(zhuǎn)90° 變回之前那樣子(注意:這個(gè)過(guò)程是瞬間發(fā)生的,玩家不會(huì)看到這個(gè)變化過(guò)程?。?
 transform.RotateAround(pivot.position, Vector3.forward, 90);
 }
 else
 {
 ctrl.audioManager.PlayControl();
 }
 }
 //按鍵盤(pán)↓會(huì)進(jìn)行加速方塊下移
 if(Input.GetKeyDown(KeyCode.DownArrow))
 {
 isSpeedUp = true;
 stepTime /= multiple;
 }
 }
 public void Init(Color color,Ctrl ctrl,GameManager gameManager)
 {
 this.gameManager = gameManager;
 this.ctrl = ctrl;
 foreach(Transform t in transform)
 {
 if(t.tag=="Block")
 {
 t.GetComponent<SpriteRenderer>().color = color;
 }
 }
 }
 public void Pause()
 {
 isPause = true;
 }
 public void Resume()
 {
 isPause = false;
 }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class GameManager : MonoBehaviour {
 
 private Ctrl ctrl;
 private bool isPause = true;//是否暫停狀態(tài)
 private Shape currentShape = null;
 public Shape[] shapes;//shape prefabs
 public Color[] colors;//shape colors
 private Transform blockHolder;
 private void Awake()
 {
 ctrl = GetComponent<Ctrl>();
 blockHolder = transform.Find("BlockHolder");
 } 
 
 void Update () {
 if(isPause)
 {
 return;
 }
 //如果當(dāng)前方塊為空,生成一個(gè)方塊(這個(gè)currentShape是由Shape
 if (currentShape == null)
 {
 SpawnShape();
 }
 }
 /// <summary>
 /// 刪除已經(jīng)沒(méi)有小方塊Block的sharp方塊物體,即childCount小于等于1的
 /// 并且判斷游戲結(jié)束邏輯
 /// </summary>
 public void FallDown()
 {
 currentShape = null;//將當(dāng)前方塊設(shè)置為空,這一步是為了生成新的方塊
 //更新UI邏輯
 if(ctrl.model.isDataUpdate)
 {
 ctrl.view.UpdateGameUI(ctrl.model.Score, ctrl.model.HighScore);
 }
 //刪除已經(jīng)沒(méi)有小方塊的sharp物體
 foreach(Transform t in blockHolder)
 {
 if(t.childCount<=1)
 {
 Destroy(t.gameObject);
 }
 }
 //判斷游戲結(jié)束
 if(ctrl.model.isGameOver())
 {
 PauseGame();
 ctrl.view.ShowGameOverUI(ctrl.model.Score);
 }
 }
 public void StartGame()
 {
 isPause = false;
 if (currentShape != null)
 {
 currentShape.Resume();
 }
 }
 public void PauseGame()
 {
 isPause = true;
 if(currentShape!=null)
 {
 currentShape.Pause();
 }
 }
 /// <summary>
 /// 生成一個(gè)方塊sharp
 /// </summary>
 void SpawnShape()
 {
 //隨機(jī)方塊類型
 int index = Random.Range(0, shapes.Length);//random create a shape
 //隨機(jī)顏色
 int indexColor = Random.Range(0, colors.Length);//random shape color
 //實(shí)例化方塊
 currentShape = GameObject.Instantiate(shapes[index]);
 //放入blockholder物體下
 currentShape.transform.parent = blockHolder;
 //初始化其方塊顏色等工作
 currentShape.Init(colors[indexColor],ctrl,this);
 
 }
 /// <summary>
 /// 刪除當(dāng)前正在下落的方塊
 /// </summary>
 public void ClearShape()
 {
 if(currentShape!=null)
 {
 Destroy(currentShape.gameObject);
 currentShape = null;
 }
 }
}

大致上,俄羅斯方塊的核心邏輯都總結(jié)在這3個(gè)腳本,Sharp是處理了方塊的移動(dòng)邏輯,Model是真正的核心處理方塊的位置是否合理、消行、消行后將上方方塊整體下移一行等邏輯,GameManager是處理游戲結(jié)束之類的邏輯。

更多俄羅斯方塊精彩文章請(qǐng)點(diǎn)擊專題:俄羅斯方塊游戲集合 進(jìn)行學(xué)習(xí)。

更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:

C++經(jīng)典小游戲匯總

python經(jīng)典小游戲匯總

python俄羅斯方塊游戲集合

JavaScript經(jīng)典游戲 玩不停

javascript經(jīng)典小游戲匯總

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于C#實(shí)現(xiàn)圖片合成功能

    基于C#實(shí)現(xiàn)圖片合成功能

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)圖片合成的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • C#簡(jiǎn)單操作MongoDB的步驟全紀(jì)錄

    C#簡(jiǎn)單操作MongoDB的步驟全紀(jì)錄

    最近花了不少時(shí)間研究學(xué)習(xí)了MongoDB數(shù)據(jù)庫(kù)的相關(guān)知識(shí),下面這篇文章主要給大家介紹了關(guān)于C#簡(jiǎn)單操作MongoDB的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧
    2018-09-09
  • C#使用HtmlAgilityPack組件解析html文檔

    C#使用HtmlAgilityPack組件解析html文檔

    這篇文章介紹了C#使用HtmlAgilityPack組件解析html文檔的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • C#使用Socket實(shí)現(xiàn)分布式事件總線的示例代碼

    C#使用Socket實(shí)現(xiàn)分布式事件總線的示例代碼

    這篇文章主要介紹了C#使用Socket實(shí)現(xiàn)分布式事件總線,文中通過(guò)代碼示例給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-10-10
  • c#的dllimport使用方法詳解

    c#的dllimport使用方法詳解

    DllImport是System.Runtime.InteropServices命名空間下的一個(gè)屬性類,其功能是提供從非托管DLL導(dǎo)出的函數(shù)的必要調(diào)用信息
    2014-01-01
  • Unity Undo實(shí)現(xiàn)原理和使用方法詳解

    Unity Undo實(shí)現(xiàn)原理和使用方法詳解

    本文將詳細(xì)介紹Unity Undo實(shí)現(xiàn)原理和使用方法,并提供多個(gè)使用例子,幫助開(kāi)發(fā)者更好地理解和應(yīng)用該功能,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • C# 建造者模式(Builder Pattern)詳細(xì)講解

    C# 建造者模式(Builder Pattern)詳細(xì)講解

    建造者模式是一種創(chuàng)建型設(shè)計(jì)模式,通過(guò)將復(fù)雜對(duì)象的構(gòu)建過(guò)程與其表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示,它適用于構(gòu)建過(guò)程復(fù)雜且涉及多個(gè)步驟的場(chǎng)景,本文介紹C# 建造者模式(Builder Pattern)詳細(xì)講解,感興趣的朋友一起看看吧
    2025-03-03
  • C#圖像對(duì)比度調(diào)整的方法

    C#圖像對(duì)比度調(diào)整的方法

    這篇文章主要介紹了C#圖像對(duì)比度調(diào)整的方法,涉及C#實(shí)現(xiàn)圖像對(duì)比度操作的相關(guān)技巧,需要的朋友可以參考下
    2015-04-04
  • 基于WPF實(shí)現(xiàn)裁剪圖像功能

    基于WPF實(shí)現(xiàn)裁剪圖像功能

    這篇文章主要為大家詳細(xì)介紹了如何基于WPF實(shí)現(xiàn)裁剪圖像功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定幫助,感興趣的小伙伴可以了解一下
    2023-06-06
  • C#中overrid和new修飾符有什么不同

    C#中overrid和new修飾符有什么不同

    在C#的繼承中嘗嘗會(huì)用到相關(guān)的修飾詞:override和new。這兩個(gè)修飾符都可以在新的子類中,重寫(xiě)同名的父類方法。下面通過(guò)本文給大家介紹C#中overrid和new修飾符的區(qū)別,感興趣的朋友一起看看吧
    2018-02-02

最新評(píng)論

苍南县| 报价| 乌兰浩特市| 财经| 甘肃省| 三都| 德安县| 塘沽区| 绿春县| 渝北区| 绍兴县| 米泉市| 阜新市| 蓬溪县| 湛江市| 建宁县| 喀什市| 昌江| 汪清县| 福泉市| 襄垣县| 黄骅市| 新郑市| 大庆市| 烟台市| 怀来县| 东辽县| 大田县| 永清县| 工布江达县| 中方县| 姜堰市| 穆棱市| 彰化市| 革吉县| 道孚县| 聂荣县| 辉县市| 温泉县| 满洲里市| 青川县|