Compare commits

..

No commits in common. "fd94cd670150642a7d61803d005339e0916a39d0" and "5279eeb7d45bf5c8857a365f09f1a93f67918722" have entirely different histories.

19 changed files with 139 additions and 234 deletions

2
assets

@ -1 +1 @@
Subproject commit 45f65b6a639f3e59d9d1db2a4cf452fe406bd4b2 Subproject commit 66b7aab8af273cac9b805d813f2e5cb70a920000

View File

@ -3,26 +3,11 @@
name = "12 Autumn above" name = "12 Autumn above"
[object.star] [object.star]
sprite = "star::star" sprite = "star::a0"
position = [0.0, 0.0] center = [0.0, 0.0]
size = 1000
parallax = 20.0
[object.earth] [object.earth]
sprite = "planet::earth" sprite = "planet::earth"
position.center = "star" center = "star"
position.radius = 4000 radius = 200
position.angle = 0 angle = 14
size = 1000
parallax = 10.0
[object.luna]
sprite = "planet::luna"
position.center = "earth"
position.radius = 1600
position.angle = 135
size = 500
angle = -45
parallax = 7.8

View File

@ -1,25 +1,24 @@
use anyhow::{Context, Result}; use anyhow::Result;
use std::path::PathBuf;
use super::{syntax, ContentType}; use super::{syntax, ContentType};
#[derive(Debug)] #[derive(Debug)]
pub struct Content { pub struct Content {
pub systems: Vec<syntax::system::System>, systems: Vec<syntax::System>,
} }
impl Content { impl Content {
pub fn new(cv: Vec<(PathBuf, ContentType)>) -> Result<Self> { pub fn new(cv: Vec<ContentType>) -> Result<Self> {
let mut content = Self { let mut content = Self {
systems: Vec::new(), systems: Vec::new(),
}; };
// TODO: locate bad files
// These methods check intra-file consistency // These methods check intra-file consistency
for (p, c) in cv { for c in cv {
match c { match c {
ContentType::System(v) => content ContentType::System(v) => content.add_system(v)?,
.add_system(v)
.with_context(|| format!("Could not parse {}", p.display()))?,
}; };
} }
@ -27,7 +26,7 @@ impl Content {
} }
fn add_system(&mut self, toml: syntax::system::toml::SystemRoot) -> Result<()> { fn add_system(&mut self, toml: syntax::system::toml::SystemRoot) -> Result<()> {
self.systems.push(syntax::system::System::parse(toml)?); self.systems.push(syntax::System::parse(toml)?);
return Ok(()); return Ok(());
} }
} }

View File

@ -1,4 +1,4 @@
use anyhow::{bail, Result}; use anyhow::Result;
use std::{fs::File, io::Read, path::Path}; use std::{fs::File, io::Read, path::Path};
use super::syntax; use super::syntax;
@ -12,21 +12,12 @@ pub enum ContentType {
impl ContentType { impl ContentType {
pub fn try_parse(file_string: &str) -> Result<Option<Self>> { pub fn try_parse(file_string: &str) -> Result<Option<Self>> {
// TODO: More advanced parsing, read the whole top comment // TODO: More advanced parsing, read the whole top comment
let first = match file_string.split_once("\n") { let (first, _) = file_string.split_once("\n").unwrap();
None => bail!("This file is empty."),
Some((first, _)) => first,
};
let type_spec = first[1..].trim(); // Remove hash let type_spec = first[1..].trim(); // Remove hash
let type_spec = if type_spec.starts_with("content type: ") { return Ok(match type_spec {
type_spec[14..].to_owned() "content type: system" => Some(Self::System(toml::from_str(&file_string)?)),
} else { _ => None,
bail!("No content type specified")
};
return Ok(match &type_spec[..] {
"system" => Some(Self::System(toml::from_str(&file_string)?)),
_ => bail!("Invalid content type `{}`", type_spec),
}); });
} }

View File

@ -4,38 +4,3 @@ mod syntax;
pub use content::Content; pub use content::Content;
pub use contenttype::ContentType; pub use contenttype::ContentType;
pub use syntax::system;
use anyhow::{Context, Result};
use walkdir::WalkDir;
pub fn load_content_dir(path: &str) -> Result<Content> {
let mut raw_content = Vec::new();
for e in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) {
if e.metadata().unwrap().is_file() {
// TODO: better warnings
match e.path().extension() {
Some(t) => {
if t.to_str() != Some("toml") {
println!("[WARNING] {e:#?} is not a toml file, skipping.");
continue;
}
}
None => {
println!("[WARNING] {e:#?} is not a toml file, skipping.");
continue;
}
}
let c = crate::content::ContentType::from_path(e.path())
.with_context(|| format!("Could not load {:#?}", e.path()))?;
match c {
Some(c) => raw_content.push((e.path().to_path_buf(), c)),
None => continue,
}
}
}
return crate::content::Content::new(raw_content);
}

View File

@ -1,2 +1,3 @@
#![allow(dead_code)] #![allow(dead_code)]
pub mod system; pub mod system;
pub use system::System;

View File

@ -1,8 +1,8 @@
use anyhow::{bail, Context, Result}; use anyhow::{bail, Result};
use cgmath::{Deg, Point2}; use cgmath::Point2;
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
use crate::physics::{Pfloat, Polar}; use crate::physics::Pfloat;
/// Toml file syntax /// Toml file syntax
pub(in crate::content) mod toml { pub(in crate::content) mod toml {
@ -24,106 +24,43 @@ pub(in crate::content) mod toml {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct Object { pub struct Object {
pub sprite: String, pub sprite: String,
pub position: Position, pub center: Center,
pub size: Pfloat, #[serde(default)]
pub parallax: Pfloat,
pub radius: Option<Pfloat>,
pub angle: Option<Pfloat>,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum Position {
Polar(PolarCoords),
Cartesian(Coordinates),
}
#[derive(Debug, Deserialize)]
pub struct PolarCoords {
pub center: Coordinates,
pub radius: Pfloat, pub radius: Pfloat,
#[serde(default)]
pub angle: Pfloat, pub angle: Pfloat,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum Coordinates { pub enum Center {
Label(String), Label(String),
Coords([Pfloat; 2]), Coords([Pfloat; 2]),
} }
impl ToString for Coordinates {
fn to_string(&self) -> String {
match self {
Self::Label(s) => s.to_owned(),
Self::Coords(v) => format!("{:?}", v),
}
}
}
} }
#[derive(Debug)] #[derive(Debug)]
pub struct System { pub struct System {
pub name: String, name: String,
pub objects: Vec<Object>, objects: Vec<Object>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Object { struct Object {
pub sprite: String, sprite: String,
pub position: Point2<f32>, center: Point2<Pfloat>,
pub size: Pfloat, radius: Pfloat,
pub parallax: Pfloat, angle: Pfloat,
pub angle: Deg<Pfloat>,
} }
fn resolve_coordinates( fn resolve_center(
objects: &HashMap<String, toml::Object>,
cor: &toml::Coordinates,
mut cycle_detector: HashSet<String>,
) -> Result<Point2<f32>> {
match cor {
toml::Coordinates::Coords(c) => Ok((*c).into()),
toml::Coordinates::Label(l) => {
if cycle_detector.contains(l) {
bail!(
"Found coordinate cycle: `{}`",
cycle_detector.iter().fold(String::new(), |sum, a| {
if sum.is_empty() {
a.to_string()
} else {
sum + " -> " + a
}
})
);
}
cycle_detector.insert(l.to_owned());
let p = match objects.get(l) {
Some(p) => p,
None => bail!("Could not resolve coordinate label `{l}`"),
};
Ok(resolve_position(&objects, &p, cycle_detector)
.with_context(|| format!("In object {:#?}", l))?)
}
}
}
fn resolve_position(
objects: &HashMap<String, toml::Object>, objects: &HashMap<String, toml::Object>,
obj: &toml::Object, obj: &toml::Object,
cycle_detector: HashSet<String>, ) -> Option<Point2<f32>> {
) -> Result<Point2<f32>> { match &obj.center {
match &obj.position { toml::Center::Label(s) => resolve_center(&objects, objects.get(s)?),
toml::Position::Cartesian(c) => Ok(resolve_coordinates(objects, c, cycle_detector)?), toml::Center::Coords(v) => Some(Point2::from(*v)),
toml::Position::Polar(p) => Ok(Polar {
center: resolve_coordinates(&objects, &p.center, cycle_detector)?,
radius: p.radius,
angle: Deg(p.angle),
}
.to_cartesian()),
} }
} }
@ -131,17 +68,22 @@ impl System {
pub fn parse(value: toml::SystemRoot) -> Result<Self> { pub fn parse(value: toml::SystemRoot) -> Result<Self> {
let mut objects = Vec::new(); let mut objects = Vec::new();
for (label, obj) in &value.object { for (_, obj) in &value.object {
let mut cycle_detector = HashSet::new(); let center = match resolve_center(&value.object, obj) {
cycle_detector.insert(label.to_owned()); Some(v) => v,
None => {
bail!(
"Failed to parse content file: could not resolve center label `{:?}`",
obj.center
);
}
};
objects.push(Object { objects.push(Object {
sprite: obj.sprite.clone(), sprite: obj.sprite.clone(),
position: resolve_position(&value.object, &obj, cycle_detector) center,
.with_context(|| format!("In object {:#?}", label))?, radius: obj.radius,
size: obj.size, angle: obj.angle,
parallax: obj.parallax,
angle: Deg(obj.angle.unwrap_or(0.0)),
}); });
} }

View File

@ -6,18 +6,17 @@ pub struct Doodad {
pub sprite: SpriteTexture, pub sprite: SpriteTexture,
pub pos: Point2<Pfloat>, pub pos: Point2<Pfloat>,
pub parallax: Pfloat, pub parallax: Pfloat,
pub size: Pfloat, pub height: Pfloat,
pub angle: Deg<Pfloat>,
} }
impl Spriteable for Doodad { impl Spriteable for Doodad {
fn get_sprite(&self) -> Sprite { fn get_sprite(&self) -> Sprite {
return Sprite { return Sprite {
texture: self.sprite.clone(), texture: self.sprite.clone(),
scale: 1.0,
pos: self.pos, pos: self.pos,
angle: self.angle, angle: Deg { 0: 0.0 },
size: self.size, scale: 1.0,
height: self.height,
parallax: self.parallax, parallax: self.parallax,
}; };
} }

View File

@ -8,8 +8,8 @@ mod system;
use anyhow::Result; use anyhow::Result;
use cgmath::{Deg, Point2}; use cgmath::{Deg, Point2};
use content::Content;
use std::time::Instant; use std::time::Instant;
use walkdir::WalkDir;
use winit::{ use winit::{
event::{ event::{
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase,
@ -69,10 +69,10 @@ struct Sprite {
/// The size of this sprite, /// The size of this sprite,
/// given as height in world units. /// given as height in world units.
size: Pfloat, height: Pfloat,
/// Scale factor. /// Scale factor.
/// if this is 1, sprite height is exactly self.size. /// if this is 1, sprite height is exactly self.height.
scale: Pfloat, scale: Pfloat,
/// This sprite's rotation /// This sprite's rotation
@ -95,7 +95,7 @@ struct Game {
} }
impl Game { impl Game {
fn new(ct: Content) -> Self { fn new() -> Self {
Game { Game {
last_update: Instant::now(), last_update: Instant::now(),
input: InputStatus::new(), input: InputStatus::new(),
@ -104,7 +104,7 @@ impl Game {
pos: (0.0, 0.0).into(), pos: (0.0, 0.0).into(),
zoom: 500.0, zoom: 500.0,
}, },
system: System::new(&ct.systems[0]), system: System::new(),
} }
} }
@ -128,11 +128,11 @@ impl Game {
} }
if self.input.key_right { if self.input.key_right {
self.player.body.rot(Deg(35.0) * t); self.player.body.rot(Deg { 0: 35.0 } * t);
} }
if self.input.key_left { if self.input.key_left {
self.player.body.rot(Deg(-35.0) * t); self.player.body.rot(Deg { 0: -35.0 } * t);
} }
if self.input.v_scroll != 0.0 { if self.input.v_scroll != 0.0 {
@ -140,7 +140,6 @@ impl Game {
self.input.v_scroll = 0.0; self.input.v_scroll = 0.0;
} }
println!("{:?}", self.player.body.pos);
self.player.body.tick(t); self.player.body.tick(t);
self.camera.pos = self.player.body.pos; self.camera.pos = self.player.body.pos;
@ -164,11 +163,12 @@ impl Game {
} }
} }
async fn run(mut game: Game) -> Result<()> { pub async fn run() -> Result<()> {
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
let mut gpu = GPUState::new(window).await?; let mut gpu = GPUState::new(window).await?;
let mut game = Game::new();
gpu.update_starfield_buffer(&game); gpu.update_starfield_buffer(&game);
@ -231,10 +231,20 @@ async fn run(mut game: Game) -> Result<()> {
} }
fn main() -> Result<()> { fn main() -> Result<()> {
let content = content::load_content_dir("./content")?; let mut raw_content = Vec::new();
println!("{:?}", content); for e in WalkDir::new("content").into_iter().filter_map(|e| e.ok()) {
let game = Game::new(content); if e.metadata().unwrap().is_file() {
let c = crate::content::ContentType::from_path(e.path())?;
match c {
Some(c) => raw_content.push(c),
None => continue,
}
}
}
pollster::block_on(run(game))?; let a = crate::content::Content::new(raw_content)?;
println!("{:?}", a);
//pollster::block_on(run())?;
return Ok(()); return Ok(());
} }

View File

@ -14,7 +14,7 @@ impl PhysBody {
pos, pos,
vel: (0.0, 0.0).into(), vel: (0.0, 0.0).into(),
mass: 0.3, mass: 0.3,
angle: Deg(0.0), angle: Deg { 0: 0.0 },
}; };
} }
@ -43,7 +43,9 @@ impl PhysBody {
// Wrap angles // Wrap angles
if self.angle.0.abs() > 180.0 { if self.angle.0.abs() > 180.0 {
self.angle -= Deg(self.angle.0.signum() * 360.0); self.angle -= Deg {
0: self.angle.0.signum() * 360.0,
};
} }
} }
} }

View File

@ -1,5 +1,5 @@
use super::Pfloat; use super::Pfloat;
use cgmath::{Angle, Deg, Point2, Vector2}; use cgmath::{Angle, Deg, EuclideanSpace, Point2};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Polar { pub struct Polar {
@ -10,11 +10,9 @@ pub struct Polar {
impl Polar { impl Polar {
pub fn to_cartesian(self) -> Point2<Pfloat> { pub fn to_cartesian(self) -> Point2<Pfloat> {
let v = Vector2 { return Point2 {
x: self.radius * self.angle.sin(), x: self.radius * self.angle.sin(),
y: self.radius * self.angle.cos(), y: self.radius * self.angle.cos(),
}; } + self.center.to_vec();
return self.center + v;
} }
} }

View File

@ -223,7 +223,7 @@ impl GPUState {
// Game dimensions of this sprite post-scale. // Game dimensions of this sprite post-scale.
// Don't divide by 2, we use this later. // Don't divide by 2, we use this later.
let height = s.size * s.scale / s.parallax; let height = s.height * s.scale;
let width = height * texture.aspect; let width = height * texture.aspect;
// Don't draw (or compute matrices for) // Don't draw (or compute matrices for)
@ -311,7 +311,7 @@ impl GPUState {
instances.push(StarfieldInstance { instances.push(StarfieldInstance {
position: (s.pos + offset).into(), position: (s.pos + offset).into(),
parallax: s.parallax, parallax: s.parallax,
size: s.size, height: s.height,
tint: s.tint.into(), tint: s.tint.into(),
}) })
} }

View File

@ -7,8 +7,10 @@ mod vertexbuffer;
pub use gpustate::GPUState; pub use gpustate::GPUState;
/// A handle to a sprite texture /// A handle to a sprite texture
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct SpriteTexture(pub String); pub struct SpriteTexture {
pub name: &'static str,
}
// API correction matrix. // API correction matrix.
// cgmath uses OpenGL's matrix format, which // cgmath uses OpenGL's matrix format, which

View File

@ -2,7 +2,7 @@
struct InstanceInput { struct InstanceInput {
@location(2) position: vec2<f32>, @location(2) position: vec2<f32>,
@location(3) parallax: f32, @location(3) parallax: f32,
@location(4) size: f32, @location(4) height: f32,
@location(5) tint: vec2<f32>, @location(5) tint: vec2<f32>,
}; };
@ -57,7 +57,7 @@ fn vertex_shader_main(
// Apply sprite aspect ratio & scale factor // Apply sprite aspect ratio & scale factor
// also applies screen aspect ratio // also applies screen aspect ratio
var scale: f32 = instance.size / global.camera_zoom.x; var scale: f32 = instance.height / global.camera_zoom.x;
// Minimum scale to prevent flicker at large zoom levels // Minimum scale to prevent flicker at large zoom levels
var real_size = scale * global.window_size.xy; var real_size = scale * global.window_size.xy;

View File

@ -21,7 +21,7 @@ impl TextureArray {
} }
pub fn get_sprite_texture(&self, sprite: SpriteTexture) -> Texture { pub fn get_sprite_texture(&self, sprite: SpriteTexture) -> Texture {
return self.get_texture(&sprite.0); return self.get_texture(sprite.name);
} }
fn get_texture(&self, name: &str) -> Texture { fn get_texture(&self, name: &str) -> Texture {

View File

@ -1,11 +1,10 @@
use anyhow::Result; use anyhow::Result;
use std::{collections::HashMap, fs::File, io::Read, path::Path, path::PathBuf}; use std::{collections::HashMap, fs::File, io::Read, path::Path};
use super::{rawtexture::RawTexture, Texture, TextureArrayConfig}; use super::{rawtexture::RawTexture, Texture, TextureArrayConfig};
mod fields { mod fields {
use super::{File, Path, RawTexture, Read, Result, TextureArrayConfig};
use super::{File, HashMap, Path, PathBuf, RawTexture, Read, Result, TextureArrayConfig};
use serde::Deserialize; use serde::Deserialize;
// Config is used outside of this file, // Config is used outside of this file,
@ -14,7 +13,7 @@ mod fields {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Index { pub struct Index {
pub config: TextureArrayConfig, pub config: TextureArrayConfig,
pub include: Option<HashMap<PathBuf, String>>, pub include: Option<Vec<String>>,
pub texture: Vec<Texture>, pub texture: Vec<Texture>,
} }
@ -32,7 +31,7 @@ mod fields {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct SubIndex { pub struct SubIndex {
pub include: Option<HashMap<PathBuf, String>>, pub include: Option<Vec<String>>,
pub texture: Vec<Texture>, pub texture: Vec<Texture>,
} }
@ -153,8 +152,8 @@ impl TextureLoader {
// Load included files // Load included files
if let Some(include) = index.include { if let Some(include) = index.include {
for (path, sub_prefix) in include { for i in include {
let sub_root = texture_root.join(&path); let sub_root = texture_root.join(&i);
let index: fields::SubIndex = { let index: fields::SubIndex = {
let mut texture_index_string = String::new(); let mut texture_index_string = String::new();
let _ = File::open(sub_root.join(Self::INDEX_NAME))? let _ = File::open(sub_root.join(Self::INDEX_NAME))?
@ -168,9 +167,9 @@ impl TextureLoader {
index, index,
&sub_root, &sub_root,
if prefix.is_empty() { if prefix.is_empty() {
sub_prefix i
} else { } else {
format!("{prefix}::{sub_prefix}") format!("{prefix}::{i}")
}, },
)?; )?;
for (s, data) in sub_textures { for (s, data) in sub_textures {

View File

@ -44,7 +44,9 @@ pub struct StarfieldInstance {
/// Parallax factor (same unit as usual) /// Parallax factor (same unit as usual)
pub parallax: f32, pub parallax: f32,
pub size: f32, /// Height of (unrotated) sprite in world units
pub height: f32,
pub tint: [f32; 2], pub tint: [f32; 2],
} }
@ -66,7 +68,7 @@ impl BufferObject for StarfieldInstance {
shader_location: 3, shader_location: 3,
format: wgpu::VertexFormat::Float32, format: wgpu::VertexFormat::Float32,
}, },
// Size // Height
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
shader_location: 4, shader_location: 4,

View File

@ -12,10 +12,10 @@ impl ShipKind {
Self::Gypsum => "ship::gypsum", Self::Gypsum => "ship::gypsum",
}; };
return SpriteTexture(name.to_owned()); return SpriteTexture { name };
} }
fn size(&self) -> Pfloat { fn height(&self) -> Pfloat {
match self { match self {
Self::Gypsum => 100.0, Self::Gypsum => 100.0,
} }
@ -44,7 +44,7 @@ impl Spriteable for Ship {
angle: self.body.angle, angle: self.body.angle,
scale: 1.0, scale: 1.0,
parallax: 1.0, parallax: 1.0,
size: self.kind.size(), height: self.kind.height(),
}; };
} }
} }

View File

@ -1,8 +1,10 @@
use crate::{ use crate::{
content, physics::Pfloat, render::SpriteTexture, Doodad, Sprite, Spriteable, STARFIELD_COUNT, physics::{Pfloat, Polar},
STARFIELD_PARALLAX_MAX, STARFIELD_PARALLAX_MIN, STARFIELD_SIZE, render::SpriteTexture,
Doodad, Sprite, Spriteable, STARFIELD_COUNT, STARFIELD_PARALLAX_MAX, STARFIELD_PARALLAX_MIN,
STARFIELD_SIZE,
}; };
use cgmath::{Point2, Vector2}; use cgmath::{Deg, Point2, Vector2};
use rand::{self, Rng}; use rand::{self, Rng};
pub struct StarfieldStar { pub struct StarfieldStar {
@ -10,9 +12,8 @@ pub struct StarfieldStar {
/// These are relative to the center of a starfield tile. /// These are relative to the center of a starfield tile.
pub pos: Point2<Pfloat>, pub pos: Point2<Pfloat>,
// TODO: z-coordinate?
pub parallax: Pfloat, pub parallax: Pfloat,
pub size: Pfloat, pub height: Pfloat,
/// Color/brightness variation. /// Color/brightness variation.
/// See shader. /// See shader.
@ -20,17 +21,15 @@ pub struct StarfieldStar {
} }
pub struct System { pub struct System {
pub name: String,
bodies: Vec<Doodad>, bodies: Vec<Doodad>,
pub starfield: Vec<StarfieldStar>, pub starfield: Vec<StarfieldStar>,
} }
impl System { impl System {
pub fn new(ct: &content::system::System) -> Self { pub fn new() -> Self {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let sz = STARFIELD_SIZE as f32 / 2.0; let sz = STARFIELD_SIZE as f32 / 2.0;
let mut s = System { let mut s = System {
name: ct.name.clone(),
bodies: Vec::new(), bodies: Vec::new(),
starfield: (0..STARFIELD_COUNT) starfield: (0..STARFIELD_COUNT)
.map(|_| StarfieldStar { .map(|_| StarfieldStar {
@ -39,7 +38,7 @@ impl System {
y: rng.gen_range(-sz..=sz), y: rng.gen_range(-sz..=sz),
}, },
parallax: rng.gen_range(STARFIELD_PARALLAX_MIN..STARFIELD_PARALLAX_MAX), parallax: rng.gen_range(STARFIELD_PARALLAX_MIN..STARFIELD_PARALLAX_MAX),
size: rng.gen_range(0.2..0.8), // TODO: configurable height: rng.gen_range(0.2..0.8), // TODO: configurable
tint: Vector2 { tint: Vector2 {
x: rng.gen_range(0.0..=1.0), x: rng.gen_range(0.0..=1.0),
y: rng.gen_range(0.0..=1.0), y: rng.gen_range(0.0..=1.0),
@ -48,15 +47,26 @@ impl System {
.collect(), .collect(),
}; };
for o in &ct.objects {
s.bodies.push(Doodad { s.bodies.push(Doodad {
pos: o.position, pos: (0.0, 0.0).into(),
sprite: SpriteTexture(o.sprite.to_owned()), sprite: SpriteTexture { name: "star::star" },
size: o.size, parallax: 10.0,
parallax: o.parallax, height: 80.0,
angle: o.angle,
}); });
s.bodies.push(Doodad {
pos: Polar {
center: (0.0, 0.0).into(),
radius: 5000.0,
angle: Deg { 0: 31.0 },
} }
.to_cartesian(),
sprite: SpriteTexture {
name: "planet::earth",
},
parallax: 5.0,
height: 120.0,
});
return s; return s;
} }