胡闹厨房练习(三)
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