当前位置: 首页 > article >正文

胡闹厨房练习(三)

ScriptableObject

一、初步了解

1、实质:是一种特殊类型的Unity对象,

2、作用:用于存储大量数据,而不必依附于游戏场景中的某个GameObject。

3、特点:

可以在不增加场景中对象数量的情况下,管理和存储复杂的数据结构、配置信息、游戏状态等。

4、适用:非常适合用来管理游戏中的各种数据,如角色属性、关卡配置、道具列表等。

5、意义:

使数据的管理更加集中和高效,避免将大量数据直接硬编码在脚本中或在多个GameObject上重复配置相同的数据。

还可以用于实现游戏数据的序列化,方便在游戏运行时保存和加载游戏状态。

二、创建方法

创建一个ScriptableObject.cs,名字自取,例如

using UnityEngine;

[CreateAssetMenu(fileName = "NewItem", menuName = "Inventory/Item")]
public class Item : ScriptableObject
{
    public new string name;
    public Sprite icon = null;
    public string description = "";
    public int value;
}
三、使用方法

1、在Unity编辑器中通过CreateAssetMenu定义的菜单项创建ScriptableObject实例

2、在其他脚本中,通过Resources.Load<T>()或其他方式加载这个ScriptableObject实例,并使用它的属性,例如

Item myItem = Resources.Load<Item>("Path/To/Your/Item");
Debug.Log(myItem.name);

菜单管理

一、食谱

1、食谱名称和食谱成分:在Scripts/ScriptableObject文件夹下,新建RecipeSO.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu()]
public class RecipeSO : ScriptableObject
{
    public List<KitchenObjectSO> kitchenObjectSOList;
    public string recipeName;
}

2、在ScriptableObjects文件夹下,新建RecipeSO文件夹

3、新建RecipeSO对象:Burger

3、复制Burger,重命名为Cheeseburger,更改名称、添加CheeseSlicesSO(如上图)

4、同样的方法制作RecipeSO对象:MEGAburger、Salad

二、菜单

1、菜单列表:

(1) 在Scripts/ScriptableObjects中新建RecipeListSO.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu()]
public class RecipeListSO : ScriptableObject
{
    public List<RecipeSO> recipeSOList;
}

 (2) 创建RecipeListSO对象,命名为_RecipeListSO,设置菜单

2、取消创建项:编辑RecipeListSO.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//[CreateAssetMenu()]
public class RecipeListSO : ScriptableObject
{
    public List<RecipeSO> recipeSOList;
}
三、订单

1、Create Empty,命名为DeliveryManager,Reset它的Transform

2、随机订单:为DeliveryManager添加DeliveryManager.cs

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

public class DeliveryManager : MonoBehaviour
{
    [SerializeField] private RecipeListSO recipeListSO;

    private List<RecipeSO> waitingRecipeSOList;
    private float spawnRecipeTimer;
    private float spawnRecipeTimeMax = 4f;
    private int waitingRecipesMax = 4;
    private void Awake()
    {
        waitingRecipeSOList = new List<RecipeSO>();
    }
    private void Update()
    {
        // 时间计时器
        spawnRecipeTimer -= Time.deltaTime;
        // 检查倒计时是否结束‌
        if (spawnRecipeTimer <= 0f)
        {
            // 当倒计时结束时,将spawnRecipeTimer重置为spawnRecipeTimeMax
            spawnRecipeTimer = spawnRecipeTimeMax;

            if (waitingRecipeSOList.Count < waitingRecipesMax)
            {
                // 随机选择食谱并添加到等待列表‌
                RecipeSO waitingRecipeSO = recipeListSO.recipeSOList[Random.Range(0, recipeListSO.recipeSOList.Count)];
                // 在控制台打印出所选食谱的名称
                Debug.Log(waitingRecipeSO.recipeName);
                waitingRecipeSOList.Add(waitingRecipeSO);
            }
        }
    }
}

3、检查玩家提交食品与订单是否匹配

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

public class DeliveryManager : MonoBehaviour
{
    public static DeliveryManager Instance { get; private set; }
    [SerializeField] private RecipeListSO recipeListSO;

