unity实现丧尸围城项目(第二天)

1,089 阅读7分钟

1.拖入人物物体

找到士兵和丧尸的人物包,将他们拖拽到3D窗口中去,人物资源包在Toon_Zombies_extended/prefabs/specials文件夹里面

image.png

在Resources文件夹下面新建两个动画控制器,这两个动画控制器分别控制两个物体的动画,比如在这里我们可以一运行项目的时候,会出现丧尸在吃士兵的动画效果

新建动画控制器Hulk,同时将TZ_crouch_eating动画拖入大动画器窗格中,动画处在Toon_Zombies_extended/animation/Generic文件夹下,并将新建好的控制器拖入到TZ_Hulk_03的控制源中,这样我们就完整的将人物与动画绑定上了。

image.png

同时TZ_Soldier_01人物也是这样的步骤,双击solidier动画控制器,打开动画器窗格,将动画拖到动画器窗格中,并将动画控制器拖入到TZ_Soldier_01的控制源中

image.png

运行项目,效果如下:

界面.gif

2.搭建丧尸围城UI首页

1.设置UI界面

正如向上面的效果图也看到了有对应的按钮,图像,其实这些都是通过UI来实现的淡入淡出的效果,当然了,不可否认这里还是要通过UI管理器以及单例模式代码来实现。

下一步我们实现设置按钮的UI窗口,也就是当我们点击设置按钮的时候,会打开设置的UI界面,在里面我们可以设置丧尸围城项目的音乐音效的开启关闭,调节音乐音效的大小。

image.png

设置UI窗口如下:新建一个面板名为SettingPanle,在面板下新建一个图片作为设置界面的底图,新建1个关闭按钮,实现它设置窗口的关闭,名为btnClose。新建两个toggle(单选框)、Slider(滑块),控制音乐音效。总体布局如下:

image.png

2.创建脚本文件

将SettingPanle脚本文件挂载到创建好的面板SettingPanle之中,首先实现其功能之前,我们先思考控制音效音乐关闭开启、大小,以及关闭窗口,这些控件的功能都是要公开变量,将他们作为预制体拖入进行绑定才能在代码里面更好的获取。在这里我们引入了JSON数据的概念。通过JSON传递这些参数我们实现这是按钮对应的功能。

首先呢我们创建一个音乐数据结构类,在这个类中我们存储的是对应要修改的数据类型

//音乐的数据结构类
public class MusicData
{
    //单独作为一个存储数据的类
    //音乐是否静音
    public bool musicOpen = true;
    //音乐音量
    public float musicValue = 0.2f;
    //音效是否静音
    public bool soundOpen = true;
    //音效音量
    public float soundValue = 0.2f;
}

创建GameDataMgr类,在这个脚本文件里面实现的是首先采用静态方法将类实例化,静态类在运行项目的时候只会实例化一次,被其他类所共享,并且项目运行期间一直都存在。我们先定义了一个自定义类型的MusicData类,通过GameDataMgr的构造方法我们先将MusicData里面的参数进行初始化加载(因为他们一开始是有默认值的,我们需要先加载它),同时定义了SavaMusicData方法,这个方法实现保存你修改后的数据(就是用户修改了之后的数据我们要更新在MusicData所有变量中),同时并通过构造方法进行加载再次的赋值,这样设置才不会脱节。

GameDataMgr代码如下:

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

public class GameDataMgr
{
    //首先这里应该有一个保存的方法,第一步加载音乐数据获取当前的音乐信息
    public static GameDataMgr Instance = new GameDataMgr();

    //在这个类中创建一个音乐数据变量来存储音乐信息,然后UI中改变的音乐信息就直接改变这个变量中的数据
    //然后在讲数据更新到文件中

    public MusicData musicData;

    private GameDataMgr() //构造方法中加载文件中的数据
    {
        //一开始玩游戏是没有存储音乐文件信息的,所以这里做了判断,返回了默认的MusicData类对应的对象的值
        musicData = JsonMgr.Instance.LoadData<MusicData>("MusicData");
    }

    //保存我的音乐数据
    public void SavaMusicData()
    {
        //第一个参数是更新的数据,第二个参数是保存的文件名
        JsonMgr.Instance.SaveData(musicData, "MusicData");
    }
}

JsonMgr脚本文件代码如下:

    using LitJson;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

/// <summary>
/// 序列化和反序列化Json时  使用的是哪种方案
/// </summary>
public enum JsonType
{
    JsonUtlity,
    LitJson,
}

/// <summary>
/// Json数据管理类 主要用于进行 Json的序列化存储到硬盘 和 反序列化从硬盘中读取到内存中
/// </summary>
public class JsonMgr
{
    private static JsonMgr instance = new JsonMgr();
    public static JsonMgr Instance => instance;

    private JsonMgr() { }

    //存储Json数据 序列化
    public void SaveData(object data, string fileName, JsonType type = JsonType.LitJson)
    {
        //确定存储路径
        string path = Application.persistentDataPath + "/" + fileName + ".json";
        //序列化 得到Json字符串
        string jsonStr = "";
        switch (type)
        {
            case JsonType.JsonUtlity:
                jsonStr = JsonUtility.ToJson(data);
                break;
            case JsonType.LitJson:
                jsonStr = JsonMapper.ToJson(data);
                break;
        }
        //把序列化的Json字符串 存储到指定路径的文件中
        File.WriteAllText(path, jsonStr);
    }

