Unity破窗游戏制作(简易版)

2022-12-03,,,

Unity破窗游戏制作简易版

参考:“对不起,我选择摸鱼”—《扫雷》小游戏开发实战,算法、源代码,基于Unity3D开发 - 掘金 (juejin.cn)

到“制作默认方块(4)”均为相同操作

2-1、新建项目

(1)项目开发,从新建项目开始,我使用的Unity版本是Unity 2019.4.7f1,模板就选择2D,项目名称随意,别中文就行:

(2)创建目录,在Project视图,右击选择Create→Folder,新建几个文件夹:

(3)目录如下图所示:

Prefabs:预制体资源文件夹
Scenes:场景资源文件夹
Scripts:脚本资源文件夹
Sprites:图片资源文件夹

2-2、导入资源

接下来将需要的资源导入:

全部右键另存为图片,然后导入到Project视图的Sprites文件夹内:

选中所有图片,在Inspector视图中,设置Pixels Per Unit为16:

之所以设置为16,是因为16X16这个单位在游戏世界中是一个比较适合的值。

2-3、设置摄像机属性

在Hierarchy视图中,选中Main Cameras对象,然后在Inspector视图中找到Camera组件,设置属性:

注意:Clear Flags设置为Skybox,Background按照图中设置,然后Size设置为20。

2-4、制作默认方块

(1)将Project视图的Sprites目录中的default对象拖入Hierarchy视图中:

(2)选中default对象,在Inspector视图中,选择Add Componet→Physics 2D→Box Collider 2D,添加碰撞器组件:

注意:勾选Is Trigger

(3)选中default对象,拖回到Projcet视图的Prefabs文件夹内,做成一个预制体,我们将在后面的代码中去实例化生成它:

(4)Hierarchy视图中的default对象就可以删除了。

(5)新建脚本CreateBg.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class CreateBg : MonoBehaviour
{
public GameObject block;//默认方块
void Start()
{
//创建默认方块
CreateBlock();
} private void CreateBlock()
{
//创建方块父物体
GameObject blockParent = new GameObject("blockParent");
//创建10行10列的默认方块
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
//Instantiate参数为:预制体 位置 旋转 父物体
Instantiate(block, new Vector2(i, j), Quaternion.identity, blockParent.transform);
}
}
}
}

将脚本托给Main Camera对象,然后将预制体拖入Block卡槽中:

基本界面就做好了。

2-5、制作窗户类型

(1)新建一个脚本Element.cs,然后在Project视图的Prefabs文件夹中选中default对象,点击Add Componet→Element添加脚本:

 .....
public bool Lock;//判断是否是锁住
public bool Perfect;//判断是否是完好
public bool Broken;
public Sprite LockTexture;
public Sprite PerfectTexture;
public Sprite BrokenTexture;
void Start()
{
//随机锁住
Lock = Random.value < 0.1;
Perfect = !Lock;
// 在Grid注册
int x = (int)transform.position.x;
int y = (int)transform.position.y;
Grids.elements[x, y] = this;
if (Lock) Grids.elements[x, y].loadTexture(0); }
public void loadTexture(int adjacentCount)
{
if (adjacentCount==0)
GetComponent<SpriteRenderer>().sprite = LockTexture;
else if(adjacentCount==1)
GetComponent<SpriteRenderer>().sprite = PerfectTexture;
else GetComponent<SpriteRenderer>().sprite = BrokenTexture;
}
.....

(2)选中default预制体,将对应的资源拖入Element.cs脚本的属性卡槽中:

(3)新建一个Grid.cs脚本,将脚本也添加到预制体default身上,Grid脚本将处理更加复杂的游戏逻辑:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class Grids : MonoBehaviour
{
public static int w=4; // 网格的长
public static int h=6; // 网格的高
public static Element[,] elements = new Element[w, h];
public static bool isPerfect(int x,int y)
{
....
}
public static bool isBroken(int x, int y)
{
....
}
public static void brokeWin(int x,int y)
{
....
}
public static bool isWin()
{
....
}
public static bool GameOver()
{
....
}
}

2-6、破坏窗户

Grids.cs:

 public static bool isPerfect(int x,int y)
{
if (x >= 0 && y >= 0 && x < w && y < h)
return elements[x, y].Perfect;
return false;
}
public static bool isBroken(int x, int y)
{
if (x >= 0 && y >= 0 && x < w && y < h)
return elements[x, y].Broken;
return false;
} public static void brokeWin(int x,int y)
{
if (isPerfect(x , y)) { elements[x, y].loadTexture(2);elements[x, y].Broken = true; elements[x, y].Perfect = false; }
else if (isBroken(x, y)) { elements[x, y].loadTexture(1); elements[x, y].Broken = false; elements[x, y].Perfect = true; } }

Elements.cs:

 void OnMouseUpAsButton()
{
if (!Lock) //锁住的窗无法互动
{
//反转5格内的非锁住窗户
int x = (int)transform.position.x;
int y = (int)transform.position.y;
Grids.brokeWin(x , y);
Grids.brokeWin(x-1, y);
Grids.brokeWin(x+ 1, y);
Grids.brokeWin(x, y-1);
Grids.brokeWin(x , y+1);
//判断是否胜利
if (Grids.isWin())
{
Debug.Log("Game Win");
}
if (Grids.GameOver())
{
Debug.Log("Game Over");
}
}
}

