用 Rust + Bevy 游戏引擎打造一个可爱的桌面宠物伙伴

  • King
  • 发布于 8小时前
  • 阅读 28

前言你是否想过在电脑桌面上养一只可爱的虚拟宠物?它可以是你的AI助手,在你工作疲惫时给你一些治愈感。今天,我们就用Rust和Bevy游戏引擎,从零开始设计一个常驻桌面的AI助手!技术选型为什么选择Rust?高性能:系统级性能,运行流畅不卡顿内存安全:无GC,无

前言

你是否想过在电脑桌面上养一只可爱的虚拟宠物? 它可以是你的 AI 助手,在你工作疲惫时给你一些治愈感。

今天,我们就用 Rust 和 Bevy 游戏引擎,从零开始设计一个常驻桌面的 AI 助手!

技术选型

为什么选择 Rust?

  • 高性能:系统级性能,运行流畅不卡顿
  • 内存安全:无 GC,无悬垂指针烦恼
  • 跨平台:支持 Windows、macOS、Linux

为什么选择 Bevy?

Bevy 是一个简单、数据驱动的游戏引擎,特点包括:

  • ECS 架构:Entity-Component-System,代码结构清晰
  • 热重载:开发体验极佳
  • 原生支持 2D:非常适合做桌面宠物

项目架构设计

让我们先规划一下项目的模块划分:

src/
├── main.rs       # 应用入口,系统集成
├── pet.rs        # 宠物状态系统
├── animation.rs  # 动画控制
├── ui.rs         # 用户界面
└── window.rs     # 窗口配置

核心实现

1. 项目配置

首先创建 Cargo.toml,添加必要依赖:

[package]
name = "ai-assistant"
version = "0.1.0"
edition = "2024"

[dependencies]
bevy = "0.18"
log = "0.4"

[profile.release]
opt-level = "z"
lto = true
codegen-units = 1

2. 透明置顶窗口

桌面助手的灵魂在于——透明背景始终置顶。让我们配置窗口:

use bevy::prelude::*;
use bevy::window::{WindowPlugin, CompositeAlphaMode, WindowLevel};

pub fn window_plugin() -> WindowPlugin {
    WindowPlugin {
        primary_window: Some(Window {
            title: "AI Assistant".into(),
            resolution: (140_u32, 180_u32).into(),  // 小巧的窗口尺寸
            decorations: false,                      // 无边框
            transparent: true,                       // 透明背景
            resizable: false,
            movable_by_window_background: true,      // 可拖拽
            window_level: WindowLevel::AlwaysOnTop,  // 始终置顶
            #[cfg(target_os = "macos")]
            composite_alpha_mode: CompositeAlphaMode::PostMultiplied,
            #[cfg(target_os = "linux")]
            composite_alpha_mode: CompositeAlphaMode::PreMultiplied,
            ..default()
        }),
        ..default()
    }
}

关键点说明

  • transparent: true + CompositeAlphaMode 配合实现真正的透明
  • WindowLevel::AlwaysOnTop 确保助手始终可见
  • movable_by_window_background: true 让用户可以拖动助手

3. 宠物状态系统

设计一个有"生命感"的助手,需要有状态系统:

#[derive(Component)]
pub struct Pet {
    pub hunger: f32,    // 饥饿度 (0-100)
    pub happiness: f32, // 快乐度 (0-100)
    pub energy: f32,    // 能量值 (0-100)
}

impl Pet {
    pub fn new() -> Self {
        Self {
            hunger: 80.0,
            happiness: 80.0,
            energy: 100.0,
        }
    }

    pub fn mood(&self) -> PetMood {
        if self.hunger < 20.0 {
            PetMood::Hungry
        } else if self.energy < 20.0 {
            PetMood::Sleepy
        } else if self.happiness < 30.0 {
            PetMood::Sad
        } else {
            PetMood::Happy
        }
    }
}

状态会随时间自然衰减,让助手更有"生命感":

