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

胡闹厨房练习(三)

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重置为spawnRecipeTimeMaxspawnRecipeTimer = 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 ingredientsbool 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 PlatesDeliveryManager.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 ingredientsbool plateContentsMatchesRecipe = true;foreach (KitchenObjectSO recipeKitchenObjectSO in waitingRecipeSO.kitchenObjectSOList){// Cycling through all ingredients in the Recipebool ingredientFound = false;foreach (KitchenObjectSO plateKitchenObjectSO in plateKitchenObject.GetKitchenObjectsSOList()){// Cycling through all ingredients in the plateif (plateKitchenObjectSO == recipeKitchenObjectSO){// Ingredients matches!ingredientFound = true;break;}}if (!ingredientFound){// This Recipe ingredient was not found on the plateplateContentsMatchesRecipe = 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 ingredientsbool plateContentsMatchesRecipe = true;foreach (KitchenObjectSO recipeKitchenObjectSO in waitingRecipeSO.kitchenObjectSOList){// Cycling through all ingredients in the Recipebool ingredientFound = false;foreach (KitchenObjectSO plateKitchenObjectSO in plateKitchenObject.GetKitchenObjectsSOList()){// Cycling through all ingredients in the plateif (plateKitchenObjectSO == recipeKitchenObjectSO){// Ingredients matches!ingredientFound = true;break;}}if (!ingredientFound){// This Recipe ingredient was not found on the plateplateContentsMatchesRecipe = 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 PlatesDeliveryManager.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 hereif (player.HasKitchenObject()){// player is carrying somethingif (HasRecipeWithInput(player.GetKitchenObject().GetKitchenObjectSO())){// Player carrying something that can be cutplayer.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 hereif (player.HasKitchenObject()){// Player is carrying somethingif (player.GetKitchenObject().TryGetPlate(out PlateKitchenObject plateKitchenObject)){// Player is holding a Plateif (plateKitchenObject.TryAddIngredient(GetKitchenObject().GetKitchenObjectSO())){GetKitchenObject().DestroySelf();}}}else{// Player is not carrying anythingGetKitchenObject().SetKitchenObjectParent(player);}}}public override void InteractAlternate(Player player){if (HasKitchenObject() && HasRecipeWithInput(GetKitchenObject().GetKitchenObjectSO())){// There is a KitchenObject her and it can be cutcuttingProgress++;Oncut?.Invoke(this, EventArgs.Empty);OnAnyCut?.Invoke(this, EventArgs.Empty);CuttingRecipeSO cuttingRecipeSO = GetCuttingRecipeSOWithInput(GetKitchenObject().GetKitchenObjectSO());OnProgressChanged?.Invoke(this, new IHasProgress.OnprogressChangedEventArgs

相关文章:

胡闹厨房练习(三)

ScriptableObject 一、初步了解 1、实质:是一种特殊类型的Unity对象, 2、作用:用于存储大量数据,而不必依附于游戏场景中的某个GameObject。 3、特点: 可以在不增加场景中对象数量的情况下,管理和存储复杂的数据结构、配置信息、游戏状态等。 4、适用:非常适合用来…...

关于ESD(静电放电)等级的划分

关于ESD&#xff08;静电放电&#xff09;等级的划分&#xff0c;主要依据不同的测试模型和测试标准。以下是对HBM&#xff08;人体模型&#xff09;和CDM&#xff08;充电器件模型&#xff09;两种测试模型下ESD等级划分的详细解释&#xff1a; HBM ESD等级划分 HBM ESD等级…...

探究步进电机与输入脉冲的关系

深入了解步进电机 前言一、 步进电机原理二、 细分三、脉冲数总结 前言 主要是探究以下内容&#xff1a; 1、步进电机的步进角。 2、什么是细分。 3、脉冲的计算。 最后再扩展以下STM32定时器的计算方法。 一、 步进电机原理 其实语言描述怎么样都不直观&#xff0c;我更建议…...

基于YOLOV5+Flask安全帽RTSP视频流实时目标检测

1、背景 在现代工业和建筑行业中&#xff0c;安全始终是首要考虑的因素之一。特别是在施工现场&#xff0c;工人佩戴安全帽是确保人身安全的基本要求。然而&#xff0c;人工监督难免会有疏漏&#xff0c;尤其是在大型工地或复杂环境中&#xff0c;确保每个人都佩戴安全帽变得非…...

Windows内置的服务器IIS(Internet Information Services)托管网站

一. 安装IIS 打开控制面板&#xff1a;在开始菜单搜索“控制面板”并打开它。程序和功能&#xff1a;点击“程序”然后选择“程序和功能”。启用或关闭Windows功能&#xff1a;在左侧菜单中选择“启用或关闭Windows功能”。查找并勾选IIS&#xff1a;在弹出的窗口中&#xff0c…...

虚幻引擎结构之UObject

一. UObject 的介绍 UObject 是虚幻引擎中的核心基础类,所有其他游戏对象和资源类都直接或间接地继承自它。作为虚幻引擎的基石,UObject 提供了多项关键功能,包括内存管理、序列化、反射(introspection)、垃圾回收以及元数据支持。在虚幻引擎中,UObject 类的实例通常被称…...

js的Reflect对象

Reflect 对象是 JavaScript ES6 中引入的一个内建对象&#xff0c;它提供了一系列与对象操作相关的方法。这些方法与 Object 对象上的方法类似&#xff0c;但在行为上有一些差异&#xff0c;并且更加规范和统一。Reflect 对象并不是一个构造函数&#xff0c;不能被 new 操作符调…...

this指向了谁?

看函数在执行的时候是如何调用的&#xff0c; 1 如果这个函数是用普通函数调用模式来进行调用&#xff0c;它内部的this指向了window; 2 如果一个函数在调用的时候是通过对象方法模式来进行调用&#xff0c;则它内部的this就是我们的对象; 3 如果一个函数在调用的时候通过构…...

基于Resnet、LSTM、Shufflenet及CNN网络的Daily_and_Sports_Activities数据集仿真

在深度学习领域&#xff0c;不同的网络结构设计用于解决特定的问题。本文将详细分析四种主流网络结构&#xff1a;卷积神经网络&#xff08;CNN&#xff09;、残差网络&#xff08;ResNet&#xff09;、长短期记忆网络&#xff08;LSTM&#xff09;和洗牌网络&#xff08;Shuff…...

mac系统vsCode中使用Better Comments在.vue文件里失效

问题&#xff1a;关于Better Comments默认在html、TS、JS中有效&#xff0c;在vue中无效,需要单独进行配置 windows系统可以参考友链Better Comments&#xff08;注释高亮&#xff09;在vue文件里失效的问题 关于Better Comments电脑的配置路径&#xff1a; Windows系统&…...

UE5.3 C++ Ceiusm中的POI 制作3DUI 结合坐标转化

一.核心思路WidgetComponent CesiumGloberAnchor 二.先制作POI 创建C Actor来制作&#xff0c;APOI。直接上代码 #pragma once#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "CesiumGlobeAnchorComponent.h" #includ…...

一起学Git【第六节:查看版本差异】

git diff是 Git 版本控制系统中用于展示差异的强大工具。他可以用于查看文件在工作区、暂存区和版本库之间的差异、任意两个指定版本之间的差异和两个分支之间的差异等,接下来进行详细的介绍。 1.显示工作区与暂存区之间的差异 # 显示工作区和暂存区之间的差异,后面不加参数…...

numpy np.newaxis介绍

np.newaxis 是 NumPy 中用于增加数组维度的关键字。它的作用是为数组插入一个新的维度&#xff0c;从而改变数组的形状&#xff08;shape&#xff09;。 基本用法 np.newaxis 等价于 None&#xff0c;可以作为索引使用&#xff0c;用于在指定位置增加一个维度。增加的维度的大…...

小程序配置文件 —— 16 项目配置文件和配置 sass

目录 项目配置文件配置 sass 项目配置文件 在创建项目的时候&#xff0c;每个项目的根目录生成两个 config.json 文件&#xff08;project.config.json 和 project.private.config.json &#xff09;&#xff0c;用于保存开发者在工具上做的个性化配置&#xff0c;例如和编译有…...

【yolov5】实现FPS游戏人物检测,并定位到矩形框上中部分,实现自瞄

介绍 本人机器学习小白&#xff0c;通过语言大模型百度进行搜索&#xff0c;磕磕绊绊的实现了初步效果&#xff0c;能有一些锁头效果&#xff0c;但识别速度不是非常快&#xff0c;且没有做敌友区分&#xff0c;效果不是非常的理想&#xff0c;但在4399小游戏中爽一下还是可以…...

概率统计与随机过程--作业5

一、推导题 二、计算题 1、某单位为了研究太阳镜销售和广告费用之间的关系&#xff0c;搜集了以下数据&#xff0c;使用回归分析方法得到线性回归模型&#xff1a; 广告费用&#xff08;万元&#xff09;x 2 5 6 7 22 25 28 30 22 18 销售量&#xff08;个&#xf…...

“802.11g”,“802.11n”,“802.11ac”,“802.11ax”

802.11g、802.11n、802.11ac、802.11ax都是IEEE制定的无线局域网&#xff08;WLAN&#xff09;标准&#xff0c;它们各自具有不同的特点和性能。以下是对这四个标准的详细介绍&#xff1a; 1. 802.11g 定义&#xff1a;802.11g是IEEE制定的一种无线局域网标准&#xff0c;它提…...

Kubernetes 常用的网络插件

上篇内容跟大家简单聊了k8s网络模型原理。分别围绕着容器、Pod、Service、网络策略等展开了详细的讲解。这次想跟大家聊聊k8s的CNI网络插件。 CNI 是 Kubernetes 网络模型的核心组件&#xff0c;它是一个插件接口&#xff0c;允许用户选择和配置网络插件来管理 Pod 的网络。CN…...

Retrofit和rxjava 实现窜行请求,并行请求,循环多次请求,递归请求,错误重试

在使用 Retrofit 和 RxJava 时&#xff0c;可以通过多种方式实现多次请求&#xff0c;比如串行请求、并行请求、依赖请求等。以下是一些常见的实现方式&#xff1a; 1. 串行请求&#xff08;依赖关系&#xff09; 一个请求的结果作为另一个请求的输入&#xff0c;可以用 flat…...

2025年度好用便签推荐,电脑桌面便签app分享

在快节奏的现代生活中&#xff0c;高效的时间管理和任务规划变得尤为重要。一款好用的便签软件不仅能帮助我们记录灵感、待办事项&#xff0c;还能极大地提升我们的工作效率。 在众多电脑桌面便签中&#xff0c;好用便签以其出色的桌面便签功能脱颖而出&#xff0c;备受用户青…...

Git:现代软件开发的基石——原理、实践与行业智慧·优雅草卓伊凡

Git&#xff1a;现代软件开发的基石——原理、实践与行业智慧优雅草卓伊凡 一、Git的本质与核心原理 1. 技术定义 Git是一个分布式版本控制系统&#xff08;DVCS&#xff09;&#xff0c;由Linus Torvalds在2005年为管理Linux内核开发而创建。其核心是通过快照&#xff08;Sna…...

Django orm详解--组成部件

Django ORM 的核心部件可分为模型系统、查询系统、数据库后端和辅助工具四大类&#xff0c;每个部件负责不同的职责&#xff0c;共同实现对象与关系数据库的映射。以下是核心部件的分层解析&#xff1a; 一、模型系统&#xff08;Model System&#xff09; 1. 模型基类&#…...

《基于Keepalived+LVS+Web+NFS的高可用集群搭建》

目 录 1 项目概述 1.1 项目背景 1.2 项目功能 2 项目的部署 2.1 部署环境介绍 2.2 项目的拓扑结构 2.3 项目环境调试 2.4 项目的部署 2.5 项目功能的验证 2.6 项目对应服务使用的日志 3 项目的注意事项 3.1 常见问题与解决方案 3.2 项目适用背…...

Qt 中的 d-pointer 与 p-pointer小结

Qt 中的 d-pointer 与 p-pointer&#xff1a; PIMPL 惯用法解析 在 Qt 库中&#xff0c;尤其是在其核心类和模块中&#xff0c;广泛使用了 PIMPL (Pointer to IMPLementation&#xff0c;指向实现的指针) 的编程惯用法。这种模式通过一对指针来实现&#xff1a;d-pointer (d_p…...

Grafana-Gauge仪表盘

仪表盘是一种单值可视化。 可让您快速直观地查看某个值落在定义的或计算出的最小和最大范围内的位置。 通过重复选项&#xff0c;您可以显示多个仪表盘&#xff0c;每个对应不同的序列、列或行。 支持的数据格式 单值 数据集中只有一个值&#xff0c;会生成一个显示数值的…...

[图文]图6.3会计事项-Fowler分析模式的剖析和实现

1 00:00:02,090 --> 00:00:05,160 Fowler在书里面也说了&#xff0c;6.4 2 00:00:05,290 --> 00:00:07,540 这里也说了 3 00:00:08,030 --> 00:00:11,340 不是常用的 4 00:00:12,520 --> 00:00:15,060 更倾向用6.2&#xff0c;实际上就是6.3了 5 00:00:15,760 …...

字符串day7

344 反转字符串 字符串理论上也是一个数组&#xff0c;因此只需要用双指针即可 class Solution { public:void reverseString(vector<char>& s) {for(int i0,js.size()-1;i<j;i,j--){swap(s[i],s[j]);}} };541 反转字符串 自己实现一个反转从start到end的字符串…...

React从基础入门到高级实战:React 核心技术 - React Router:路由管理

React Router&#xff1a;路由管理 在现代 Web 应用开发中&#xff0c;路由管理 是构建多页面或单页应用&#xff08;SPA&#xff09;的核心技术之一。React Router 是 React 生态中最受欢迎的路由管理库&#xff0c;它为开发者提供了强大的工具来实现页面导航、动态路由和权限…...

Leetcode 3269. 构建两个递增数组

1.题目基本信息 1.1.题目描述 给定两个只包含 0 和 1 的整数数组 nums1 和 nums2&#xff0c;你的任务是执行下面操作后使数组 nums1 和 nums2 中 最大 可达数字 尽可能小。 将每个 0 替换为正偶数&#xff0c;将每个 1 替换为正奇数。在替换后&#xff0c;两个数组都应该 递…...

cursor使用mcp

问题说明 mcp就相当于给AI安装了工具包&#xff0c;它可以调用获取接口文档&#xff0c;网页&#xff0c;数据库等&#xff0c;基本上所有的mcp都是node程序&#xff0c;少数需要python环境 使用说明 使用mcp-mysql举例&#xff0c;下面是配置json "mysql": {&qu…...