2-7、判断是否已经破坏所有窗户

接下来,需要判断玩家破坏所有窗户,

接着修改Grid类的代码,添加函数isWin

public static bool isWin()
{
foreach (Element elem in elements)
if (elem.Perfect)
return false;
return true; } public static bool GameOver()
{
for(int i = 0; i < w; i++)
{
for(int j = 0; j < h; j++)
{
if (elements[i, j].Perfect && (i - 1 < 0 || !elements[i - 1, j].Perfect) && (i + 1 >= w || !elements[i + 1, j].Perfect) && (j - 1 < 0 || !elements[i, j - 1].Perfect) && (j + 1 >= h || !elements[i, j + 1].Perfect))
return true; }
}
return false; }

在这里游戏失败的原因可以有很多:

本就无解
超过了限制步数
超过时间

这些都可以自己写

然后获胜或失败的UI可以自己加

2-8、总结

游戏的大体框架就开发完成了,当然,你也可以添加一些元素让游戏更加有趣:

分成更多难度,比如简单、中等、困难
切换更加漂亮的UI
输赢界面以及重新开始
添加音效

2-9、源码

Grids:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class Grids : MonoBehaviour
{
public static int w=4; // 网格的长
public static int h=6; // 网格的高
public static Element[,] elements = new Element[w, h]; public static bool isPerfect(int x,int y)
{
if (x >= 0 && y >= 0 && x < w && y < h)
return elements[x, y].Perfect;
return false;
}
public static bool isBroken(int x, int y)
{
if (x >= 0 && y >= 0 && x < w && y < h)
return elements[x, y].Broken;
return false;
} public static void brokeWin(int x,int y)
{
if (isPerfect(x , y)) { elements[x, y].loadTexture(2);elements[x, y].Broken = true; elements[x, y].Perfect = false; }
else if (isBroken(x, y)) { elements[x, y].loadTexture(1); elements[x, y].Broken = false; elements[x, y].Perfect = true; } } public static bool isWin()
{
foreach (Element elem in elements)
if (elem.Perfect)
return false;
return true; } public static bool GameOver()
{
for(int i = 0; i < w; i++)
{
for(int j = 0; j < h; j++)
{
if (elements[i, j].Perfect && (i - 1 < 0 || !elements[i - 1, j].Perfect) && (i + 1 >= w || !elements[i + 1, j].Perfect) && (j - 1 < 0 || !elements[i, j - 1].Perfect) && (j + 1 >= h || !elements[i, j + 1].Perfect))
return true; }
}
return false; } }

Element:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class Element : MonoBehaviour
{
public bool Lock;//判断是否是锁住
public bool Perfect;//判断是否是完好
public bool Broken;
public Sprite LockTexture;
public Sprite PerfectTexture;
public Sprite BrokenTexture; void Start()
{
//随机锁住
Lock = Random.value < 0.1;
Perfect = !Lock;
int x = (int)transform.position.x;
int y = (int)transform.position.y;
Grids.elements[x, y] = this;
if (Lock) Grids.elements[x, y].loadTexture(0); } public void loadTexture(int adjacentCount)
{
if (adjacentCount==0)
GetComponent<SpriteRenderer>().sprite = LockTexture;
else if(adjacentCount==1)
GetComponent<SpriteRenderer>().sprite = PerfectTexture;
else GetComponent<SpriteRenderer>().sprite = BrokenTexture;
} // 判断是否被点击
public bool isCovered()
{
//判断当前纹理的名称是不是默认值
return GetComponent<SpriteRenderer>().sprite.texture.name == "default";
} // 鼠标点击
void OnMouseUpAsButton()
{
if (!Lock)
{ //破坏周围的窗户
int x = (int)transform.position.x;
int y = (int)transform.position.y;
Grids.brokeWin(x , y);
Grids.brokeWin(x-1, y);
Grids.brokeWin(x+ 1, y);
Grids.brokeWin(x, y-1);
Grids.brokeWin(x , y+1); //判断是否胜利
if (Grids.isWin())
{
Debug.Log("Game Win");
}
if (Grids.GameOver())
{
Debug.Log("Game Over");
}
}
} }

CreateBg:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class CreateBg : MonoBehaviour
{
public GameObject block;//默认方块
void Start()
{
//创建默认方块
CreateBlock();
} public void CreateBlock()
{
//创建方块父物体
GameObject blockParent = new GameObject("blockParent");
//创建10行10列的默认方块
for (int i = 0; i <Grids.w; i++)
{
for (int j = 0; j < Grids.h; j++)
{
//Instantiate参数为:预制体 位置 旋转 父物体
Instantiate(block, new Vector2(i, j), Quaternion.identity, blockParent.transform);
}
}
}
}

2-10、效果

Unity破窗游戏制作(简易版)的相关教程结束。

《Unity破窗游戏制作(简易版).doc》

下载本文的Word格式文档,以方便收藏与打印。