Skip to content

GrenAnHao/Snake2D-Rust

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Snake 2D - 模块化贪吃蛇游戏

一个使用 Rust + Macroquad 开发的高度可扩展贪吃蛇游戏,采用模块化架构设计。

🎮 游戏特性

  • 丰富的果实系统: 15种不同果实,包括普通、陷阱、功能和特殊类型
  • AI蛇系统: 蛇蛋孵化出的AI蛇,增加游戏挑战性
  • 多种Buff效果: 护盾、速度、幽灵、冰冻、减速、眩晕、粘液等
  • 沙虫模式: 独特的多阶段变身动画,可吞噬AI蛇
  • 视觉特效: 粒子系统、血迹、传送门、残影效果
  • 音效系统: 程序化生成的WAV音效
  • Combo系统: 连续吃果实获得额外分数

🚀 快速开始

# 编译并运行
cargo run --bin snake2d

# 运行测试
cargo test

# 发布构建
cargo build --release

🎯 操作说明

按键 功能
↑↓←→ 移动方向
Space 暂停/继续
Enter/R 重新开始
W 切换穿墙模式

📁 项目结构

src/
├── lib.rs                 # 库入口,导出所有模块
├── snake2d_v2.rs          # 游戏主入口(GameWorld)
├── constants.rs           # 游戏常量配置
│
├── types/                 # 数据类型定义
│   ├── mod.rs             # 模块导出
│   ├── game_state.rs      # 游戏状态枚举
│   ├── buff.rs            # Buff状态结构体
│   ├── damage.rs          # 受伤状态
│   ├── particle.rs        # 粒子结构体
│   ├── portal.rs          # 传送门结构体
│   ├── combo.rs           # Combo状态
│   └── fruit.rs           # 果实实例
│
├── game/                  # 游戏核心逻辑
│   ├── mod.rs             # 模块导出
│   ├── snake.rs           # 蛇状态和移动
│   ├── collision.rs       # 碰撞检测
│   ├── spawn.rs           # 生成逻辑
│   ├── spawn_manager.rs   # 声明式果实生成管理器
│   ├── buff_manager.rs    # Buff管理
│   ├── bomb_manager.rs    # 炸弹逻辑封装
│   ├── damage_manager.rs  # 受伤动画
│   ├── fruit_handler.rs   # 果实消费处理
│   ├── ai_snake.rs        # AI蛇结构体和行为
│   └── ai_manager.rs      # AI蛇管理器
│
├── render/                # 渲染模块
│   ├── mod.rs             # 模块导出
│   ├── snake_renderer.rs  # 蛇渲染
│   ├── fruit_renderer.rs  # 果实渲染
│   ├── effect_renderer.rs # 特效渲染
│   ├── hud_renderer.rs    # HUD渲染
│   ├── sandworm_renderer.rs # 沙虫渲染
│   └── ai_snake_renderer.rs # AI蛇渲染
│
├── audio/                 # 音效模块
│   ├── mod.rs             # 模块导出
│   └── sound_manager.rs   # 音效管理器
│
└── fruits/                # 果实系统(可扩展)
    ├── mod.rs             # 模块导出和注册表创建
    ├── fruit_trait.rs     # FruitBehavior Trait定义
    ├── fruit_registry.rs  # 果实注册表(含动态权重计算)
    ├── fruit_context.rs   # 扩展的果实上下文(可直接操作游戏资源)
    ├── normal/            # 普通果实
    ├── trap/              # 陷阱果实(含炸弹)
    ├── power/             # 功能果实
    └── special/           # 特殊果实(蛇蛋带 on_expire 回调)

🏗️ 架构设计

核心设计原则

  1. 关注点分离: 游戏逻辑、渲染、音效完全独立
  2. Trait驱动: 果实系统通过 FruitBehavior Trait 实现可扩展性
  3. 数据驱动: 果实配置与行为分离,便于调整平衡性
  4. 声明式架构: 通过 FruitSpawnManager 配置生成规则,无需修改主循环
  5. 回调封装: 果实的 on_consume/on_expire 直接操作游戏资源
  6. 属性测试: 使用 proptest 验证核心逻辑正确性

模块依赖关系

┌─────────────────────────────────────────────────────────┐
│                    snake2d_v2.rs                        │
│                    (游戏主循环)                          │
└─────────────────────────────────────────────────────────┘
         │              │              │              │
         ▼              ▼              ▼              ▼
    ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐
    │  game   │   │ render  │   │  audio  │   │ fruits  │
    │ (逻辑)  │   │ (渲染)  │   │ (音效)  │   │ (果实)  │
    └─────────┘   └─────────┘   └─────────┘   └─────────┘
         │              │              │              │
         └──────────────┴──────────────┴──────────────┘
                               │
                               ▼
                        ┌─────────────┐
                        │   types     │
                        │ (数据结构)  │
                        └─────────────┘
                               │
                               ▼
                        ┌─────────────┐
                        │ constants   │
                        │  (常量)     │
                        └─────────────┘

🔌 扩展指南

添加新果实

  1. 创建果实结构体
// src/fruits/power/my_fruit.rs
use macroquad::prelude::*;
use crate::fruits::{FruitBehavior, FruitConfig, FruitCategory, FruitContext, ConsumeResult};
use crate::constants::CELL;

pub struct MyFruit {
    config: FruitConfig,
}

impl MyFruit {
    pub fn new() -> Self {
        MyFruit {
            config: FruitConfig {
                id: "my_fruit",           // 唯一标识
                name: "我的果实",          // 显示名称
                category: FruitCategory::Power,  // 类别
                color: Color { r: 1.0, g: 0.5, b: 0.0, a: 1.0 },  // 基础颜色
                lifetime: 10.0,           // 存在时长(0=永久)
                spawn_weight: 10,         // 生成权重(基础值)
                unlock_length: 5,         // 解锁所需蛇长
                immune_to_buffs: false,   // 是否受Buff免疫影响
                weight_growth: 0,         // 权重增长系数(0=不增长)
            },
        }
    }
}

