Unity制作扫雷游戏
2016-12-23 10:41
344 查看
曾经在网上看了一篇扫雷教程,链接如下: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还能优化,有建议的告诉我哈!
工程下载
但是照着做出来有点问题,后来自己尝试的做了一个,效果如图:
主要有三个代码,一个是排序代码,一个是管理脚本,还有一个是子物体属性脚本,脚本内容如下:
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制作3D版iOS游戏
- <Unity 3D工作笔记>游戏角色 - 经验条的制作
- 使用Unity制作游戏关卡的教程(二)
- unity制作2d游戏(捕鱼达人)优化
- Unity制作Roll-a-Ball游戏
- Unity 3D制作2D游戏的几种方法
- 简单的扫雷游戏制作
- 如何使用Unity制作一款自己喜欢玩的游戏demo(Unity萌新的进阶技巧)
- Unity制作游戏在部分手机上显示黑白屏幕
- Unity 游戏开发技巧集锦之制作一个望远镜与查看器摄像机
- Unity学习笔记3 简易2D横版RPG游戏制作(三)
- 简单两步使用Unity制作ZigZag游戏
- unity制作斗地主游戏大致流程
- Unity5.5 制作2D游戏
- [教程] 究极 Unity 地形制作 - 极速创建华丽的游戏地形
- 扫雷游戏制作全过程01 地雷生成及表示
- 扫雷游戏制作全过程02 之JLabel弯路
- unity2D 4.3版 游戏制作教程
- Unity游戏开发--30s制作精美地图
- 使用Unity制作游戏关卡的教程(三)