2D猎宝行动(类扫雷小游戏)DAY 4

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

猜你喜欢

转载自blog.csdn.net/kouzhuanjing1849/article/details/83108630