#game-engine #ecs #multi-threading #performance #graphics

ABC_Game_Engine

一个简单、快速且灵活的由 Rust 编写的游 戏 引擎,注重简洁性

3 个 版 本

0.1.2 2024 年 7 月 25 日
0.1.1 2024 年 7 月 25 日
0.1.0 2024 年 7 月 25 日

#719 in 游 戏 开 发


2 库 中使用

MIT/Apache

135KB
3K SLoC

s2Kkdcv

网站

建设中 🚧

该项目仍在建设中,处于预发布阶段。可能会进行重大更改,可能会破坏某些功能。我们为此带来的不便表示歉意。

易用性

这个项目的想法是使其使用起来非常直观,以至于可以通过这个游 戏 引擎学习 Rust。当你可以制作出可交互的东 西,而不是仅仅操作数据时,学习通常会更好,我们希望在 Rust 中提供这种机会。

操作系统 支持

大多数主要操作系 统 应该 支持,然而只有 Windows 已经经过测试。

当前功能

有关计划中或已完成的功能的完整列表,请访问 这里

渲染器

一个 控制台渲染器 和一个 像素艺术渲染器

物理 引擎

使用 Rapier 进行物理,并可作为资源访问碰撞信息。

一个简单的 平 台 游 戏 示例

use ABC_Game_Engine::physics::rapier2d::geometry::Ray;
use ABC_Game_Engine::physics::rapier2d::math::Real;
use ABC_Game_Engine::physics::rapier2d::na as nalgebra;
use ABC_Game_Engine::physics::rapier2d::na::vector;
use ABC_Game_Engine::prelude::*;
use ABC_lumenpyx::prelude::*;

struct Player;
struct Ground;

struct PlayerController {
    speed: f32,
    jump_force: f32,
}

impl System for PlayerController {
    fn run(&mut self, entities_and_components: &mut EntitiesAndComponents) {
        let player_entity;
        let (player_x, player_y) = {
            let player_entities = entities_and_components
                .get_entities_with_component::<Player>()
                .cloned()
                .collect::<Vec<Entity>>();

            player_entity = player_entities[0];

            let (transform,) =
                entities_and_components.get_components::<(Transform,)>(player_entity);
            (transform.x, transform.y)
        };

        let delta_time: f32;
        let mut normalized_dir = [0.0 as f32; 2];
        {
            delta_time = entities_and_components
                .get_resource::<DeltaTime>()
                .expect("Failed to get DeltaTime resource")
                .get_delta_time() as f32;

            let physics_info = entities_and_components
                .get_resource::<RapierPhysicsInfo>()
                .expect("Failed to get PhysicsInfo resource");

            let input = entities_and_components.get_resource::<Input>().unwrap();

            if input.get_key_state(KeyCode::A) == KeyState::Held {
                normalized_dir[0] -= 1.0;
            }

            if input.get_key_state(KeyCode::D) == KeyState::Held {
                normalized_dir[0] += 1.0;
            }

            let is_ground_check = |collider_handle: ColliderHandle, _: &Collider| {
                let entity = physics_info
                    .get_associated_entity_with_collider_handle(collider_handle.into())
                    .expect("Failed to get associated entity with collider handle");

                entities_and_components
                    .try_get_components::<(Ground,)>(entity)
                    .0
                    .is_some()
            };

            let is_ground_filter = QueryFilter {
                predicate: Some(&is_ground_check),
                ..Default::default()
            };

            let intersection = physics_info.cast_ray(
                &Ray::new(
                    vector![player_x as f32, player_y as f32 - 5.01].into(),
                    vector![0.0, -1.0],
                ),
                Real::MAX,
                true,
                is_ground_filter,
            );

            if input.get_key_state(KeyCode::Space) == KeyState::Pressed && intersection.is_some() {
                let intersection = intersection.unwrap();

                if intersection.1 < 0.01 {
                    normalized_dir[1] = 1.0;
                }
            }
        }

        if let (Some(_), Some(_), Some(rigid_body)) = entities_and_components
            .try_get_components_mut::<(Player, Transform, RigidBody)>(player_entity)
        {
            rigid_body.apply_impulse(
                vector![
                    normalized_dir[0] * self.speed * delta_time,
                    normalized_dir[1] * self.jump_force,
                ],
                true,
            );
        }
    }
}

fn main() {
    let mut scene = Scene::new();

    let mut lumenpyx_eventloop =
        LumenpyxEventLoop::new(&mut scene.world, [160, 160], "Platformer Example");

    lumenpyx_eventloop.set_render_settings(
        &mut scene.world,
        RenderSettings::default()
            .with_reflections(false)
            .with_shadows(false),
    );
    {
        let entities_and_components = &mut scene.world.entities_and_components;

        let camera = Camera::new();

        entities_and_components.add_entity_with((camera, Transform::default()));

        let ball = Circle::new([1.0, 1.0, 1.0, 1.0], 5.0);

        let circle_collider = ColliderBuilder::ball(5.0).build();
        let circle_rb = RigidBodyBuilder::dynamic().additional_mass(1.0).build();

        entities_and_components.add_entity_with((
            ball,
            Transform {
                x: -20.0,
                y: -20.0,
                z: 0.0,
                rotation: 0.0,
                scale: 1.0,
                origin_x: 0.0,
                origin_y: 0.0,
            },
            circle_rb,
            circle_collider,
            Player {},
        ));

        let ground_collider = ColliderBuilder::cuboid(160.0, 5.0).build();
        let ground_rb = RigidBodyBuilder::fixed().build();
        let ground_rect = Rectangle::new([0.0, 1.0, 1.0, 1.0], 160.0, 10.0);

        entities_and_components.add_entity_with((
            ground_rect,
            Transform {
                x: 0.0,
                y: -80.0,
                z: 0.0,
                rotation: 0.0,
                scale: 1.0,
                origin_x: 0.0,
                origin_y: 0.0,
            },
            ground_collider,
            ground_rb,
            Ground {},
        ));
    }

    scene.world.add_system(PlayerController {
        speed: 1000.0,
        jump_force: 3000.0,
    });

    physics::add_default_physics_systems(&mut scene.world);

    let physics_info = scene
        .world
        .entities_and_components
        .get_resource_mut::<RapierPhysicsInfo>();

    physics_info
        .expect("Failed to get PhysicsInfo resource")
        .set_gravity([0.0, -9.81 * 4.0].into());

    lumenpyx_eventloop.run(&mut scene.world, |world| {
        world.run();

        render(&mut world.entities_and_components);
    });
}

依 赖 项

~14–47MB
~761K SLoC