    private List<RecipeSO> waitingRecipeSOList;
    private float spawnRecipeTimer;
    private float spawnRecipeTimeMax = 4f;
    private int waitingRecipesMax = 4;
    private void Awake()
    {
        Instance = this;
        waitingRecipeSOList = new List<RecipeSO>();
    }
    private void Update()
    {
        spawnRecipeTimer -= Time.deltaTime;
        if (spawnRecipeTimer <= 0f)
        {
            spawnRecipeTimer = spawnRecipeTimeMax;

            if (waitingRecipeSOList.Count < waitingRecipesMax)
            {
                RecipeSO waitingRecipeSO = recipeListSO.recipeSOList[Random.Range(0, recipeListSO.recipeSOList.Count)];
                Debug.Log(waitingRecipeSO.recipeName);
                waitingRecipeSOList.Add(waitingRecipeSO);
            }
        }
    }
    // 检查玩家提交食品是否与订单相匹配的方法
    public void DeliverRecipe(PlateKitchenObject plateKitchenObject)
    {
        // 遍历订单列表中的每一个订单
        for (int i = 0; i < waitingRecipeSOList.Count; i++)
        {
            // 获取一个订单
            RecipeSO waitingRecipeSO = waitingRecipeSOList[i];
            // 检查食材数量与订单数量是否匹配
            if (waitingRecipeSO.kitchenObjectSOList.Count == plateKitchenObject.GetKitchenObjectsSOList().Count)
            {
                // Has the same number of ingredients
                bool plateContentsMatchesRecipe = true;
                // 遍历订单中的每一个食材
                foreach (KitchenObjectSO recipeKitchenObjectSO in waitingRecipeSO.kitchenObjectSOList)
                {
                    // Cycling through all ingredients in the Recipe
                    // 初始化一个标志,用于表示是否在当前盘子上找到了食谱中的食材
                    bool ingredientFound = false;
                    // 遍历盘子上的每一个食材
                    foreach (KitchenObjectSO plateKitchenObjectSO in plateKitchenObject.GetKitchenObjectsSOList())
                    {
                        // Cycling through all ingredients in the plate
                        // 如果盘子上的食材与订单中的食材相同
                        if (plateKitchenObjectSO == recipeKitchenObjectSO)
                        {
                            // Ingredients matches!
                            // 设置标志为true,表示找到了食材
                            ingredientFound = true;
                            // 跳出内层循环,因为已经找到了匹配的食材
                            break;
                        }
                    }
                    // 如果在当前盘子上没有找到食谱中的这个食材
                    if (!ingredientFound)
                    {
                        // This Recipe ingredient was not found on the plate
                        // 设置盘子与食谱不匹配的标志
                        plateContentsMatchesRecipe = false;
                    }
                }
                // 如果盘子与食谱匹配
                if (plateContentsMatchesRecipe)
                {
                    // Player delivered the correct recipe!
                    // 在控制台打印消息表示玩家提交了正确的食谱
                    Debug.Log("Player delivered the correct recipe!");
                    // 从订单列表中移除这个食谱
                    waitingRecipeSOList.RemoveAt(i);
                    // 退出方法,因为已经找到了匹配的食谱
                    return;
                }
            }
        }
        // No matches found! 遍历完订单列表后没有找到匹配的食谱
        // Player did not deliver a correct recipe在控制台打印消息表示玩家没有提交正确的食谱
        Debug.Log("Player did not deliver a correct recipe!");
    }
}

关于if(){}

bool a  = false;

if(a){Debug.Log("如果a为true,则输出文字。");}//这段代码不会被执行,因为不符合条件
bool a  = false;

if(!a){Debug.Log("如果!a为true,则输出文字。");}//这段代码会被执行
// 因为a = false,那么!a的结果为true

4、编辑DeliveryCounter.cs

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

public class DeliveryCounter : BaseCounter
{
    public override void Interact(Player player)
    {
        if (player.HasKitchenObject())
        {
            if (player.GetKitchenObject().TryGetPlate(out PlateKitchenObject plateKitchenObject))
            {
                // Only accepts Plates
                DeliveryManager.Instance.DeliverRecipe(plateKitchenObject);

                player.GetKitchenObject().DestroySelf();
            }
        }
    }
}
四、订单面板

1、新建并设置Hierarchy面板上的Canvas

(1) 打开Inspector面板,将Canvas下的Render Mode 设置为Screen Space - Overlay,

(2) Canvas Scaler 中UI Scale Mode 设置为Scale With Screen Size,

(3) Reference Resolution 中x = 1920,y = 1080。

(4) Match=1(完全匹配高度)

设置结果:Canvas上的UI在游戏窗口宽度改变时不会改变,在高度改变时会等比例缩小,

