Skip to main content

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}