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]);
}
}