设置目的:只关心UI的横向排布,而当纵向改变时该组件会自动缩放

2、UI-Image,设置Image的Color 为 FF0000,删除此Image

3、打开Game界面,设置为Full HD(1920*1080),可见红色图标

4、订单UI面板

(1) 以Canvas为父物体,Create Empty,命名为DeliveryManagerUI

(2) 设置面板:Alt+Stretch,Left、Top、Right、Bottom都为0。

此时,DeliveryManagerUI填满整个Canvas

五、订单内容

1、订单UI文本

(1) 以DeliveryManagerUI为父物体,UI-Text(TMP),重命名为TitleText。

(2) 文本为“RECIPES WAITING...”,字体设置为加粗(Bold)

(3) 将锚点设置到左上角,Width和Hight都为0,Wrapping设为Disabled,

(4) 移动到合适位置,posX = 33,PosY = -16

2、单个订单背景:

(1) 以DeliveryManagerUI 为父物体,Create Empty,命名为Container

(2) 锚点左上角,调整位置 Pos.x = 29,Pos.y=-91,Width和Hight都为0

(3) 给Container添加Vertical Layout Group组件,Padding下间距(Spacing)为30

3、单个订单图标模板

(1) Container下Create Empty,命名为RecipeTemplate,

(2) 选中RecipeTemplate,Shift +选择左上角图标,设置Width和Height分别为250,100

(3) 以RecipeTemplate为父物体,UI- Image,命名为Background,Alt + Stretch

(4) 颜色为黑色,透明度233

4、单个订单名称

(1) 以RecipeTemplate为父物体,UI- Text(TMP),命名为RecipeNameText

(2) 字号为20,加粗,Width、Hight都为0,Wrapping设为Disabled,文本内容为Recipe,白色

(3) 锚点左上,Pos.x = 10 ,Pos.y = -5

5、复制两个RecipeTemplate

6、编辑DeliveryManager.cs

public List<RecipeSO> GetKitchenObjectsSOList()
{
    return waitingRecipeSOList;
}

7、显示订单图标:给DeliveryManagerUI添加DeliveryManagerUI.cs组件 

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

public class DeliveryManagerUI : MonoBehaviour
{
    [SerializeField] private Transform container;
    [SerializeField] private Transform recipeTemplate;
    private void Awake()
    {
        recipeTemplate.gameObject.SetActive(false);
    }
    private void UpdateVisual()
    {
        // 清除UI界面上所有旧的订单图标
        foreach (Transform child in container)
        {
            if(child == recipeTemplate) continue;//立即结束当前循环迭代
            Destroy(child.gameObject);
        }
        // 根据当前的订单列表创建并显示新的图标
        foreach (RecipeSO recipeSO in DeliveryManager.Instance.GetOrdersList())
        {
            Transform recipeTransform = Instantiate(recipeTemplate,container);
            recipeTransform.gameObject.SetActive(true);
        }
    }
}

8、重组代码

(1) 添加委托事件和触发事件程序:编辑 DeliveryManager.cs

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

public class DeliveryManager : MonoBehaviour
{
    public event EventHandler OnRecipeSpawned;
    public event EventHandler OnRecipeCompleted;

    public static DeliveryManager Instance { get; private set; }
    [SerializeField] private RecipeListSO recipeListSO;

