胡闹厨房之Manager

游戏控制器

MusicManager.cs 音乐控制器


本项目很简单,所以音乐控制器也很简单

脚本代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
using UnityEngine;

public class MusicManager : MonoBehaviour
{
// 做成单例模式
public static MusicManager Instance { get; private set; }

// 作为音量数据的key,使用PlayerPrefs存储
private const string MUSICMANAGERVOLUME = "musicManagerVolume";

// 在游戏对象上挂载的音频组件的引用
private AudioSource audioSource;

// 原始音量
private float originalVolume;

// 音量系数
private int volume = 5;


private void Awake()
{
// 单例
Instance = this;
// 加载存储音量数据
loadVolume();
}
void Start()
{
// 获取游戏对象挂载的音频组件
audioSource = GetComponent<AudioSource>();
// 获取原始音量
originalVolume = audioSource.volume;
// 更新音量
UpdateVolume();
}

public void ChangVolume()
{
// 增加音量系数
volume++;
if(volume > 10)
{
volume = 0;
}
else
{
// 更新
UpdateVolume();
// 储存
saveVolume();
}
}

private void UpdateVolume()
{
if(volume == 0)
{// 如果音量系数为零,则直接关闭音频组件
audioSource.enabled = false;
}
else
{// 设置音频组件的音量
audioSource.volume = originalVolume * (volume / 10.0f);
}

}
public int GetVolume()
{// 对外暴露的音量系数
return volume;
}

private void saveVolume()
{// 存储
PlayerPrefs.SetInt(MUSICMANAGERVOLUME,volume);
}

private void loadVolume()
{// 加载
PlayerPrefs.GetInt(MUSICMANAGERVOLUME,volume);
}
}

SoundManager.cs 音效控制器


为了更方便的调用音频文件使用SO文件。

AudioClipRefsSO 音频文件表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using UnityEngine;

[CreateAssetMenu()]
public class AudioClipRefsSO : ScriptableObject
{// 注意继承ScriptableObject
// 下面是一堆列表
public AudioClip[] chop;
public AudioClip[] deliveryFail;
public AudioClip[] deliverSuccess;
public AudioClip[] footstep;
public AudioClip[] objectDrop;
public AudioClip[] objectPickup;
public AudioClip[] stoveSizzle;
public AudioClip[] trash;
public AudioClip[] warning;

}

脚本代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using UnityEngine;

public class SoundManager : MonoBehaviour
{
// 还是单例模式
public static SoundManager instance { get; private set; }
// 音效音量的存储key
private const string SOUNDMANAGER_VOLUME = "soundManagerVolume";
// 上面的SO的引用
[SerializeField] private AudioClipRefsSO audioClipRefsSO;
// 音量系数
private int volume = 5;

private void Awake()
{// 单例
instance = this;
}

private void Start()
{
// 注册音频播放事件,做成观察者模式
// 在具体需要播放音效的时候,添加事件即可
OrderManager.Instance.OnRecipeSuccessed += OrderManger_OnRecipeSuccessed;
OrderManager.Instance.OnRecipeFailed += OrderManager_OnRecipeFailed;
CutingCounter.Oncut += CutingCounter_Oncut;
KitchenObjectHolder.OnDrop += KitchenObjectHolder_OnDrop;
KitchenObjectHolder.OnPickUp += KitchenObjectHolder_OnPickUp;
TrashCounter.OnTrashed += TrashCounter_OnTrashed;

// 加载音量
LoadVolum();
}

private void TrashCounter_OnTrashed(object sender, System.EventArgs e)
{
PlaySound(audioClipRefsSO.trash);
}

private void KitchenObjectHolder_OnPickUp(object sender, System.EventArgs e)
{
PlaySound(audioClipRefsSO.objectPickup);
}

private void KitchenObjectHolder_OnDrop(object sender, System.EventArgs e)
{
PlaySound(audioClipRefsSO.objectDrop);
}

private void CutingCounter_Oncut(object sender, System.EventArgs e)
{
PlaySound(audioClipRefsSO.chop);
}

private void OrderManager_OnRecipeFailed(object sender, System.EventArgs e)
{
PlaySound(audioClipRefsSO.deliveryFail);
}

private void OrderManger_OnRecipeSuccessed(object sender, System.EventArgs e)
{
PlaySound(audioClipRefsSO.deliverSuccess, 0.35f);
}

public void PlayCoundDown()
{// 播放计数音效
PlaySound(audioClipRefsSO.warning);
}

private void PlaySound(AudioClip[] audioClips, float volumeMutipler = 0.5f)
{// 音效播放函数
PlaySound(audioClips,Camera.main.transform.position, volumeMutipler);
}

private void PlaySound(AudioClip[] audioClips, Vector3 position, float volumeMutipler = 0.5f)
{// 另一个音效播放函数
// 也是真正执行播放逻辑的源头函数
if (volume == 0) return;
// 随机挑选,同一种音效有不同版本
int index = Random.Range(0, audioClips.Length);
// 播放
AudioSource.PlayClipAtPoint(audioClips[index], position, volumeMutipler*(volume/10.0f));
}

public void PlayStepSound(float volumeMutipler = 1f)
{// 脚步音效播放函数
PlaySound(audioClipRefsSO.footstep, volumeMutipler);
}

public void ChangeVolume()
{// 改变音量函数
volume++;
if(volume > 10)
{
volume = 0;
}
SaveVolum();

}

public int GetVolume()
{// 暴露音量系数
return volume;
}

private void SaveVolum()
{// 保存音量
PlayerPrefs.SetInt(SOUNDMANAGER_VOLUME,volume);
}
private void LoadVolum()
{// 加载音量
volume = PlayerPrefs.GetInt(SOUNDMANAGER_VOLUME, volume);
}
}

