2D獵寶行動(類掃雷小遊戲)DAY 4
阿新 • • 發佈:2018-11-06
1.用陷阱和數字元素初始化地圖
private void InitMap() { //可用索引值的列表 List<int> availabaleIndex = new List<int>(); for(int i = 0; i < w * h; i++) { availabaleIndex.Add(i); } GenerateTrap(availabaleIndex); GenerateNumber(availabaleIndex); } /// <summary> /// 生成陷阱 /// </summary> /// <param name="availableIndex">尚未初始化的地圖元素的索引值</param> private void GenerateTrap(List<int> availableIndex) { float trapProbability = Random.Range(minTrapProbability, maxTrapProbability); int trapNum = (int)(availableIndex.Count * trapProbability); for(int i = 0; i < trapNum; i++) { int tempIndex = availableIndex[Random.Range(0, availableIndex.Count)]; int x, y; GetPosition(tempIndex, out x, out y); availableIndex.Remove(tempIndex); SetElement(tempIndex, ElementContent.Trap); } } /// <summary> /// 生成數字 /// </summary> /// <param name="availableIndex">尚未初始化的地圖元素的索引值</param> private void GenerateNumber(List<int> availableIndex) { foreach(int i in availableIndex) { SetElement(i, ElementContent.Number); } availableIndex.Clear(); } /// <summary> /// 設定元素的型別 /// </summary> /// <param name="index">元素所在位置的一維索引值</param> /// <param name="content">需要設定的型別</param> /// <returns>設定好的的新型別的元件</returns> private BaseElement SetElement(int index,ElementContent content) { int x, y; GetPosition(index, out x ,out y); GameObject tempGo = mapArray[x, y].gameObject; Destroy(tempGo.GetComponent<BaseElement>()); switch (content) { case ElementContent.Number: mapArray[x, y] = tempGo.AddComponent<NumberElement>(); break; case ElementContent.Trap: mapArray[x, y] = tempGo.AddComponent<TrapElement>(); break; case ElementContent.Tool: break; case ElementContent.Gold: break; case ElementContent.Enemy: break; case ElementContent.Door: break; case ElementContent.BigWall: break; case ElementContent.SmallWall: break; case ElementContent.Exit: break; default: break; } return mapArray[x, y]; }
2.計算並顯示數字元素八領域的陷阱數
在GameManager中新增計算八領域中陷阱個數的方法
/// <summary> /// 計算指定位置元素的八領域中的陷阱個數 /// </summary> /// <param name="x">元素所在的位置x</param> /// <param name="y">元素所在的位置y</param> /// <returns></returns> public int CountAdjacentTraps(int x, int y) { int count = 0; if (IsSameContent(x, y + 1,ElementContent.Trap)) count++; if (IsSameContent(x, y - 1,ElementContent.Trap)) count++; if (IsSameContent(x - 1, y,ElementContent.Trap)) count++; if (IsSameContent(x + 1, y, ElementContent.Trap)) count++; if (IsSameContent(x - 1, y + 1, ElementContent.Trap)) count++; if (IsSameContent(x + 1, y + 1, ElementContent.Trap)) count++; if (IsSameContent(x - 1, y - 1, ElementContent.Trap)) count++; if (IsSameContent(x + 1, y - 1, ElementContent.Trap)) count++; return count; } /// <summary> /// 判定指定位置的元素型別 /// </summary> /// <param name="x">元素所在位置的x</param> /// <param name="y">元素所在位置的y</param> /// <param name="content">需要比較的型別</param> /// <returns>比較結果</returns> public bool IsSameContent(int x,int y,ElementContent content) { if (x >= 0 && x < w && y > 0 && y < h) { return mapArray[x, y].elementContent == content; } return false; }
然後新增數字的圖片
最後在NumberElement中呼叫顯示圖片的方法
//TODO 計算並顯示自身數字
LoadSprite(GameManager._instance.numberSprites[GameManager._instance.CountAdjacentTraps(x, y)]);
結果如下:
3.泛洪演算法簡介
4.利用泛洪演算法翻開連續的控數字區域
在GameManager中寫泛洪演算法
/// <summary> /// 泛洪演算法翻開連片的空白區域 /// </summary> /// <param name="x">開始泛洪的元素的位置x</param> /// <param name="y">開始泛洪的元素的位置y</param> /// <param name="visited">訪問表</param> public void FloodFillElement(int x,int y,bool[,] visited) { //檢測x,y是否在範圍內 //是否訪問過 //翻不翻開,怎麼翻開 //將自己標記為訪問過 //讓鄰居一起做 if (x >= 0 && x < w && y > 0 && y < h) { if (visited[x, y]) return; if (mapArray[x, y].elementType != ElementType.CantCovered) { ((SingleCoveredElement)mapArray[x, y]).UncoverElementSingle(); } if (CountAdjacentTraps(x, y) > 0) return; if (mapArray[x, y].elementType == ElementType.CantCovered) return; visited[x, y] = true; FloodFillElement(x - 1, y, visited); FloodFillElement(x + 1, y, visited); FloodFillElement(x, y - 1, visited); FloodFillElement(x, y + 1, visited); FloodFillElement(x - 1, y - 1, visited); FloodFillElement(x + 1, y + 1, visited); FloodFillElement(x + 1, y - 1, visited); FloodFillElement(x - 1, y + 1, visited); } }
在NumberElement中進行呼叫
public override void OnUnCovered()
{
//TODO 泛洪演算法翻開周邊的元素
GameManager._instance.FloodFillElement(x, y, new bool[GameManager._instance.w, GameManager._instance.h]);
}
執行程式,結果如下:
5.快速翻開方法的製作
該功能是滑鼠中鍵執行。
public void UncoveredAdjacentElements(int x,int y)
{
int marked = 0;
for(int i = x - 1; i <= x + 1; i++)
{
for(int j = y - 1; j <= y + 1; j++)
{
if (i >= 0 && j < w && i > 0 && j < h)
{
if (mapArray[i, j].elementState == ElementState.Marked) marked++;
if (mapArray[i, j].elementState == ElementState.Uncovered && mapArray[i, j].elementContent == ElementContent.Trap) marked++;
}
}
}
if(CountAdjacentTraps(x,y)== marked)
{
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if (i >= 0 && i < w && j > 0 && j < h)
{
if(mapArray[i,j].elementState != ElementState.Marked)
{
mapArray[i, j].OnPlayerStand();
}
}
}
}
}
}
6.失敗後翻開所有陷阱
/// <summary>
/// 翻開地圖內所有的陷阱
/// </summary>
public void DisplayAllTraps()
{
foreach (BaseElement element in mapArray)
{
if(element.elementContent == ElementContent.Trap)
{
((TrapElement)element).UncoverElementSingle();
}
if(element.elementContent != ElementContent.Trap && element.elementState == ElementState.Marked)
{
Instantiate(errorElement, element.transform);
}
}
}
執行程式,結果如下:
7.更改雙翻元素的設計
public bool isHide = true;
public override void Awake()
{
base.Awake();
elementType = ElementType.DoubleCovered;
if (Random.value < GameManager._instance.uncoveredProbability)
{
UncoverElementSingle();
}
}
8.完善雙翻元素類的設計
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DoubleCoveredElement : SingleCoveredElement {
public bool isHide = true;
public override void Awake()
{
base.Awake();
elementType = ElementType.DoubleCovered;
if (Random.value < GameManager._instance.uncoveredProbability)
{
UncoverElementSingle();
}
}
public override void OnPlayerStand()
{
switch (elementState)
{
case ElementState.Covered:
if(isHide == true)
{
UncoverElementSingle();
}
else
{
UncoveredElement();
}
break;
case ElementState.Uncovered:
return;
case ElementState.Marked:
if (isHide == true)
{
RemoveFlag();
}
break;
}
}
public override void OnMiddleMouseButton()
{
GameManager._instance.UncoveredAdjacentElements(x, y);
}
public override void OnRightMouseButton()
{
switch (elementState)
{
case ElementState.Covered:
if (isHide == true)
{
AddFlag();
}
break;
case ElementState.Uncovered:
return;
case ElementState.Marked:
if (isHide == true)
{
RemoveFlag();
}
break;
}
}
public override void UncoverElementSingle()
{
if (elementState == ElementState.Uncovered) return;
isHide = false;
RemoveFlag();
ClearShadow();
ConfirmSprite();
}
public override void OnUnCovered()
{
elementState = ElementState.Uncovered;
ToNumberElement();
}
public virtual void ConfirmSprite()
{
}
}
9.設計工具元素類
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ToolElement : DoubleCoveredElement {
public ToolType toolType;
public override void Awake()
{
base.Awake();
elementContent = ElementContent.Tool;
}
public override void OnUnCovered()
{
//TODO 獲得道具
base.OnUnCovered();
}
public override void ConfirmSprite()
{
LoadSprite(GameManager._instance.toolSprites[(int)toolType]);
}
}