parent
10f9776108
commit
c382431747
|
@ -7,8 +7,8 @@ rate = 0.2
|
||||||
# Random rate variation (each cooldown is +- this)
|
# Random rate variation (each cooldown is +- this)
|
||||||
rate_rng = 0.1
|
rate_rng = 0.1
|
||||||
|
|
||||||
# TODO: apply force on fire
|
# TODO: apply force to ship on fire
|
||||||
projectile.sprite_texture = "projectile::blaster"
|
projectile.sprite = "projectile::blaster"
|
||||||
# Height of projectile in game units
|
# Height of projectile in game units
|
||||||
projectile.size = 6
|
projectile.size = 6
|
||||||
projectile.size_rng = 0.0
|
projectile.size_rng = 0.0
|
||||||
|
@ -29,13 +29,13 @@ projectile.force = 0.0
|
||||||
|
|
||||||
projectile.collider.ball.radius = 2.0
|
projectile.collider.ball.radius = 2.0
|
||||||
|
|
||||||
projectile.impact.texture = "particle::blaster"
|
projectile.impact.sprite = "particle::explosion"
|
||||||
projectile.impact.lifetime = "inherit"
|
projectile.impact.lifetime = "inherit"
|
||||||
projectile.impact.inherit_velocity = "target"
|
projectile.impact.inherit_velocity = "target"
|
||||||
projectile.impact.size = 3.0
|
projectile.impact.size = 3.0
|
||||||
|
|
||||||
|
|
||||||
projectile.expire.texture = "particle::blaster"
|
projectile.expire.sprite = "particle::blaster"
|
||||||
projectile.expire.lifetime = "inherit"
|
projectile.expire.lifetime = "inherit"
|
||||||
projectile.expire.inherit_velocity = "projectile"
|
projectile.expire.inherit_velocity = "projectile"
|
||||||
projectile.expire.size = 3.0
|
projectile.expire.size = 3.0
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
space.engine = 20
|
space.engine = 20
|
||||||
|
|
||||||
engine.thrust = 100
|
engine.thrust = 100
|
||||||
engine.flare_texture = "flare::ion"
|
engine.flare_sprite = "flare::ion"
|
||||||
steering.power = 20
|
steering.power = 20
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[ship."Gypsum"]
|
[ship."Gypsum"]
|
||||||
sprite_texture = "ship::gypsum"
|
sprite = "ship::gypsum"
|
||||||
size = 100
|
size = 100
|
||||||
mass = 1
|
mass = 1
|
||||||
hull = 200
|
hull = 200
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
[texture."starfield"]
|
[sprite."starfield"]
|
||||||
file = "starfield.png"
|
file = "starfield.png"
|
||||||
|
|
||||||
[texture."star::star"]
|
[sprite."star::star"]
|
||||||
file = "star/B-09.png"
|
file = "star/B-09.png"
|
||||||
|
|
||||||
[texture."flare::ion"]
|
[sprite."flare::ion"]
|
||||||
file = "flare/1.png"
|
file = "flare/1.png"
|
||||||
|
|
||||||
[texture."planet::earth"]
|
[sprite."planet::earth"]
|
||||||
file = "planet/earth.png"
|
file = "planet/earth.png"
|
||||||
|
|
||||||
[texture."planet::luna"]
|
[sprite."planet::luna"]
|
||||||
file = "planet/luna.png"
|
file = "planet/luna.png"
|
||||||
|
|
||||||
[texture."projectile::blaster"]
|
[sprite."projectile::blaster"]
|
||||||
file = "projectile/blaster.png"
|
file = "projectile/blaster.png"
|
||||||
|
|
||||||
[texture."ship::gypsum"]
|
[sprite."ship::gypsum"]
|
||||||
file = "ship/gypsum.png"
|
file = "ship/gypsum.png"
|
||||||
|
|
||||||
[texture."ui::radar"]
|
[sprite."ui::radar"]
|
||||||
file = "ui/radar.png"
|
file = "ui/radar.png"
|
||||||
|
|
||||||
[texture."ui::shipblip"]
|
[sprite."ui::shipblip"]
|
||||||
file = "ui/ship-blip.png"
|
file = "ui/ship-blip.png"
|
||||||
|
|
||||||
[texture."ui::planetblip"]
|
[sprite."ui::planetblip"]
|
||||||
file = "ui/planet-blip.png"
|
file = "ui/planet-blip.png"
|
||||||
|
|
||||||
[texture."ui::radarframe"]
|
[sprite."ui::radarframe"]
|
||||||
file = "ui/radarframe.png"
|
file = "ui/radarframe.png"
|
||||||
|
|
||||||
[texture."ui::centerarrow"]
|
[sprite."ui::centerarrow"]
|
||||||
file = "ui/center-arrow.png"
|
file = "ui/center-arrow.png"
|
||||||
|
|
||||||
[texture."particle::blaster"]
|
[sprite."particle::blaster"]
|
||||||
duration = 0.15
|
duration = 0.15
|
||||||
repeat = "once"
|
repeat = "once"
|
||||||
frames = [
|
frames = [
|
||||||
|
@ -45,7 +45,7 @@ frames = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[texture."particle::explosion"]
|
[sprite."particle::explosion"]
|
||||||
duration = 0.4
|
duration = 0.4
|
||||||
repeat = "once"
|
repeat = "once"
|
||||||
frames = [
|
frames = [
|
|
@ -1,17 +1,17 @@
|
||||||
[system."12 Autumn Above"]
|
[system."12 Autumn Above"]
|
||||||
|
|
||||||
object.star.sprite_texture = "star::star"
|
object.star.sprite = "star::star"
|
||||||
object.star.position = [0.0, 0.0, 30.0]
|
object.star.position = [0.0, 0.0, 30.0]
|
||||||
object.star.size = 2000
|
object.star.size = 2000
|
||||||
|
|
||||||
object.earth.sprite_texture = "planet::earth"
|
object.earth.sprite = "planet::earth"
|
||||||
object.earth.position.center = "star"
|
object.earth.position.center = "star"
|
||||||
object.earth.position.radius = 4000
|
object.earth.position.radius = 4000
|
||||||
object.earth.position.angle = 0
|
object.earth.position.angle = 0
|
||||||
object.earth.position.z = 10.0
|
object.earth.position.z = 10.0
|
||||||
object.earth.size = 1000
|
object.earth.size = 1000
|
||||||
|
|
||||||
object.luna.sprite_texture = "planet::luna"
|
object.luna.sprite = "planet::luna"
|
||||||
object.luna.position.center = "earth"
|
object.luna.position.center = "earth"
|
||||||
object.luna.position.radius = 1600
|
object.luna.position.radius = 1600
|
||||||
object.luna.position.angle = 135
|
object.luna.position.angle = 135
|
||||||
|
|
|
@ -35,14 +35,14 @@ pub const STARFIELD_DENSITY: f64 = 0.01;
|
||||||
/// Must fit inside an i32
|
/// Must fit inside an i32
|
||||||
pub const STARFIELD_COUNT: u64 = (STARFIELD_SIZE as f64 * STARFIELD_DENSITY) as u64;
|
pub const STARFIELD_COUNT: u64 = (STARFIELD_SIZE as f64 * STARFIELD_DENSITY) as u64;
|
||||||
|
|
||||||
/// Name of starfield texture
|
/// Name of starfield sprite
|
||||||
pub const STARFIELD_TEXTURE_NAME: &'static str = "starfield";
|
pub const STARFIELD_SPRITE_NAME: &'static str = "starfield";
|
||||||
|
|
||||||
/// Root directory of game content
|
/// Root directory of game content
|
||||||
pub const CONTENT_ROOT: &'static str = "./content";
|
pub const CONTENT_ROOT: &'static str = "./content";
|
||||||
|
|
||||||
/// Root directory of game textures
|
/// Root directory of game images
|
||||||
pub const TEXTURE_ROOT: &'static str = "./assets/render";
|
pub const IMAGE_ROOT: &'static str = "./assets/render";
|
||||||
|
|
||||||
/// We can draw at most this many object sprites on the screen.
|
/// We can draw at most this many object sprites on the screen.
|
||||||
pub const OBJECT_SPRITE_INSTANCE_LIMIT: u64 = 500;
|
pub const OBJECT_SPRITE_INSTANCE_LIMIT: u64 = 500;
|
||||||
|
|
|
@ -17,6 +17,8 @@ readme = { workspace = true }
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
galactica-packer = { workspace = true }
|
||||||
|
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
toml = { workspace = true }
|
toml = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
|
|
@ -7,24 +7,24 @@
|
||||||
//! in our code. It's managable, but the approach here is simpler and easier to understand.
|
//! in our code. It's managable, but the approach here is simpler and easier to understand.
|
||||||
use std::{cmp::Eq, hash::Hash};
|
use std::{cmp::Eq, hash::Hash};
|
||||||
|
|
||||||
/// A lightweight representation of a
|
/// A lightweight representation of a sprite
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct TextureHandle {
|
pub struct SpriteHandle {
|
||||||
/// The index of this texture in content.textures
|
/// The index of this sprite in content.sprites
|
||||||
pub(crate) index: usize,
|
pub(crate) index: usize,
|
||||||
|
|
||||||
/// The aspect ratio of this texture (width / height)
|
/// The aspect ratio of this sprite (width / height)
|
||||||
pub aspect: f32,
|
pub aspect: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for TextureHandle {
|
impl Hash for SpriteHandle {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.index.hash(state)
|
self.index.hash(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for TextureHandle {}
|
impl Eq for SpriteHandle {}
|
||||||
impl PartialEq for TextureHandle {
|
impl PartialEq for SpriteHandle {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.index.eq(&other.index)
|
self.index.eq(&other.index)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ mod part;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use galactica_packer::{SpriteAtlas, SpriteAtlasImage};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::File,
|
fs::File,
|
||||||
|
@ -17,10 +18,10 @@ use std::{
|
||||||
use toml;
|
use toml;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
pub use handle::{FactionHandle, GunHandle, OutfitHandle, ShipHandle, SystemHandle, TextureHandle};
|
pub use handle::{FactionHandle, GunHandle, OutfitHandle, ShipHandle, SpriteHandle, SystemHandle};
|
||||||
pub use part::{
|
pub use part::{
|
||||||
EnginePoint, Faction, Gun, GunPoint, ImpactInheritVelocity, Outfit, OutfitSpace, Projectile,
|
EnginePoint, Faction, Gun, GunPoint, ImpactInheritVelocity, Outfit, OutfitSpace, Projectile,
|
||||||
ProjectileCollider, ProjectileParticle, Relationship, RepeatMode, Ship, System, Texture,
|
ProjectileCollider, ProjectileParticle, Relationship, RepeatMode, Ship, Sprite, System,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod syntax {
|
mod syntax {
|
||||||
|
@ -28,7 +29,7 @@ mod syntax {
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{collections::HashMap, fmt::Display, hash::Hash};
|
use std::{collections::HashMap, fmt::Display, hash::Hash};
|
||||||
|
|
||||||
use crate::part::{faction, gun, outfit, ship, system, texture};
|
use crate::part::{faction, gun, outfit, ship, sprite, system};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Root {
|
pub struct Root {
|
||||||
|
@ -36,7 +37,7 @@ mod syntax {
|
||||||
pub ship: Option<HashMap<String, ship::syntax::Ship>>,
|
pub ship: Option<HashMap<String, ship::syntax::Ship>>,
|
||||||
pub system: Option<HashMap<String, system::syntax::System>>,
|
pub system: Option<HashMap<String, system::syntax::System>>,
|
||||||
pub outfit: Option<HashMap<String, outfit::syntax::Outfit>>,
|
pub outfit: Option<HashMap<String, outfit::syntax::Outfit>>,
|
||||||
pub texture: Option<HashMap<String, texture::syntax::Texture>>,
|
pub sprite: Option<HashMap<String, sprite::syntax::Sprite>>,
|
||||||
pub faction: Option<HashMap<String, faction::syntax::Faction>>,
|
pub faction: Option<HashMap<String, faction::syntax::Faction>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ mod syntax {
|
||||||
ship: None,
|
ship: None,
|
||||||
system: None,
|
system: None,
|
||||||
outfit: None,
|
outfit: None,
|
||||||
texture: None,
|
sprite: None,
|
||||||
faction: None,
|
faction: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,8 +85,8 @@ mod syntax {
|
||||||
.with_context(|| "while merging systems")?;
|
.with_context(|| "while merging systems")?;
|
||||||
merge_hashmap(&mut self.outfit, other.outfit)
|
merge_hashmap(&mut self.outfit, other.outfit)
|
||||||
.with_context(|| "while merging outfits")?;
|
.with_context(|| "while merging outfits")?;
|
||||||
merge_hashmap(&mut self.texture, other.texture)
|
merge_hashmap(&mut self.sprite, other.sprite)
|
||||||
.with_context(|| "while merging textures")?;
|
.with_context(|| "while merging sprites")?;
|
||||||
merge_hashmap(&mut self.faction, other.faction)
|
merge_hashmap(&mut self.faction, other.faction)
|
||||||
.with_context(|| "while merging factions")?;
|
.with_context(|| "while merging factions")?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -94,10 +95,10 @@ mod syntax {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Build {
|
trait Build {
|
||||||
type InputSyntax;
|
type InputSyntaxType;
|
||||||
|
|
||||||
/// Build a processed System struct from raw serde data
|
/// Build a processed System struct from raw serde data
|
||||||
fn build(root: Self::InputSyntax, ct: &mut Content) -> Result<()>
|
fn build(root: Self::InputSyntaxType, ct: &mut Content) -> Result<()>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
@ -106,18 +107,21 @@ trait Build {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Content {
|
pub struct Content {
|
||||||
/* Configuration values */
|
/* Configuration values */
|
||||||
/// Root directory for textures
|
/// Root directory for image
|
||||||
texture_root: PathBuf,
|
image_root: PathBuf,
|
||||||
/// Name of starfield texture
|
/// Name of starfield sprite
|
||||||
starfield_texture_name: String,
|
starfield_sprite_name: String,
|
||||||
|
|
||||||
/// Textures
|
/// Sprites
|
||||||
pub textures: Vec<part::texture::Texture>,
|
pub sprites: Vec<part::sprite::Sprite>,
|
||||||
/// Map strings to texture names.
|
/// Map strings to texture names.
|
||||||
/// This is only necessary because we need to hard-code a few texture names for UI elements.
|
/// This is only necessary because we need to hard-code a few texture names for UI elements.
|
||||||
texture_index: HashMap<String, handle::TextureHandle>,
|
sprite_index: HashMap<String, handle::SpriteHandle>,
|
||||||
/// The texture to use for starfield stars
|
/// The texture to use for starfield stars
|
||||||
starfield_handle: Option<handle::TextureHandle>,
|
starfield_handle: Option<handle::SpriteHandle>,
|
||||||
|
|
||||||
|
/// Keeps track of which images are in which texture
|
||||||
|
sprite_atlas: SpriteAtlas,
|
||||||
|
|
||||||
/// Outfits
|
/// Outfits
|
||||||
outfits: Vec<part::outfit::Outfit>,
|
outfits: Vec<part::outfit::Outfit>,
|
||||||
|
@ -148,6 +152,7 @@ impl Content {
|
||||||
pub fn load_dir(
|
pub fn load_dir(
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
texture_root: PathBuf,
|
texture_root: PathBuf,
|
||||||
|
atlas_index: PathBuf,
|
||||||
starfield_texture_name: String,
|
starfield_texture_name: String,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let mut root = syntax::Root::new();
|
let mut root = syntax::Root::new();
|
||||||
|
@ -177,23 +182,32 @@ impl Content {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let atlas: SpriteAtlas = {
|
||||||
|
let mut file_string = String::new();
|
||||||
|
let _ = File::open(atlas_index)?.read_to_string(&mut file_string);
|
||||||
|
let file_string = file_string.trim();
|
||||||
|
toml::from_str(&file_string)?
|
||||||
|
};
|
||||||
|
|
||||||
let mut content = Self {
|
let mut content = Self {
|
||||||
|
sprite_atlas: atlas,
|
||||||
systems: Vec::new(),
|
systems: Vec::new(),
|
||||||
ships: Vec::new(),
|
ships: Vec::new(),
|
||||||
guns: Vec::new(),
|
guns: Vec::new(),
|
||||||
outfits: Vec::new(),
|
outfits: Vec::new(),
|
||||||
textures: Vec::new(),
|
sprites: Vec::new(),
|
||||||
factions: Vec::new(),
|
factions: Vec::new(),
|
||||||
texture_index: HashMap::new(),
|
sprite_index: HashMap::new(),
|
||||||
starfield_handle: None,
|
starfield_handle: None,
|
||||||
texture_root,
|
image_root: texture_root,
|
||||||
starfield_texture_name,
|
starfield_sprite_name: starfield_texture_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Order here matters, usually
|
// Order here matters, usually
|
||||||
if root.texture.is_some() {
|
if root.sprite.is_some() {
|
||||||
part::texture::Texture::build(root.texture.take().unwrap(), &mut content)?;
|
part::sprite::Sprite::build(root.sprite.take().unwrap(), &mut content)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if root.ship.is_some() {
|
if root.ship.is_some() {
|
||||||
part::ship::Ship::build(root.ship.take().unwrap(), &mut content)?;
|
part::ship::Ship::build(root.ship.take().unwrap(), &mut content)?;
|
||||||
}
|
}
|
||||||
|
@ -216,27 +230,32 @@ impl Content {
|
||||||
|
|
||||||
// Access methods
|
// Access methods
|
||||||
impl Content {
|
impl Content {
|
||||||
/// Get the texture handle for the starfield texture
|
/// Get the handle for the starfield sprite
|
||||||
pub fn get_starfield_handle(&self) -> TextureHandle {
|
pub fn get_starfield_handle(&self) -> SpriteHandle {
|
||||||
match self.starfield_handle {
|
match self.starfield_handle {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => unreachable!("Starfield texture hasn't been loaded yet!"),
|
None => unreachable!("Starfield sprite hasn't been loaded yet!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a handle from a texture name
|
/// Get a handle from a sprite name
|
||||||
pub fn get_texture_handle(&self, name: &str) -> TextureHandle {
|
pub fn get_sprite_handle(&self, name: &str) -> SpriteHandle {
|
||||||
return match self.texture_index.get(name) {
|
return match self.sprite_index.get(name) {
|
||||||
Some(s) => *s,
|
Some(s) => *s,
|
||||||
None => unreachable!("get_texture_handle was called with a bad handle!"),
|
None => unreachable!("get_sprite_handle was called with a bad name!"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a texture from a handle
|
/// Get a sprite from a handle
|
||||||
pub fn get_texture(&self, h: TextureHandle) -> &Texture {
|
pub fn get_sprite(&self, h: SpriteHandle) -> &Sprite {
|
||||||
// In theory, this could fail if h has a bad index, but that shouldn't ever happen.
|
// In theory, this could fail if h has a bad index, but that shouldn't ever happen.
|
||||||
// The only TextureHandles that exist should be created by this crate.
|
// The only handles that exist should be created by this crate.
|
||||||
return &self.textures[h.index];
|
return &self.sprites[h.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a sprite from a path
|
||||||
|
pub fn get_image(&self, p: &Path) -> &SpriteAtlasImage {
|
||||||
|
self.sprite_atlas.index.get(p).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an outfit from a handle
|
/// Get an outfit from a handle
|
||||||
|
@ -249,7 +268,7 @@ impl Content {
|
||||||
return &self.guns[h.index];
|
return &self.guns[h.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a texture from a handle
|
/// Get a ship from a handle
|
||||||
pub fn get_ship(&self, h: ShipHandle) -> &Ship {
|
pub fn get_ship(&self, h: ShipHandle) -> &Ship {
|
||||||
return &self.ships[h.index];
|
return &self.ships[h.index];
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,9 +59,9 @@ pub struct Faction {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Build for Faction {
|
impl crate::Build for Faction {
|
||||||
type InputSyntax = HashMap<String, syntax::Faction>;
|
type InputSyntaxType = HashMap<String, syntax::Faction>;
|
||||||
|
|
||||||
fn build(factions: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(factions: Self::InputSyntaxType, ct: &mut Content) -> Result<()> {
|
||||||
// Keeps track of position in faction array.
|
// Keeps track of position in faction array.
|
||||||
// This lets us build FactionHandles before finishing all factions.
|
// This lets us build FactionHandles before finishing all factions.
|
||||||
let faction_names: Vec<String> = factions.keys().map(|x| x.to_owned()).collect();
|
let faction_names: Vec<String> = factions.keys().map(|x| x.to_owned()).collect();
|
||||||
|
|
|
@ -3,7 +3,7 @@ use cgmath::Deg;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{handle::TextureHandle, Content};
|
use crate::{handle::SpriteHandle, Content};
|
||||||
|
|
||||||
use crate::OutfitSpace;
|
use crate::OutfitSpace;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ pub(crate) mod syntax {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Projectile {
|
pub struct Projectile {
|
||||||
pub sprite_texture: String,
|
pub sprite: String,
|
||||||
pub size: f32,
|
pub size: f32,
|
||||||
pub size_rng: f32,
|
pub size_rng: f32,
|
||||||
pub speed: f32,
|
pub speed: f32,
|
||||||
|
@ -40,7 +40,7 @@ pub(crate) mod syntax {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct ProjectileParticle {
|
pub struct ProjectileParticle {
|
||||||
pub texture: String,
|
pub sprite: String,
|
||||||
pub lifetime: ParticleLifetime,
|
pub lifetime: ParticleLifetime,
|
||||||
pub inherit_velocity: super::ImpactInheritVelocity,
|
pub inherit_velocity: super::ImpactInheritVelocity,
|
||||||
pub size: f32,
|
pub size: f32,
|
||||||
|
@ -110,7 +110,7 @@ pub struct Gun {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Projectile {
|
pub struct Projectile {
|
||||||
/// The projectile sprite
|
/// The projectile sprite
|
||||||
pub sprite_texture: TextureHandle,
|
pub sprite: SpriteHandle,
|
||||||
|
|
||||||
/// The average size of this projectile
|
/// The average size of this projectile
|
||||||
/// (height in game units)
|
/// (height in game units)
|
||||||
|
@ -155,9 +155,9 @@ pub struct Projectile {
|
||||||
/// The particle a projectile will spawn when it hits something
|
/// The particle a projectile will spawn when it hits something
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProjectileParticle {
|
pub struct ProjectileParticle {
|
||||||
/// The texture to use for this particle.
|
/// The sprite to use for this particle.
|
||||||
/// This is most likely animated.
|
/// This is most likely animated.
|
||||||
pub texture: TextureHandle,
|
pub sprite: SpriteHandle,
|
||||||
|
|
||||||
/// How many seconds this particle should live
|
/// How many seconds this particle should live
|
||||||
pub lifetime: f32,
|
pub lifetime: f32,
|
||||||
|
@ -174,8 +174,8 @@ fn parse_projectile_particle(
|
||||||
p: Option<syntax::ProjectileParticle>,
|
p: Option<syntax::ProjectileParticle>,
|
||||||
) -> Result<Option<ProjectileParticle>> {
|
) -> Result<Option<ProjectileParticle>> {
|
||||||
if let Some(impact) = p {
|
if let Some(impact) = p {
|
||||||
let impact_texture = match ct.texture_index.get(&impact.texture) {
|
let impact_sprite_handle = match ct.sprite_index.get(&impact.sprite) {
|
||||||
None => bail!("impact texture `{}` doesn't exist", impact.texture),
|
None => bail!("impact sprite `{}` doesn't exist", impact.sprite),
|
||||||
Some(t) => *t,
|
Some(t) => *t,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -183,8 +183,8 @@ fn parse_projectile_particle(
|
||||||
syntax::ParticleLifetime::Seconds(s) => s,
|
syntax::ParticleLifetime::Seconds(s) => s,
|
||||||
syntax::ParticleLifetime::Inherit(s) => {
|
syntax::ParticleLifetime::Inherit(s) => {
|
||||||
if s == "inherit" {
|
if s == "inherit" {
|
||||||
let t = ct.get_texture(impact_texture);
|
let sprite = ct.get_sprite(impact_sprite_handle);
|
||||||
t.fps * t.frames.len() as f32
|
sprite.fps * sprite.frames.len() as f32
|
||||||
} else {
|
} else {
|
||||||
bail!("bad impact lifetime, must be float or \"inherit\"",)
|
bail!("bad impact lifetime, must be float or \"inherit\"",)
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ fn parse_projectile_particle(
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(ProjectileParticle {
|
Ok(Some(ProjectileParticle {
|
||||||
texture: impact_texture,
|
sprite: impact_sprite_handle,
|
||||||
lifetime: impact_lifetime,
|
lifetime: impact_lifetime,
|
||||||
inherit_velocity: impact.inherit_velocity,
|
inherit_velocity: impact.inherit_velocity,
|
||||||
size: impact.size,
|
size: impact.size,
|
||||||
|
@ -203,15 +203,15 @@ fn parse_projectile_particle(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Build for Gun {
|
impl crate::Build for Gun {
|
||||||
type InputSyntax = HashMap<String, syntax::Gun>;
|
type InputSyntaxType = HashMap<String, syntax::Gun>;
|
||||||
|
|
||||||
fn build(gun: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(gun: Self::InputSyntaxType, ct: &mut Content) -> Result<()> {
|
||||||
for (gun_name, gun) in gun {
|
for (gun_name, gun) in gun {
|
||||||
let projectile_texture = match ct.texture_index.get(&gun.projectile.sprite_texture) {
|
let projectile_sprite_handle = match ct.sprite_index.get(&gun.projectile.sprite) {
|
||||||
None => bail!(
|
None => bail!(
|
||||||
"In gun `{}`: projectile texture `{}` doesn't exist",
|
"In gun `{}`: projectile sprite `{}` doesn't exist",
|
||||||
gun_name,
|
gun_name,
|
||||||
gun.projectile.sprite_texture
|
gun.projectile.sprite
|
||||||
),
|
),
|
||||||
Some(t) => *t,
|
Some(t) => *t,
|
||||||
};
|
};
|
||||||
|
@ -229,7 +229,7 @@ impl crate::Build for Gun {
|
||||||
rate_rng: gun.rate_rng,
|
rate_rng: gun.rate_rng,
|
||||||
projectile: Projectile {
|
projectile: Projectile {
|
||||||
force: gun.projectile.force,
|
force: gun.projectile.force,
|
||||||
sprite_texture: projectile_texture,
|
sprite: projectile_sprite_handle,
|
||||||
size: gun.projectile.size,
|
size: gun.projectile.size,
|
||||||
size_rng: gun.projectile.size_rng,
|
size_rng: gun.projectile.size_rng,
|
||||||
speed: gun.projectile.speed,
|
speed: gun.projectile.speed,
|
||||||
|
|
|
@ -5,13 +5,13 @@ pub mod gun;
|
||||||
pub mod outfit;
|
pub mod outfit;
|
||||||
mod shared;
|
mod shared;
|
||||||
pub mod ship;
|
pub mod ship;
|
||||||
|
pub mod sprite;
|
||||||
pub mod system;
|
pub mod system;
|
||||||
pub mod texture;
|
|
||||||
|
|
||||||
pub use faction::{Faction, Relationship};
|
pub use faction::{Faction, Relationship};
|
||||||
pub use gun::{Gun, ImpactInheritVelocity, Projectile, ProjectileCollider, ProjectileParticle};
|
pub use gun::{Gun, ImpactInheritVelocity, Projectile, ProjectileCollider, ProjectileParticle};
|
||||||
pub use outfit::Outfit;
|
pub use outfit::Outfit;
|
||||||
pub use shared::OutfitSpace;
|
pub use shared::OutfitSpace;
|
||||||
pub use ship::{EnginePoint, GunPoint, Ship};
|
pub use ship::{EnginePoint, GunPoint, Ship};
|
||||||
|
pub use sprite::{RepeatMode, Sprite};
|
||||||
pub use system::{Object, System};
|
pub use system::{Object, System};
|
||||||
pub use texture::{RepeatMode, Texture};
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
use crate::{handle::TextureHandle, Content, OutfitSpace};
|
use crate::{handle::SpriteHandle, Content, OutfitSpace};
|
||||||
|
|
||||||
pub(crate) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use crate::part::shared;
|
use crate::part::shared;
|
||||||
|
@ -20,7 +20,7 @@ pub(crate) mod syntax {
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
pub thrust: f32,
|
pub thrust: f32,
|
||||||
pub flare_texture: String,
|
pub flare_sprite: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -44,37 +44,37 @@ pub struct Outfit {
|
||||||
/// The engine flare sprite this outfit creates.
|
/// The engine flare sprite this outfit creates.
|
||||||
/// Its location and size is determined by a ship's
|
/// Its location and size is determined by a ship's
|
||||||
/// engine points.
|
/// engine points.
|
||||||
pub engine_flare_texture: Option<TextureHandle>,
|
pub engine_flare_sprite: Option<SpriteHandle>,
|
||||||
|
|
||||||
/// How much space this outfit requires
|
/// How much space this outfit requires
|
||||||
pub space: OutfitSpace,
|
pub space: OutfitSpace,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Build for Outfit {
|
impl crate::Build for Outfit {
|
||||||
type InputSyntax = HashMap<String, syntax::Outfit>;
|
type InputSyntaxType = HashMap<String, syntax::Outfit>;
|
||||||
|
|
||||||
fn build(outfits: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(outfits: Self::InputSyntaxType, ct: &mut Content) -> Result<()> {
|
||||||
for (outfit_name, outfit) in outfits {
|
for (outfit_name, outfit) in outfits {
|
||||||
let mut o = Self {
|
let mut o = Self {
|
||||||
name: outfit_name.clone(),
|
name: outfit_name.clone(),
|
||||||
engine_thrust: 0.0,
|
engine_thrust: 0.0,
|
||||||
steer_power: 0.0,
|
steer_power: 0.0,
|
||||||
engine_flare_texture: None,
|
engine_flare_sprite: None,
|
||||||
space: OutfitSpace::from(outfit.space),
|
space: OutfitSpace::from(outfit.space),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Engine stats
|
// Engine stats
|
||||||
if let Some(engine) = outfit.engine {
|
if let Some(engine) = outfit.engine {
|
||||||
let th = match ct.texture_index.get(&engine.flare_texture) {
|
let th = match ct.sprite_index.get(&engine.flare_sprite) {
|
||||||
None => bail!(
|
None => bail!(
|
||||||
"In outfit `{}`: texture `{}` doesn't exist",
|
"In outfit `{}`: flare sprite `{}` doesn't exist",
|
||||||
outfit_name,
|
outfit_name,
|
||||||
engine.flare_texture
|
engine.flare_sprite
|
||||||
),
|
),
|
||||||
Some(t) => *t,
|
Some(t) => *t,
|
||||||
};
|
};
|
||||||
o.engine_thrust = engine.thrust;
|
o.engine_thrust = engine.thrust;
|
||||||
o.engine_flare_texture = Some(th);
|
o.engine_flare_sprite = Some(th);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steering stats
|
// Steering stats
|
||||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::{bail, Result};
|
||||||
use cgmath::Point2;
|
use cgmath::Point2;
|
||||||
use nalgebra::{point, Point};
|
use nalgebra::{point, Point};
|
||||||
|
|
||||||
use crate::{handle::TextureHandle, Content, OutfitSpace};
|
use crate::{handle::SpriteHandle, Content, OutfitSpace};
|
||||||
|
|
||||||
pub(crate) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use crate::part::shared;
|
use crate::part::shared;
|
||||||
|
@ -15,7 +15,7 @@ pub(crate) mod syntax {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Ship {
|
pub struct Ship {
|
||||||
pub sprite_texture: String,
|
pub sprite: String,
|
||||||
pub size: f32,
|
pub size: f32,
|
||||||
pub engines: Vec<Engine>,
|
pub engines: Vec<Engine>,
|
||||||
pub guns: Vec<Gun>,
|
pub guns: Vec<Gun>,
|
||||||
|
@ -57,7 +57,7 @@ pub struct Ship {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
/// This ship's sprite
|
/// This ship's sprite
|
||||||
pub sprite_texture: TextureHandle,
|
pub sprite: SpriteHandle,
|
||||||
|
|
||||||
/// The size of this ship.
|
/// The size of this ship.
|
||||||
/// Measured as unrotated height,
|
/// Measured as unrotated height,
|
||||||
|
@ -123,26 +123,26 @@ pub struct GunPoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Build for Ship {
|
impl crate::Build for Ship {
|
||||||
type InputSyntax = HashMap<String, syntax::Ship>;
|
type InputSyntaxType = HashMap<String, syntax::Ship>;
|
||||||
|
|
||||||
fn build(ship: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(ship: Self::InputSyntaxType, ct: &mut Content) -> Result<()> {
|
||||||
for (ship_name, ship) in ship {
|
for (ship_name, ship) in ship {
|
||||||
let th = match ct.texture_index.get(&ship.sprite_texture) {
|
let handle = match ct.sprite_index.get(&ship.sprite) {
|
||||||
None => bail!(
|
None => bail!(
|
||||||
"In ship `{}`: texture `{}` doesn't exist",
|
"In ship `{}`: sprite `{}` doesn't exist",
|
||||||
ship_name,
|
ship_name,
|
||||||
ship.sprite_texture
|
ship.sprite
|
||||||
),
|
),
|
||||||
Some(t) => *t,
|
Some(t) => *t,
|
||||||
};
|
};
|
||||||
|
|
||||||
let size = ship.size;
|
let size = ship.size;
|
||||||
let aspect = th.aspect;
|
let aspect = ct.get_sprite(handle).aspect;
|
||||||
|
|
||||||
ct.ships.push(Self {
|
ct.ships.push(Self {
|
||||||
aspect,
|
aspect,
|
||||||
name: ship_name,
|
name: ship_name,
|
||||||
sprite_texture: th,
|
sprite: handle,
|
||||||
mass: ship.mass,
|
mass: ship.mass,
|
||||||
space: OutfitSpace::from(ship.space),
|
space: OutfitSpace::from(ship.space),
|
||||||
angular_drag: ship.angular_drag,
|
angular_drag: ship.angular_drag,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use image::io::Reader;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
use crate::{handle::TextureHandle, Content};
|
use crate::{handle::SpriteHandle, Content};
|
||||||
|
|
||||||
pub(crate) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -16,18 +16,18 @@ pub(crate) mod syntax {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum Texture {
|
pub enum Sprite {
|
||||||
Static(StaticTexture),
|
Static(StaticSprite),
|
||||||
Frames(FramesTexture),
|
Frames(FrameSprite),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct StaticTexture {
|
pub struct StaticSprite {
|
||||||
pub file: PathBuf,
|
pub file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct FramesTexture {
|
pub struct FrameSprite {
|
||||||
pub frames: Vec<PathBuf>,
|
pub frames: Vec<PathBuf>,
|
||||||
pub duration: f32,
|
pub duration: f32,
|
||||||
pub repeat: RepeatMode,
|
pub repeat: RepeatMode,
|
||||||
|
@ -57,90 +57,94 @@ impl RepeatMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a texture that may be used in the game.
|
/// Represents a sprite that may be used in the game.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Texture {
|
pub struct Sprite {
|
||||||
/// The name of this texture
|
/// The name of this sprite
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
/// The handle for this texture
|
/// This sprite's handle
|
||||||
pub handle: TextureHandle,
|
pub handle: SpriteHandle,
|
||||||
|
|
||||||
/// The frames of this texture
|
/// The file names of frames of this sprite.
|
||||||
/// (static textures have one frame)
|
/// unanimated sprites have one frame.
|
||||||
pub frames: Vec<PathBuf>,
|
pub frames: Vec<PathBuf>,
|
||||||
|
|
||||||
/// The speed of this texture's animation
|
/// The speed of this sprite's animation.
|
||||||
/// (static textures have zero fps)
|
/// unanimated sprites have zero fps.
|
||||||
pub fps: f32,
|
pub fps: f32,
|
||||||
|
|
||||||
/// How to replay this texture's animation
|
/// How to replay this sprite's animation
|
||||||
pub repeat: RepeatMode,
|
pub repeat: RepeatMode,
|
||||||
|
|
||||||
|
/// Aspect ratio of this sprite (width / height)
|
||||||
|
pub aspect: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Build for Texture {
|
impl crate::Build for Sprite {
|
||||||
type InputSyntax = HashMap<String, syntax::Texture>;
|
type InputSyntaxType = HashMap<String, syntax::Sprite>;
|
||||||
|
|
||||||
fn build(texture: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(sprites: Self::InputSyntaxType, ct: &mut Content) -> Result<()> {
|
||||||
for (texture_name, t) in texture {
|
for (sprite_name, t) in sprites {
|
||||||
match t {
|
match t {
|
||||||
syntax::Texture::Static(t) => {
|
syntax::Sprite::Static(t) => {
|
||||||
let file = ct.texture_root.join(t.file);
|
let file = ct.image_root.join(&t.file);
|
||||||
let reader = Reader::open(&file).with_context(|| {
|
let reader = Reader::open(&file).with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to read texture `{}` from file `{}`",
|
"Failed to read file `{}` in sprite `{}`",
|
||||||
texture_name,
|
file.display(),
|
||||||
file.display()
|
sprite_name,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let dim = reader.into_dimensions().with_context(|| {
|
let dim = reader.into_dimensions().with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to get dimensions of texture `{}` from file `{}`",
|
"Failed to get dimensions of file `{}` in sprite `{}`",
|
||||||
texture_name,
|
file.display(),
|
||||||
file.display()
|
sprite_name,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let h = TextureHandle {
|
let h = SpriteHandle {
|
||||||
index: ct.textures.len(),
|
index: ct.sprites.len(),
|
||||||
aspect: dim.0 as f32 / dim.1 as f32,
|
aspect: dim.0 as f32 / dim.1 as f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
if texture_name == ct.starfield_texture_name {
|
if sprite_name == ct.starfield_sprite_name {
|
||||||
if ct.starfield_handle.is_none() {
|
if ct.starfield_handle.is_none() {
|
||||||
ct.starfield_handle = Some(h)
|
ct.starfield_handle = Some(h)
|
||||||
} else {
|
} else {
|
||||||
// This can't happen, since this is a hashmap.
|
// This can't happen, since this is a hashmap.
|
||||||
unreachable!("Found two starfield textures! Something is very wrong.")
|
unreachable!("Found two starfield sprites! Something is very wrong.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ct.texture_index.insert(texture_name.clone(), h);
|
ct.sprite_index.insert(sprite_name.clone(), h);
|
||||||
|
|
||||||
ct.textures.push(Self {
|
ct.sprites.push(Self {
|
||||||
name: texture_name,
|
name: sprite_name,
|
||||||
frames: vec![file],
|
frames: vec![t.file],
|
||||||
fps: 0.0,
|
fps: 0.0,
|
||||||
handle: h,
|
handle: h,
|
||||||
repeat: RepeatMode::Once,
|
repeat: RepeatMode::Once,
|
||||||
|
aspect: dim.0 as f32 / dim.1 as f32,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
syntax::Texture::Frames(t) => {
|
syntax::Sprite::Frames(t) => {
|
||||||
let mut dim = None;
|
let mut dim = None;
|
||||||
for f in &t.frames {
|
for f in &t.frames {
|
||||||
let file = ct.texture_root.join(f);
|
let file = ct.image_root.join(f);
|
||||||
let reader = Reader::open(&file).with_context(|| {
|
let reader = Reader::open(&file).with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to read texture `{}` from file `{}`",
|
"Failed to read file `{}` in sprite `{}`",
|
||||||
texture_name,
|
file.display(),
|
||||||
file.display()
|
sprite_name,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let d = reader.into_dimensions().with_context(|| {
|
let d = reader.into_dimensions().with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to get dimensions of texture `{}` from file `{}`",
|
"Failed to get dimensions of file `{}` in sprite `{}`",
|
||||||
texture_name,
|
file.display(),
|
||||||
file.display()
|
sprite_name,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
match dim {
|
match dim {
|
||||||
|
@ -148,37 +152,34 @@ impl crate::Build for Texture {
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
if d != e {
|
if d != e {
|
||||||
bail!(
|
bail!(
|
||||||
"Failed to load frames of texture `{}`. Frames have different sizes `{}`",
|
"Failed to load frames of sprite `{}` because frames have different sizes.",
|
||||||
texture_name,
|
sprite_name,
|
||||||
file.display()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let dim = dim.unwrap();
|
||||||
|
|
||||||
let h = TextureHandle {
|
let h = SpriteHandle {
|
||||||
index: ct.textures.len(),
|
index: ct.sprites.len(),
|
||||||
aspect: dim.unwrap().0 as f32 / dim.unwrap().1 as f32,
|
aspect: dim.0 as f32 / dim.1 as f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
if texture_name == ct.starfield_texture_name {
|
if sprite_name == ct.starfield_sprite_name {
|
||||||
unreachable!("Starfield texture may not be animated")
|
unreachable!("Starfield texture may not be animated")
|
||||||
}
|
}
|
||||||
|
|
||||||
let fps = t.duration / t.frames.len() as f32;
|
let fps = t.duration / t.frames.len() as f32;
|
||||||
|
|
||||||
ct.texture_index.insert(texture_name.clone(), h);
|
ct.sprite_index.insert(sprite_name.clone(), h);
|
||||||
ct.textures.push(Self {
|
ct.sprites.push(Self {
|
||||||
name: texture_name,
|
name: sprite_name,
|
||||||
frames: t
|
frames: t.frames,
|
||||||
.frames
|
|
||||||
.into_iter()
|
|
||||||
.map(|f| ct.texture_root.join(f))
|
|
||||||
.collect(),
|
|
||||||
fps,
|
fps,
|
||||||
handle: h,
|
handle: h,
|
||||||
repeat: t.repeat,
|
repeat: t.repeat,
|
||||||
|
aspect: dim.0 as f32 / dim.1 as f32,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +188,7 @@ impl crate::Build for Texture {
|
||||||
if ct.starfield_handle.is_none() {
|
if ct.starfield_handle.is_none() {
|
||||||
bail!(
|
bail!(
|
||||||
"Could not find a starfield texture (name: `{}`)",
|
"Could not find a starfield texture (name: `{}`)",
|
||||||
ct.starfield_texture_name
|
ct.starfield_sprite_name
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result};
|
||||||
use cgmath::{Deg, Point3};
|
use cgmath::{Deg, Point3};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::{handle::TextureHandle, util::Polar, Content};
|
use crate::{handle::SpriteHandle, util::Polar, Content};
|
||||||
|
|
||||||
pub(crate) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -17,7 +17,7 @@ pub(crate) mod syntax {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
pub sprite_texture: String,
|
pub sprite: String,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
|
|
||||||
pub size: f32,
|
pub size: f32,
|
||||||
|
@ -94,7 +94,7 @@ pub struct System {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
/// This object's sprite
|
/// This object's sprite
|
||||||
pub sprite_texture: TextureHandle,
|
pub sprite: SpriteHandle,
|
||||||
|
|
||||||
/// This object's size.
|
/// This object's size.
|
||||||
/// Measured as height in game units.
|
/// Measured as height in game units.
|
||||||
|
@ -175,9 +175,9 @@ fn resolve_position(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Build for System {
|
impl crate::Build for System {
|
||||||
type InputSyntax = HashMap<String, syntax::System>;
|
type InputSyntaxType = HashMap<String, syntax::System>;
|
||||||
|
|
||||||
fn build(system: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(system: Self::InputSyntaxType, ct: &mut Content) -> Result<()> {
|
||||||
for (system_name, system) in system {
|
for (system_name, system) in system {
|
||||||
let mut objects = Vec::new();
|
let mut objects = Vec::new();
|
||||||
|
|
||||||
|
@ -185,17 +185,17 @@ impl crate::Build for System {
|
||||||
let mut cycle_detector = HashSet::new();
|
let mut cycle_detector = HashSet::new();
|
||||||
cycle_detector.insert(label.clone());
|
cycle_detector.insert(label.clone());
|
||||||
|
|
||||||
let th = match ct.texture_index.get(&obj.sprite_texture) {
|
let handle = match ct.sprite_index.get(&obj.sprite) {
|
||||||
None => bail!(
|
None => bail!(
|
||||||
"In system `{}`: texture `{}` doesn't exist",
|
"In system `{}`: sprite `{}` doesn't exist",
|
||||||
system_name,
|
system_name,
|
||||||
obj.sprite_texture
|
obj.sprite
|
||||||
),
|
),
|
||||||
Some(t) => *t,
|
Some(t) => *t,
|
||||||
};
|
};
|
||||||
|
|
||||||
objects.push(Object {
|
objects.push(Object {
|
||||||
sprite_texture: th,
|
sprite: handle,
|
||||||
position: resolve_position(&system.object, &obj, cycle_detector)
|
position: resolve_position(&system.object, &obj, cycle_detector)
|
||||||
.with_context(|| format!("In object {:#?}", label))?,
|
.with_context(|| format!("In object {:#?}", label))?,
|
||||||
size: obj.size,
|
size: obj.size,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use galactica_behavior::{behavior, ShipBehavior};
|
||||||
use galactica_constants;
|
use galactica_constants;
|
||||||
use galactica_content as content;
|
use galactica_content as content;
|
||||||
use galactica_gameobject as object;
|
use galactica_gameobject as object;
|
||||||
use galactica_render::{FrameState, ObjectSprite, ParticleBuilder, UiSprite};
|
use galactica_render::{ObjectSprite, ParticleBuilder, RenderState, UiSprite};
|
||||||
use galactica_ui as ui;
|
use galactica_ui as ui;
|
||||||
use galactica_world::{util, ShipPhysicsHandle, World};
|
use galactica_world::{util, ShipPhysicsHandle, World};
|
||||||
|
|
||||||
|
@ -174,8 +174,8 @@ impl Game {
|
||||||
self.last_update = Instant::now();
|
self.last_update = Instant::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_frame_state(&mut self) -> FrameState {
|
pub fn get_frame_state(&mut self) -> RenderState {
|
||||||
FrameState {
|
RenderState {
|
||||||
camera_pos: self.camera.pos,
|
camera_pos: self.camera.pos,
|
||||||
camera_zoom: self.camera.zoom,
|
camera_zoom: self.camera.zoom,
|
||||||
object_sprites: self.get_object_sprites(),
|
object_sprites: self.get_object_sprites(),
|
||||||
|
|
|
@ -17,14 +17,15 @@ fn main() -> Result<()> {
|
||||||
// TODO: error if missing
|
// TODO: error if missing
|
||||||
let content = content::Content::load_dir(
|
let content = content::Content::load_dir(
|
||||||
PathBuf::from(galactica_constants::CONTENT_ROOT),
|
PathBuf::from(galactica_constants::CONTENT_ROOT),
|
||||||
PathBuf::from(galactica_constants::TEXTURE_ROOT),
|
PathBuf::from(galactica_constants::IMAGE_ROOT),
|
||||||
PathBuf::from("spriteatlas.toml"),
|
PathBuf::from("spriteatlas.toml"),
|
||||||
galactica_constants::STARFIELD_TEXTURE_NAME.to_owned(),
|
galactica_constants::STARFIELD_SPRITE_NAME.to_owned(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
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 = pollster::block_on(galactica_render::GPUState::new(window, &content))?;
|
let mut gpu = pollster::block_on(galactica_render::GPUState::new(window, &content))?;
|
||||||
|
gpu.init();
|
||||||
|
|
||||||
let mut game = game::Game::new(content);
|
let mut game = game::Game::new(content);
|
||||||
gpu.update_starfield_buffer();
|
gpu.update_starfield_buffer();
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl ShipGun {
|
||||||
pub struct OutfitStatSum {
|
pub struct OutfitStatSum {
|
||||||
pub engine_thrust: f32,
|
pub engine_thrust: f32,
|
||||||
pub steer_power: f32,
|
pub steer_power: f32,
|
||||||
pub engine_flare_textures: Vec<content::TextureHandle>,
|
pub engine_flare_sprites: Vec<content::SpriteHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutfitStatSum {
|
impl OutfitStatSum {
|
||||||
|
@ -41,23 +41,23 @@ impl OutfitStatSum {
|
||||||
Self {
|
Self {
|
||||||
engine_thrust: 0.0,
|
engine_thrust: 0.0,
|
||||||
steer_power: 0.0,
|
steer_power: 0.0,
|
||||||
engine_flare_textures: Vec::new(),
|
engine_flare_sprites: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, o: &content::Outfit) {
|
pub fn add(&mut self, o: &content::Outfit) {
|
||||||
self.engine_thrust += o.engine_thrust;
|
self.engine_thrust += o.engine_thrust;
|
||||||
if let Some(t) = o.engine_flare_texture {
|
if let Some(t) = o.engine_flare_sprite {
|
||||||
self.engine_flare_textures.push(t);
|
self.engine_flare_sprites.push(t);
|
||||||
};
|
};
|
||||||
self.steer_power += o.steer_power;
|
self.steer_power += o.steer_power;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, o: &content::Outfit) {
|
pub fn remove(&mut self, o: &content::Outfit) {
|
||||||
self.engine_thrust -= o.engine_thrust;
|
self.engine_thrust -= o.engine_thrust;
|
||||||
if let Some(t) = o.engine_flare_texture {
|
if let Some(t) = o.engine_flare_sprite {
|
||||||
self.engine_flare_textures.remove(
|
self.engine_flare_sprites.remove(
|
||||||
self.engine_flare_textures
|
self.engine_flare_sprites
|
||||||
.iter()
|
.iter()
|
||||||
.position(|x| *x == t)
|
.position(|x| *x == t)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -185,7 +185,7 @@ impl<'a> OutfitSet {
|
||||||
pub fn update_engine_flares(&mut self) {
|
pub fn update_engine_flares(&mut self) {
|
||||||
// TODO: better way to pick flare texture
|
// TODO: better way to pick flare texture
|
||||||
self.engine_flare_sprites.clear();
|
self.engine_flare_sprites.clear();
|
||||||
let t = if let Some(e) = self.stats.engine_flare_textures.iter().next() {
|
let s = if let Some(e) = self.stats.engine_flare_sprites.iter().next() {
|
||||||
e
|
e
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
|
@ -200,7 +200,7 @@ impl<'a> OutfitSet {
|
||||||
y: p.pos.y,
|
y: p.pos.y,
|
||||||
z: 1.0,
|
z: 1.0,
|
||||||
},
|
},
|
||||||
texture: *t,
|
sprite: *s,
|
||||||
angle: Deg(0.0),
|
angle: Deg(0.0),
|
||||||
size: p.size,
|
size: p.size,
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,7 +18,7 @@ impl System {
|
||||||
for o in &sys.objects {
|
for o in &sys.objects {
|
||||||
s.bodies.push(SystemObject {
|
s.bodies.push(SystemObject {
|
||||||
pos: o.position,
|
pos: o.position,
|
||||||
sprite_texture: o.sprite_texture,
|
sprite: o.sprite,
|
||||||
size: o.size,
|
size: o.size,
|
||||||
angle: o.angle,
|
angle: o.angle,
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ use galactica_content as content;
|
||||||
use galactica_render::ObjectSprite;
|
use galactica_render::ObjectSprite;
|
||||||
|
|
||||||
pub struct SystemObject {
|
pub struct SystemObject {
|
||||||
pub sprite_texture: content::TextureHandle,
|
pub sprite: content::SpriteHandle,
|
||||||
pub pos: Point3<f32>,
|
pub pos: Point3<f32>,
|
||||||
pub size: f32,
|
pub size: f32,
|
||||||
pub angle: Deg<f32>,
|
pub angle: Deg<f32>,
|
||||||
|
@ -13,7 +13,7 @@ pub struct SystemObject {
|
||||||
impl SystemObject {
|
impl SystemObject {
|
||||||
pub(crate) fn get_sprite(&self) -> ObjectSprite {
|
pub(crate) fn get_sprite(&self) -> ObjectSprite {
|
||||||
return ObjectSprite {
|
return ObjectSprite {
|
||||||
texture: self.sprite_texture,
|
sprite: self.sprite,
|
||||||
pos: self.pos,
|
pos: self.pos,
|
||||||
angle: self.angle,
|
angle: self.angle,
|
||||||
size: self.size,
|
size: self.size,
|
||||||
|
|
|
@ -24,12 +24,12 @@ pub fn build_radar(
|
||||||
|
|
||||||
let (_, player_body) = physics.get_ship_body(player).unwrap();
|
let (_, player_body) = physics.get_ship_body(player).unwrap();
|
||||||
let player_position = util::rigidbody_position(player_body);
|
let player_position = util::rigidbody_position(player_body);
|
||||||
let planet_texture = ct.get_texture_handle("ui::planetblip");
|
let planet_sprite = ct.get_sprite_handle("ui::planetblip");
|
||||||
let ship_texture = ct.get_texture_handle("ui::shipblip");
|
let ship_sprite = ct.get_sprite_handle("ui::shipblip");
|
||||||
let arrow_texture = ct.get_texture_handle("ui::centerarrow");
|
let arrow_sprite = ct.get_sprite_handle("ui::centerarrow");
|
||||||
|
|
||||||
out.push(UiSprite {
|
out.push(UiSprite {
|
||||||
texture: ct.get_texture_handle("ui::radar"),
|
sprite: ct.get_sprite_handle("ui::radar"),
|
||||||
pos: AnchoredUiPosition::NwNw(Point2 { x: 10.0, y: -10.0 }),
|
pos: AnchoredUiPosition::NwNw(Point2 { x: 10.0, y: -10.0 }),
|
||||||
dimensions: Point2 {
|
dimensions: Point2 {
|
||||||
x: radar_size,
|
x: radar_size,
|
||||||
|
@ -57,7 +57,7 @@ pub fn build_radar(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out.push(UiSprite {
|
out.push(UiSprite {
|
||||||
texture: planet_texture,
|
sprite: planet_sprite,
|
||||||
pos: AnchoredUiPosition::NwC(
|
pos: AnchoredUiPosition::NwC(
|
||||||
Point2 {
|
Point2 {
|
||||||
x: radar_size / 2.0 + 10.0,
|
x: radar_size / 2.0 + 10.0,
|
||||||
|
@ -65,7 +65,7 @@ pub fn build_radar(
|
||||||
} + (d * (radar_size / 2.0)),
|
} + (d * (radar_size / 2.0)),
|
||||||
),
|
),
|
||||||
dimensions: Point2 {
|
dimensions: Point2 {
|
||||||
x: planet_texture.aspect,
|
x: planet_sprite.aspect,
|
||||||
y: 1.0,
|
y: 1.0,
|
||||||
} * size,
|
} * size,
|
||||||
angle: o.angle,
|
angle: o.angle,
|
||||||
|
@ -77,7 +77,7 @@ pub fn build_radar(
|
||||||
// Draw ships
|
// Draw ships
|
||||||
for (s, r) in physics.iter_ship_body() {
|
for (s, r) in physics.iter_ship_body() {
|
||||||
let ship = ct.get_ship(s.ship.handle);
|
let ship = ct.get_ship(s.ship.handle);
|
||||||
let size = (ship.size * ship.sprite_texture.aspect) * ship_scale;
|
let size = (ship.size * ship.sprite.aspect) * ship_scale;
|
||||||
let p = util::rigidbody_position(r);
|
let p = util::rigidbody_position(r);
|
||||||
let d = (p - player_position) / radar_range;
|
let d = (p - player_position) / radar_range;
|
||||||
let m = d.magnitude() + (size / (2.0 * radar_size));
|
let m = d.magnitude() + (size / (2.0 * radar_size));
|
||||||
|
@ -92,7 +92,7 @@ pub fn build_radar(
|
||||||
let f = ct.get_faction(s.ship.faction).color;
|
let f = ct.get_faction(s.ship.faction).color;
|
||||||
let f = [f[0], f[1], f[2], 1.0];
|
let f = [f[0], f[1], f[2], 1.0];
|
||||||
out.push(UiSprite {
|
out.push(UiSprite {
|
||||||
texture: ship_texture,
|
sprite: ship_sprite,
|
||||||
pos: AnchoredUiPosition::NwC(
|
pos: AnchoredUiPosition::NwC(
|
||||||
Point2 {
|
Point2 {
|
||||||
x: radar_size / 2.0 + 10.0,
|
x: radar_size / 2.0 + 10.0,
|
||||||
|
@ -100,7 +100,7 @@ pub fn build_radar(
|
||||||
} + (d * (radar_size / 2.0)),
|
} + (d * (radar_size / 2.0)),
|
||||||
),
|
),
|
||||||
dimensions: Point2 {
|
dimensions: Point2 {
|
||||||
x: ship_texture.aspect,
|
x: ship_sprite.aspect,
|
||||||
y: 1.0,
|
y: 1.0,
|
||||||
} * size,
|
} * size,
|
||||||
angle: -angle,
|
angle: -angle,
|
||||||
|
@ -118,13 +118,13 @@ pub fn build_radar(
|
||||||
let d = d * (radar_size / 2.0);
|
let d = d * (radar_size / 2.0);
|
||||||
let color = Some([0.3, 0.3, 0.3, 1.0]);
|
let color = Some([0.3, 0.3, 0.3, 1.0]);
|
||||||
if m < 0.8 {
|
if m < 0.8 {
|
||||||
let texture = ct.get_texture_handle("ui::radarframe");
|
let sprite = ct.get_sprite_handle("ui::radarframe");
|
||||||
let dimensions = Point2 {
|
let dimensions = Point2 {
|
||||||
x: texture.aspect,
|
x: sprite.aspect,
|
||||||
y: 1.0,
|
y: 1.0,
|
||||||
} * 7.0f32.min((0.8 - m) * 70.0);
|
} * 7.0f32.min((0.8 - m) * 70.0);
|
||||||
out.push(UiSprite {
|
out.push(UiSprite {
|
||||||
texture,
|
sprite,
|
||||||
pos: AnchoredUiPosition::NwNw(Point2 {
|
pos: AnchoredUiPosition::NwNw(Point2 {
|
||||||
x: (radar_size / 2.0 + 10.0) - d.x,
|
x: (radar_size / 2.0 + 10.0) - d.x,
|
||||||
y: (radar_size / -2.0 - 10.0) + d.y,
|
y: (radar_size / -2.0 - 10.0) + d.y,
|
||||||
|
@ -135,7 +135,7 @@ pub fn build_radar(
|
||||||
});
|
});
|
||||||
|
|
||||||
out.push(UiSprite {
|
out.push(UiSprite {
|
||||||
texture,
|
sprite,
|
||||||
pos: AnchoredUiPosition::NwSw(Point2 {
|
pos: AnchoredUiPosition::NwSw(Point2 {
|
||||||
x: (radar_size / 2.0 + 10.0) - d.x,
|
x: (radar_size / 2.0 + 10.0) - d.x,
|
||||||
y: (radar_size / -2.0 - 10.0) - d.y,
|
y: (radar_size / -2.0 - 10.0) - d.y,
|
||||||
|
@ -146,7 +146,7 @@ pub fn build_radar(
|
||||||
});
|
});
|
||||||
|
|
||||||
out.push(UiSprite {
|
out.push(UiSprite {
|
||||||
texture,
|
sprite,
|
||||||
pos: AnchoredUiPosition::NwSe(Point2 {
|
pos: AnchoredUiPosition::NwSe(Point2 {
|
||||||
x: (radar_size / 2.0 + 10.0) + d.x,
|
x: (radar_size / 2.0 + 10.0) + d.x,
|
||||||
y: (radar_size / -2.0 - 10.0) - d.y,
|
y: (radar_size / -2.0 - 10.0) - d.y,
|
||||||
|
@ -157,7 +157,7 @@ pub fn build_radar(
|
||||||
});
|
});
|
||||||
|
|
||||||
out.push(UiSprite {
|
out.push(UiSprite {
|
||||||
texture,
|
sprite,
|
||||||
pos: AnchoredUiPosition::NwNe(Point2 {
|
pos: AnchoredUiPosition::NwNe(Point2 {
|
||||||
x: (radar_size / 2.0 + 10.0) + d.x,
|
x: (radar_size / 2.0 + 10.0) + d.x,
|
||||||
y: (radar_size / -2.0 - 10.0) + d.y,
|
y: (radar_size / -2.0 - 10.0) + d.y,
|
||||||
|
@ -174,7 +174,7 @@ pub fn build_radar(
|
||||||
if m > 200.0 {
|
if m > 200.0 {
|
||||||
let player_angle: Deg<f32> = q.angle(Vector2 { x: 0.0, y: 1.0 }).into();
|
let player_angle: Deg<f32> = q.angle(Vector2 { x: 0.0, y: 1.0 }).into();
|
||||||
out.push(UiSprite {
|
out.push(UiSprite {
|
||||||
texture: arrow_texture,
|
sprite: arrow_sprite,
|
||||||
pos: AnchoredUiPosition::NwC(
|
pos: AnchoredUiPosition::NwC(
|
||||||
Point2 {
|
Point2 {
|
||||||
x: radar_size / 2.0 + 10.0,
|
x: radar_size / 2.0 + 10.0,
|
||||||
|
@ -182,7 +182,7 @@ pub fn build_radar(
|
||||||
} + ((q.normalize() * 0.865) * (radar_size / 2.0)),
|
} + ((q.normalize() * 0.865) * (radar_size / 2.0)),
|
||||||
),
|
),
|
||||||
dimensions: Point2 {
|
dimensions: Point2 {
|
||||||
x: arrow_texture.aspect,
|
x: arrow_sprite.aspect,
|
||||||
y: 1.0,
|
y: 1.0,
|
||||||
} * 10.0,
|
} * 10.0,
|
||||||
angle: -player_angle,
|
angle: -player_angle,
|
||||||
|
|
|
@ -44,7 +44,7 @@ impl ProjectileWorldObject {
|
||||||
let ang: Deg<f32> = rot.angle(Vector2 { x: 1.0, y: 0.0 }).into();
|
let ang: Deg<f32> = rot.angle(Vector2 { x: 1.0, y: 0.0 }).into();
|
||||||
|
|
||||||
ObjectSprite {
|
ObjectSprite {
|
||||||
texture: self.projectile.content.sprite_texture,
|
sprite: self.projectile.content.sprite,
|
||||||
pos: Point3 {
|
pos: Point3 {
|
||||||
x: pos.x,
|
x: pos.x,
|
||||||
y: pos.y,
|
y: pos.y,
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl ShipWorldObject {
|
||||||
|
|
||||||
ObjectSprite {
|
ObjectSprite {
|
||||||
pos: (ship_pos.x, ship_pos.y, 1.0).into(),
|
pos: (ship_pos.x, ship_pos.y, 1.0).into(),
|
||||||
texture: s.sprite_texture,
|
sprite: s.sprite,
|
||||||
angle: -ship_ang,
|
angle: -ship_ang,
|
||||||
size: s.size,
|
size: s.size,
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,7 @@ impl<'a> World {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
particles.push(ParticleBuilder {
|
particles.push(ParticleBuilder {
|
||||||
texture: x.texture,
|
sprite: x.sprite,
|
||||||
pos: Point2 { x: pos.x, y: pos.y },
|
pos: Point2 { x: pos.x, y: pos.y },
|
||||||
velocity,
|
velocity,
|
||||||
angle: -angle,
|
angle: -angle,
|
||||||
|
@ -332,7 +332,7 @@ impl<'a> World {
|
||||||
content::ImpactInheritVelocity::Projectile => util::rigidbody_velocity(&pr),
|
content::ImpactInheritVelocity::Projectile => util::rigidbody_velocity(&pr),
|
||||||
};
|
};
|
||||||
particles.push(ParticleBuilder {
|
particles.push(ParticleBuilder {
|
||||||
texture: x.texture,
|
sprite: x.sprite,
|
||||||
pos: Point2 { x: pos.x, y: pos.y },
|
pos: Point2 { x: pos.x, y: pos.y },
|
||||||
velocity,
|
velocity,
|
||||||
angle: -angle,
|
angle: -angle,
|
||||||
|
|
Loading…
Reference in New Issue