    private List<RecipeSO> waitingRecipeSOList;
    private float spawnRecipeTimer;
    private float spawnRecipeTimeMax = 4f;
    private int waitingRecipesMax = 4;
    private void Awake()
    {
        Instance = this;
        waitingRecipeSOList = new List<RecipeSO>();
    }
    private void Update()
    {
        spawnRecipeTimer -= Time.deltaTime;
        if (spawnRecipeTimer <= 0f)
        {
            spawnRecipeTimer = spawnRecipeTimeMax;

            if (waitingRecipeSOList.Count < waitingRecipesMax)
            {
                RecipeSO waitingRecipeSO = recipeListSO.recipeSOList[UnityEngine.Random.Range(0, recipeListSO.recipeSOList.Count)];

                waitingRecipeSOList.Add(waitingRecipeSO);

                OnRecipeSpawned?.Invoke(this,EventArgs.Empty);
            }
        }
    }
    public void DeliverRecipe(PlateKitchenObject plateKitchenObject)
    {
        for (int i = 0; i < waitingRecipeSOList.Count; i++)
        {
            RecipeSO waitingRecipeSO = waitingRecipeSOList[i];
            if (waitingRecipeSO.kitchenObjectSOList.Count == plateKitchenObject.GetKitchenObjectsSOList().Count)
            {
                // Has the same number of ingredients
                bool plateContentsMatchesRecipe = true;
                foreach (KitchenObjectSO recipeKitchenObjectSO in waitingRecipeSO.kitchenObjectSOList)
                {
                    // Cycling through all ingredients in the Recipe
                    bool ingredientFound = false;
                    foreach (KitchenObjectSO plateKitchenObjectSO in plateKitchenObject.GetKitchenObjectsSOList())
                    {
                        // Cycling through all ingredients in the plate
                        if (plateKitchenObjectSO == recipeKitchenObjectSO)
                        {
                            // Ingredients matches!
                            ingredientFound = true;
                            break;
                        }
                    }
                    if (!ingredientFound)
                    {
                        // This Recipe ingredient was not found on the plate
                        plateContentsMatchesRecipe = false;
                    }
                }
                if (plateContentsMatchesRecipe)
                {
                    // Player delivered the correct recipe!

                    waitingRecipeSOList.RemoveAt(i);

                    OnRecipeCompleted?.Invoke(this,EventArgs.Empty);
                    return;
                }
            }
        }
    }
    public List<RecipeSO> GetWaitingRecipeSOList()
    {
        return waitingRecipeSOList;
    }
}

(2) 订阅事件和事件处理程序:编辑DeliveryManagerUI.cs

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

public class DeliveryManagerUI : MonoBehaviour
{
    [SerializeField] private Transform container;
    [SerializeField] private Transform recipeTemplate;
    private void Awake()
    {
        recipeTemplate.gameObject.SetActive(false);
    }
    private void Start()
    {
        DeliveryManager.Instance.OnRecipeSpawned += DeliveryManager_OnRecipeSpawned;
        DeliveryManager.Instance.OnRecipeCompleted += DeliveryManager_OnRecipeCompleted;

        UpdateVisul();
    }

    private void DeliveryManager_OnRecipeCompleted(object sender, System.EventArgs e)
    {
        UpdateVisul();
    }

    private void DeliveryManager_OnRecipeSpawned(object sender, System.EventArgs e)
    {
        UpdateVisul();
    }

    private void UpdateVisul()
    {
        foreach (Transform child in container)
        {
            if (child == recipeTemplate) continue;
            Destroy(child.gameObject);
        }
        foreach (RecipeSO recipeSO in DeliveryManager.Instance.GetWaitingRecipeSOList())
        {
            Transform recipeTransform = Instantiate (recipeTemplate,container);
            recipeTransform.gameObject.SetActive(true);
        }
    }
}

(3) 赋值

9、获取订单上的文本

(1) 给RecipeTemplate添加 DeliveryManagerSingleUI.cs组件

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

public class DeliveryManagerSingleUI : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI recipeNameText;
    public void SetRecipeSO(RecipeSO recipeSO)
    {
        recipeNameText.text = recipeSO.recipeName;
    }
}

(2) 赋值

10、组织脚本文件夹:在Scripts文件夹下新建文件夹,命名为UI

11、显示订单内容:编辑DeliveryManagerUI.cs

private void UpdateVisul()
{
    foreach (Transform child in container)
    {
        if (child == recipeTemplate) continue;
        Destroy(child.gameObject);
    }
    foreach (RecipeSO recipeSO in DeliveryManager.Instance.GetWaitingRecipeSOList())
    {
        Transform recipeTransform = Instantiate (recipeTemplate,container);
        recipeTransform.gameObject.SetActive(true);
        recipeTransform.GetComponent<DeliveryManagerSingleUI>().SetRecipeSO(recipeSO);
    }
}

12、显示订单图标

(1) 以RecipeTemplate为父物体,Create Empty,命名为IconContainer,Pos.x = -110,Width和Height都为0

(2) 以IconContainer为父物体,UI - Image,命名为IconTemplate,Width和Height都为40、

(3) Source Image 为Bread

(4) 给IconContainer添加Horizontal Layout Group组件,可复制几个IconTemplate查看效果

(5) 显示订单图标:编辑DeliveryManagerSingleUI.cs

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