impl FruitBehavior for MyFruit {
    fn config(&self) -> &FruitConfig {
        &self.config
    }

    fn on_consume(&self, ctx: &mut FruitContext) -> ConsumeResult {
        // 实现消费效果
        ctx.snake.push(ctx.snake.last().cloned().unwrap()); // 增长一节
        ConsumeResult::AddScore(50)
    }

    // 可选:自定义渲染
    fn render(&self, x: f32, y: f32, time: f32) {
        let pulse = (time * 4.0).sin() * 0.2 + 0.8;
        let color = Color { a: pulse, ..self.config.color };
        draw_rectangle(x, y, CELL, CELL, color);
    }
}
  1. 注册果实
// src/fruits/mod.rs
pub mod my_fruit;
use my_fruit::MyFruit;

pub fn create_fruit_registry() -> FruitRegistry {
    let mut registry = FruitRegistry::new();
    // ... 其他果实
    registry.register(Box::new(MyFruit::new()));
    registry
}

添加新Buff效果

  1. 在 BuffState 中添加字段
// src/types/buff.rs
pub struct BuffState {
    // ... 现有字段
    pub my_buff_active: bool,
    pub my_buff_timer: f32,
}
  1. 在 buff_manager 中添加更新逻辑
// src/game/buff_manager.rs
impl BuffState {
    pub fn update(&mut self, dt: f32) {
        // ... 现有逻辑
        if self.my_buff_active {
            self.my_buff_timer -= dt;
            if self.my_buff_timer <= 0.0 {
                self.my_buff_active = false;
            }
        }
    }

    pub fn activate_my_buff(&mut self) {
        self.my_buff_active = true;
        self.my_buff_timer = 5.0;
    }
}
  1. 在渲染中添加视觉效果
// src/render/snake_renderer.rs
pub fn draw_snake(...) {
    // ... 现有逻辑
    if buff.my_buff_active {
        // 自定义视觉效果
    }
}

添加新渲染效果

// src/render/effect_renderer.rs
pub fn draw_my_effect(snake_body: &[IVec2], time: f32) {
    for seg in snake_body {
        let x = seg.x as f32 * CELL;
        let y = seg.y as f32 * CELL;
        // 绘制效果
    }
}

🧪 测试

项目使用 proptest 进行属性测试,验证核心逻辑的正确性:

# 运行所有测试
cargo test

# 运行特定模块测试
cargo test game::snake
cargo test game::collision
cargo test audio::sound_manager

属性测试覆盖

属性 描述 验证内容
Property 1 蛇移动保持长度 移动不改变蛇身长度
Property 2 碰撞检测正确性 自撞检测逻辑正确
Property 3 生成位置有效性 生成位置不与蛇身/果实重叠
Property 4 Buff计时器单调递减 计时器正确递减
Property 5 WAV格式有效性 生成的WAV文件格式正确
Property 6 果实解锁条件 解锁逻辑正确

📊 性能优化

  • 固定时间步长: 游戏逻辑以固定间隔更新,渲染帧率独立
  • 插值渲染: 蛇身位置在帧间插值,实现平滑移动
  • 粒子池: 粒子系统自动回收过期粒子
  • Release构建: 启用LTO和单代码单元优化

🎨 果实类型一览

普通果实 (Normal)

果实 效果
普通 +10分,蛇增长1节

陷阱果实 (Trap)

果实 效果
陷阱 蛇缩短2节,受伤动画
冰冻 冻结2秒
减速 移动速度减半5秒
眩晕 方向随机偏移5秒
粘液 移动拖拽效果5秒
炸弹 吞食后炸弹在体内移动,到达中间位置时爆炸,将蛇拦腰炸断(蛇越长出现概率越高)

功能果实 (Power)

果实 效果
护盾 免疫负面效果10秒
速度 移动速度翻倍5秒
幽灵 可穿过任何物体5秒(墙壁、自身),AI蛇也可穿过玩家,但不免疫Debuff
反转 头尾互换
沙虫 触发沙虫全屏吞噬
恢复 瞬间清除所有Debuff(包括炸弹),+20分

特殊果实 (Special)

果实 效果
幸运方块 随机触发其他果实效果(包括生成AI蛇)
蛇蛋 过期时自动孵化AI蛇;吃掉可阻止孵化(+5分)

🐍 AI蛇系统

触发方式

  • 蛇蛋果实: 蛇蛋过期时自动孵化AI蛇(吃掉蛇蛋可阻止孵化)
  • 幸运方块: 负面效果之一是生成AI蛇

AI蛇特性

  • 随机颜色(橙、紫、粉、天蓝、金、洋红)
  • 会寻找并吃掉食物和果实
  • 吃到食物会增长
  • 会受到Buff影响(冰冻、减速、眩晕等)
  • 最多同时存在3条AI蛇

碰撞规则

碰撞类型 结果
玩家蛇头 → AI蛇身体 玩家死亡(除非有护盾/幽灵)
AI蛇头 → 玩家身体 AI蛇死亡,掉落食物
AI蛇头 → 其他AI蛇 AI蛇死亡,掉落食物
沙虫 → AI蛇 AI蛇被吞噬(不掉落)

死亡掉落

AI蛇死亡时,身体每节变成一个食物,随机散落在附近,10秒后消失。

📜 许可证

MIT License

🤝 贡献

欢迎提交 Issue 和 Pull Request!

About

一个使用 Rust + Macroquad 开发的高度可扩展贪吃蛇游戏,采用模块化架构设计

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages