Fixed radar
parent
c1e831d60c
commit
39f52ddafc
File diff suppressed because it is too large
Load Diff
|
@ -74,10 +74,4 @@ lazy_static = "1.4.0"
|
||||||
clap = { version = "4.4.18", features = ["derive"] }
|
clap = { version = "4.4.18", features = ["derive"] }
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
log4rs = { version = "1.2.0", features = ["console_appender"] }
|
log4rs = { version = "1.2.0", features = ["console_appender"] }
|
||||||
rhai = { version = "1.17.0", features = [
|
rhai = { version = "1.17.1", features = ["f32_float", "no_custom_syntax"] }
|
||||||
"f32_float",
|
|
||||||
"only_i32",
|
|
||||||
"metadata",
|
|
||||||
"no_custom_syntax",
|
|
||||||
"no_closure",
|
|
||||||
] }
|
|
||||||
|
|
|
@ -32,6 +32,46 @@ fn init(state) {
|
||||||
Anchor::NorthEast
|
Anchor::NorthEast
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let radar_size = 150.0;
|
||||||
|
let radar_range = 4000.0;
|
||||||
|
|
||||||
|
add_sprite(
|
||||||
|
"radar",
|
||||||
|
"ui::radar",
|
||||||
|
Rect(
|
||||||
|
5.0, -5.0,
|
||||||
|
radar_size, radar_size,
|
||||||
|
Anchor::NorthWest,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
let init_pos = Rect(
|
||||||
|
(radar_size / 2.0 + 5),
|
||||||
|
(radar_size / -2.0 - 5),
|
||||||
|
3.5, 3.5,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
);
|
||||||
|
|
||||||
|
add_sprite("radar.frame.ne", "ui::radarframe", init_pos);
|
||||||
|
add_sprite("radar.frame.se", "ui::radarframe", init_pos);
|
||||||
|
add_sprite("radar.frame.sw", "ui::radarframe", init_pos);
|
||||||
|
add_sprite("radar.frame.nw", "ui::radarframe", init_pos);
|
||||||
|
sprite_set_angle("radar.frame.se", 90.0);
|
||||||
|
sprite_set_angle("radar.frame.sw", 180.0);
|
||||||
|
sprite_set_angle("radar.frame.nw", 270.0);
|
||||||
|
sprite_set_color("radar.frame.ne", Color(0.3, 0.3, 0.3, 1.0));
|
||||||
|
sprite_set_color("radar.frame.se", Color(0.3, 0.3, 0.3, 1.0));
|
||||||
|
sprite_set_color("radar.frame.sw", Color(0.3, 0.3, 0.3, 1.0));
|
||||||
|
sprite_set_color("radar.frame.nw", Color(0.3, 0.3, 0.3, 1.0));
|
||||||
|
|
||||||
|
add_sprite("radar.arrow", "ui::centerarrow", init_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(state, event) {
|
fn event(state, event) {
|
||||||
|
@ -53,4 +93,209 @@ fn step(state) {
|
||||||
state.player_ship().get_hull()
|
state.player_ship().get_hull()
|
||||||
/ state.player_ship().get_total_hull()
|
/ state.player_ship().get_total_hull()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: share variables with init();
|
||||||
|
let radar_size = 150.0;
|
||||||
|
let radar_range = 4000.0;
|
||||||
|
let hide_range = 0.85;
|
||||||
|
let shrink_distance = 20.0;
|
||||||
|
let p_pos = state.player_ship().get_pos();
|
||||||
|
|
||||||
|
// Radar arrow
|
||||||
|
{
|
||||||
|
let q = Vector(0.0, 0.0) - state.player_ship().get_pos();
|
||||||
|
let m = q.norm();
|
||||||
|
let angle = Vector(1.0, 0.0).clockwise_angle(q);
|
||||||
|
let position = Vector(5.0 + (radar_size / 2.0), -5.0 - (radar_size / 2.0));
|
||||||
|
let rot = Vector(0.915 * (radar_size / 2.0), 0.0);
|
||||||
|
let pos = position + rot.rotate(angle);
|
||||||
|
sprite_set_rect("radar.arrow",
|
||||||
|
Rect(
|
||||||
|
pos.x(), pos.y(),
|
||||||
|
5.0, 5.0,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sprite_set_angle("radar.arrow", angle - 90.0);
|
||||||
|
sprite_set_color(
|
||||||
|
"radar.arrow",
|
||||||
|
Color(
|
||||||
|
1.0, 1.0, 1.0,
|
||||||
|
clamp((m - 200.0) /400.0, 0.0, 1.0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ships
|
||||||
|
{
|
||||||
|
for s in state.ships() {
|
||||||
|
let uid = s.get_uid();
|
||||||
|
let sprite_name = `radar.ship.${uid}`;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!s.is_some() ||
|
||||||
|
s.is_dead() ||
|
||||||
|
s.is_landed()
|
||||||
|
){
|
||||||
|
if sprite_exists(sprite_name) {
|
||||||
|
remove_sprite(sprite_name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let color = Color(0.2, 0.2, 0.2, 1.0);
|
||||||
|
if s.is_flying() {
|
||||||
|
color = s.get_faction_color()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let size_init = s.get_size() * (1.0 / 50.0);
|
||||||
|
let pos = s.get_pos();
|
||||||
|
let d = (pos - p_pos) / radar_range;
|
||||||
|
let m = d.norm() + (size_init / (2.0 * radar_size));
|
||||||
|
if m < hide_range {
|
||||||
|
let size = (hide_range - m) * size_init * shrink_distance;
|
||||||
|
if size > size_init {
|
||||||
|
size = size_init;
|
||||||
|
}
|
||||||
|
if size < 1.0 {
|
||||||
|
if sprite_exists(sprite_name) {
|
||||||
|
remove_sprite(sprite_name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = Vector(radar_size / 2.0 + 5.0, radar_size / -2.0 - 5.0);
|
||||||
|
pos = pos + (d * radar_size / 2.0);
|
||||||
|
|
||||||
|
if !sprite_exists(sprite_name) {
|
||||||
|
add_sprite(
|
||||||
|
sprite_name,
|
||||||
|
"ui::shipblip",
|
||||||
|
Rect(
|
||||||
|
pos.x(), pos.y(),
|
||||||
|
size, size,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sprite_set_rect(
|
||||||
|
sprite_name,
|
||||||
|
Rect(
|
||||||
|
pos.x(), pos.y(),
|
||||||
|
size, size,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
sprite_set_color(sprite_name, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// System objects
|
||||||
|
{
|
||||||
|
for o in state.objects() {
|
||||||
|
let sprite_name = `radar.object.${o.get_label()}`;
|
||||||
|
|
||||||
|
if !o.is_some() {
|
||||||
|
if sprite_exists(sprite_name) {
|
||||||
|
remove_sprite(sprite_name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let size_init = (o.get_size() / o.get_pos_z()) / (radar_range * (1.0 / 300.0));
|
||||||
|
let pos = o.get_pos();
|
||||||
|
let d = (pos - p_pos) / radar_range;
|
||||||
|
let m = d.norm() + (size_init / (2.0 * radar_size));
|
||||||
|
if m < hide_range {
|
||||||
|
let size = (hide_range - m) * size_init * shrink_distance;
|
||||||
|
if size > size_init {
|
||||||
|
size = size_init;
|
||||||
|
}
|
||||||
|
if size < 1.0 {
|
||||||
|
// Don't draw tiny sprites, they flicker
|
||||||
|
if sprite_exists(sprite_name) {
|
||||||
|
remove_sprite(sprite_name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = (
|
||||||
|
Vector(radar_size / 2.0 + 5.0, radar_size / -2.0 - 5.0)
|
||||||
|
+ (d * radar_size / 2.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
if !sprite_exists(sprite_name) {
|
||||||
|
add_sprite(
|
||||||
|
sprite_name,
|
||||||
|
"ui::planetblip",
|
||||||
|
Rect(
|
||||||
|
pos.x(), pos.y(),
|
||||||
|
size, size,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sprite_set_rect(
|
||||||
|
sprite_name,
|
||||||
|
Rect(
|
||||||
|
pos.x(), pos.y(),
|
||||||
|
size, size,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window frame
|
||||||
|
{
|
||||||
|
let dx = (((state.camera_zoom() / 2.0) * state.window_aspect()) / radar_range) * (radar_size / 2.0);
|
||||||
|
let dy = ((state.camera_zoom() / 2.0) / radar_range) * (radar_size / 2.0);
|
||||||
|
sprite_set_rect("radar.frame.ne",
|
||||||
|
Rect(
|
||||||
|
(radar_size / 2.0 + 5) - dx,
|
||||||
|
(radar_size / -2.0 - 5) + dy,
|
||||||
|
3.5, 3.5,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sprite_set_rect("radar.frame.se",
|
||||||
|
Rect(
|
||||||
|
(radar_size / 2.0 + 5) - dx,
|
||||||
|
(radar_size / -2.0 - 5) - dy,
|
||||||
|
3.5, 3.5,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sprite_set_rect("radar.frame.sw",
|
||||||
|
Rect(
|
||||||
|
(radar_size / 2.0 + 5) + dx,
|
||||||
|
(radar_size / -2.0 - 5) - dy,
|
||||||
|
3.5, 3.5,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sprite_set_rect("radar.frame.nw",
|
||||||
|
Rect(
|
||||||
|
(radar_size / 2.0 + 5) + dx,
|
||||||
|
(radar_size / -2.0 - 5) + dy,
|
||||||
|
3.5, 3.5,
|
||||||
|
Anchor::Center,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ pub(crate) mod syntax {
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use galactica_packer::SpriteAtlas;
|
use galactica_packer::SpriteAtlas;
|
||||||
use galactica_util::rhai_error_to_anyhow;
|
use galactica_util::rhai_error_to_anyhow;
|
||||||
use rhai::Engine;
|
use rhai::{Engine, OptimizationLevel};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
@ -61,7 +61,9 @@ pub(crate) mod syntax {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let engine = Engine::new();
|
let mut engine = Engine::new_raw();
|
||||||
|
engine.set_optimization_level(OptimizationLevel::Full);
|
||||||
|
engine.set_max_expr_depths(0, 0);
|
||||||
let mut ui_scenes = HashMap::new();
|
let mut ui_scenes = HashMap::new();
|
||||||
for (n, p) in self.ui_scene {
|
for (n, p) in self.ui_scene {
|
||||||
ui_scenes.insert(
|
ui_scenes.insert(
|
||||||
|
|
|
@ -126,9 +126,12 @@ pub struct SystemObject {
|
||||||
/// If true, ships may land on this object
|
/// If true, ships may land on this object
|
||||||
pub landable: bool,
|
pub landable: bool,
|
||||||
|
|
||||||
/// The display name of this object
|
/// The pretty display name of this object
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
|
||||||
|
/// The system-unique label of this object
|
||||||
|
pub label: String,
|
||||||
|
|
||||||
/// The description of this object (shown on landed ui)
|
/// The description of this object (shown on landed ui)
|
||||||
pub desc: Option<String>,
|
pub desc: Option<String>,
|
||||||
|
|
||||||
|
@ -259,6 +262,7 @@ impl crate::Build for System {
|
||||||
}
|
}
|
||||||
|
|
||||||
objects.push(SystemObject {
|
objects.push(SystemObject {
|
||||||
|
label: label.clone(),
|
||||||
sprite: sprite_handle,
|
sprite: sprite_handle,
|
||||||
image: image_handle,
|
image: image_handle,
|
||||||
pos: resolve_position(&system.object, &obj, cycle_detector)
|
pos: resolve_position(&system.object, &obj, cycle_detector)
|
||||||
|
|
|
@ -33,3 +33,4 @@ bytemuck = { workspace = true }
|
||||||
glyphon = { workspace = true }
|
glyphon = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
rhai = { workspace = true }
|
rhai = { workspace = true }
|
||||||
|
rapier2d = { workspace = true }
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rhai::{CustomType, TypeBuilder};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
pub val: Vector4<f32>,
|
val: Vector4<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
use rhai::{CustomType, TypeBuilder};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SceneConfig {
|
||||||
|
pub show_phys: bool,
|
||||||
|
pub show_starfield: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SceneConfig {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
show_phys: false,
|
||||||
|
show_starfield: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomType for SceneConfig {
|
||||||
|
fn build(mut builder: TypeBuilder<Self>) {
|
||||||
|
builder
|
||||||
|
.with_name("SceneConfig")
|
||||||
|
.with_fn("SceneConfig", Self::new)
|
||||||
|
.with_fn("show_phys", |s: &mut Self, x: bool| s.show_phys = x)
|
||||||
|
.with_fn("show_starfield", |s: &mut Self, x: bool| {
|
||||||
|
s.show_starfield = x
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,12 +3,14 @@ mod color;
|
||||||
mod event;
|
mod event;
|
||||||
mod rect;
|
mod rect;
|
||||||
mod state;
|
mod state;
|
||||||
|
mod vector;
|
||||||
|
|
||||||
pub use anchor::*;
|
pub use anchor::*;
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
pub use event::*;
|
pub use event::*;
|
||||||
pub use rect::*;
|
pub use rect::*;
|
||||||
pub use state::*;
|
pub use state::*;
|
||||||
|
pub use vector::*;
|
||||||
|
|
||||||
use rhai::{exported_module, Engine};
|
use rhai::{exported_module, Engine};
|
||||||
|
|
||||||
|
@ -17,6 +19,7 @@ pub fn register_into_engine(engine: &mut Engine) {
|
||||||
// Helpers
|
// Helpers
|
||||||
.build_type::<Rect>()
|
.build_type::<Rect>()
|
||||||
.build_type::<Color>()
|
.build_type::<Color>()
|
||||||
|
.build_type::<UiVector>()
|
||||||
// State
|
// State
|
||||||
.build_type::<State>()
|
.build_type::<State>()
|
||||||
.build_type::<ShipState>()
|
.build_type::<ShipState>()
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
use galactica_content::{Ship, SystemObject, SystemObjectHandle};
|
use galactica_content::{Ship, SystemObject, SystemObjectHandle};
|
||||||
use galactica_system::{
|
use galactica_system::{
|
||||||
data::{self, ShipData},
|
data::{self},
|
||||||
phys::PhysSimShipHandle,
|
phys::{objects::PhysShip, PhysSimShipHandle},
|
||||||
};
|
};
|
||||||
|
use galactica_util::to_degrees;
|
||||||
use log::error;
|
use log::error;
|
||||||
use rhai::{CustomType, TypeBuilder};
|
use rapier2d::dynamics::RigidBody;
|
||||||
|
use rhai::{Array, CustomType, Dynamic, ImmutableString, TypeBuilder};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::RenderInput;
|
use super::{Color, UiVector};
|
||||||
|
use crate::{RenderInput, RenderState};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ShipState {
|
pub struct ShipState {
|
||||||
|
@ -15,10 +18,6 @@ pub struct ShipState {
|
||||||
input: Arc<RenderInput>,
|
input: Arc<RenderInput>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this
|
|
||||||
unsafe impl Send for ShipState {}
|
|
||||||
unsafe impl Sync for ShipState {}
|
|
||||||
|
|
||||||
impl ShipState {
|
impl ShipState {
|
||||||
fn get_content(&mut self) -> &Ship {
|
fn get_content(&mut self) -> &Ship {
|
||||||
let ship = self
|
let ship = self
|
||||||
|
@ -30,18 +29,27 @@ impl ShipState {
|
||||||
self.input.ct.get_ship(handle)
|
self.input.ct.get_ship(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_data(&mut self) -> &ShipData {
|
fn get_ship(&mut self) -> &PhysShip {
|
||||||
let ship = self
|
let ship = self
|
||||||
.input
|
.input
|
||||||
.phys_img
|
.phys_img
|
||||||
.get_ship(self.ship.as_ref().unwrap())
|
.get_ship(self.ship.as_ref().unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ship.ship.get_data()
|
&ship.ship
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_body(&mut self) -> &RigidBody {
|
||||||
|
let ship = self
|
||||||
|
.input
|
||||||
|
.phys_img
|
||||||
|
.get_ship(self.ship.as_ref().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
&ship.rigidbody
|
||||||
}
|
}
|
||||||
|
|
||||||
fn landed_on(&mut self) -> SystemObjectState {
|
fn landed_on(&mut self) -> SystemObjectState {
|
||||||
let input = self.input.clone();
|
let input = self.input.clone();
|
||||||
match self.get_data().get_state() {
|
match self.get_ship().get_data().get_state() {
|
||||||
data::ShipState::Landed { target } => {
|
data::ShipState::Landed { target } => {
|
||||||
return SystemObjectState {
|
return SystemObjectState {
|
||||||
input,
|
input,
|
||||||
|
@ -63,31 +71,48 @@ impl CustomType for ShipState {
|
||||||
builder
|
builder
|
||||||
.with_name("ShipState")
|
.with_name("ShipState")
|
||||||
.with_fn("is_some", |s: &mut Self| s.ship.is_some())
|
.with_fn("is_some", |s: &mut Self| s.ship.is_some())
|
||||||
.with_fn("is_dead", |s: &mut Self| s.get_data().get_state().is_dead())
|
.with_fn("is_dead", |s: &mut Self| {
|
||||||
|
s.get_ship().get_data().get_state().is_dead()
|
||||||
|
})
|
||||||
.with_fn("is_landed", |s: &mut Self| {
|
.with_fn("is_landed", |s: &mut Self| {
|
||||||
s.get_data().get_state().is_landed()
|
s.get_ship().get_data().get_state().is_landed()
|
||||||
})
|
})
|
||||||
.with_fn("is_landing", |s: &mut Self| {
|
.with_fn("is_landing", |s: &mut Self| {
|
||||||
s.get_data().get_state().is_landing()
|
s.get_ship().get_data().get_state().is_landing()
|
||||||
})
|
})
|
||||||
.with_fn("is_flying", |s: &mut Self| {
|
.with_fn("is_flying", |s: &mut Self| {
|
||||||
s.get_data().get_state().is_flying()
|
s.get_ship().get_data().get_state().is_flying()
|
||||||
})
|
})
|
||||||
.with_fn("is_unlanding", |s: &mut Self| {
|
.with_fn("is_unlanding", |s: &mut Self| {
|
||||||
s.get_data().get_state().is_unlanding()
|
s.get_ship().get_data().get_state().is_unlanding()
|
||||||
})
|
})
|
||||||
.with_fn("is_collapsing", |s: &mut Self| {
|
.with_fn("is_collapsing", |s: &mut Self| {
|
||||||
s.get_data().get_state().is_collapsing()
|
s.get_ship().get_data().get_state().is_collapsing()
|
||||||
})
|
})
|
||||||
.with_fn("name", |s: &mut Self| s.get_content().name.clone())
|
.with_fn("name", |s: &mut Self| s.get_content().name.clone())
|
||||||
.with_fn("thumbnail", |s: &mut Self| s.get_content().thumb)
|
.with_fn("thumbnail", |s: &mut Self| s.get_content().thumb)
|
||||||
.with_fn("landed_on", |s: &mut Self| s.landed_on())
|
.with_fn("landed_on", |s: &mut Self| s.landed_on())
|
||||||
.with_fn("get_shields", |s: &mut Self| s.get_data().get_shields())
|
.with_fn("get_shields", |s: &mut Self| {
|
||||||
|
s.get_ship().get_data().get_shields()
|
||||||
|
})
|
||||||
.with_fn("get_total_shields", |s: &mut Self| {
|
.with_fn("get_total_shields", |s: &mut Self| {
|
||||||
s.get_data().get_outfits().get_total_shields()
|
s.get_ship().get_data().get_outfits().get_total_shields()
|
||||||
})
|
})
|
||||||
.with_fn("get_total_hull", |s: &mut Self| s.get_content().hull)
|
.with_fn("get_total_hull", |s: &mut Self| s.get_content().hull)
|
||||||
.with_fn("get_hull", |s: &mut Self| s.get_data().get_hull());
|
.with_fn("get_hull", |s: &mut Self| {
|
||||||
|
s.get_ship().get_data().get_hull()
|
||||||
|
})
|
||||||
|
.with_fn("get_size", |s: &mut Self| s.get_content().size)
|
||||||
|
.with_fn("get_uid", |s: &mut Self| format!("{}", s.get_ship().uid))
|
||||||
|
.with_fn("get_pos", |s: &mut Self| {
|
||||||
|
let t = s.get_body().translation();
|
||||||
|
UiVector::new(t.x, t.y)
|
||||||
|
})
|
||||||
|
.with_fn("get_faction_color", |s: &mut Self| {
|
||||||
|
let h = s.get_ship().get_data().get_faction();
|
||||||
|
let c = s.input.ct.get_faction(h).color;
|
||||||
|
Color::new(c[0], c[1], c[2], 1.0)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,10 +122,6 @@ pub struct SystemObjectState {
|
||||||
input: Arc<RenderInput>,
|
input: Arc<RenderInput>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this
|
|
||||||
unsafe impl Send for SystemObjectState {}
|
|
||||||
unsafe impl Sync for SystemObjectState {}
|
|
||||||
|
|
||||||
impl SystemObjectState {
|
impl SystemObjectState {
|
||||||
fn get_content(&mut self) -> &SystemObject {
|
fn get_content(&mut self) -> &SystemObject {
|
||||||
self.input.ct.get_system_object(self.object.unwrap())
|
self.input.ct.get_system_object(self.object.unwrap())
|
||||||
|
@ -146,13 +167,30 @@ impl CustomType for SystemObjectState {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.with_fn("is_some", |s: &mut Self| s.object.is_some());
|
.with_fn("is_some", |s: &mut Self| s.object.is_some())
|
||||||
|
.with_fn("==", |a: &mut Self, b: Self| a.object == b.object)
|
||||||
|
.with_fn("get_size", |s: &mut Self| s.get_content().size)
|
||||||
|
.with_fn("get_label", |s: &mut Self| {
|
||||||
|
ImmutableString::from(&s.get_content().label)
|
||||||
|
})
|
||||||
|
.with_fn("get_angle", |s: &mut Self| {
|
||||||
|
to_degrees(s.get_content().angle)
|
||||||
|
})
|
||||||
|
.with_fn("get_pos", |s: &mut Self| {
|
||||||
|
let t = s.get_content().pos;
|
||||||
|
UiVector::new(t.x, t.y)
|
||||||
|
})
|
||||||
|
.with_fn("get_pos_z", |s: &mut Self| {
|
||||||
|
let t = s.get_content().pos;
|
||||||
|
t.z
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
input: Arc<RenderInput>,
|
input: Arc<RenderInput>,
|
||||||
|
window_aspect: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this
|
// TODO: remove this
|
||||||
|
@ -160,8 +198,11 @@ unsafe impl Send for State {}
|
||||||
unsafe impl Sync for State {}
|
unsafe impl Sync for State {}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new(input: Arc<RenderInput>) -> Self {
|
pub fn new(state: &RenderState, input: Arc<RenderInput>) -> Self {
|
||||||
Self { input }
|
Self {
|
||||||
|
input,
|
||||||
|
window_aspect: state.window_aspect,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn player_ship(&mut self) -> ShipState {
|
pub fn player_ship(&mut self) -> ShipState {
|
||||||
|
@ -170,12 +211,39 @@ impl State {
|
||||||
ship: self.input.player.ship.map(|x| PhysSimShipHandle(x)),
|
ship: self.input.player.ship.map(|x| PhysSimShipHandle(x)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ships(&mut self) -> Array {
|
||||||
|
let mut a = Array::new();
|
||||||
|
for s in self.input.phys_img.iter_ships() {
|
||||||
|
a.push(Dynamic::from(ShipState {
|
||||||
|
input: self.input.clone(),
|
||||||
|
ship: Some(PhysSimShipHandle(s.ship.collider)),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn objects(&mut self) -> Array {
|
||||||
|
let mut a = Array::new();
|
||||||
|
let s = self.input.current_system;
|
||||||
|
for o in &self.input.ct.get_system(s).objects {
|
||||||
|
a.push(Dynamic::from(SystemObjectState {
|
||||||
|
input: self.input.clone(),
|
||||||
|
object: Some(o.handle),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomType for State {
|
impl CustomType for State {
|
||||||
fn build(mut builder: TypeBuilder<Self>) {
|
fn build(mut builder: TypeBuilder<Self>) {
|
||||||
builder
|
builder
|
||||||
.with_name("State")
|
.with_name("State")
|
||||||
.with_fn("player_ship", Self::player_ship);
|
.with_fn("player_ship", Self::player_ship)
|
||||||
|
.with_fn("ships", Self::ships)
|
||||||
|
.with_fn("objects", Self::objects)
|
||||||
|
.with_fn("window_aspect", |s: &mut Self| s.window_aspect)
|
||||||
|
.with_fn("camera_zoom", |s: &mut Self| s.input.camera_zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
use galactica_util::{clockwise_angle, to_degrees, to_radians};
|
||||||
|
use nalgebra::{Rotation2, Vector2};
|
||||||
|
use rhai::{CustomType, TypeBuilder};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct UiVector {
|
||||||
|
val: Vector2<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UiVector {
|
||||||
|
pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
val: Vector2::new(x, y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate(&mut self, angle: f32) -> Self {
|
||||||
|
return UiVector {
|
||||||
|
val: Rotation2::new(to_radians(angle)) * self.val,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clockwise_angle(&mut self, other: UiVector) -> f32 {
|
||||||
|
return to_degrees(clockwise_angle(&self.val, &other.val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomType for UiVector {
|
||||||
|
fn build(mut builder: TypeBuilder<Self>) {
|
||||||
|
builder
|
||||||
|
.with_name("Vector")
|
||||||
|
.with_fn("Vector", Self::new)
|
||||||
|
.with_fn("rotate", Self::rotate)
|
||||||
|
.with_fn("clockwise_angle", Self::clockwise_angle)
|
||||||
|
.with_fn("+", |a: UiVector, b: UiVector| UiVector {
|
||||||
|
val: a.val + b.val,
|
||||||
|
})
|
||||||
|
.with_fn("-", |a: UiVector, b: UiVector| UiVector {
|
||||||
|
val: a.val - b.val,
|
||||||
|
})
|
||||||
|
.with_fn("/", |s: &mut Self, x: f32| UiVector { val: s.val / x })
|
||||||
|
.with_fn("*", |s: &mut Self, x: f32| UiVector { val: s.val * x })
|
||||||
|
.with_fn("x", |s: &mut Self| s.val.x)
|
||||||
|
.with_fn("y", |s: &mut Self| s.val.y)
|
||||||
|
.with_fn("norm", |s: &mut Self| s.val.magnitude());
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,10 @@ use galactica_system::phys::PhysSimShipHandle;
|
||||||
use galactica_util::rhai_error_to_anyhow;
|
use galactica_util::rhai_error_to_anyhow;
|
||||||
use glyphon::{cosmic_text::Align, FamilyOwned, FontSystem, Style, Weight};
|
use glyphon::{cosmic_text::Align, FamilyOwned, FontSystem, Style, Weight};
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use rhai::{Dynamic, Engine, ImmutableString, Scope};
|
use rhai::{
|
||||||
|
packages::{BasicArrayPackage, BasicStringPackage, LogicPackage, MoreStringPackage, Package},
|
||||||
|
Dynamic, Engine, ImmutableString, Scope,
|
||||||
|
};
|
||||||
use std::{cell::RefCell, num::NonZeroU32, rc::Rc, sync::Arc};
|
use std::{cell::RefCell, num::NonZeroU32, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -31,6 +34,18 @@ impl UiScriptExecutor {
|
||||||
let elements = Rc::new(RefCell::new(UiState::new(ct.clone(), state)));
|
let elements = Rc::new(RefCell::new(UiState::new(ct.clone(), state)));
|
||||||
|
|
||||||
let mut engine = Engine::new_raw();
|
let mut engine = Engine::new_raw();
|
||||||
|
|
||||||
|
// Required for array iteration
|
||||||
|
// We may need to add more packages here later.
|
||||||
|
engine.register_global_module(BasicArrayPackage::new().as_shared_module());
|
||||||
|
engine.register_global_module(LogicPackage::new().as_shared_module());
|
||||||
|
engine.register_global_module(BasicStringPackage::new().as_shared_module());
|
||||||
|
engine.register_global_module(MoreStringPackage::new().as_shared_module());
|
||||||
|
|
||||||
|
engine.set_max_expr_depths(0, 0);
|
||||||
|
// Enables custom operators
|
||||||
|
engine.set_fast_operators(false);
|
||||||
|
|
||||||
api::register_into_engine(&mut engine);
|
api::register_into_engine(&mut engine);
|
||||||
Self::register_api(
|
Self::register_api(
|
||||||
ct.clone(),
|
ct.clone(),
|
||||||
|
@ -53,7 +68,7 @@ impl UiScriptExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the current scene
|
/// Change the current scene
|
||||||
pub fn set_scene(&mut self, input: Arc<RenderInput>) -> Result<()> {
|
pub fn set_scene(&mut self, state: &RenderState, input: Arc<RenderInput>) -> Result<()> {
|
||||||
let current_scene = (*self.state).borrow().get_scene().clone();
|
let current_scene = (*self.state).borrow().get_scene().clone();
|
||||||
if self.last_scene == current_scene {
|
if self.last_scene == current_scene {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -85,7 +100,7 @@ impl UiScriptExecutor {
|
||||||
.get(current_scene.as_ref().unwrap().as_str())
|
.get(current_scene.as_ref().unwrap().as_str())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"init",
|
"init",
|
||||||
(State::new(input.clone()),),
|
(State::new(state, input.clone()),),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.with_context(|| format!("while running `init()`"))
|
.with_context(|| format!("while running `init()`"))
|
||||||
|
@ -104,7 +119,7 @@ impl UiScriptExecutor {
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_scene(ImmutableString::from(&ct.get_config().start_ui_scene));
|
.set_scene(ImmutableString::from(&ct.get_config().start_ui_scene));
|
||||||
}
|
}
|
||||||
self.set_scene(input.clone())?;
|
self.set_scene(state, input.clone())?;
|
||||||
let current_scene = (*self.state).borrow().get_scene().clone();
|
let current_scene = (*self.state).borrow().get_scene().clone();
|
||||||
|
|
||||||
(*self.state).borrow_mut().step(state, input.clone());
|
(*self.state).borrow_mut().step(state, input.clone());
|
||||||
|
@ -121,7 +136,7 @@ impl UiScriptExecutor {
|
||||||
&mut self.scope,
|
&mut self.scope,
|
||||||
ast,
|
ast,
|
||||||
"step",
|
"step",
|
||||||
(State::new(input.clone()),),
|
(State::new(state, input.clone()),),
|
||||||
))
|
))
|
||||||
.with_context(|| format!("while calling `step()`"))
|
.with_context(|| format!("while calling `step()`"))
|
||||||
.with_context(|| format!("in ui scene `{}`", current_scene.as_ref().unwrap()))?;
|
.with_context(|| format!("in ui scene `{}`", current_scene.as_ref().unwrap()))?;
|
||||||
|
@ -154,7 +169,7 @@ impl UiScriptExecutor {
|
||||||
.get(current_scene.as_ref().unwrap().as_str())
|
.get(current_scene.as_ref().unwrap().as_str())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"event",
|
"event",
|
||||||
(State::new(input.clone()), PlayerShipStateEvent {}),
|
(State::new(state, input.clone()), PlayerShipStateEvent {}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.with_context(|| format!("while handling player state change event"))
|
.with_context(|| format!("while handling player state change event"))
|
||||||
|
@ -214,7 +229,7 @@ impl UiScriptExecutor {
|
||||||
.get(current_scene.as_ref().unwrap().as_str())
|
.get(current_scene.as_ref().unwrap().as_str())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"event",
|
"event",
|
||||||
(State::new(input.clone()), event_arg.clone()),
|
(State::new(state, input.clone()), event_arg.clone()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.with_context(|| format!("while handling event `{:?}`", event_arg))
|
.with_context(|| format!("while handling event `{:?}`", event_arg))
|
||||||
|
@ -222,6 +237,7 @@ impl UiScriptExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.scope.rewind(0);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,6 +269,12 @@ impl UiScriptExecutor {
|
||||||
let mut ui_state = c.borrow_mut();
|
let mut ui_state = c.borrow_mut();
|
||||||
ui_state.config.show_starfield = b;
|
ui_state.config.show_starfield = b;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
engine.register_fn("print", move |d: Dynamic| {
|
||||||
|
debug!("{:?}", d);
|
||||||
|
});
|
||||||
|
|
||||||
|
engine.register_fn("clamp", move |x: f32, l: f32, h: f32| x.clamp(l, h));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sprites
|
// Sprites
|
||||||
|
@ -263,7 +285,6 @@ impl UiScriptExecutor {
|
||||||
"add_sprite",
|
"add_sprite",
|
||||||
move |name: ImmutableString, sprite: ImmutableString, rect: Rect| {
|
move |name: ImmutableString, sprite: ImmutableString, rect: Rect| {
|
||||||
let mut ui_state = c.borrow_mut();
|
let mut ui_state = c.borrow_mut();
|
||||||
let len = ui_state.len();
|
|
||||||
|
|
||||||
let sprite_handle = ct.get_sprite_handle(sprite.as_str());
|
let sprite_handle = ct.get_sprite_handle(sprite.as_str());
|
||||||
if sprite_handle.is_none() {
|
if sprite_handle.is_none() {
|
||||||
|
@ -271,16 +292,35 @@ impl UiScriptExecutor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_state.names.insert(name.clone(), len);
|
if ui_state.elements.contains_key(&name) {
|
||||||
ui_state.elements.push(UiElement::Sprite(Sprite::new(
|
error!("tried to make a sprite using an existing name `{name}`");
|
||||||
&ct,
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_state.names.push(name.clone());
|
||||||
|
ui_state.elements.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
sprite_handle.unwrap(),
|
UiElement::Sprite(Sprite::new(
|
||||||
rect,
|
&ct,
|
||||||
)));
|
name.clone(),
|
||||||
|
sprite_handle.unwrap(),
|
||||||
|
rect,
|
||||||
|
)),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let c = s.clone();
|
||||||
|
engine.register_fn("remove_sprite", move |name: ImmutableString| {
|
||||||
|
let mut ui_state = c.borrow_mut();
|
||||||
|
if ui_state.elements.contains_key(&name) {
|
||||||
|
ui_state.elements.remove(&name).unwrap();
|
||||||
|
ui_state.names.retain(|x| *x != name);
|
||||||
|
} else {
|
||||||
|
error!("called `remove_sprite` on an invalid name `{name}`")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let c = s.clone();
|
let c = s.clone();
|
||||||
let ct = ct_src.clone();
|
let ct = ct_src.clone();
|
||||||
engine.register_fn(
|
engine.register_fn(
|
||||||
|
@ -299,7 +339,7 @@ impl UiScriptExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
error!("called `set_sprite_mask` on an invalid name `{name}`")
|
error!("called `sprite_set_mask` on an invalid name `{name}`")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -339,6 +379,51 @@ impl UiScriptExecutor {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let c = s.clone();
|
||||||
|
engine.register_fn("sprite_set_angle", move |name: ImmutableString, x: f32| {
|
||||||
|
let mut ui_state = c.borrow_mut();
|
||||||
|
match ui_state.get_mut_by_name(&name) {
|
||||||
|
Some(UiElement::Sprite(s)) => s.set_angle(x),
|
||||||
|
_ => {
|
||||||
|
error!("called `sprite_set_angle` on an invalid name `{name}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let c = s.clone();
|
||||||
|
engine.register_fn("sprite_set_rect", move |name: ImmutableString, x: Rect| {
|
||||||
|
let mut ui_state = c.borrow_mut();
|
||||||
|
match ui_state.get_mut_by_name(&name) {
|
||||||
|
Some(UiElement::Sprite(s)) => s.set_rect(x),
|
||||||
|
_ => {
|
||||||
|
error!("called `sprite_set_rect` on an invalid name `{name}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let c = s.clone();
|
||||||
|
engine.register_fn(
|
||||||
|
"sprite_set_color",
|
||||||
|
move |name: ImmutableString, x: Color| {
|
||||||
|
let mut ui_state = c.borrow_mut();
|
||||||
|
match ui_state.get_mut_by_name(&name) {
|
||||||
|
Some(UiElement::Sprite(s)) => s.set_color(x),
|
||||||
|
_ => {
|
||||||
|
error!("called `sprite_set_color` on an invalid name `{name}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let c = s.clone();
|
||||||
|
engine.register_fn("sprite_exists", move |name: ImmutableString| {
|
||||||
|
let mut ui_state = c.borrow_mut();
|
||||||
|
match ui_state.get_mut_by_name(&name) {
|
||||||
|
Some(UiElement::Sprite(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Textboxes
|
// Textboxes
|
||||||
|
@ -354,17 +439,24 @@ impl UiScriptExecutor {
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
color: Color| {
|
color: Color| {
|
||||||
let mut ui_state = c.borrow_mut();
|
let mut ui_state = c.borrow_mut();
|
||||||
let len = ui_state.len();
|
|
||||||
|
|
||||||
ui_state.names.insert(name.clone(), len);
|
if ui_state.elements.contains_key(&name) {
|
||||||
ui_state.elements.push(UiElement::Text(TextBox::new(
|
error!("tried to make a textbox using an existing name `{name}`");
|
||||||
&mut font.borrow_mut(),
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_state.names.push(name.clone());
|
||||||
|
ui_state.elements.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
font_size,
|
UiElement::Text(TextBox::new(
|
||||||
line_height,
|
&mut font.borrow_mut(),
|
||||||
rect,
|
name.clone(),
|
||||||
color,
|
font_size,
|
||||||
)));
|
line_height,
|
||||||
|
rect,
|
||||||
|
color,
|
||||||
|
)),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -536,16 +628,23 @@ impl UiScriptExecutor {
|
||||||
// TODO: fix ugly spaces
|
// TODO: fix ugly spaces
|
||||||
move |name: ImmutableString, stroke: f32, color: Color, rect: Rect| {
|
move |name: ImmutableString, stroke: f32, color: Color, rect: Rect| {
|
||||||
let mut ui_state = c.borrow_mut();
|
let mut ui_state = c.borrow_mut();
|
||||||
let len = ui_state.len();
|
|
||||||
|
|
||||||
ui_state.names.insert(name.clone(), len);
|
if ui_state.elements.contains_key(&name) {
|
||||||
ui_state.elements.push(UiElement::RadialBar(RadialBar::new(
|
error!("tried to make a radialbar using an existing name `{name}`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_state.names.push(name.clone());
|
||||||
|
ui_state.elements.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
stroke,
|
UiElement::RadialBar(RadialBar::new(
|
||||||
color,
|
name.clone(),
|
||||||
rect,
|
stroke,
|
||||||
1.0,
|
color,
|
||||||
)));
|
rect,
|
||||||
|
1.0,
|
||||||
|
)),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ pub(crate) struct UiConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct UiState {
|
pub(crate) struct UiState {
|
||||||
pub names: HashMap<ImmutableString, usize>,
|
pub elements: HashMap<ImmutableString, UiElement>,
|
||||||
pub elements: Vec<UiElement>,
|
pub names: Vec<ImmutableString>,
|
||||||
|
|
||||||
pub ct: Arc<Content>,
|
pub ct: Arc<Content>,
|
||||||
current_scene: Option<ImmutableString>,
|
current_scene: Option<ImmutableString>,
|
||||||
|
@ -42,8 +42,8 @@ impl UiState {
|
||||||
pub fn new(ct: Arc<Content>, state: &mut RenderState) -> Self {
|
pub fn new(ct: Arc<Content>, state: &mut RenderState) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ct,
|
ct,
|
||||||
names: HashMap::new(),
|
elements: HashMap::new(),
|
||||||
elements: Vec::new(),
|
names: Vec::new(),
|
||||||
|
|
||||||
current_scene: None,
|
current_scene: None,
|
||||||
show_timings: true,
|
show_timings: true,
|
||||||
|
@ -79,15 +79,15 @@ impl UiState {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn get_mut_by_idx(&mut self, idx: usize) -> Option<&mut UiElement> {
|
pub fn get_mut_by_idx(&mut self, idx: usize) -> Option<&mut UiElement> {
|
||||||
self.elements.get_mut(idx)
|
let name = self.names.get(idx);
|
||||||
|
if name.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.elements.get_mut(name.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut_by_name(&mut self, name: &ImmutableString) -> Option<&mut UiElement> {
|
pub fn get_mut_by_name(&mut self, name: &ImmutableString) -> Option<&mut UiElement> {
|
||||||
let idx = self.names.get(name);
|
self.elements.get_mut(name)
|
||||||
if idx.is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
self.get_mut_by_idx(*idx.unwrap())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_scene(&self) -> &Option<ImmutableString> {
|
pub fn get_scene(&self) -> &Option<ImmutableString> {
|
||||||
|
@ -124,7 +124,7 @@ impl<'a> UiState {
|
||||||
v.push(self.fps_indicator.get_textarea(input, window))
|
v.push(self.fps_indicator.get_textarea(input, window))
|
||||||
}
|
}
|
||||||
|
|
||||||
for t in self.elements.iter() {
|
for t in self.elements.values() {
|
||||||
match &t {
|
match &t {
|
||||||
UiElement::Text(x) => v.push(x.get_textarea(input, window)),
|
UiElement::Text(x) => v.push(x.get_textarea(input, window)),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
use super::super::api::Rect;
|
use super::super::api::Rect;
|
||||||
use crate::{ui::event::Event, vertexbuffer::types::UiInstance, RenderInput, RenderState};
|
use crate::{
|
||||||
|
ui::{api::Color, event::Event},
|
||||||
|
vertexbuffer::types::UiInstance,
|
||||||
|
RenderInput, RenderState,
|
||||||
|
};
|
||||||
use galactica_content::{Content, SpriteAutomaton, SpriteHandle};
|
use galactica_content::{Content, SpriteAutomaton, SpriteHandle};
|
||||||
use galactica_util::to_radians;
|
use galactica_util::to_radians;
|
||||||
use rhai::ImmutableString;
|
use rhai::ImmutableString;
|
||||||
|
@ -9,8 +13,12 @@ pub struct Sprite {
|
||||||
pub anim: SpriteAutomaton,
|
pub anim: SpriteAutomaton,
|
||||||
pub name: ImmutableString,
|
pub name: ImmutableString,
|
||||||
|
|
||||||
|
/// Sprite angle, in degrees
|
||||||
|
angle: f32,
|
||||||
|
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
mask: Option<SpriteHandle>,
|
mask: Option<SpriteHandle>,
|
||||||
|
color: Color,
|
||||||
|
|
||||||
/// If true, ignore mouse events until click is released
|
/// If true, ignore mouse events until click is released
|
||||||
waiting_for_release: bool,
|
waiting_for_release: bool,
|
||||||
|
@ -24,6 +32,8 @@ impl Sprite {
|
||||||
name,
|
name,
|
||||||
anim: SpriteAutomaton::new(&ct, sprite),
|
anim: SpriteAutomaton::new(&ct, sprite),
|
||||||
rect,
|
rect,
|
||||||
|
angle: 0.0,
|
||||||
|
color: Color::new(1.0, 1.0, 1.0, 1.0),
|
||||||
mask: None,
|
mask: None,
|
||||||
has_mouse: false,
|
has_mouse: false,
|
||||||
has_click: false,
|
has_click: false,
|
||||||
|
@ -35,6 +45,18 @@ impl Sprite {
|
||||||
self.mask = mask;
|
self.mask = mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_angle(&mut self, angle: f32) {
|
||||||
|
self.angle = angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_rect(&mut self, rect: Rect) {
|
||||||
|
self.rect = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_color(&mut self, color: Color) {
|
||||||
|
self.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push_to_buffer(&self, input: &RenderInput, state: &mut RenderState) {
|
pub fn push_to_buffer(&self, input: &RenderInput, state: &mut RenderState) {
|
||||||
let rect = self
|
let rect = self
|
||||||
.rect
|
.rect
|
||||||
|
@ -46,9 +68,9 @@ impl Sprite {
|
||||||
|
|
||||||
state.push_ui_buffer(UiInstance {
|
state.push_ui_buffer(UiInstance {
|
||||||
position: rect.pos.into(),
|
position: rect.pos.into(),
|
||||||
angle: to_radians(90.0),
|
angle: to_radians(90.0 + self.angle),
|
||||||
dim: rect.dim.into(),
|
dim: rect.dim.into(),
|
||||||
color: [1.0, 1.0, 1.0, 1.0],
|
color: self.color.as_array(),
|
||||||
texture_index: anim_state.texture_index(),
|
texture_index: anim_state.texture_index(),
|
||||||
texture_fade: anim_state.fade,
|
texture_fade: anim_state.fade,
|
||||||
mask_index: self
|
mask_index: self
|
||||||
|
|
|
@ -6,7 +6,15 @@ mod physsim;
|
||||||
mod physwrapper;
|
mod physwrapper;
|
||||||
mod stepresources;
|
mod stepresources;
|
||||||
|
|
||||||
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
pub use physimage::*;
|
pub use physimage::*;
|
||||||
pub use physsim::{PhysSim, PhysSimShipHandle};
|
pub use physsim::{PhysSim, PhysSimShipHandle};
|
||||||
pub use physwrapper::PhysWrapper;
|
pub use physwrapper::PhysWrapper;
|
||||||
pub use stepresources::*;
|
pub use stepresources::*;
|
||||||
|
|
||||||
|
/// A unique id given to each physics object
|
||||||
|
static PHYS_UID: AtomicU64 = AtomicU64::new(0);
|
||||||
|
fn get_phys_id() -> u64 {
|
||||||
|
PHYS_UID.fetch_add(1, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use super::{autopilot, collapse::ShipCollapseSequence, controller::ShipControlle
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{ShipAutoPilot, ShipData, ShipPersonality, ShipState},
|
data::{ShipAutoPilot, ShipData, ShipPersonality, ShipState},
|
||||||
phys::{
|
phys::{
|
||||||
|
get_phys_id,
|
||||||
objects::{PhysEffect, PhysProjectile},
|
objects::{PhysEffect, PhysProjectile},
|
||||||
physsim::NewObjects,
|
physsim::NewObjects,
|
||||||
PhysImage, PhysSimShipHandle, PhysStepResources, PhysWrapper,
|
PhysImage, PhysSimShipHandle, PhysStepResources, PhysWrapper,
|
||||||
|
@ -23,6 +24,9 @@ use crate::{
|
||||||
/// A ship instance in the physics system
|
/// A ship instance in the physics system
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PhysShip {
|
pub struct PhysShip {
|
||||||
|
/// This ship's unique id
|
||||||
|
pub uid: u64,
|
||||||
|
|
||||||
/// This ship's physics handle
|
/// This ship's physics handle
|
||||||
pub rigid_body: RigidBodyHandle,
|
pub rigid_body: RigidBodyHandle,
|
||||||
|
|
||||||
|
@ -71,6 +75,7 @@ impl PhysShip {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let ship_ct = ct.get_ship(handle);
|
let ship_ct = ct.get_ship(handle);
|
||||||
PhysShip {
|
PhysShip {
|
||||||
|
uid: get_phys_id(),
|
||||||
anim: SpriteAutomaton::new(ct, ship_ct.sprite),
|
anim: SpriteAutomaton::new(ct, ship_ct.sprite),
|
||||||
rigid_body,
|
rigid_body,
|
||||||
collider,
|
collider,
|
||||||
|
|
|
@ -13,6 +13,11 @@ pub fn to_radians(degrees: f32) -> f32 {
|
||||||
return (degrees / 360.0) * std::f32::consts::TAU;
|
return (degrees / 360.0) * std::f32::consts::TAU;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert an angle in radians to degrees
|
||||||
|
pub fn to_degrees(radians: f32) -> f32 {
|
||||||
|
return (radians / std::f32::consts::TAU) * 360.0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute the clockwise angle between two vectors
|
/// Compute the clockwise angle between two vectors
|
||||||
/// Returns a value in [-pi, pi]
|
/// Returns a value in [-pi, pi]
|
||||||
pub fn clockwise_angle(a: &Vector2<f32>, b: &Vector2<f32>) -> f32 {
|
pub fn clockwise_angle(a: &Vector2<f32>, b: &Vector2<f32>) -> f32 {
|
||||||
|
|
Loading…
Reference in New Issue