public class DeliveryManagerSingleUI : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI recipeNameText;
    [SerializeField] private Transform iconContainer;
    [SerializeField] private Transform iconTemplate;

    private void Awake()
    {
        iconTemplate.gameObject.SetActive(false);
    }
    public void SetRecipeSO(RecipeSO recipeSO)
    {
        recipeNameText.text = recipeSO.recipeName;
        foreach (Transform child in iconContainer)
        {
            if (child == iconTemplate) continue;
            Destroy(child.gameObject);
        }

        foreach (KitchenObjectSO kitchenObjectSO in recipeSO.kitchenObjectSOList)
        {
            Transform iconTransform = Instantiate(iconTemplate, iconContainer);
            iconTransform.gameObject.SetActive(true);
            iconTransform.GetComponent<Image>().sprite = kitchenObjectSO.sprite;
        }
    }
}

赋值

测试结果:按订单制作食物,送到配送台后,食物消失,订单消失

声音

一、背景音乐

1、Create Empy,命名为MusicManager,Reset Transform

2、为MusicManager添加Audio Source组件

设置Audio Source下的AudioClip为Music

勾选Play On Awake,勾选Loop(循环)

Priority为0,Volume为0.5

3、确保Main Camera上有Audio Listener组件 

二、配送音效

1、音效对象

(1) 在Scripts/ScripatableObjects文件夹下新建AudioClipRefsSO.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu()]
public class AudioClipRefsSO : ScriptableObject
{
    public AudioClip[] chop;
    public AudioClip[] deliveryFail;
    public AudioClip[] deliverySuccess;
    public AudioClip[] footstep;
    public AudioClip[] objectDrop;
    public AudioClip[] objectPickup;
    public AudioClip[] trash;
    public AudioClip[] warning;
    public AudioClip stoveSizzle;
}

(2) 在ScriptableObjects文件夹,制作 AudioClipRefsSO对象,命名为AudioClipRefsSO

(3) 添加对应属性

2、在DeliveryManager.cs中,声明两个EventHandler委托事件

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

public class DeliveryManager : MonoBehaviour
{
    public event EventHandler OnRecipeSpawned;
    public event EventHandler OnRecipeCompleted;
    // 委托事件
    public event EventHandler OnRecipeSuccess;
    public event EventHandler OnRecipeFailed;

    public static DeliveryManager Instance { get; private set; }
    [SerializeField] private RecipeListSO recipeListSO;

    private List<RecipeSO> waitingRecipeSOList;
    private float spawnRecipeTimer;
    private float spawnRecipeTimeMax = 4f;
    private int waitingRecipesMax = 4;
    private void Awake()
    {
        Instance = this;
        waitingRecipeSOList = new List<RecipeSO>();
    }
    private void Update()
    {
        spawnRecipeTimer -= Time.deltaTime;
        if (spawnRecipeTimer <= 0f)
        {
            spawnRecipeTimer = spawnRecipeTimeMax;

            if (waitingRecipeSOList.Count < waitingRecipesMax)
            {
                RecipeSO waitingRecipeSO = recipeListSO.recipeSOList[UnityEngine.Random.Range(0, recipeListSO.recipeSOList.Count)];

                waitingRecipeSOList.Add(waitingRecipeSO);

                OnRecipeSpawned?.Invoke(this,EventArgs.Empty);
            }
        }
    }
    public void DeliverRecipe(PlateKitchenObject plateKitchenObject)
    {
        for (int i = 0; i < waitingRecipeSOList.Count; i++)
        {
            RecipeSO waitingRecipeSO = waitingRecipeSOList[i];
            if (waitingRecipeSO.kitchenObjectSOList.Count == plateKitchenObject.GetKitchenObjectsSOList().Count)
            {
                // Has the same number of ingredients
                bool plateContentsMatchesRecipe = true;
                foreach (KitchenObjectSO recipeKitchenObjectSO in waitingRecipeSO.kitchenObjectSOList)
                {
                    // Cycling through all ingredients in the Recipe
                    bool ingredientFound = false;
                    foreach (KitchenObjectSO plateKitchenObjectSO in plateKitchenObject.GetKitchenObjectsSOList())
                    {
                        // Cycling through all ingredients in the plate
                        if (plateKitchenObjectSO == recipeKitchenObjectSO)
                        {
                            // Ingredients matches!
                            ingredientFound = true;
                            break;
                        }
                    }
                    if (!ingredientFound)
                    {
                        // This Recipe ingredient was not found on the plate
                        plateContentsMatchesRecipe = false;
                    }
                }
                if (plateContentsMatchesRecipe)
                {
                    // Player delivered the correct recipe!

                    waitingRecipeSOList.RemoveAt(i);

                    OnRecipeCompleted?.Invoke(this,EventArgs.Empty);

                    // 触发成功事件
                    OnRecipeSuccess?.Invoke(this,EventArgs.Empty);
                    return;
                }
            }
        }
        // 触发失败事件
        OnRecipeFailed?.Invoke(this,EventArgs.Empty);
    }
    public List<RecipeSO> GetWaitingRecipeSOList()
    {
        return waitingRecipeSOList;
    }
}

