pvz_rust_wsll_lib/mechanics/level_controller.rs
1//! # 关卡控制器模块 (`level_controller`)
2//!
3//! 本模块负责管理游戏的关卡流程,特别是僵尸的生成逻辑。
4//! 它决定了何时、何种类型以及在哪一行生成僵尸,从而控制游戏的难度和节奏。
5
6use crate::zombies::{ZombieType, Zombie};
7use std::time::{Duration, Instant};
8use rand::Rng;
9use crate::ui::grid::GRID_HEIGHT;
10
11/// 定义了生成僵尸时所需的信息。
12///
13/// 包含要生成的僵尸类型和其出现的行号。
14pub struct ZombieSpawnInfo {
15 /// 要生成的僵尸的类型。
16 pub zombie_type: ZombieType,
17 /// 僵尸将要生成的行索引。
18 pub row: usize,
19}
20
21/// 关卡控制器结构体。
22///
23/// 管理僵尸的生成时机、类型和波次。它实现了完整的关卡流程控制,
24/// 包括初始等待时间、波次管理、难度递增和胜利条件判定。
25pub struct LevelController {
26 /// 上一次生成僵尸的时间点。
27 last_spawn_time: Instant,
28 /// 生成僵尸之间的时间间隔。
29 spawn_interval: Duration,
30 /// 关卡开始的时间点。
31 start_time: Instant,
32 /// 当前波次,从0开始。
33 current_wave: usize,
34 /// 本关卡的总波数。
35 total_waves: usize,
36 /// 当前波次中已生成的僵尸数量。
37 zombies_spawned_in_wave: usize,
38 /// 当前波次需要生成的僵尸总数。
39 zombies_per_wave: usize,
40 /// 标记最后一波是否已经提示。
41 final_wave_announced: bool,
42 /// 标记所有僵尸是否已生成完毕。
43 all_zombies_spawned: bool,
44 /// 是否正在等待开始第一波。
45 waiting_for_first_wave: bool,
46}
47
48impl LevelController {
49 /// 创建一个新的 `LevelController` 实例。
50 ///
51 /// 初始化时,设置关卡开始时间为当前时间,并配置波次和生成规律。
52 /// 第一波僵尸将在关卡开始后18秒出现。
53 ///
54 /// # Returns
55 ///
56 /// 返回一个新的 `LevelController` 实例。
57 pub fn new() -> Self {
58 LevelController {
59 last_spawn_time: Instant::now(),
60 spawn_interval: Duration::from_secs(2), // 同一波内僵尸生成间隔
61 start_time: Instant::now(),
62 current_wave: 0,
63 total_waves: 7, // 总共7波僵尸
64 zombies_spawned_in_wave: 0,
65 zombies_per_wave: 1, // 第一波只有1个僵尸
66 final_wave_announced: false,
67 all_zombies_spawned: false,
68 waiting_for_first_wave: true,
69 }
70 }
71
72 /// 获取当前是否已经宣布最后一波来袭。
73 ///
74 /// 当最后一波僵尸出现时,此方法将返回`true`,可用于在UI上显示"最后一波来袭"的通知。
75 /// 注意:此方法会设置内部标记,确保只返回一次`true`。
76 ///
77 /// # Returns
78 ///
79 /// 如果最后一波已经开始且尚未宣布,则返回`true`;否则返回`false`。
80 pub fn is_final_wave_announced(&mut self) -> bool {
81 if self.current_wave == self.total_waves - 1 && !self.final_wave_announced {
82 self.final_wave_announced = true;
83 return true;
84 }
85 false
86 }
87
88 /// 检查关卡是否胜利完成。
89 ///
90 /// 当所有波次的僵尸都已生成且场上没有活着的僵尸时,表示关卡胜利。
91 ///
92 /// # Arguments
93 ///
94 /// * `zombies` - 当前场上所有僵尸的引用切片。
95 ///
96 /// # Returns
97 ///
98 /// 如果满足胜利条件,则返回`true`;否则返回`false`。
99 pub fn is_level_completed(&self, zombies: &[Zombie]) -> bool {
100 if self.all_zombies_spawned && zombies.is_empty() {
101 return true;
102 }
103 false
104 }
105
106 /// 检查当前场上是否还有僵尸存活。
107 ///
108 /// # Arguments
109 ///
110 /// * `zombies` - 当前场上所有僵尸的引用切片。
111 ///
112 /// # Returns
113 ///
114 /// 如果场上没有活着的僵尸,则返回`true`;否则返回`false`。
115 pub fn is_wave_cleared(&self, zombies: &[Zombie]) -> bool {
116 zombies.is_empty()
117 }
118
119 /// 更新关卡控制器的状态,并决定是否需要生成新的僵尸。
120 ///
121 /// 实现了完整的波次管理逻辑:
122 /// 1. 游戏开始后18秒开始第一波
123 /// 2. 每波内生成指定数量的僵尸
124 /// 3. 波次之间有休息时间
125 /// 4. 难度随波次递增
126 /// 5. 最后一波时会标记"最后一波来袭"
127 ///
128 /// # Arguments
129 ///
130 /// * `_dt` - 自上次更新以来的时间增量(毫秒)。
131 ///
132 /// # Returns
133 ///
134 /// 返回一个 `Vec<ZombieSpawnInfo>`,其中包含所有在本次更新中需要生成的僵尸的信息。
135 /// 如果不需要生成僵尸,则返回空向量。
136 pub fn update(&mut self, _dt: u64, zombies: &[Zombie]) -> Vec<ZombieSpawnInfo> {
137 let mut spawns = Vec::new();
138 let now = Instant::now();
139
140 // 如果已经生成了所有僵尸,直接返回
141 if self.all_zombies_spawned {
142 return spawns;
143 }
144
145 // 等待游戏开始后18秒再生成第一波
146 if self.waiting_for_first_wave {
147 if now.duration_since(self.start_time) < Duration::from_secs(18) {
148 return spawns; // 继续等待
149 }
150 // 18秒后开始第一波
151 self.waiting_for_first_wave = false;
152 self.last_spawn_time = now; // 立即开始生成第一只僵尸
153 }
154
155 // 检查是否需要生成新僵尸
156 if now.duration_since(self.last_spawn_time) >= self.spawn_interval {
157 // 首先检查当前波次是否已经生成了足够数量的僵尸
158 if self.zombies_spawned_in_wave < self.zombies_per_wave {
159 // 在波次内生成一个僵尸
160 let mut rng = rand::thread_rng();
161 let row = rng.gen_range(0..GRID_HEIGHT);
162
163 // 根据波次决定僵尸类型,只有第四波开始才会出现路障僵尸
164 let zombie_type = if self.current_wave >= 3 && rng.gen_range(0..10) < (self.current_wave - 2) {
165 ZombieType::Conehead
166 } else {
167 ZombieType::Normal
168 };
169
170 spawns.push(ZombieSpawnInfo { zombie_type, row });
171
172 self.zombies_spawned_in_wave += 1;
173 self.last_spawn_time = now; // 重置计时器
174
175 println!("生成僵尸: 波次 {}, 僵尸 {}/{}",
176 self.current_wave + 1,
177 self.zombies_spawned_in_wave,
178 self.zombies_per_wave);
179 }
180 // 如果当前波次中的僵尸已经全部生成完毕,并且场上没有存活的僵尸,考虑进入下一波
181 else if self.is_wave_cleared(zombies) {
182 // 波次间隔为6秒
183 if now.duration_since(self.last_spawn_time) >= Duration::from_secs(6) {
184 // 进入下一波
185 self.current_wave += 1;
186
187 // 判断是否所有波次已完成
188 if self.current_wave >= self.total_waves {
189 self.all_zombies_spawned = true;
190 return spawns;
191 }
192
193 // 重置当前波次的僵尸计数
194 self.zombies_spawned_in_wave = 0;
195
196 // 根据波次设置僵尸数量
197 if self.current_wave == 1 || self.current_wave == 2 {
198 // 第二、三波各2只僵尸
199 self.zombies_per_wave = 2;
200 } else if self.current_wave >= 3 {
201 // 后续波次每波递增1只
202 self.zombies_per_wave = self.current_wave;
203 }
204
205 // 最后一波前减少生成间隔,增加难度
206 if self.current_wave == self.total_waves - 1 {
207 self.spawn_interval = Duration::from_secs(1);
208 }
209
210 println!("波次 {} 已开始,僵尸数量: {}", self.current_wave + 1, self.zombies_per_wave);
211 self.last_spawn_time = now; // 重置计时器,准备生成新一波的僵尸
212 }
213 }
214 }
215
216 spawns
217 }
218}