Unity破窗游戏制作(简易版)
阅读原文时间:2023年07月08日阅读:2

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

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

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

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

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

(3)目录如下图所示:

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

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

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

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

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

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

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

(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卡槽中:

基本界面就做好了。

(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()
    {
        ....
    }
}

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

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

接着修改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可以自己加

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

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

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