游戏介绍

这是一个基于 Rust 语言开发的命令行摘苹果小游戏。游戏中,玩家将控制一个角色在屏幕底部左右移动,接住从上方掉落的苹果得分。随着分数增加,苹果掉落速度会逐渐加快,增加游戏挑战性。游戏结束后会显示最终得分。

游戏特色与难点
难度递增机制:随着玩家得分增加,苹果生成间隔会按一定比例缩短(difficulty_increase_rate),使游戏难度逐渐提高,增加挑战性。
终端交互处理:使用 crossterm 库实现非阻塞式输入处理,确保游戏流畅运行而不会在等待输入时卡顿。
帧率控制:通过计时器控制游戏状态更新频率(update_interval),使游戏速度稳定可控。
跨平台兼容性:借助 crossterm 库的跨平台特性,游戏可以在 Windows、macOS 和 Linux 等不同操作系统上运行。
游戏扩展

总结

这款命令行摘苹果游戏虽然简单,但涵盖了游戏开发的基本要素:游戏循环、输入处理、状态更新、碰撞检测和画面渲染。通过 Rust 语言的特性和相关库的使用,我们能够高效地开发出这样一个交互性强、运行流畅的终端游戏。

Rust 的内存安全特性和高性能保证了游戏的稳定运行,而面向对象的设计使代码结构清晰、易于维护和扩展。这个项目不仅适合作为 Rust 初学者的练习项目,也展示了在命令行环境下开发小游戏的可能性。

通过开发这款游戏,我们可以深入理解游戏开发的基本原理,以及如何在 Rust 中处理终端交互、时间控制和状态管理等关键技术点。希望这个项目能为你的 Rust 学习和游戏开发之路提供一些帮助和启发。

​
use crossterm::{
    event::{self, Event, KeyCode, KeyEvent},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use rand::Rng;
use std::{
    collections::VecDeque,
    io,
    time::{Duration, Instant},
};
use tui::{
    backend::{Backend, CrosstermBackend},
    layout::{Constraint, Direction, Layout},
    widgets::{Block, Borders, Paragraph, Text},
    Terminal,
};

struct Apple {
    x: u16,
    y: u16,
}

struct Player {
    x: u16,
    y: u16,
}

struct Game {
    player: Player,
    apples: VecDeque<Apple>,
    score: u32,
    width: u16,
    height: u16,
    game_over: bool,
    last_apple_spawn: Instant,
    apple_spawn_interval: Duration,
    difficulty_increase_rate: f32,
}

impl Game {
    fn new(width: u16, height: u16) -> Self {
        Self {
            player: Player {
                x: width / 2,
                y: height - 2,
            },
            apples: VecDeque::new(),
            score: 0,
            width,
            height,
            game_over: false,
            last_apple_spawn: Instant::now(),
            apple_spawn_interval: Duration::from_secs(1),
            difficulty_increase_rate: 0.95,
        }
    }

    fn spawn_apple(&mut self) {
        let mut rng = rand::thread_rng();
        let x = rng.gen_range(1..self.width - 1);
        self.apples.push_back(Apple { x, y: 1 });
    }

    fn update(&mut self) {
        // 检查是否需要生成新苹果
        if Instant::now() - self.last_apple_spawn > self.apple_spawn_interval {
            self.spawn_apple();
            self.last_apple_spawn = Instant::now();
        }

        // 移动所有苹果
        let mut i = 0;
        while i < self.apples.len() {
            self.apples[i].y += 1;
            
            // 检查苹果是否被玩家接住
            if self.apples[i].y == self.player.y && self.apples[i].x == self.player.x {
                self.apples.remove(i);
                self.score += 1;
                
                // 随着分数增加,加快苹果生成速度
                self.apple_spawn_interval = Duration::from_secs_f32(
                    self.apple_spawn_interval.as_secs_f32() * self.difficulty_increase_rate
                );
            }
            // 检查苹果是否落地(游戏结束)
            else if self.apples[i].y >= self.height - 1 {
                self.game_over = true;
                break;
            } else {
                i += 1;
            }
        }
    }

    fn handle_input(&mut self, key: KeyCode) {
        match key {
            KeyCode::Left => {
                if self.player.x > 1 {
                    self.player.x -= 1;
                }
            }
            KeyCode::Right => {
                if self.player.x < self.width - 2 {
                    self.player.x += 1;
                }
            }
            KeyCode::Q => {
                self.game_over = true;
            }
            _ => {}
        }
    }

    fn render<B: Backend>(&self, terminal: &mut Terminal<B>) -> io::Result<()> {
        let mut game_area = String::new();
        
        // 绘制顶部边框
        game_area.push_str(&"─".repeat(self.width as usize));
        game_area.push('\n');
        
        // 绘制游戏区域
        for y in 1..self.height - 1 {
            game_area.push('│');
            
            for x in 1..self.width - 1 {
                // 检查是否是苹果
                let is_apple = self.apples.iter().any(|a| a.x == x && a.y == y);
                // 检查是否是玩家
                let is_player = self.player.x == x && self.player.y == y;
                
                if is_apple {
                    game_area.push('🍎');
                } else if is_player {
                    game_area.push('😀');
                } else {
                    game_area.push(' ');
                }
            }
            
            game_area.push('│');
            game_area.push('\n');
        }
        
        // 绘制底部边框
        game_area.push_str(&"─".repeat(self.width as usize));
        game_area.push('\n');
        
        // 绘制分数和控制说明
        game_area.push_str(&format!("得分: {}\n", self.score));
        game_area.push_str("使用 ← → 键移动,Q 键退出游戏\n");
        
        if self.game_over {
            game_area.push_str(&format!("\n游戏结束!最终得分: {}\n", self.score));
            game_area.push_str("按 Q 键退出\n");
        }
        
        let para = Paragraph::new(Text::raw(game_area))
            .block(Block::default().borders(Borders::ALL).title("摘苹果游戏"));
        
        terminal.draw(|f| {
            let size = f.size();
            f.render_widget(para, size);
        })?;
        
        Ok(())
    }

    fn run(&mut self) -> io::Result<()> {
        // 初始化终端
        enable_raw_mode()?;
        let mut stdout = io::stdout();
        execute!(stdout, EnterAlternateScreen)?;
        let backend = CrosstermBackend::new(stdout);
        let mut terminal = Terminal::new(backend)?;
        terminal.clear()?;

        // 游戏主循环
        let mut last_update = Instant::now();
        let update_interval = Duration::from_millis(200);
        
        while !self.game_over {
            // 处理输入
            if event::poll(Duration::from_millis(10))? {
                if let Event::Key(event) = event::read()? {
                    self.handle_input(event.code);
                }
            }
            
            // 更新游戏状态
            if Instant::now() - last_update > update_interval {
                self.update();
                last_update = Instant::now();
            }
            
            // 渲染游戏
            self.render(&mut terminal)?;
        }

        // 清理终端
        disable_raw_mode()?;
        execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
        terminal.show_cursor()?;
        
        Ok(())
    }
}

fn main() -> io::Result<()> {
    let game_width = 40;
    let game_height = 20;
    
    let mut game = Game::new(game_width, game_height);
    game.run()
}

​

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