pub fn update_pet_state(
    time: Res<Time>,
    mut pet_query: Query<&mut Pet>,
) {
    for mut pet in &mut pet_query {
        pet.hunger = (pet.hunger - 1.5 * time.delta_secs()).clamp(0.0, 100.0);
        pet.happiness = (pet.happiness - 1.0 * time.delta_secs()).clamp(0.0, 100.0);
        pet.energy = (pet.energy - 0.8 * time.delta_secs()).clamp(0.0, 100.0);
    }
}

4. 精灵动画系统

根据宠物心情切换不同的动画帧:

#[derive(Component, Clone, Copy)]
pub struct AnimationIndices {
    pub first: usize,
    pub last: usize,
}

pub fn animate_sprite(
    time: Res<Time>,
    mut query: Query<(&AnimationIndices, &mut AnimationTimer, &mut Sprite)>,
) {
    for (indices, mut timer, mut sprite) in &mut query {
        timer.tick(time.delta());

        if timer.just_finished() {
            if let Some(atlas) = &mut sprite.texture_atlas {
                atlas.index = if atlas.index >= indices.last {
                    indices.first
                } else {
                    atlas.index + 1
                };
            }
        }
    }
}

精灵图采用 4x4 网格布局,不同心情对应不同的行:

pub enum PetMood {
    Happy,   // 帧 0-3
    Hungry,  // 帧 4-7
    Sleepy,  // 帧 8-11
    Sad,     // 帧 12-15
}

5. 交互菜单

点击助手弹出交互菜单:

pub fn setup_ui(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut textures: ResMut<Assets<TextureAtlasLayout>>,
) {
    // 创建精灵图集
    let layout = TextureAtlasLayout::from_grid(UVec2::splat(128), 4, 4, None, None);
    let texture_atlas_layout = textures.add(layout);

    // 生成宠物精灵
    commands.spawn((
        Node {
            width: Val::Px(80.0),
            height: Val::Px(80.0),
            ..default()
        },
        PetSprite,
        Button,  // 可点击
    ))
    .with_children(|pet| {
        pet.spawn((
            Sprite::from_atlas_image(
                asset_server.load("textures/pony.png"),
                TextureAtlas { layout: texture_atlas_layout, index: 0 },
            ),
            // 动画组件...
        ));
    });

    // 创建交互菜单(默认隐藏)
    commands.spawn((
        ActionMenuContainer,
        Visibility::Hidden,
        // Feed、Pet、Play 按钮...
    ));
}

6. 主程序入口

最后,将所有系统集成到一起:

fn main() {
    App::new()
        .insert_resource(ClearColor(Color::NONE))  // 透明背景
        .add_plugins(DefaultPlugins.set(window::window_plugin()))
        .add_systems(Startup, setup_ui)
        .add_systems(Update, (
            animate_sprite, 
            update_pet_state, 
            update_mood_animation,
            handle_pet_click,
            handle_menu_actions,
        ))
        .run();
}

项目亮点总结

特性 实现方式
透明窗口 transparent: true + CompositeAlphaMode
始终置顶 WindowLevel::AlwaysOnTop
可拖动 movable_by_window_background: true
动画切换 基于 TextureAtlas 的帧动画
状态衰减 基于时间的数值递减
交互反馈 点击触发状态变更 + 动画切换

运行效果

编译运行:

cargo run --release

你将看到一只可爱的小马出现在桌面上:

  • 😊 心情好时欢快地蹦跳
  • 🍎 饿了会做出饥饿的动作
  • 😴 累了会打瞌睡
  • 😢 不开心时垂头丧气

点击它,可以选择喂食、抚摸、玩耍来提升它的心情!

扩展思路

这个项目还有很大的扩展空间:

  1. 接入真正的 AI:集成大模型 API,让助手能对话
  2. 通知提醒:结合系统通知,定时提醒休息
  3. 多人互动:不同桌面助手之间可以"串门"
  4. 自定义外观:支持导入任意精灵图,打造个性化助手

结语

通过这个项目,我们学习了:

  • Bevy 游戏引擎的 ECS 架构
  • 桌面透明窗口的实现技巧
  • 精灵动画系统设计
  • 游戏状态管理

希望这篇教程能激发你的创意,打造出属于自己的桌面 AI 助手!

参考资料

点赞 0
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
King
King
0x56af...a0dd
擅长Rust/Solidity/FunC/Move开发