pvz_rust_wsll 0.2.1

一个用 Rust 实现的植物大战僵尸风格游戏的库和可执行程序。目前基本完成.
Documentation
//! # 向日葵模块 (`sunflower`)
//!
//! 实现了游戏中核心的资源产生单位——向日葵。
//! 向日葵会周期性地产生阳光,供玩家收集并用于购买其他植物。

use crate::ui::grid::{GRID_CELL_HEIGHT, GRID_CELL_WIDTH, GRID_START_X, GRID_START_Y};
use crate::entities::sun::{Sun, SunType};
use crate::entities::pea::Pea;
use crate::plants::plant_trait::PlantTrait;
use crate::core::resources::Resources;
use ggez::graphics;
use crate::zombies::Zombie;
use rand::Rng;

/// 向日葵植物的结构体。
///
/// 包含一个标记字段,用于跟踪是否为第一次产生阳光。
pub struct Sunflower {
    /// 是否为首次生产阳光
    is_first_production: bool,
}

impl Sunflower {
    /// 创建一个新的 `Sunflower` 实例。
    ///
    /// # Returns
    ///
    /// 返回一个新的 `Sunflower` 实例,初始化为首次生产状态。
    pub fn new() -> Self {
        Sunflower {
            is_first_production: true,
        }
    }
}

/// 向日葵的初始生命值。
const INITIAL_HEALTH: i32 = 300;
/// 种植向日葵所需的阳光花费。
const COST: i32 = 50;

impl PlantTrait for Sunflower {
    /// 获取向日葵的初始生命值。
    fn get_initial_health(&self) -> i32 {
        INITIAL_HEALTH
    }

    /// 获取向日葵产生阳光的冷却时间。
    /// 
    /// 如果是首次生产阳光,返回3到12.5秒的随机值(3000-12500ms)
    /// 否则返回正常的23.5到25秒的随机值(23500-25000ms)
    fn get_cooldown(&self) -> u64 {
        if self.is_first_production {
            // 首次生产阳光:3到12.5秒的随机值
            rand::thread_rng().gen_range(3000..=12500)
        } else {
            // 之后的正常生产:23.5到25秒的随机值
            rand::thread_rng().gen_range(23500..=25000)
        }
    }

    /// 获取向日葵动画的总帧数。
    fn get_frame_count(&self) -> usize {
        18 // 向日葵动画有18帧
    }

    /// 更新向日葵的动作,主要是产生阳光。
    ///
    /// 当冷却完成后,此方法被调用。
    /// 它会在向日葵附近的一个随机位置创建一个新的阳光 (`SunType::SunflowerGeneration`),
    /// 并将其添加到游戏世界的阳光列表中。
    ///
    /// # Arguments
    ///
    /// * `grid_x` - 向日葵所在的网格x坐标。
    /// * `grid_y` - 向日葵所在的网格y坐标。
    /// * `_suns` - 阳光列表的引用 (向日葵不产生阳光,故未使用)。
    /// * `_peas` - 豌豆列表的引用 (向日葵不发射豌豆,故未使用)。
    /// * `_zombies` - 僵尸列表的引用 (向日葵的动作不依赖僵尸状态,故未使用)。
    fn update_action(&mut self, grid_x: usize, grid_y: usize, suns: &mut Vec<Sun>, _peas: &mut Vec<Pea>, _zombies: &Vec<Zombie>) {
        // 计算阳光生成的位置 (在向日葵上方一点)
        let sun_x = GRID_START_X + (grid_x as f32) * GRID_CELL_WIDTH + GRID_CELL_WIDTH / 2.0;
        let sun_y = GRID_START_Y + (grid_y as f32) * GRID_CELL_HEIGHT; 

        // 创建新的阳光
        suns.push(Sun::new(sun_x, sun_y, SunType::SunflowerGeneration));
        
        // 如果是首次生产,将标记更新为false,表示后续生产将使用正常时间间隔
        if self.is_first_production {
            self.is_first_production = false;
        }
    }

    /// 获取种植向日葵所需的阳光花费。
    fn get_cost(&self) -> i32 {
        COST
    }

    /// 获取向日葵在商店中显示的卡片图像。
    ///
    /// # Arguments
    ///
    /// * `resources` - 游戏资源实例的引用,用于获取图像。
    ///
    /// # Returns
    ///
    /// 返回向日葵卡片图像的引用。
    fn get_card_image<'a>(&self, resources: &'a Resources) -> &'a graphics::Image {
        &resources.sunflower_card
    }
    
    /// 获取向日葵当前动画帧对应的图像。
    ///
    /// # Arguments
    ///
    /// * `resources` - 游戏资源实例的引用,用于获取动画帧图像序列。
    /// * `animation_frame` - 当前需要显示的动画帧的索引。
    ///
    /// # Returns
    ///
    /// 返回当前动画帧图像的引用。如果图像资源未加载,则返回卡片图像作为备用。
    fn get_current_frame_image<'a>(&self, resources: &'a Resources, animation_frame: usize) -> &'a graphics::Image {
        let frame_count = resources.sunflower_images.len();
        if frame_count > 0 {
            let safe_index = animation_frame % frame_count;
            &resources.sunflower_images[safe_index]
        } else {
            // 如果没有图像,返回卡片
            &resources.sunflower_card
        }
    }
}