Unity制作扫雷游戏

Posted 御雪妃舞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity制作扫雷游戏相关的知识,希望对你有一定的参考价值。

曾经在网上看了一篇扫雷教程,链接如下:https://noobtuts.com/unity/2d-minesweeper-game

但是照着做出来有点问题,后来自己尝试的做了一个,效果如图:



主要有三个代码,一个是排序代码,一个是管理脚本,还有一个是子物体属性脚本,脚本内容如下:


GridTransform.cs

using UnityEngine;
using System.Collections;

public class GridTransform : MonoBehaviour


    //排序的列数
    public int column = 1;

    //间距的宽和高
    public float space_w;
    public float space_h;

    //组件对象的宽和高
    public float width;
    public float Height;

    //排序对象的数目
    public int itemNumber;

    public bool Direction;

    //字段封装实时排序
    public bool repositionNow
    
        set
        
            _repositionNow = value;
            if (value)
            
                Sort();
                _repositionNow = false;
            
        

        get
        
            return _repositionNow;
        
    
    private bool _repositionNow;

    //排序方法
    void Sort()
    
        itemNumber = transform.childCount; ;
        for (int i = 0; i < itemNumber; i++)
        
            transform.GetChild(i).localPosition = new Vector3((width + space_w) * ((i) % (column)), (Direction?1:-1)*((i) / column) * (Height + space_h), 0);
        
    


Element.cs

using UnityEngine;
using System.Collections;


public enum MineState

    Empty = 0,
    Mine = 1,
    Num = 2,
    MaybeMine = 3


public class Element : MonoBehaviour


    /// <summary>
    /// current box mine state
    /// </summary>
    public MineState mine;

    public Sprite[] emptyTextures;
    public Sprite mineTexture;

    public void loadTexture(int mineCount = 0)
    
        if ((int)mine == 1)
            GetComponent<SpriteRenderer>().sprite = mineTexture;
        else
            GetComponent<SpriteRenderer>().sprite = emptyTextures[mineCount];
    


    public bool isCovered()
    
        return GetComponent<SpriteRenderer>().sprite.texture.name == "default";
    

    void OnMouseUpAsButton()
    
        Debug.Log(transform.localPosition.x + "   " + transform.localPosition.y+"    "+mine);

        if ((int)mine == 1)
        
            MineManager.Instance.uncoverMines();

            print("you lose");
        
        else
        
            int x = (int)transform.localPosition.x;
            int y = (int)transform.localPosition.y;
            loadTexture(MineManager.Instance.MineCount(x, y));

            MineManager.Instance.FFuncover(x, y, new bool[MineManager.Instance.width, MineManager.Instance.height]);

            if (MineManager.Instance.isFinished())
            
                print("you win");
            

        
    



