当前位置: 首页 > 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;备受用户青…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...