    //读取指定文件中的 Json数据 反序列化
    public T LoadData<T>(string fileName, JsonType type = JsonType.LitJson) where T : new()
    {
        //确定从哪个路径读取
        //首先先判断 默认数据文件夹中是否有我们想要的数据 如果有 就从中获取
        string path = Application.streamingAssetsPath + "/" + fileName + ".json";
        //先判断 是否存在这个文件
        //如果不存在默认文件 就从 读写文件夹中去寻找
        if(!File.Exists(path))
            path = Application.persistentDataPath + "/" + fileName + ".json";
        //如果读写文件夹中都还没有 那就返回一个默认对象
        if (!File.Exists(path))
            return new T();

        //进行反序列化
        string jsonStr = File.ReadAllText(path);
        //数据对象
        T data = default(T);
        switch (type)
        {
            case JsonType.JsonUtlity:
                data = JsonUtility.FromJson<T>(jsonStr);
                break;
            case JsonType.LitJson:
                data = JsonMapper.ToObject<T>(jsonStr);
                break;
        }

        //把对象返回出去
        return data;
    }
}

里面的SaveData方法实现的是获取确定的存储路径,将变量类型转化为JSON数据类型进行值的传递,同时通过写文件的形式将变量值写入对应的变量之中。当然LoadData方法就是读文件的操作了。在这里就不一一介绍了,理解为一种封装好的模板,我们直接调用即可

GameDataMgr和MusicData是新建在Resources/Data文件夹下。

image.png Json包是通过导入资源包生成的

image.png

创建一个空对象,名为BGM,同时添加音频源组件Audio Source,将音乐导入项目中,并将音乐拖入到音频源中,同时新建脚本文件BGM,并挂载到BGM空对象身上。

BGM脚本文件如下:

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

public class BGM : MonoBehaviour
{
    public static BGM Instance;
    // 当我播放音乐的时候,这里是不是要设置上默认的音乐参数\
    MusicData musicData;
    //获取音乐组件
    AudioSource audio;
    private void Awake()
    {
        Instance = this; //Instance=当前的游戏对象
        audio = GetComponent<AudioSource>();
        musicData = GameDataMgr.Instance.musicData;
        //给当前的音乐组件设置值
        changeOpen(musicData.musicOpen);
        changeValue(musicData.musicValue);
    }

    //创建一个方法来实现音乐静音
    public void changeOpen(bool isOpen) //打钩表示就是有声音
    {
        audio.mute = !isOpen;
    }



    //创建一个方法来实现改变音量的方法
    public void changeValue(float v)
    {
        audio.volume = v;
    }
}

在BGM脚本文件中实现的是:通过AWake方法当项目加载的时候,自动唤醒方法,加载musicData的默认值,并且每次运行完项目后再次打开项目还是得要保存上次用户设置的值,所以在这里面实现。

上述设置好后,我们就需要在面板脚本文件SettingPanle实现业务。 SettingPanle脚本文件如下:

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

public class SettingPanle : basePanle

{
    //关联设置面板的一些控件
    public Button btnClose;
    public Toggle togMusic;
    public Toggle togSound;
    public Slider musicSlider;
    public Slider soundSlider;

    //
    public override void Init() //这个初始化的方法我们都知道它在basePanle中Start运行
    {
        togMusic.isOn = GameDataMgr.Instance.musicData.musicOpen;
        togSound.isOn = GameDataMgr.Instance.musicData.soundOpen;
        musicSlider.value = GameDataMgr.Instance.musicData.musicValue;
        soundSlider.value = GameDataMgr.Instance.musicData.soundValue;
        btnClose.onClick.AddListener(() =>
        {
            GameDataMgr.Instance.SavaMusicData(); //保存当前设置的音乐信息
            //关闭设置面板
            UIManager.Instance.hidePanle<SettingPanle>();
        });

        //监听按钮,修改按钮值后也同时监听到
        togMusic.onValueChanged.AddListener((v) =>
        {
            GameDataMgr.Instance.musicData.musicOpen = v;
            //更改背景音乐
            BGM.Instance.changeOpen(v);
        });

        musicSlider.onValueChanged.AddListener((v) => {
            GameDataMgr.Instance.musicData.musicValue = v; //更改音乐的数据
            BGM.Instance.changeValue(v); //更改播放音乐对象的音量
        });
    }
}

SettingPanle类继承基类basePanle,实现抽象方法Init方法,在方法里面我们进行值的获取,并且当我们点击关闭按钮的时候,我们要保存当前用户调节的参数值后再将设置UI界面淡出。

当所有设置好后,把SettingPanle当做预制体拖入到Resources/UI文件夹里面去。当我们运行项目的时候,点击设置按钮,调用设置业务

UIManager.Instance.showpanle<SettingPanle>();

调用UI管理器中的showpanle方法,打开设置界面,在SettingPanle脚本文件里面,加载每次的musicData的值,保存每次修改后设置的值,关闭按钮点击后,保存值,关闭设置UI界面,这样我们的功能就实现好了。

3.效果如下:

声音界面.gif