15 releases

0.0.15 Jun 13, 2020
0.0.14 Jun 9, 2020

#513 in WebAssembly

29 downloads per month

MIT/Apache

150KB
847 lines

babylon.rs

docs.rs docs

A WebAssembly wrapper for babylon.js in Rust.

This project is pre-alpha and the api is in active exploration. Current priorities:

  • get a basic GLTF up
  • get a camera
  • get some sort of interaction

This project uses js_ffi for javascript binding and lazy_static for global static singletons fairly extensively.

Idioms

  • Scenes hold 3D objects
  • Materials determine how a 3D object looks
  • When an 3D object drops it's removed from the scene

HelloWorld

use babylon::prelude::*;
#[macro_use]
extern crate lazy_static;
use std::sync::Mutex;

lazy_static! {
    static ref GAME: Mutex<Game> = Mutex::new(Game::new());
}

struct Game {
    scene: Scene,
    shape: Vec<Sphere>,
}

impl Game {
    fn new() -> Self {
        Game {
            scene: Scene::create_from_basic_engine("#renderCanvas"),
            shape: vec![],
        }
    }
}

#[no_mangle]
pub fn main() {
    babylon::js::log("Starting demo...");
    let mut game = GAME.lock().unwrap();
    for _ in 0..10 {
        let mut sphere = Sphere::new(&game.scene, babylon::js::random());
        sphere.set_position(Vector::new(
            babylon::js::random() - 0.5,
            babylon::js::random() - 0.5,
            babylon::js::random() - 0.5,
        ));
        game.shape.push(sphere);
    }
}

See this demo here ( be sure to play with mouse and arrow keys ⬅️ ⬆️ ⬇️ ➡️!)

Materials

let mut game = GAME.lock().unwrap();
for _ in 0..10 {
    let mut cube = Cube::new(
        &game.scene,
        babylon::js::random(),
        babylon::js::random(),
        babylon::js::random(),
    );
    let mut mat = StandardMaterial::new(&game.scene);
    mat.set_diffuse_color(Color::new(babylon::js::random(),babylon::js::random(),babylon::js::random()));
    mat.set_alpha(babylon::js::random());
    cube.set_material(&mat);
    cube.set_position(Vector::new(
        babylon::js::random() - 0.5,
        babylon::js::random() - 0.5,
        babylon::js::random() - 0.5,
    ));
    game.shape.push(cube);
}

See this demo here ( be sure to play with mouse and arrow keys ⬅️ ⬆️ ⬇️ ➡️!)

GLTF

let mut game = GAME.lock().unwrap();
let mut gltf = GLTF::new(&game.scene, "BoomBox.gltf");
gltf.set_scaling(Vector::new(50.0, 50.0, 50.0));

See this demo here ( be sure to play with mouse and arrow keys ⬅️ ⬆️ ⬇️ ➡️!)

Pong in 100 Lines

use babylon::prelude::*;

struct Game {
    scene: Scene,
    _camera: Camera,
    _light_1: HemisphericLight,
    _light_2: PointLight,
    ball: Sphere,
    paddle_1: Cube,
    paddle_2: Cube,
    paddle_dir: f64,
    ball_dir: Vector,
}

impl Default for Game {
    fn default() -> Self {
        let mut scene = Scene::new("#renderCanvas");
        scene.set_clear_color(Color::new(0.0, 0.0, 0.0));
        let _camera = Camera::new(&scene);
        let _light_1 = HemisphericLight::new(&scene);
        let _light_2 = PointLight::new(&scene);
        let ball = Sphere::new(&scene, 0.05);
        let mut paddle_mat = StandardMaterial::new(&scene);
        paddle_mat.set_diffuse_color(Color::new(0.5, 0.5, 0.5));
        paddle_mat.set_emmisive_color(Color::new(0.5, 0.5, 0.5));
        let mut paddle_1 = Cube::new(&scene, 0.5, 0.05, 0.05);
        paddle_1.set_position(Vector::new(0.0, 0.5, 0.0));
        paddle_1.set_material(&paddle_mat);
        let mut paddle_2 = Cube::new(&scene, 0.5, 0.05, 0.05);
        paddle_2.set_position(Vector::new(0.0, -0.5, 0.0));
        paddle_2.set_material(&paddle_mat);
        Game {
            scene,
            _camera,
            _light_1,
            _light_2,
            ball,
            paddle_1,
            paddle_2,
            paddle_dir: 0.0,
            ball_dir: Vector::new(babylon::js::random() - 0.5, -1.0, 0.0),
        }
    }
}

impl BasicGame for Game {
    fn get_scene(&self) -> &Scene {
        &self.scene
    }

    fn run(&mut self, delta_time: f64) {
        // get positions
        let p2 = self.paddle_2.get_position();
        let bp = self.ball.get_position();

        // move ball
        let b_x = self.ball_dir.x * delta_time + bp.x;
        let b_y = self.ball_dir.y * delta_time + bp.y;
        if b_x > 0.5 || b_x < -0.5 {
            self.ball_dir.x = -self.ball_dir.x;
        }

        if b_y > 0.75 || b_y < -0.75 {
            self.ball.set_position(Vector::new(0.0, 0.0, 0.0));
            self.ball_dir.x = babylon::js::random() - 0.5;
            self.ball_dir.y = -self.ball_dir.y;
        } else if b_y > 0.45 || (b_y < -0.45 && b_x <= p2.x + 0.25 && b_x >= p2.x - 0.25) {
            self.ball_dir.y = -self.ball_dir.y;
            self.ball.set_position(Vector::new(b_x, b_y, 0.0));
        } else {
            self.ball.set_position(Vector::new(b_x, b_y, 0.0));
        }

        // move opponent paddle to match ball
        self.paddle_1.set_position_x(b_x);

        // move paddle if it has velocity
        if self.paddle_dir != 0.0 {
            let p2_x = p2.x + delta_time * self.paddle_dir;
            self.paddle_2.set_position_x(p2_x)
        }
    }

    fn key_up(&mut self, _key_code: f64) {
        self.paddle_dir = 0.0;
    }

    fn key_down(&mut self, key_code: f64) {
        if key_code == 37.0 {
            self.paddle_dir = 1.0;
        } else if key_code == 39.0 {
            self.paddle_dir = -1.0;
        }
    }
}

#[no_mangle]
pub fn main() {
    run_basic_game::<Game>();
}

See this demo here

Other Demos

License

This project is licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in babylon.rs by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~4.5MB
~83K SLoC