GameManager.cs 游戏控制器


用来控制游戏流程,变化游戏状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using System;
using UnityEngine;

public class GameManager : MonoBehaviour
{
// 单例模式
public static GameManager instance { get; private set; }
// 游戏状态变化事件
public event EventHandler OnStateChanged;
// 游戏暂停和不暂停事件
public event EventHandler OnGameStop;
public event EventHandler OnGameUnStop;

// 简陋的有限状态机
private enum State
{
WaitingToStart,
CountDownToStart,
GamePlaying,
GameOver
}

// 游戏当前的状态
private State state;

// 游戏各级段时限
private float waitingToStartTimer = 1;
private float countDownToStartTimaer = 3;
private float gamePlayingTimer = 60;
private float gamePlayingTimerTotal;
// 游戏是否暂停
private bool isGameStop = false;


private void Awake()
{
instance = this;
// 这里设置游戏时间的最大值
gamePlayingTimerTotal = gamePlayingTimer;
}

private void Start()
{// 改变游戏状态为WaitToStart
TurnToWaitToStart();
// 注册游戏状态暂停的事件
GameInput.instance.OnStopGameAction += GameInPut_OnStopGameAction;
}

private void GameInPut_OnStopGameAction(object sender, EventArgs e)
{
// 改变游戏暂停状态
ToggleGame();
}

void Update()
{
// 不同状态不同逻辑
switch (state)
{
case State.WaitingToStart:
// 这时时间倒计时
waitingToStartTimer -= Time.deltaTime;
if(waitingToStartTimer < 0)
{// 时间到就改到下一状态
TurnToCountDownToStart();
}
break;
case State.CountDownToStart:
countDownToStartTimaer -= Time.deltaTime;
if(countDownToStartTimaer < 0)
{
TurnToGamePlaying();
}
break;
case State.GamePlaying:
gamePlayingTimer -= Time.deltaTime;
if (gamePlayingTimer < 0)
{
TurnToGameOver();
}
break;
case State.GameOver:

break;
default:
break;
}
}

private void TurnToWaitToStart()
{// 改变状态到WaitToStart
state = State.WaitingToStart;
// 抛出游戏状态改变事件
OnStateChanged?.Invoke(this, EventArgs.Empty);
}

private void TurnToCountDownToStart()
{
state = State.CountDownToStart;
OnStateChanged?.Invoke(this, EventArgs.Empty);
}

private void TurnToGamePlaying()
{
state = State.GamePlaying;
OnStateChanged?.Invoke(this, EventArgs.Empty);
}

private void TurnToGameOver()
{
state = State.GameOver;
OnStateChanged?.Invoke(this, EventArgs.Empty);
}


// 以下是游戏状态的暴露
public bool IsWaitToStart()
{
return state == State.WaitingToStart;
}

public bool IsCountDownToStart()
{
return state == State.CountDownToStart;
}

public bool IsGamePlaying()
{
return state == State.GamePlaying;
}

public bool IsGameOver()
{
return state == State.GameOver;
}

// 暴露
public float GetCountDownTimer()
{
// 返回倒计时的时间
return countDownToStartTimaer;
}

public void ToggleGame()
{// 游戏暂停转变函数
// 游戏暂停状态取反
isGameStop = !isGameStop;
if (isGameStop)
{
// 改变游戏时间缩放比例为0,实现暂停
Time.timeScale = 0.0f;
// 抛出游戏暂停事件
OnGameStop?.Invoke(this, EventArgs.Empty);
}
else
{
Time.timeScale = 1.0f;
// 抛出游戏不暂停事件
OnGameUnStop?.Invoke(this, EventArgs.Empty);
}
}
public float GetGamePlayingTimer()
{// 暴露游戏时间
return gamePlayingTimer;
}
public float GetGamePlayingTimerNormalized()
{// 返回游戏进行的比例
return gamePlayingTimer/gamePlayingTimerTotal;
}
}

