From 3e266f5baa99a3b576c67ef4242fd119097bf591 Mon Sep 17 00:00:00 2001 From: Max Roncace Date: Thu, 12 Dec 2024 00:14:08 -0500 Subject: [PATCH] game2d_rs: Add script bindings --- engine/static/game2d_rs/src/actor.rs | 13 +++- engine/static/game2d_rs/src/sprite.rs | 32 ++++++++-- engine/static/game2d_rs/src/world.rs | 74 +++++++++++++++++++++- engine/static/game2d_rs/src/world_layer.rs | 3 + 4 files changed, 114 insertions(+), 8 deletions(-) diff --git a/engine/static/game2d_rs/src/actor.rs b/engine/static/game2d_rs/src/actor.rs index 61c1951e..cf1f4c73 100644 --- a/engine/static/game2d_rs/src/actor.rs +++ b/engine/static/game2d_rs/src/actor.rs @@ -15,11 +15,13 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +use argus_scripting_bind::script_bind; use lowlevel_rustabi::argus::lowlevel::{Dirtiable, Handle, Vector2f}; use render_rustabi::argus::render::Transform2d; use resman_rustabi::argus::resman::Resource; use crate::sprite::Sprite; +#[script_bind(ref_only)] pub struct Actor2d { size: Vector2f, z_index: u32, @@ -31,8 +33,9 @@ pub struct Actor2d { pub(crate) render_obj: Option, } +#[script_bind] impl Actor2d { - pub fn new( + pub(crate) fn new( sprite_defn_res: Resource, size: Vector2f, z_index: u32, @@ -51,34 +54,42 @@ impl Actor2d { } } + #[script_bind] pub fn get_size(&self) -> Vector2f { self.size } + #[script_bind] pub fn get_z_index(&self) -> u32 { self.z_index } + #[script_bind] pub fn can_occlude_light(&self) -> bool { self.can_occlude_light.peek().value } + #[script_bind] pub fn set_can_occlude_light(&mut self, can_occlude: bool) { self.can_occlude_light.set(can_occlude); } + #[script_bind] pub fn get_transform(&self) -> Transform2d { self.transform.peek().value } + #[script_bind] pub fn set_transform(&mut self, transform: Transform2d) { self.transform.set(transform); } + #[script_bind] pub fn get_sprite(&self) -> &Sprite { &self.sprite } + #[script_bind] pub fn get_sprite_mut(&mut self) -> &mut Sprite { &mut self.sprite } diff --git a/engine/static/game2d_rs/src/sprite.rs b/engine/static/game2d_rs/src/sprite.rs index 95aba8c2..08b7e2b3 100644 --- a/engine/static/game2d_rs/src/sprite.rs +++ b/engine/static/game2d_rs/src/sprite.rs @@ -18,17 +18,19 @@ use std::collections::HashMap; use std::time::{Duration, Instant}; +use argus_scripting_bind::script_bind; use lowlevel_rustabi::argus::lowlevel::{Dirtiable, Padding, Vector2u}; use render_rustabi::argus::render::RenderObject2d; use resman_rustabi::argus::resman::Resource; -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct SpriteAnimationFrame { pub(crate) offset: Vector2u, pub(crate) duration: f32, } -#[derive(Clone)] +#[script_bind] +#[derive(Clone, Debug)] pub(crate) struct SpriteAnimation { pub(crate) id: String, @@ -45,7 +47,7 @@ impl SpriteAnimation { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct SpriteDefinition { pub(crate) def_anim: String, pub(crate) def_speed: f32, @@ -55,6 +57,8 @@ pub(crate) struct SpriteDefinition { pub(crate) animations: HashMap, } +#[derive(Debug)] +#[script_bind(ref_only)] pub struct Sprite { definition: SpriteDefinition, @@ -69,6 +73,7 @@ pub struct Sprite { pub(crate) pending_reset: bool, } +#[script_bind] impl Sprite { pub fn new(defn_res: Resource) -> Self { let defn = defn_res.get::(); @@ -100,10 +105,12 @@ impl Sprite { &mut self.anim_start_offsets } + #[script_bind] pub fn get_animation_speed(&self) -> f32 { self.speed } + #[script_bind] pub fn set_animation_speed(&mut self, speed: f32) { self.speed = speed; } @@ -112,6 +119,7 @@ impl Sprite { self.definition.animations.keys().cloned().collect() } + #[script_bind] pub fn get_current_animation_id(&self) -> &str { self.cur_anim_id.as_str() } @@ -120,22 +128,31 @@ impl Sprite { self.definition.animations.get(&self.cur_anim_id).expect("Sprite animation is missing") } - pub(crate) fn set_current_animation(&mut self, animation_id: String) -> Result<(), &'static str> { + pub(crate) fn set_current_animation(&mut self, animation_id: String) + -> Result<(), &'static str> { match self.definition.animations.get(&animation_id) { Some(_) => { self.cur_anim_id = animation_id; - self.cur_frame = Dirtiable::new(self.anim_start_offsets.get(&self.cur_anim_id).cloned() - .expect("Sprite animation start offset is missing")); + self.cur_frame = + Dirtiable::new(self.anim_start_offsets.get(&self.cur_anim_id).cloned() + .unwrap_or_default()); Ok(()) } None => Err("Animation not found by ID") } } + #[script_bind(rename = "set_current_animation")] + pub(crate) fn set_current_animation_or_die(&mut self, animation_id: String) { + self.set_current_animation(animation_id).expect("Failed to set sprite animation"); + } + + #[script_bind] pub fn does_current_animation_loop(&self) -> bool { self.get_current_animation().does_loop } + #[script_bind] pub fn is_current_animation_static(&self) -> bool { self.get_current_animation().frames.len() == 1 } @@ -144,14 +161,17 @@ impl Sprite { self.get_current_animation().padding } + #[script_bind] pub fn pause_animation(&mut self) { self.paused = false; } + #[script_bind] pub fn resume_animation(&mut self) { self.paused = true; } + #[script_bind] pub fn reset_animation(&mut self) { self.pending_reset = true; } diff --git a/engine/static/game2d_rs/src/world.rs b/engine/static/game2d_rs/src/world.rs index 089c05e8..686ceacd 100644 --- a/engine/static/game2d_rs/src/world.rs +++ b/engine/static/game2d_rs/src/world.rs @@ -21,9 +21,12 @@ use lazy_static::lazy_static; use lowlevel_rustabi::argus::lowlevel::{Dirtiable, Vector2f, Vector3f}; use render_rustabi::argus::render::{Canvas, Transform2d}; use std::collections::HashMap; +use std::ptr; use std::sync::{Arc, RwLock}; use std::time::Duration; +use argus_scripting_bind::script_bind; use uuid::Uuid; +use wm_rustabi::argus::wm::get_window; use crate::static_object::StaticObject2d; const MAX_BACKGROUND_LAYERS: u32 = 16; @@ -35,6 +38,7 @@ lazy_static! { Arc::new(RwLock::new(HashMap::new())); } +#[script_bind(ref_only)] pub struct World2d { id: String, pub(crate) canvas: Canvas, @@ -49,6 +53,7 @@ pub struct World2d { abstract_camera: Dirtiable, } +#[script_bind] impl World2d { pub fn create(id: String, mut canvas: Canvas, scale_factor: f32) -> Arc> { let world = Self { @@ -75,6 +80,14 @@ impl World2d { g_worlds.read().unwrap().get(&id).unwrap().clone() } + #[script_bind(rename = "create")] + pub fn create_unsafe<'a>(id: String, window_id: &str, scale_factor: f32) -> &'a mut World2d { + let window = get_window(window_id).unwrap(); + let arc = Self::create(id, Canvas::of(window.get_canvas()), scale_factor); + let mut guard = arc.write(); + unsafe { &mut *ptr::from_mut(guard.as_deref_mut().unwrap()) } + } + pub fn get(id: &str) -> Result>, &'static str> { match g_worlds.read().expect("Failed to acquire lock for worlds list").get(id) { Some(world) => Ok(world.clone()), @@ -82,6 +95,13 @@ impl World2d { } } + #[script_bind(rename = "get")] + pub fn get_unsafe<'a>(id: &str) -> &'a mut World2d { + let arc = Self::get(id).unwrap(); + let mut guard = arc.write(); + unsafe { &mut *ptr::from_mut(guard.as_deref_mut().unwrap()) } + } + pub fn get_or_crash(id: &str) -> Arc> { match Self::get(id) { Ok(world) => world, @@ -97,26 +117,33 @@ impl World2d { self.scale_factor } + #[script_bind] pub fn get_camera_transform(&self) -> Transform2d { - self.abstract_camera.peek().value + let val = self.abstract_camera.peek().value; + val } + #[script_bind] pub fn set_camera_transform(&mut self, transform: Transform2d) { self.abstract_camera.set(transform); } + #[script_bind] pub fn get_ambient_light_level(&self) -> f32 { self.al_level.peek().value } + #[script_bind] pub fn set_ambient_light_level(&mut self, level: f32) { self.al_level.set(level); } + #[script_bind] pub fn get_ambient_light_color(&self) -> Vector3f { self.al_color.peek().value } + #[script_bind] pub fn set_ambient_light_color(&mut self, color: Vector3f) { self.al_color.set(color); } @@ -158,6 +185,14 @@ impl World2d { Ok(self.bg_layers[bg_index as usize].as_mut().expect("Background layer is missing")) } + #[script_bind(rename = "add_background_layer")] + pub fn add_background_layer_unsafe( + &mut self, + parallax_coeff: f32, + ) -> &mut World2dLayer { + self.add_background_layer(parallax_coeff, None).unwrap() + } + fn render(&mut self) { let scale_factor = self.get_scale_factor(); let camera_transform = self.abstract_camera.read(); @@ -216,6 +251,19 @@ impl World2d { ) } + #[script_bind(rename = "create_static_object")] + pub fn create_static_object_unsafe( + &mut self, + sprite: String, + size: Vector2f, + z_index: u32, + can_occlude_light: bool, + transform: Transform2d, + ) -> String { + self.create_static_object(sprite, size, z_index, can_occlude_light, transform).unwrap() + .to_string() + } + pub fn delete_static_object(&mut self, id: &Uuid) -> Result<(), &'static str> { self.get_foreground_layer_mut().delete_static_object(id) } @@ -228,6 +276,11 @@ impl World2d { self.get_foreground_layer_mut().get_actor_mut(id) } + #[script_bind(rename = "get_actor_mut")] + pub fn get_actor_mut_unsafe(&mut self, id: &str) -> &mut Actor2d { + self.get_actor_mut(&Uuid::parse_str(id).unwrap()).unwrap() + } + pub fn create_actor( &mut self, sprite: String, @@ -245,6 +298,25 @@ impl World2d { ) } + #[script_bind(rename = "create_actor")] + pub fn create_actor_unsafe( + &mut self, + sprite: String, + size: Vector2f, + z_index: u32, + can_occlude_light: bool, + transform: Transform2d, + ) -> String { + self.create_actor( + sprite, + size, + z_index, + can_occlude_light, + transform, + ).unwrap() + .to_string() + } + pub fn delete_actor(&mut self, id: &Uuid) -> Result<(), &'static str> { self.get_foreground_layer_mut().delete_actor(id) } diff --git a/engine/static/game2d_rs/src/world_layer.rs b/engine/static/game2d_rs/src/world_layer.rs index 834eda6a..908dd2ea 100644 --- a/engine/static/game2d_rs/src/world_layer.rs +++ b/engine/static/game2d_rs/src/world_layer.rs @@ -30,6 +30,7 @@ use crate::static_object::StaticObject2d; const LAYER_PREFIX: &str = "_worldlayer_"; +#[script_bind(ref_only)] pub struct World2dLayer { id: String, world_id: String, @@ -45,6 +46,7 @@ pub struct World2dLayer { actors: HashMap, } +#[script_bind] impl World2dLayer { pub(crate) fn new( world_id: String, @@ -117,6 +119,7 @@ impl World2dLayer { self.get_scene().find_camera(self.render_camera_id.as_str()) } + #[script_bind] pub fn get_world_id(&self) -> &str { self.world_id.as_str() }