maple 0.4.0

A 3D game engine
Documentation
use maple::prelude::*;
use maple_egui::{
    egui,
    plugin::{EguiPlugin, EguiUpdate},
};

fn main() {
    App::new(Config {
        ..Default::default()
    })
    .add_plugin(Core3D)
    .add_plugin(Physics3D)
    .add_plugin(EguiPlugin)
    .load_scene(PhysicsScene)
    .run();
}

pub struct PhysicsScene;

impl SceneBuilder for PhysicsScene {
    fn build(self, assets: &AssetLibrary) -> Scene {
        let scene = Scene::default();

        scene.spawn(Environment::new(assets.load("res/cayley_interior_4k.hdr")));

        // Camera
        let camera = scene.spawn(
            Camera3D::builder()
                .position(Vec3::new(-10.0, 10.0, -10.0))
                .looking_at((0.0, 0.0, 0.0))
                .far_plane(500.0)
                .build(),
        );
        camera
            .on::<Ready>(|ctx| {
                ctx.get_resource_mut::<Window>().set_cursor_locked(true);
            })
            .on::<Update>(Camera3D::free_fly(5.0, 0.5))
            .on::<Update>(|ctx| {
                let input = ctx.get_resource::<Input>();
                if input.mouse_button_just_pressed.contains(&MouseButton::Left) {
                    let transform = ctx.node_ref().transform;
                    let position = transform.position;
                    let forward = transform.get_forward_vector();
                    let speed = 100.0;

                    let projectile = ctx.scene().spawn(
                        RigidBody3DBuilder::dynamic()
                            .position(position)
                            .linear_velocity(forward * speed)
                            .build(),
                    );
                    projectile.spawn_child(
                        MeshInstance3D::builder()
                            .mesh(ctx.assets().add(Cuboid::default()))
                            .material(ctx.assets().add(Color::BLUE))
                            .scale_factor(0.1)
                            .build(),
                    );
                    projectile.spawn_child(Collider3DBuilder::ball(0.5).mass(10.0).build());
                }
            })
            .on::<EguiUpdate>(|ctx| {
                egui::Window::new("").show(&ctx, |ui| {
                    ui.label("Use left click to shoot!");
                    ui.label(format!(
                        "fps: {}",
                        ctx.get_resource_mut::<Frame>().avg_fps()
                    ));
                    ui.label(format!(
                        "1% low: {}",
                        ctx.get_resource_mut::<Frame>().low_percent(0.01)
                    ))
                });
            });

        // Light
        scene.spawn(
            DirectionalLight::builder()
                .direction(Vec3::new(0.0, -1.0, 0.0))
                .intensity(1.0)
                .build(),
        );

        // Ground - static rigid body with box collider
        let ground = scene.spawn(
            RigidBody3DBuilder::fixed()
                .position(Vec3::new(0.0, -1.0, 0.0))
                .build(),
        );
        ground.spawn_child(
            MeshInstance3D::builder()
                .mesh(assets.add(Cuboid::default()))
                .material(assets.add(PbrMaterial {
                    base_color_factor: Color::WHITE,
                    metallic_factor: 0.5,
                    roughness_factor: 0.5,
                    ..Default::default()
                }))
                .scale(Vec3 {
                    x: 10000.0,
                    y: 1.0,
                    z: 10000.0,
                })
                .build(),
        );
        ground.spawn_child(
            Collider3DBuilder::cuboid(5000.0, 0.5, 5000.0)
                .friction(1000.0)
                .build(),
        );

        let cube_mesh = assets.add(Cuboid::default());
        let material = assets.add(PbrMaterial {
            base_color_factor: Color::MAGENTA,
            roughness_factor: 0.2,
            metallic_factor: 0.2,
            ..Default::default()
        });
        for x in 0..5 {
            for y in 0..5 {
                let body = scene.spawn(
                    RigidBody3DBuilder::dynamic()
                        .position(Vec3::new(x as f32 * 1.01, y as f32 * 1.01, 0.0))
                        .build(),
                );
                body.spawn_child(
                    MeshInstance3D::builder()
                        .mesh(cube_mesh.clone())
                        .material(material.clone())
                        .build(),
                );
                body.spawn_child(Collider3DBuilder::cuboid(0.5, 0.5, 0.5).build());
            }
        }

        scene
    }
}