OrderManager.cs 订单控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Collections.Generic;
using UnityEngine;

public class OrderManager : MonoBehaviour
{
// 单例模式
public static OrderManager Instance { get; private set; }

// 订单生成的事件
public event EventHandler OnRecipeSpawned;
// 订单成功
public event EventHandler OnRecipeSuccessed;
// 订单失败
public event EventHandler OnRecipeFailed;

// 菜单数据类
[SerializeField] private RecipeListSO recipeSOList;
// 订单最大数
[SerializeField] private int orderMaxRecipe = 5;
// 是否开始生成订单
[SerializeField] private bool isStartOrder = false;
// 订单生成间隔时间
[SerializeField] private float orderRate = 1.0f;
// 订单生成计时器
private float orderTimer = 0.0f;
// 订单计数器
private int orderCount = 0;
// 订单列表
private List<RecipeSO> orderRecipeListSO = new List<RecipeSO>();
// 成功计数
private int successedDeliveryCount = 0;

private void Awake()
{
Instance = this;
}

private void Start()
{// 注册游戏状态变化事件
GameManager.instance.OnStateChanged += GameManager_OnStateChanged;
}

private void GameManager_OnStateChanged(object sender, EventArgs e)
{
if (GameManager.instance.IsGamePlaying())
{// 如果游戏状态是Playing
// 开始生成订单
StartToOrder();
}
}

private void Update()
{
if (isStartOrder)
{// 如果正在开始生成订单
// 订单生成器
OrderUpdate();
}
}

private void OrderUpdate()
{
// 变更计时器
orderTimer += Time.deltaTime;
if(orderTimer >= orderRate)
{// 计时器大于时间间隔
// 计时器归零
orderTimer = 0.0f;
// 添加新订单
OrderANewRecipe();
}
}

private void OrderANewRecipe()
{// 如果订单数量达到最大值返回
if (orderCount >= orderMaxRecipe) return;
// 增加计数
orderCount++;
// 生成随机数
int index = UnityEngine.Random.Range(0, recipeSOList.recipes.Count);
// 在订单列表中添加订单
orderRecipeListSO.Add(recipeSOList.recipes[index]);
// 抛出订单生成事件
OnRecipeSpawned?.Invoke(this, EventArgs.Empty);
}

public void DeliveryRecipe(PlateKitchenObject plateKitchenObject)
{// 上菜检测函数,检测上菜是否正确
RecipeSO correctRecipe = null;
foreach(RecipeSO recipeSO in orderRecipeListSO)
{// 遍历订单列表
if(IsCorrect(recipeSO, plateKitchenObject))
{// 如果上菜和列表中的某一项相同
// 获取正确的菜品引用
correctRecipe = recipeSO;
break;
}
}
if (correctRecipe == null)
{// 如果上菜失败
print("上菜失败");
// 抛出上菜失败事件
OnRecipeFailed?.Invoke(this, EventArgs.Empty);
}
else
{// 如果上菜成功
// 从订单列表中删除成功菜品
orderRecipeListSO.Remove(correctRecipe);
print("上菜成功");
// 正确菜品技术增加
successedDeliveryCount++;
// 抛出上菜成功事件
OnRecipeSuccessed?.Invoke(this, EventArgs.Empty);
}
}

private bool IsCorrect(RecipeSO recipeSO, PlateKitchenObject plateKitchenObject)
{// 菜品相同判定
// 两个临时菜品材料列表
List<KitchenObjectSO> list1 = recipeSO.KitchenObjectSOList;
List<KitchenObjectSO> list2 = plateKitchenObject.GetKitchenObjectSOList();
// 如果列表长度不同直接返回false
if(list1.Count != list2.Count) return false;

foreach (KitchenObjectSO item1 in list1)
{// 遍历list1
// 如果list1中的元素有不再list2中的元素,返回false
if(list2.Contains(item1) == false) return false;
}
// 如果list1和list2完全相同,返回true
return true;
}

public List<RecipeSO> GetRecipeList()
{// 暴露菜品列表,用于UI
return orderRecipeListSO;
}

public void StartToOrder()
{// 开始生成订单表
isStartOrder = true;
}

public int GetsuccessedDeliveryCount()
{// 暴露订单完成数
return successedDeliveryCount;
}
}