MineManager.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MineManager : MonoBehaviour


    public GameObject elementPrefab;
    public GridTransform grid;

    public int width;
    public int height;

    public Element[,] elements;

    public int mineNumber;

    public ArrayList MineLocation;

    public static MineManager Instance;

    // Use this for initialization
    void Start()
    
        Instance = this;

        elements = new Element[width, height];

        MineLocation = new ArrayList();

        Init();
    

    void Init()
    

        //create element
        for (int j = 0; j < height; j++)
        
            for (int i = 0; i < width; i++)
            
                elements[i, j] = CreateElement();
                elements[i, j].mine = MineState.Empty;
            
        

        //reset position
        grid.repositionNow = true;


        //random mine in the current elements
        for (int n = 0; n < mineNumber; n++)
        
            int k = Random.Range(0, width);
            int m = Random.Range(0, height);

            Vector2 temp = new Vector2(k, m);

            if (MineLocation.Contains(temp))
            
                n--;
                continue;
            
            elements[k, m].mine = MineState.Mine;

            Debug.Log(elements[k, m].mine);

            //elements[k, m].loadTexture();

            var c = new Vector2(k, m);

            Debug.Log(c);
            MineLocation.Add(c);
        

        //set numbers near mine
        foreach (var item in MineLocation)
        
            Vector2 t = (Vector2)item;
            int x = (int)t.x;
            int y = (int)t.y;
            JudegeMinesNear(x - 1, y + 1);
            JudegeMinesNear(x, y + 1);
            JudegeMinesNear(x + 1, y + 1);
            JudegeMinesNear(x - 1, y);
            JudegeMinesNear(x + 1, y);
            JudegeMinesNear(x - 1, y - 1);
            JudegeMinesNear(x, y - 1);
            JudegeMinesNear(x + 1, y - 1);
        

    

    // Find out if a mine is at the coordinates
    public bool mineAt(int x, int y)
    
        // Coordinates in range? Then check for mine.
        if (x >= 0 && y >= 0 && x < width && y < height)
            return (int)elements[x, y].mine == 1;
        return false;
    


    public bool IsInclude(int x, int y)
    
        if (x >= 0 && y >= 0 && x < width && y < height)
            return true;
        return false;
    

    public void JudegeMinesNear(int x, int y)
    
        if (IsInclude(x, y) == false)
            return;

        if ((int)elements[x, y].mine != 1)
        
            elements[x, y].mine = MineState.Num;
            //elements[x, y].loadTexture(MineCount(x, y));
        

    

    // Count adjacent mines for an element
    public int MineCount(int x, int y)
    
        int count = 0;

        if (mineAt(x, y + 1)) ++count; // top
        if (mineAt(x + 1, y + 1)) ++count; // top-right
        if (mineAt(x + 1, y)) ++count; // right
        if (mineAt(x + 1, y - 1)) ++count; // bottom-right
        if (mineAt(x, y - 1)) ++count; // bottom
        if (mineAt(x - 1, y - 1)) ++count; // bottom-left
        if (mineAt(x - 1, y)) ++count; // left
        if (mineAt(x - 1, y + 1)) ++count; // top-left
        return count;
    

    // Flood Fill empty elements
    public void FFuncover(int x, int y, bool[,] visited)
    
        // Coordinates in Range?
        if (IsInclude(x,y))
        
            // visited already?
            if (visited[x, y])
                return;

            // uncover element
            elements[x, y].loadTexture(MineCount(x, y));
            Debug.Log("            " + x + "   " + y);
            // close to a mine? then no more work needed here
            if (MineCount(x, y) > 0)
                return;

            // set visited flag
            visited[x, y] = true;

            // recursion
            FFuncover(x - 1, y + 1, visited);
            FFuncover(x, y + 1, visited);
            FFuncover(x + 1, y + 1, visited);
            FFuncover(x - 1, y, visited);
            FFuncover(x + 1, y, visited);
            FFuncover(x - 1, y - 1, visited);
            FFuncover(x, y - 1, visited);
            FFuncover(x + 1, y - 1, visited);
            Debug.Log("----------------------------------------");
        
    

    // Uncover all Mines
    public void uncoverMines()
    
        foreach (Element elem in elements)
            if (elem.mine == MineState.Mine)
                elem.loadTexture(0);
    

    Element CreateElement()
    
        GameObject temp = Instantiate(elementPrefab) as GameObject;
        temp.transform.parent = grid.transform;
        temp.transform.position = Vector3.zero;

        return temp.GetComponent<Element>();
    

    public bool isFinished()
    
        // Try to find a covered element that is no mine
        foreach (Element elem in elements)
            if (elem.isCovered() && (int)elem.mine != 1)
                return false;
        // There are none => all are mines => game won.
        return true;
    


最终运行起来有点卡,也许MineManager还能优化,有建议的告诉我哈!


工程下载

以上是关于Unity制作扫雷游戏的主要内容,如果未能解决你的问题,请参考以下文章

unity 实现物体破碎效果的一些方法 - 细雨淅淅

unity获取游戏物体

pygamePython 制作 XP 经典扫雷游戏

Unity 3D——场景制作3D模型

为扫雷游戏动态创建游戏板

Unity3D游戏物体操作 ( 场景简介 | 添加游戏物体 | 操作游戏物体 | 选中游戏物体 | 场景显示效果缩放 | 重命名游戏物体 | 复制游戏物体 | 删除游戏物体 | 移动游戏物体 )