3、Create Empty,命名为SoundManager,Reset Transform

4、为SoundManager添加SoundManager.cs

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

public class SoundManager : MonoBehaviour
{
    [SerializeField] private AudioClipRefsSO audioClipRefsSO;
    private void Start()
    {
        DeliveryManager.Instance.OnRecipeSuccess += DeliveryManager_OnRecipeSuccess;
        DeliveryManager.Instance.OnRecipeFailed += DeliveryManager_OnRecipeFailed;
    }

    private void DeliveryManager_OnRecipeFailed(object sender, System.EventArgs e)
    {
        PlaySound(audioClipRefsSO.deliveryFail,Camera.main.transform.position);
    }

    private void DeliveryManager_OnRecipeSuccess(object sender, System.EventArgs e)
    {
        PlaySound(audioClipRefsSO.deliverySuccess, Camera.main.transform.position);
    }

    private void PlaySound(AudioClip[] audioClipArray ,Vector3 position,float volume = 1f)
    {
        PlaySound(audioClipArray[Random.Range(0,audioClipArray.Length)],position,volume);
    }
    private void PlaySound(AudioClip audioClip ,Vector3 position,float volume = 1f)
    {
        AudioSource.PlayClipAtPoint(audioClip,position,volume);
    }    
}

5、赋值

6、调节声音播放的位置:

(1) 编辑DeliveryCounter.cs

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

public class DeliveryCounter : BaseCounter
{
    public static DeliveryCounter Instance {  get; private set; }
    private void Awake()
    {
        Instance = this;
    }
    public override void Interact(Player player)
    {
        if (player.HasKitchenObject())
        {
            if (player.GetKitchenObject().TryGetPlate(out PlateKitchenObject plateKitchenObject))
            {
                // Only accepts Plates
                DeliveryManager.Instance.DeliverRecipe(plateKitchenObject);

                player.GetKitchenObject().DestroySelf();
            }
        }
    }
}

(2) 编辑SoundManager.cs

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

public class SoundManager : MonoBehaviour
{
    [SerializeField] private AudioClipRefsSO audioClipRefsSO;
    private void Start()
    {
        DeliveryManager.Instance.OnRecipeSuccess += DeliveryManager_OnRecipeSuccess;
        DeliveryManager.Instance.OnRecipeFailed += DeliveryManager_OnRecipeFailed;
    }

    private void DeliveryManager_OnRecipeFailed(object sender, System.EventArgs e)
    {
        DeliveryCounter deliveryCounter = DeliveryCounter.Instance;
        PlaySound(audioClipRefsSO.deliveryFail, deliveryCounter.transform.position);
    }

    private void DeliveryManager_OnRecipeSuccess(object sender, System.EventArgs e)
    {
        DeliveryCounter deliveryCounter = DeliveryCounter.Instance;
        PlaySound(audioClipRefsSO.deliverySuccess, deliveryCounter.transform.position);
    }

    private void PlaySound(AudioClip[] audioClipArray ,Vector3 position,float volume = 1f)
    {
        PlaySound(audioClipArray[Random.Range(0,audioClipArray.Length)],position,volume);
    }
    private void PlaySound(AudioClip audioClip ,Vector3 position,float volume = 1f)
    {
        AudioSource.PlayClipAtPoint(audioClip,position,volume);
    }
    
}
三、切菜音效

1、声明、触发委托(按F时播放音效):编辑CuttingCounter.cs

场景存在多个处理台,不能用配送台的单例模式。所以使用静态委托:

以便使多个 CuttingCounter 实例能够共享同一个事件响应逻辑(共享OnAnyCut事件)

