[Day 27] Bevy 游戏引擎 (Part 1)

昨天大概讲完 Rocket 的运用了
所以接下来就来介绍其他东西吧
这次要讲的是 Game Engine
目前 Rust 里面比较大的游戏引擎有两个

  • RG3D
  • Bevy

这次我会介绍 Bevy 因为他比较简单易用
而 RG3D 他可以应付比较大的场景
也有编辑器
整体来说目前 RG3D 的前景是良好的
而 Bevy 也正在快速发展中
Bevy 是以 ECS 存储和管理所有数据
简单来说就是在资料库中。不同数据类型以表的「列」,并且可以存在包含实体的「行」。
比如说给予一个玩家结构血量 还有攻击力跟防御值 这样的概念

那本篇使用版本是 Bevy 0.5.0
且本次不会介绍 Example 直冲专案
那专案的部份我是直接去撰写的所以可能进度上比较缓慢 可能 30 天内写不完
但是我尽量
让我们开始吧!
首先起手式

$ cargo add bevy

就这样 不用添加其他东西了 应该目前也只会用到这个
我想做的是类似於 Undertale 对决 Undyne 时的小游戏
但是简化很多 就单纯箭头飘过去而已

大概这种感觉
好OK 开始ㄅ
今天会做的是 创建会移动的物件

初始化

fn main() {
    App::build()
        .insert_resource(WindowDescriptor {
            title: "owo!".to_string(),
            width: 800.,
            height: 600.,
            ..Default::default()
        })
        .insert_resource(ClearColor(Color::rgb(1., 0.4, 0.4)))
        .run();
}

首先会长这样
就是我们的 main function
那这边主要是创建一个视窗
并且我们给他 长宽 标题以及颜色

fn setup(mut commands: Commands) {
    commands
        .spawn_bundle(OrthographicCameraBundle::new_2d())
        .commands()
        .spawn_bundle(UiCameraBundle::default());
}

然後这边是设置 camera 的部份
因为我们是 2D 游戏所以就直接设置一个 2D 场景


材质

那麽由於我们 ECS 的特性所以在我们要使用材质的时候也要对物件归类

pub struct ArrowMaterial {
    up: Handle<ColorMaterial>,
    down: Handle<ColorMaterial>,
    left: Handle<ColorMaterial>,
    right: Handle<ColorMaterial>,
}

其实不一定要用 pub 但是我只是怕 Debug 麻烦

impl FromWorld for ArrowMaterial {
    fn from_world(world: &mut World) -> Self {
        let world = world.cell();
        let mut material = world.get_resource_mut::<Assets<ColorMaterial>>().unwrap();
        let asset_server = world.get_resource::<AssetServer>().unwrap();
        let up = asset_server.load("up.png");
        let down = asset_server.load("down.png");
        let left = asset_server.load("left.png");
        let right = asset_server.load("right.png");
        ArrowMaterial {
            up: material.add(up.into()),
            down: material.add(down.into()),
            left: material.add(left.into()),
            right: material.add(right.into()),
        }
    }
}

至於这边的部份可以看到说我让他去读取了图片资源
而资源位置会位於 assets 资料夹中

也就是现在档案目录应该要长这样
这边的部份没有什麽技术成份 直接抄就好了
虽然当初也是想很久 第一次写的时候

物件

pub fn spawn_arrow_up(mut commands: Commands,
                      materials: Res<ArrowMaterial>,
                      time: Res<Time>,
                      mut timer: ResMut<SpawnTimer>) {
    if timer.0.tick(time.delta()).just_finished() {
        let transform = Transform::from_translation(Vec3::new(0., -450., 1.));
        commands
            .spawn_bundle(SpriteBundle {
                material: materials.up.clone(),
                sprite: Sprite::new(Vec2::new(100., 100.)),
                transform,
                ..Default::default()
            })
            .insert(UpArrow);
    }
}

那麽既然讲完材质 固然要讲一下如何让物件出现在场景上
而这边我让他去读秒 也就是会随着时间生成

pub struct SpawnTimer(pub Timer);

所以记得要定义好 Struct
这边可以看到说我使用了一个 transform
而也代表了物件的 x, y, z
至於 z 的部份由於我们是 2D 游戏所以不会有任何影响
然後材质记得要用 clone 的新增
而 sprite 是大小的意思 可以自己设定

移动物件

fn up_arrows(time: Res<Time>, mut query: Query<(&mut Transform, &UpArrow)>) {
    for (mut transform, _arrow) in query.iter_mut() {
        transform.translation.y += time.delta_seconds() * 200.;
    }
}

而这边的部份就比较简单了
就是随着时间去更改他的位置
而也因为他时间是使用 float 所以看起来会是缓慢移动的感觉
後面的 200. 是速度
然後上面的 for 回圈是 tuple 是因为他包含了两个项目
总之大概这样


upd

早上起来才发现有地方少讲
基本上要使用弄好的 function
就只要在 main function 里面 在 App build 那边的最下面使用 .add_system(<函数名称>.system())
要注意的是 函数名称不包含 ()
明天我们来讲另一个统整的方法

而最後运行会长这样

而其他四个方向就由读者自行操作了
今天大概这样 打 BNT 手有点痛


<<:  DAY19 - 在win10家用版上安装Docker Desktop

>>:  Day 19. v-bind - Class的绑定

学习Python纪录Day10 - 变数的有效范围

变数的有效范围 全域变数(Global Variables) 函式之外的变数为全域变数没有属於哪一个...

Day 14:动态 Route 对号入座

上篇完成了巢状路由的设置之後,紧接着新需求又出现了!接续会员後台的收藏纪录页面,我们要进一步让收藏的...

DAY12 - 使用 angular fire 操作firebase

firebase sdk 是什麽 firebase sdk 是 firebase 官方推出和 fir...

D30. 学习基础C、C++语言

D30. 心得 虽然之前已经有学过一些C语言,但经过这30天的自学还是学到很多东西,像是C语言之前我...

第六天:首次启动设定

若是您选择以软件包或 Docker 这种 On Premises 的安装方式安装在本机电脑的话,那首...