public static event EventHandler OnAnyCut;
public override void InteractAlternate(Player player)
{
    if (HasKitchenObject() && HasRecipeWithInput(GetKitchenObject().GetKitchenObjectSO()))
    {
        
        cuttingProgress++;
        Oncut?.Invoke(this, EventArgs.Empty);
        OnAnyCut?.Invoke(this, EventArgs.Empty);
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class CuttingCounter : BaseCounter, IHasProgress
{
    public static event EventHandler OnAnyCut;
    public event EventHandler<IHasProgress.OnprogressChangedEventArgs> OnProgressChanged;
    public event EventHandler Oncut;

    [SerializeField] private CuttingRecipeSO[] cuttingRecipeSOArray;

    private int cuttingProgress;
    public override void Interact(Player player)
    {
        if (!HasKitchenObject())
        {
            // There is no KitchenObject here
            if (player.HasKitchenObject())
            {
                // player is carrying something
                if (HasRecipeWithInput(player.GetKitchenObject().GetKitchenObjectSO()))
                {
                    // Player carrying something that can be cut
                    player.GetKitchenObject().SetKitchenObjectParent(this);
                    cuttingProgress = 0;
                    // 
                    CuttingRecipeSO cuttingRecipeSO = GetCuttingRecipeSOWithInput(GetKitchenObject().GetKitchenObjectSO());
                    OnProgressChanged?.Invoke(this, new IHasProgress.OnprogressChangedEventArgs
                    {
                        progressNormalized = (float)cuttingProgress / cuttingRecipeSO.cuttingProgressMax
                    });
                }
            }
            else
            {
                // Player not carrying anything
            }
        }
        else
        {
            // There is a KitchenObject here
            if (player.HasKitchenObject())
            {
                // Player is carrying something
                if (player.GetKitchenObject().TryGetPlate(out PlateKitchenObject plateKitchenObject))
                {
                    // Player is holding a Plate
                    if (plateKitchenObject.TryAddIngredient(GetKitchenObject().GetKitchenObjectSO()))
                    {
                        GetKitchenObject().DestroySelf();
                    }
                }
            }
            else
            {
                // Player is not carrying anything
                GetKitchenObject().SetKitchenObjectParent(player);
            }
        }
    }
    public override void InteractAlternate(Player player)
    {
        if (HasKitchenObject() && HasRecipeWithInput(GetKitchenObject().GetKitchenObjectSO()))
        {
            // There is a KitchenObject her and it can be cut
            cuttingProgress++;

            Oncut?.Invoke(this, EventArgs.Empty);
            OnAnyCut?.Invoke(this, EventArgs.Empty);

            CuttingRecipeSO cuttingRecipeSO = GetCuttingRecipeSOWithInput(GetKitchenObject().GetKitchenObjectSO());
            
            OnProgressChanged?.Invoke(this, new IHasProgress.OnprogressChangedEventArgs
   

http://www.kler.cn/a/459349.html

相关文章:

  • oceanbase集群访问异常问题处理
  • flink-connector-kafka 3.4源码编译
  • 【unity错误】Unity 6 LTS 打开就报错Assertion failed on expressionxxx?
  • 【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(五)
  • 详细了解Redis分布式存储的常见方案
  • OpenMV与STM32通信全面指南
  • UE5材质节点SimpleGrassWind
  • 《艺术的启示》最新答案2024
  • 前端(Ajax)
  • 日本东京阿里云200M不限流量轻量云主机测试报告
  • 如何利用云计算进行灾难恢复?
  • 发表文章去哪里投稿?软文推广常见的几种渠道类型
  • NAT 技术如何解决 IP 地址短缺问题?
  • 【项目日记(9)】项目整体测试,优化以及缺陷分析
  • 计算机网络 (15)宽带接入技术
  • 基于Python实现车辆检测、机动车检测、识别位置标记、计数
  • STM32-笔记22-sg90舵机
  • 雷军:科技传奇的逐梦之旅
  • ArrayList和LinkedList的区别是什么?
  • 支持最新 mysql9的workbench8.0.39 中文汉化教程来了
  • Selenium 浏览器驱动代理 - 无需下载本地浏览器驱动镜像!(Python 版本!)
  • 3.从制定标准到持续监控:7个关键阶段提升App用户体验
  • 【Python高级374】正则表达式
  • 深入解析MySQL索引结构:从数组到B+树的演变与优化
  • 【2024年-8月-6日-开源社区openEuler实践记录】ChatIG:开启智能交互新体验的开源项目
  • 21. 【.NET 8 实战--孢子记账--从单体到微服务】--简易权限--补充--自动添加角色可访问接口