Compare commits
No commits in common. "6b5588b0617bae43f26ce79739398eacd887da25" and "1992bd7bb8eed297f47f28c4d22126fd40c19304" have entirely different histories.
6b5588b061
...
1992bd7bb8
28
TODO.md
28
TODO.md
|
@ -1,21 +1,13 @@
|
||||||
## Specific Jobs
|
## Specific Jobs
|
||||||
|
- Particle variation
|
||||||
- UI: health, shield, fuel, heat, energy bars
|
- UI: health, shield, fuel, heat, energy bars
|
||||||
- UI: text arranger
|
- UI: text arranger
|
||||||
- Sound system
|
- Sound system
|
||||||
- Ship death debris
|
- Ship death debris
|
||||||
- Sprite reels
|
- Sprite reels
|
||||||
- random start frame
|
|
||||||
- ship leaks
|
|
||||||
- Passive engine glow
|
- Passive engine glow
|
||||||
- Ship death damage and force events
|
- Ship death damage and force events
|
||||||
- Gun fire effect
|
- Fix particle inherit velocity
|
||||||
- Sprite color variation
|
|
||||||
- Multi-particle effects
|
|
||||||
- Better loading
|
|
||||||
- incremental?
|
|
||||||
- Higher texture limit (16 x 8096 x 8096 isn't enough)
|
|
||||||
- GPU limits? (texture size, texture number)
|
|
||||||
- Particles when a ship is damaged (events)
|
|
||||||
|
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
|
@ -49,11 +41,10 @@
|
||||||
- Orbiting debris (asteroids)
|
- Orbiting debris (asteroids)
|
||||||
- Collectibles (flotsam)
|
- Collectibles (flotsam)
|
||||||
- UI
|
- UI
|
||||||
- health, shields (cpu by tinyskia?)
|
|
||||||
- loading screen, menus
|
|
||||||
- Indicators (planet names, enemy ship stats)
|
|
||||||
- Landable planets
|
- Landable planets
|
||||||
- Back arrow: reverse thruster or reverse ship
|
- Back arrow: reverse thruster or reverse ship
|
||||||
|
- Loading screen, incremental texturearray loading
|
||||||
|
- Indicators (planet names, enemy ship stats)
|
||||||
- Multiplayer? (how does that fit into gameplay?)
|
- Multiplayer? (how does that fit into gameplay?)
|
||||||
- On-screen text
|
- On-screen text
|
||||||
- Controller input & key bindings
|
- Controller input & key bindings
|
||||||
|
@ -68,6 +59,10 @@
|
||||||
- how to target them
|
- how to target them
|
||||||
- where to go
|
- where to go
|
||||||
- etc, extra flags
|
- etc, extra flags
|
||||||
|
- Higher texture limit (16 x 8096 x 8096 isn't enough)
|
||||||
|
- Fast-load menu, progress bar for the rest
|
||||||
|
- Only load what is needed?
|
||||||
|
- GPU limits? (texture size, texture number)
|
||||||
- Advanced particle physics (must move to cpu. Maybe both?)
|
- Advanced particle physics (must move to cpu. Maybe both?)
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,11 +82,14 @@
|
||||||
- Clear all `// TODO:` comments littered in the source
|
- Clear all `// TODO:` comments littered in the source
|
||||||
- CLI options (debug, save location, content location, check content)
|
- CLI options (debug, save location, content location, check content)
|
||||||
- Config file and compile options, remove all those consts.
|
- Config file and compile options, remove all those consts.
|
||||||
|
- Engine flares shouldn't be centered
|
||||||
- Sprite optimization: do we need to allocate a new `Vec` every frame? Probably not.
|
- Sprite optimization: do we need to allocate a new `Vec` every frame? Probably not.
|
||||||
- Better error when run outside of directory
|
- Better error when run outside of directory
|
||||||
- Documentation site & front page
|
- Documentation site & front page
|
||||||
|
- Random animation age for objects * ui
|
||||||
- Random animation delay/fps?
|
- Random animation delay/fps?
|
||||||
- Better WGSL preprocessor
|
- Fade between animation frames
|
||||||
|
- Better WGSL preprocessor (warning when including a bad file!)
|
||||||
|
|
||||||
## Content
|
## Content
|
||||||
- Angled engines
|
- Angled engines
|
||||||
|
@ -123,8 +121,10 @@
|
||||||
- Zoom parallax (?)
|
- Zoom parallax (?)
|
||||||
- Background haze
|
- Background haze
|
||||||
- Nova dust parallax
|
- Nova dust parallax
|
||||||
|
- Ship outlines in radar
|
||||||
- Engine flare ease in/out
|
- Engine flare ease in/out
|
||||||
- Lens flare
|
- Lens flare
|
||||||
|
- Particles when a ship is damaged
|
||||||
|
|
||||||
## Write and Document
|
## Write and Document
|
||||||
- Parallax
|
- Parallax
|
||||||
|
|
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 95558076be1819b10d5a56c62274cdf7f61ea9a8
|
Subproject commit 74ddbde9e1cec1418c17844bc7336324ece88d15
|
|
@ -6,8 +6,6 @@ size = 8.0
|
||||||
size_rng = 1.6
|
size_rng = 1.6
|
||||||
angle_rng = 360
|
angle_rng = 360
|
||||||
velocity_scale_parent = 1.0
|
velocity_scale_parent = 1.0
|
||||||
fade = 0.2
|
|
||||||
fade_rng = 0.1
|
|
||||||
|
|
||||||
|
|
||||||
[effect."large explosion"]
|
[effect."large explosion"]
|
||||||
|
@ -18,8 +16,6 @@ size = 25.0
|
||||||
size_rng = 5.0
|
size_rng = 5.0
|
||||||
angle_rng = 360
|
angle_rng = 360
|
||||||
velocity_scale_parent = 1.0
|
velocity_scale_parent = 1.0
|
||||||
fade = 0.2
|
|
||||||
fade_rng = 0.1
|
|
||||||
|
|
||||||
|
|
||||||
[effect."huge explosion"]
|
[effect."huge explosion"]
|
||||||
|
@ -30,46 +26,6 @@ size = 50.0
|
||||||
size_rng = 10.0
|
size_rng = 10.0
|
||||||
angle_rng = 360
|
angle_rng = 360
|
||||||
velocity_scale_parent = 1.0
|
velocity_scale_parent = 1.0
|
||||||
fade = 0.2
|
|
||||||
fade_rng = 0.1
|
|
||||||
|
|
||||||
|
|
||||||
[effect."blue spark"]
|
|
||||||
sprite = "particle::spark::blue"
|
|
||||||
lifetime = 0.5
|
|
||||||
lifetime_rng = 0.5
|
|
||||||
inherit_velocity = "parent"
|
|
||||||
size = 4.0
|
|
||||||
size_rng = 2.0
|
|
||||||
angle_rng = 360
|
|
||||||
angvel_rng = 0.0
|
|
||||||
velocity_scale_parent = 1.0
|
|
||||||
fade = 0.2
|
|
||||||
fade_rng = 0.1
|
|
||||||
|
|
||||||
[effect."yellow spark"]
|
|
||||||
sprite = "particle::spark::yellow"
|
|
||||||
lifetime = "inherit"
|
|
||||||
inherit_velocity = "parent"
|
|
||||||
size = 4.0
|
|
||||||
size_rng = 2.0
|
|
||||||
angle_rng = 360
|
|
||||||
angvel_rng = 0.0
|
|
||||||
velocity_scale_parent = 1.0
|
|
||||||
fade = 0.2
|
|
||||||
fade_rng = 0.1
|
|
||||||
|
|
||||||
[effect."red spark"]
|
|
||||||
sprite = "particle::spark::red"
|
|
||||||
lifetime = "inherit"
|
|
||||||
inherit_velocity = "parent"
|
|
||||||
size = 4.0
|
|
||||||
size_rng = 1.0
|
|
||||||
angle_rng = 360
|
|
||||||
angvel_rng = 0.0
|
|
||||||
velocity_scale_parent = 1.0
|
|
||||||
fade = 0.2
|
|
||||||
fade_rng = 0.1
|
|
||||||
|
|
||||||
|
|
||||||
# Every effect has a parent, some effects have a target
|
# Every effect has a parent, some effects have a target
|
||||||
|
@ -82,7 +38,7 @@ size = 3.0 # sprite size, in game units
|
||||||
size_rng = 1.0 # random size variation
|
size_rng = 1.0 # random size variation
|
||||||
|
|
||||||
angle = 0.0 # absolute starting angle. always added to parent angle.
|
angle = 0.0 # absolute starting angle. always added to parent angle.
|
||||||
angle_rng = 0.0 # Starting angle randomness (up to this value)
|
angle_rng = 90.0 # Starting angle randomness (up to this value)
|
||||||
|
|
||||||
# Does not affect velocity, only sprite angle
|
# Does not affect velocity, only sprite angle
|
||||||
angvel_rng = 0.0 # Angvel randomness, applied to angvel
|
angvel_rng = 0.0 # Angvel randomness, applied to angvel
|
||||||
|
@ -95,10 +51,8 @@ velocity_scale_parent_rng = 0.0 # random variation of scale
|
||||||
velocity_scale_target = 1.0
|
velocity_scale_target = 1.0
|
||||||
velocity_scale_target_rng = 1.0
|
velocity_scale_target_rng = 1.0
|
||||||
|
|
||||||
direction_rng = 0.0 # Random variation of travel direction, in degrees, applied to velocity vector (/2 each side?)
|
direction_rng = 1.0 # Random variation of travel direction, in degrees, applied to velocity vector (/2 each side?)
|
||||||
|
|
||||||
fade = 0.2
|
|
||||||
fade_rng = 0.1
|
|
||||||
|
|
||||||
# TODO:
|
# TODO:
|
||||||
# effect probabilities & variants
|
# effect probabilities & variants
|
||||||
|
|
|
@ -13,19 +13,10 @@ space.outfit = 200
|
||||||
space.engine = 50
|
space.engine = 50
|
||||||
space.weapon = 50
|
space.weapon = 50
|
||||||
|
|
||||||
engines = [{ x = 0.0, y = -1, size = 25.0 }]
|
engines = [{ x = 0.0, y = -1.05, size = 50.0 }]
|
||||||
guns = [{ x = 0.0, y = 1 }, { x = 0.1, y = 0.80 }, { x = -0.1, y = 0.80 }]
|
guns = [{ x = 0.0, y = 1 }, { x = 0.1, y = 0.80 }, { x = -0.1, y = 0.80 }]
|
||||||
|
|
||||||
|
|
||||||
# Show these once we've been reduced to this much hull
|
|
||||||
damage.hull = 190
|
|
||||||
# Spawn this effect once every n seconds, on average
|
|
||||||
damage.effects = [
|
|
||||||
{ effect = "blue spark", frequency = 3 },
|
|
||||||
{ effect = "yellow spark", frequency = 1 },
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# Length of death sequence, in seconds
|
# Length of death sequence, in seconds
|
||||||
collapse.length = 5.0
|
collapse.length = 5.0
|
||||||
|
|
||||||
|
|
|
@ -139,39 +139,3 @@ frames = [
|
||||||
"particle/explosion-huge/09.png",
|
"particle/explosion-huge/09.png",
|
||||||
"particle/explosion-huge/10.png",
|
"particle/explosion-huge/10.png",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[sprite."particle::spark::blue"]
|
|
||||||
timing.duration = 0.3
|
|
||||||
#timing.rng = 0.2 # each frame will be independently sped up/slowed by this factor
|
|
||||||
#timing.uniform_rng = 0.2 # one factor for all frames
|
|
||||||
repeat = "reverse"
|
|
||||||
frames = [
|
|
||||||
"particle/spark-blue/01.png",
|
|
||||||
"particle/spark-blue/02.png",
|
|
||||||
"particle/spark-blue/03.png",
|
|
||||||
"particle/spark-blue/04.png",
|
|
||||||
"particle/spark-blue/05.png",
|
|
||||||
]
|
|
||||||
|
|
||||||
[sprite."particle::spark::yellow"]
|
|
||||||
timing.duration = 0.3
|
|
||||||
timing.rng = 0.2
|
|
||||||
repeat = "once"
|
|
||||||
frames = [
|
|
||||||
"particle/spark-yellow/01.png",
|
|
||||||
"particle/spark-yellow/02.png",
|
|
||||||
"particle/spark-yellow/03.png",
|
|
||||||
"particle/spark-yellow/04.png",
|
|
||||||
"particle/spark-yellow/05.png",
|
|
||||||
]
|
|
||||||
|
|
||||||
[sprite."particle::spark::red"]
|
|
||||||
timing.duration = 0.3
|
|
||||||
timing.rng = 0.2
|
|
||||||
repeat = "once"
|
|
||||||
frames = [
|
|
||||||
"particle/spark-red/01.png",
|
|
||||||
"particle/spark-red/02.png",
|
|
||||||
"particle/spark-red/03.png",
|
|
||||||
]
|
|
||||||
|
|
|
@ -29,8 +29,6 @@ pub(crate) mod syntax {
|
||||||
pub velocity_scale_target: Option<f32>,
|
pub velocity_scale_target: Option<f32>,
|
||||||
pub velocity_scale_target_rng: Option<f32>,
|
pub velocity_scale_target_rng: Option<f32>,
|
||||||
pub direction_rng: Option<f32>,
|
pub direction_rng: Option<f32>,
|
||||||
pub fade: Option<f32>,
|
|
||||||
pub fade_rng: Option<f32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -58,7 +56,7 @@ pub(crate) mod syntax {
|
||||||
TextOrFloat::Text(s) => {
|
TextOrFloat::Text(s) => {
|
||||||
if s == "inherit" {
|
if s == "inherit" {
|
||||||
let sprite = content.get_sprite(sprite);
|
let sprite = content.get_sprite(sprite);
|
||||||
sprite.frame_duration * sprite.frames.len() as f32
|
sprite.fps * sprite.frames.len() as f32
|
||||||
} else {
|
} else {
|
||||||
bail!("bad effect lifetime, must be float or \"inherit\"",)
|
bail!("bad effect lifetime, must be float or \"inherit\"",)
|
||||||
}
|
}
|
||||||
|
@ -76,16 +74,14 @@ pub(crate) mod syntax {
|
||||||
lifetime,
|
lifetime,
|
||||||
lifetime_rng: self.lifetime_rng.unwrap_or(0.0),
|
lifetime_rng: self.lifetime_rng.unwrap_or(0.0),
|
||||||
angle: Deg(self.angle.unwrap_or(0.0) / 2.0).into(),
|
angle: Deg(self.angle.unwrap_or(0.0) / 2.0).into(),
|
||||||
angle_rng: self.angle_rng.unwrap_or(0.0) / 2.0,
|
angle_rng: Deg(self.angle_rng.unwrap_or(0.0) / 2.0).into(),
|
||||||
angvel: Deg(self.angvel.unwrap_or(0.0)).into(),
|
angvel: Deg(self.angvel.unwrap_or(0.0)).into(),
|
||||||
angvel_rng: self.angvel_rng.unwrap_or(0.0),
|
angvel_rng: Deg(self.angle_rng.unwrap_or(0.0)).into(),
|
||||||
velocity_scale_parent: self.velocity_scale_parent.unwrap_or(0.0),
|
velocity_scale_parent: self.velocity_scale_parent.unwrap_or(0.0),
|
||||||
velocity_scale_parent_rng: self.velocity_scale_parent_rng.unwrap_or(0.0),
|
velocity_scale_parent_rng: self.velocity_scale_parent_rng.unwrap_or(0.0),
|
||||||
velocity_scale_target: self.velocity_scale_target.unwrap_or(0.0),
|
velocity_scale_target: self.velocity_scale_target.unwrap_or(0.0),
|
||||||
velocity_scale_target_rng: self.velocity_scale_target_rng.unwrap_or(0.0),
|
velocity_scale_target_rng: self.velocity_scale_target_rng.unwrap_or(0.0),
|
||||||
direction_rng: self.direction_rng.unwrap_or(0.0) / 2.0,
|
direction_rng: Deg(self.direction_rng.unwrap_or(0.0) / 2.0).into(),
|
||||||
fade: self.fade.unwrap_or(0.0),
|
|
||||||
fade_rng: self.fade_rng.unwrap_or(0.0),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return Ok(handle);
|
return Ok(handle);
|
||||||
|
@ -145,13 +141,13 @@ pub struct Effect {
|
||||||
pub angle: Rad<f32>,
|
pub angle: Rad<f32>,
|
||||||
|
|
||||||
/// Random angle variation
|
/// Random angle variation
|
||||||
pub angle_rng: f32,
|
pub angle_rng: Rad<f32>,
|
||||||
|
|
||||||
/// How fast this particle spins
|
/// How fast this particle spins
|
||||||
pub angvel: Rad<f32>,
|
pub angvel: Rad<f32>,
|
||||||
|
|
||||||
/// Random angvel variation
|
/// Random angvel variation
|
||||||
pub angvel_rng: f32,
|
pub angvel_rng: Rad<f32>,
|
||||||
|
|
||||||
/// The amount of this particle's parent's velocity to inherit
|
/// The amount of this particle's parent's velocity to inherit
|
||||||
pub velocity_scale_parent: f32,
|
pub velocity_scale_parent: f32,
|
||||||
|
@ -167,13 +163,7 @@ pub struct Effect {
|
||||||
pub velocity_scale_target_rng: f32,
|
pub velocity_scale_target_rng: f32,
|
||||||
|
|
||||||
/// Travel direction random variation
|
/// Travel direction random variation
|
||||||
pub direction_rng: f32,
|
pub direction_rng: Rad<f32>,
|
||||||
|
|
||||||
/// Fade this effect out over this many seconds as it ends
|
|
||||||
pub fade: f32,
|
|
||||||
|
|
||||||
/// Random fade ariation
|
|
||||||
pub fade_rng: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Build for Effect {
|
impl crate::Build for Effect {
|
||||||
|
|
|
@ -170,10 +170,7 @@ impl crate::Build for Gun {
|
||||||
lifetime: gun.projectile.lifetime,
|
lifetime: gun.projectile.lifetime,
|
||||||
lifetime_rng: gun.projectile.lifetime_rng,
|
lifetime_rng: gun.projectile.lifetime_rng,
|
||||||
damage: gun.projectile.damage,
|
damage: gun.projectile.damage,
|
||||||
|
angle_rng: Deg(gun.projectile.angle_rng),
|
||||||
// Divide by 2, so the angle matches the angle of the fire cone.
|
|
||||||
// This should ALWAYS be done in the content parser.
|
|
||||||
angle_rng: Deg(gun.projectile.angle_rng / 2.0),
|
|
||||||
impact_effect,
|
impact_effect,
|
||||||
expire_effect,
|
expire_effect,
|
||||||
collider: gun.projectile.collider,
|
collider: gun.projectile.collider,
|
||||||
|
|
|
@ -26,7 +26,6 @@ pub(crate) mod syntax {
|
||||||
pub linear_drag: f32,
|
pub linear_drag: f32,
|
||||||
pub space: outfitspace::syntax::OutfitSpace,
|
pub space: outfitspace::syntax::OutfitSpace,
|
||||||
pub collapse: Option<Collapse>,
|
pub collapse: Option<Collapse>,
|
||||||
pub damage: Option<Damage>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -42,19 +41,6 @@ pub(crate) mod syntax {
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Damage {
|
|
||||||
pub hull: f32,
|
|
||||||
pub effects: Vec<DamageEffectSpawner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct DamageEffectSpawner {
|
|
||||||
pub effect: EffectReference,
|
|
||||||
pub frequency: f32,
|
|
||||||
pub pos: Option<[f32; 2]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// plural or not? document!
|
// plural or not? document!
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -132,9 +118,6 @@ pub struct Ship {
|
||||||
|
|
||||||
/// Ship collapse sequence
|
/// Ship collapse sequence
|
||||||
pub collapse: ShipCollapse,
|
pub collapse: ShipCollapse,
|
||||||
|
|
||||||
/// Damaged ship effects
|
|
||||||
pub damage: ShipDamage,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collision shape for this ship
|
/// Collision shape for this ship
|
||||||
|
@ -178,31 +161,7 @@ pub struct ShipCollapse {
|
||||||
pub events: Vec<CollapseEvent>,
|
pub events: Vec<CollapseEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parameters for damaged ship effects
|
/// A scripted event during a ship collapse sequence
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ShipDamage {
|
|
||||||
/// Show damaged ship effects if hull is below this value
|
|
||||||
pub hull: f32,
|
|
||||||
|
|
||||||
/// Effects to create during collapse
|
|
||||||
pub effects: Vec<DamageEffectSpawner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An effect shown when a ship is damaged
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct DamageEffectSpawner {
|
|
||||||
/// The effect to create
|
|
||||||
pub effect: EffectHandle,
|
|
||||||
|
|
||||||
/// How often to create this effect
|
|
||||||
pub frequency: f32,
|
|
||||||
|
|
||||||
/// Where to create is effect.
|
|
||||||
/// Position is random if None.
|
|
||||||
pub pos: Option<Point2<f32>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An effect shown during a ship collapse sequence
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CollapseEffectSpawner {
|
pub struct CollapseEffectSpawner {
|
||||||
/// The effect to create
|
/// The effect to create
|
||||||
|
@ -211,7 +170,7 @@ pub struct CollapseEffectSpawner {
|
||||||
/// How many effects to create
|
/// How many effects to create
|
||||||
pub count: f32,
|
pub count: f32,
|
||||||
|
|
||||||
/// Where to create this effect.
|
/// Where to create these effects.
|
||||||
/// Position is random if None.
|
/// Position is random if None.
|
||||||
pub pos: Option<Point2<f32>>,
|
pub pos: Option<Point2<f32>>,
|
||||||
}
|
}
|
||||||
|
@ -254,8 +213,7 @@ impl crate::Build for Ship {
|
||||||
let size = ship.size;
|
let size = ship.size;
|
||||||
let aspect = ct.get_sprite(handle).aspect;
|
let aspect = ct.get_sprite(handle).aspect;
|
||||||
|
|
||||||
let collapse = {
|
let collapse = if let Some(c) = ship.collapse {
|
||||||
if let Some(c) = ship.collapse {
|
|
||||||
let mut effects = Vec::new();
|
let mut effects = Vec::new();
|
||||||
for e in c.effects {
|
for e in c.effects {
|
||||||
effects.push(CollapseEffectSpawner {
|
effects.push(CollapseEffectSpawner {
|
||||||
|
@ -278,12 +236,9 @@ impl crate::Build for Ship {
|
||||||
let mut effects = Vec::new();
|
let mut effects = Vec::new();
|
||||||
for g in e.effects {
|
for g in e.effects {
|
||||||
effects.push(CollapseEffectSpawner {
|
effects.push(CollapseEffectSpawner {
|
||||||
effect: g
|
effect: g.effect.to_handle(build_context, ct).with_context(
|
||||||
.effect
|
|| format!("while loading ship `{}`", ship_name),
|
||||||
.to_handle(build_context, ct)
|
)?,
|
||||||
.with_context(|| {
|
|
||||||
format!("while loading ship `{}`", ship_name)
|
|
||||||
})?,
|
|
||||||
count: g.count,
|
count: g.count,
|
||||||
pos: g.pos.map(|p| Point2 {
|
pos: g.pos.map(|p| Point2 {
|
||||||
x: p[0] * (size / 2.0) * aspect,
|
x: p[0] * (size / 2.0) * aspect,
|
||||||
|
@ -312,43 +267,11 @@ impl crate::Build for Ship {
|
||||||
effects: vec![],
|
effects: vec![],
|
||||||
events: vec![],
|
events: vec![],
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let damage = {
|
|
||||||
if let Some(c) = ship.damage {
|
|
||||||
let mut effects = Vec::new();
|
|
||||||
for e in c.effects {
|
|
||||||
effects.push(DamageEffectSpawner {
|
|
||||||
effect: e
|
|
||||||
.effect
|
|
||||||
.to_handle(build_context, ct)
|
|
||||||
.with_context(|| format!("while loading ship `{}`", ship_name))?,
|
|
||||||
frequency: e.frequency,
|
|
||||||
pos: e.pos.map(|p| Point2 {
|
|
||||||
x: p[0] * (size / 2.0) * aspect,
|
|
||||||
y: p[1] * size / 2.0,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ShipDamage {
|
|
||||||
hull: c.hull,
|
|
||||||
effects: effects,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Default damage effects
|
|
||||||
ShipDamage {
|
|
||||||
hull: 0.0,
|
|
||||||
effects: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ct.ships.push(Self {
|
ct.ships.push(Self {
|
||||||
aspect,
|
aspect,
|
||||||
collapse,
|
collapse,
|
||||||
damage,
|
|
||||||
name: ship_name,
|
name: ship_name,
|
||||||
sprite: handle,
|
sprite: handle,
|
||||||
mass: ship.mass,
|
mass: ship.mass,
|
||||||
|
|
|
@ -35,20 +35,13 @@ pub(crate) mod syntax {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub enum TimingVariant {
|
pub enum Timing {
|
||||||
#[serde(rename = "duration")]
|
#[serde(rename = "duration")]
|
||||||
Duration(f32),
|
Duration(f32),
|
||||||
|
|
||||||
#[serde(rename = "fps")]
|
#[serde(rename = "fps")]
|
||||||
Fps(f32),
|
Fps(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Timing {
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub variant: TimingVariant,
|
|
||||||
//pub uniform_rng: Option<f32>,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How to replay a texture's animation
|
/// How to replay a texture's animation
|
||||||
|
@ -93,11 +86,8 @@ pub struct Sprite {
|
||||||
pub frames: Vec<PathBuf>,
|
pub frames: Vec<PathBuf>,
|
||||||
|
|
||||||
/// The speed of this sprite's animation.
|
/// The speed of this sprite's animation.
|
||||||
/// This is zero for unanimate sprites.
|
/// unanimated sprites have zero fps.
|
||||||
pub frame_duration: f32,
|
pub fps: f32,
|
||||||
|
|
||||||
/// All frames will be sped up/slowed by this factor.
|
|
||||||
//pub frame_uniform_rng: f32,
|
|
||||||
|
|
||||||
/// How to replay this sprite's animation
|
/// How to replay this sprite's animation
|
||||||
pub repeat: RepeatMode,
|
pub repeat: RepeatMode,
|
||||||
|
@ -155,8 +145,7 @@ impl crate::Build for Sprite {
|
||||||
content.sprites.push(Self {
|
content.sprites.push(Self {
|
||||||
name: sprite_name,
|
name: sprite_name,
|
||||||
frames: vec![t.file],
|
frames: vec![t.file],
|
||||||
frame_duration: 0.0,
|
fps: 0.0,
|
||||||
//frame_uniform_rng: 0.0,
|
|
||||||
handle: h,
|
handle: h,
|
||||||
repeat: RepeatMode::Once,
|
repeat: RepeatMode::Once,
|
||||||
aspect: dim.0 as f32 / dim.1 as f32,
|
aspect: dim.0 as f32 / dim.1 as f32,
|
||||||
|
@ -204,17 +193,16 @@ impl crate::Build for Sprite {
|
||||||
unreachable!("Starfield texture may not be animated")
|
unreachable!("Starfield texture may not be animated")
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame_duration = match t.timing.variant {
|
let fps = match t.timing {
|
||||||
syntax::TimingVariant::Duration(d) => d / t.frames.len() as f32,
|
syntax::Timing::Duration(d) => d / t.frames.len() as f32,
|
||||||
syntax::TimingVariant::Fps(f) => 1.0 / f,
|
syntax::Timing::Fps(f) => 1.0 / f,
|
||||||
};
|
};
|
||||||
|
|
||||||
content.sprite_index.insert(sprite_name.clone(), h);
|
content.sprite_index.insert(sprite_name.clone(), h);
|
||||||
content.sprites.push(Self {
|
content.sprites.push(Self {
|
||||||
name: sprite_name,
|
name: sprite_name,
|
||||||
frames: t.frames,
|
frames: t.frames,
|
||||||
frame_duration,
|
fps,
|
||||||
//frame_uniform_rng: t.timing.uniform_rng.unwrap_or(0.0),
|
|
||||||
handle: h,
|
handle: h,
|
||||||
repeat: t.repeat,
|
repeat: t.repeat,
|
||||||
aspect: dim.0 as f32 / dim.1 as f32,
|
aspect: dim.0 as f32 / dim.1 as f32,
|
||||||
|
|
|
@ -197,7 +197,7 @@ impl<'a> OutfitSet {
|
||||||
.map(|p| ObjectSubSprite {
|
.map(|p| ObjectSubSprite {
|
||||||
pos: Point3 {
|
pos: Point3 {
|
||||||
x: p.pos.x,
|
x: p.pos.x,
|
||||||
y: p.pos.y - p.size / 2.0,
|
y: p.pos.y,
|
||||||
z: 1.0,
|
z: 1.0,
|
||||||
},
|
},
|
||||||
sprite: *s,
|
sprite: *s,
|
||||||
|
|
|
@ -63,15 +63,13 @@ impl Ship {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
g.cooldown = g.kind.rate + &rng.gen_range(-g.kind.rate_rng..=g.kind.rate_rng);
|
g.cooldown = g.kind.rate + &rng.gen_range(-g.kind.rate_rng..=g.kind.rate_rng);
|
||||||
|
|
||||||
let lifetime = g.kind.projectile.lifetime
|
|
||||||
+ rng.gen_range(
|
|
||||||
-g.kind.projectile.lifetime_rng..=g.kind.projectile.lifetime_rng,
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Projectile {
|
Projectile {
|
||||||
content: g.kind.projectile.clone(),
|
content: g.kind.projectile.clone(),
|
||||||
lifetime: 0f32.max(lifetime),
|
lifetime: g.kind.projectile.lifetime
|
||||||
|
+ rng.gen_range(
|
||||||
|
-g.kind.projectile.lifetime_rng..=g.kind.projectile.lifetime_rng,
|
||||||
|
),
|
||||||
faction: self.faction,
|
faction: self.faction,
|
||||||
},
|
},
|
||||||
p.clone(),
|
p.clone(),
|
||||||
|
|
|
@ -90,21 +90,6 @@ impl AtlasSet {
|
||||||
|
|
||||||
let image_dim = img.dimensions();
|
let image_dim = img.dimensions();
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: seperate CLI argument to check these.
|
|
||||||
don't check this every run,because sometimes it's necessary. (for animated sprites!)
|
|
||||||
let mut transparent_border = true;
|
|
||||||
for (x, y, c) in img.pixels() {
|
|
||||||
if (x == 0 || y == 0 || x == img.width() - 1 || y == img.height() - 1) && c[3] != 0 {
|
|
||||||
transparent_border = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if transparent_border {
|
|
||||||
println!("[WARNING] {} wastes space with a transmparent border",);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
let dim = [
|
let dim = [
|
||||||
image_dim.0 + 2 * self.image_margin,
|
image_dim.0 + 2 * self.image_margin,
|
||||||
image_dim.1 + 2 * self.image_margin,
|
image_dim.1 + 2 * self.image_margin,
|
||||||
|
|
|
@ -64,7 +64,7 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create atlas set
|
// Create atlas set
|
||||||
let mut atlas_set = AtlasSet::new(8192, 8192, 16, &asset_root, 1);
|
let mut atlas_set = AtlasSet::new(8192, 8192, 16, &asset_root, 2);
|
||||||
let total = files.len();
|
let total = files.len();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut peak_efficiency = 0f64;
|
let mut peak_efficiency = 0f64;
|
||||||
|
@ -88,8 +88,8 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
println!("Saving files...");
|
println!("Saving files...");
|
||||||
atlas_set.save_files(
|
atlas_set.save_files(
|
||||||
|x| PathBuf::from(format!("cache/atlas-{x:0.2}.bmp")),
|
|x| PathBuf::from(format!("atlas-{x:0.2}.bmp")),
|
||||||
&PathBuf::from("cache/spriteatlas.toml"),
|
&PathBuf::from("spriteatlas.toml"),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
|
@ -3,20 +3,20 @@ fn animate(sprite_index: u32, age: f32, offset: f32) -> f32 {
|
||||||
|
|
||||||
let len = global_sprites[sprite_index].frame_count;
|
let len = global_sprites[sprite_index].frame_count;
|
||||||
let rep = global_sprites[sprite_index].repeatmode;
|
let rep = global_sprites[sprite_index].repeatmode;
|
||||||
let frame_duration = global_sprites[sprite_index].frame_duration;
|
let fps = global_sprites[sprite_index].fps;
|
||||||
var frame: f32 = 0.0;
|
var frame: f32 = 0.0;
|
||||||
|
|
||||||
// Once
|
// Once
|
||||||
if rep == u32(1) {
|
if rep == u32(1) {
|
||||||
|
|
||||||
frame = min(
|
frame = min(
|
||||||
age / frame_duration + offset,
|
age / fps + offset,
|
||||||
f32(len) - 1.0
|
f32(len) - 1.0
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reverse
|
// Reverse
|
||||||
} else if rep == u32(2) {
|
} else if rep == u32(2) {
|
||||||
let x = age / frame_duration + offset;
|
let x = age / fps + offset;
|
||||||
let m = f32(len) * 2.0 - 1.0;
|
let m = f32(len) * 2.0 - 1.0;
|
||||||
// x fmod m
|
// x fmod m
|
||||||
frame = x - floor(x / m) * m;
|
frame = x - floor(x / m) * m;
|
||||||
|
@ -32,7 +32,7 @@ fn animate(sprite_index: u32, age: f32, offset: f32) -> f32 {
|
||||||
|
|
||||||
// Repeat (default)
|
// Repeat (default)
|
||||||
} else {
|
} else {
|
||||||
let x = age / frame_duration + offset;
|
let x = age / fps + offset;
|
||||||
let m = f32(len);
|
let m = f32(len);
|
||||||
frame = x - floor(x / m) * m;
|
frame = x - floor(x / m) * m;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,7 @@ struct InstanceInput {
|
||||||
@location(6) size: f32,
|
@location(6) size: f32,
|
||||||
@location(7) created: f32,
|
@location(7) created: f32,
|
||||||
@location(8) expires: f32,
|
@location(8) expires: f32,
|
||||||
@location(9) fade: f32,
|
@location(9) sprite_index: u32,
|
||||||
@location(10) sprite_index: u32,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertexInput {
|
struct VertexInput {
|
||||||
|
@ -20,11 +19,10 @@ struct VertexInput {
|
||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
@builtin(position) position: vec4<f32>,
|
@builtin(position) position: vec4<f32>,
|
||||||
@location(0) tween: f32,
|
@location(0) tween: f32,
|
||||||
@location(1) fade: f32,
|
@location(1) texture_index_a: u32,
|
||||||
@location(2) texture_index_a: u32,
|
@location(2) texture_coords_a: vec2<f32>,
|
||||||
@location(3) texture_coords_a: vec2<f32>,
|
@location(3) texture_index_b: u32,
|
||||||
@location(4) texture_index_b: u32,
|
@location(4) texture_coords_b: vec2<f32>,
|
||||||
@location(5) texture_coords_b: vec2<f32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,11 +84,6 @@ fn vertex_main(
|
||||||
|
|
||||||
out.position = vec4(pos, 0.0, 1.0);
|
out.position = vec4(pos, 0.0, 1.0);
|
||||||
|
|
||||||
if instance.expires - global_data.current_time.x <= instance.fade {
|
|
||||||
out.fade = (instance.expires - global_data.current_time.x) / instance.fade;
|
|
||||||
} else {
|
|
||||||
out.fade = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute texture coordinates
|
// Compute texture coordinates
|
||||||
let frame = animate(instance.sprite_index, age, 0.0);
|
let frame = animate(instance.sprite_index, age, 0.0);
|
||||||
|
@ -138,5 +131,5 @@ fn fragment_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
0.0
|
0.0
|
||||||
).rgba,
|
).rgba,
|
||||||
in.tween
|
in.tween
|
||||||
) * vec4(1.0, 1.0, 1.0, in.fade);
|
);
|
||||||
}
|
}
|
|
@ -83,7 +83,7 @@ impl GlobalUniform {
|
||||||
frame_count: u32,
|
frame_count: u32,
|
||||||
repeatmode: u32,
|
repeatmode: u32,
|
||||||
aspect: f32,
|
aspect: f32,
|
||||||
frame_duration: f32,
|
fps: f32,
|
||||||
first_frame: u32,
|
first_frame: u32,
|
||||||
|
|
||||||
padding_a: f32,
|
padding_a: f32,
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub struct SpriteData {
|
||||||
pub frame_count: u32,
|
pub frame_count: u32,
|
||||||
pub repeatmode: u32,
|
pub repeatmode: u32,
|
||||||
pub aspect: f32,
|
pub aspect: f32,
|
||||||
pub frame_duration: f32,
|
pub fps: f32,
|
||||||
|
|
||||||
// Index of first frame in ImageLocationArray
|
// Index of first frame in ImageLocationArray
|
||||||
pub first_frame: u32,
|
pub first_frame: u32,
|
||||||
|
|
|
@ -586,7 +586,6 @@ impl GPUState {
|
||||||
sprite_index: i.sprite.get_index(),
|
sprite_index: i.sprite.get_index(),
|
||||||
created: state.current_time,
|
created: state.current_time,
|
||||||
expires: state.current_time + i.lifetime,
|
expires: state.current_time + i.lifetime,
|
||||||
fade: i.fade,
|
|
||||||
}]),
|
}]),
|
||||||
);
|
);
|
||||||
self.vertex_buffers.particle_array_head += 1;
|
self.vertex_buffers.particle_array_head += 1;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::content;
|
use crate::content;
|
||||||
use cgmath::{Deg, Matrix2, Point2, Point3, Rad, Vector2};
|
use cgmath::{Deg, Point2, Point3, Rad, Vector2};
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
/// Instructions to create a new particle
|
/// Instructions to create a new particle
|
||||||
pub struct ParticleBuilder {
|
pub struct ParticleBuilder {
|
||||||
|
@ -25,65 +24,6 @@ pub struct ParticleBuilder {
|
||||||
/// The size of this particle,
|
/// The size of this particle,
|
||||||
/// given as height in world units.
|
/// given as height in world units.
|
||||||
pub size: f32,
|
pub size: f32,
|
||||||
|
|
||||||
/// Fade this particle out over this many seconds as it expires
|
|
||||||
pub fade: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParticleBuilder {
|
|
||||||
/// Create a ParticleBuilder from an Effect
|
|
||||||
pub fn from_content(
|
|
||||||
effect: &content::Effect,
|
|
||||||
pos: Point2<f32>,
|
|
||||||
parent_angle: Rad<f32>,
|
|
||||||
parent_velocity: Vector2<f32>,
|
|
||||||
target_velocity: Vector2<f32>,
|
|
||||||
) -> Self {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
let velocity = {
|
|
||||||
let a =
|
|
||||||
rng.gen_range(-effect.velocity_scale_parent_rng..=effect.velocity_scale_parent_rng);
|
|
||||||
let b =
|
|
||||||
rng.gen_range(-effect.velocity_scale_target_rng..=effect.velocity_scale_target_rng);
|
|
||||||
|
|
||||||
let velocity = ((effect.velocity_scale_parent + a) * parent_velocity)
|
|
||||||
+ ((effect.velocity_scale_target + b) * target_velocity);
|
|
||||||
|
|
||||||
Matrix2::from_angle(Rad(
|
|
||||||
rng.gen_range(-effect.direction_rng..=effect.direction_rng)
|
|
||||||
)) * velocity
|
|
||||||
};
|
|
||||||
|
|
||||||
// Rad has odd behavior when its angle is zero, so we need extra checks here
|
|
||||||
let angvel = if effect.angvel_rng == 0.0 {
|
|
||||||
effect.angvel
|
|
||||||
} else {
|
|
||||||
Rad(effect.angvel.0 + rng.gen_range(-effect.angvel_rng..=effect.angvel_rng))
|
|
||||||
};
|
|
||||||
let angle = if effect.angle_rng == 0.0 {
|
|
||||||
parent_angle + effect.angle
|
|
||||||
} else {
|
|
||||||
parent_angle + effect.angle + Rad(rng.gen_range(-effect.angle_rng..=effect.angle_rng))
|
|
||||||
};
|
|
||||||
|
|
||||||
ParticleBuilder {
|
|
||||||
sprite: effect.sprite,
|
|
||||||
pos,
|
|
||||||
velocity,
|
|
||||||
|
|
||||||
angle,
|
|
||||||
angvel,
|
|
||||||
|
|
||||||
lifetime: 0f32
|
|
||||||
.max(effect.lifetime + rng.gen_range(-effect.lifetime_rng..=effect.lifetime_rng)),
|
|
||||||
|
|
||||||
// Make sure size isn't negative. This check should be on EVERY rng!
|
|
||||||
size: 0f32.max(effect.size + rng.gen_range(-effect.size_rng..=effect.size_rng)),
|
|
||||||
|
|
||||||
fade: 0f32.max(effect.fade + rng.gen_range(-effect.fade_rng..=effect.fade_rng)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The location of a UI element, in one of a few
|
/// The location of a UI element, in one of a few
|
||||||
|
|
|
@ -77,7 +77,7 @@ impl RawTexture {
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
pub index: u32, // Index in texture array
|
pub index: u32, // Index in texture array
|
||||||
pub len: u32, // Number of frames
|
pub len: u32, // Number of frames
|
||||||
pub frame_duration: f32, // Frames per second
|
pub fps: f32, // Frames per second
|
||||||
pub aspect: f32, // width / height
|
pub aspect: f32, // width / height
|
||||||
pub repeat: u32, // How to re-play this texture
|
pub repeat: u32, // How to re-play this texture
|
||||||
pub location: Vec<SpriteAtlasImage>,
|
pub location: Vec<SpriteAtlasImage>,
|
||||||
|
@ -120,7 +120,7 @@ impl TextureArray {
|
||||||
frame_count: t.frames.len() as u32,
|
frame_count: t.frames.len() as u32,
|
||||||
repeatmode: t.repeat.as_int(),
|
repeatmode: t.repeat.as_int(),
|
||||||
aspect: t.aspect,
|
aspect: t.aspect,
|
||||||
frame_duration: t.frame_duration,
|
fps: t.fps,
|
||||||
first_frame: image_counter,
|
first_frame: image_counter,
|
||||||
_padding: Default::default(),
|
_padding: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -206,9 +206,6 @@ pub struct ParticleInstance {
|
||||||
/// Time is kept by a variable in the global uniform.
|
/// Time is kept by a variable in the global uniform.
|
||||||
pub expires: f32,
|
pub expires: f32,
|
||||||
|
|
||||||
/// Fade this particle out over this many seconds as it expires
|
|
||||||
pub fade: f32,
|
|
||||||
|
|
||||||
/// What sprite to use for this particle
|
/// What sprite to use for this particle
|
||||||
pub sprite_index: u32,
|
pub sprite_index: u32,
|
||||||
}
|
}
|
||||||
|
@ -261,16 +258,10 @@ impl BufferObject for ParticleInstance {
|
||||||
shader_location: 8,
|
shader_location: 8,
|
||||||
format: wgpu::VertexFormat::Float32,
|
format: wgpu::VertexFormat::Float32,
|
||||||
},
|
},
|
||||||
// Fade
|
// Sprite
|
||||||
wgpu::VertexAttribute {
|
wgpu::VertexAttribute {
|
||||||
offset: mem::size_of::<[f32; 9]>() as wgpu::BufferAddress,
|
offset: mem::size_of::<[f32; 9]>() as wgpu::BufferAddress,
|
||||||
shader_location: 9,
|
shader_location: 9,
|
||||||
format: wgpu::VertexFormat::Float32,
|
|
||||||
},
|
|
||||||
// Sprite
|
|
||||||
wgpu::VertexAttribute {
|
|
||||||
offset: mem::size_of::<[f32; 10]>() as wgpu::BufferAddress,
|
|
||||||
shader_location: 10,
|
|
||||||
format: wgpu::VertexFormat::Uint32,
|
format: wgpu::VertexFormat::Uint32,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use cgmath::{Deg, InnerSpace, Point3, Vector2};
|
use cgmath::{Deg, InnerSpace, Point3, Vector2};
|
||||||
use rand::Rng;
|
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
dynamics::{RigidBody, RigidBodyHandle},
|
dynamics::{RigidBody, RigidBodyHandle},
|
||||||
geometry::ColliderHandle,
|
geometry::ColliderHandle,
|
||||||
|
@ -20,9 +19,6 @@ pub struct ProjectileWorldObject {
|
||||||
|
|
||||||
/// This projectile's collider
|
/// This projectile's collider
|
||||||
pub collider: ColliderHandle,
|
pub collider: ColliderHandle,
|
||||||
|
|
||||||
/// This projectile's size variation
|
|
||||||
pub size_rng: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectileWorldObject {
|
impl ProjectileWorldObject {
|
||||||
|
@ -32,13 +28,10 @@ impl ProjectileWorldObject {
|
||||||
rigid_body: RigidBodyHandle,
|
rigid_body: RigidBodyHandle,
|
||||||
collider: ColliderHandle,
|
collider: ColliderHandle,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let size_rng = projectile.content.size_rng;
|
|
||||||
ProjectileWorldObject {
|
ProjectileWorldObject {
|
||||||
rigid_body,
|
rigid_body,
|
||||||
collider,
|
collider,
|
||||||
projectile,
|
projectile,
|
||||||
size_rng: rng.gen_range(-size_rng..=size_rng),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +50,7 @@ impl ProjectileWorldObject {
|
||||||
y: pos.y,
|
y: pos.y,
|
||||||
z: 1.0,
|
z: 1.0,
|
||||||
},
|
},
|
||||||
size: 0f32.max(self.projectile.content.size + self.size_rng),
|
size: self.projectile.content.size,
|
||||||
angle: -ang,
|
angle: -ang,
|
||||||
children: None,
|
children: None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,21 +98,51 @@ impl ShipCollapseSequence {
|
||||||
} else {
|
} else {
|
||||||
self.random_in_ship(ship_content, collider)
|
self.random_in_ship(ship_content, collider)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Position, adjusted for ship rotation
|
||||||
let pos = ship_pos
|
let pos = ship_pos
|
||||||
+ (Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos);
|
+ Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos;
|
||||||
|
|
||||||
let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
let velocity = {
|
||||||
|
let a = self.rng.gen_range(
|
||||||
|
-effect.velocity_scale_parent_rng
|
||||||
|
..=effect.velocity_scale_parent_rng,
|
||||||
|
);
|
||||||
|
|
||||||
particles.push(ParticleBuilder::from_content(
|
let velocity = (effect.velocity_scale_parent + a)
|
||||||
effect,
|
* rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||||
pos,
|
|
||||||
Rad::zero(),
|
Matrix2::from_angle(Rad(self.rng.gen_range(
|
||||||
Vector2 {
|
-effect.direction_rng.0..=effect.direction_rng.0,
|
||||||
|
))) * Vector2 {
|
||||||
x: velocity.x,
|
x: velocity.x,
|
||||||
y: velocity.y,
|
y: velocity.y,
|
||||||
},
|
}
|
||||||
Vector2::zero(),
|
};
|
||||||
))
|
|
||||||
|
particles.push(ParticleBuilder {
|
||||||
|
sprite: effect.sprite,
|
||||||
|
pos,
|
||||||
|
velocity,
|
||||||
|
|
||||||
|
angle: effect.angle
|
||||||
|
+ Rad(self
|
||||||
|
.rng
|
||||||
|
.gen_range(-effect.angle_rng.0..=effect.angle_rng.0)),
|
||||||
|
|
||||||
|
angvel: Rad(effect.angvel.0
|
||||||
|
+ self
|
||||||
|
.rng
|
||||||
|
.gen_range(-effect.angvel_rng.0..=effect.angvel_rng.0)),
|
||||||
|
|
||||||
|
lifetime: effect.lifetime
|
||||||
|
+ self
|
||||||
|
.rng
|
||||||
|
.gen_range(-effect.lifetime_rng..=effect.lifetime_rng),
|
||||||
|
|
||||||
|
size: effect.size
|
||||||
|
+ self.rng.gen_range(-effect.size_rng..=effect.size_rng),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +188,6 @@ impl ShipCollapseSequence {
|
||||||
angvel: Rad::zero(),
|
angvel: Rad::zero(),
|
||||||
lifetime: effect.lifetime,
|
lifetime: effect.lifetime,
|
||||||
size: effect.size,
|
size: effect.size,
|
||||||
fade: 0.0,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,68 +236,21 @@ impl ShipWorldObject {
|
||||||
&mut self,
|
&mut self,
|
||||||
ct: &content::Content,
|
ct: &content::Content,
|
||||||
particles: &mut Vec<ParticleBuilder>,
|
particles: &mut Vec<ParticleBuilder>,
|
||||||
rigid_body: &mut RigidBody,
|
r: &mut RigidBody,
|
||||||
collider: &mut Collider,
|
c: &mut Collider,
|
||||||
t: f32,
|
t: f32,
|
||||||
) {
|
) {
|
||||||
if self.ship.is_dead() {
|
if self.ship.is_dead() {
|
||||||
return self
|
return self
|
||||||
.collapse_sequence
|
.collapse_sequence
|
||||||
.step(&self.ship, ct, particles, rigid_body, collider, t);
|
.step(&self.ship, ct, particles, r, c, t);
|
||||||
}
|
|
||||||
|
|
||||||
let ship_content = ct.get_ship(self.ship.handle);
|
|
||||||
let ship_pos = util::rigidbody_position(&rigid_body);
|
|
||||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
|
||||||
let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 });
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
if self.ship.hull <= ship_content.damage.hull {
|
|
||||||
for e in &ship_content.damage.effects {
|
|
||||||
if rng.gen_range(0.0..=1.0) <= t / e.frequency {
|
|
||||||
let effect = ct.get_effect(e.effect);
|
|
||||||
let ship_content = ct.get_ship(self.ship.handle);
|
|
||||||
|
|
||||||
let pos = if let Some(pos) = e.pos {
|
|
||||||
pos.to_vec()
|
|
||||||
} else {
|
|
||||||
// Pick a random point inside this ship's collider
|
|
||||||
let mut y = 0.0;
|
|
||||||
let mut x = 0.0;
|
|
||||||
let mut a = false;
|
|
||||||
while !a {
|
|
||||||
y = rng.gen_range(-1.0..=1.0) * ship_content.size / 2.0;
|
|
||||||
x = rng.gen_range(-1.0..=1.0)
|
|
||||||
* ship_content.size * ship_content.sprite.aspect
|
|
||||||
/ 2.0;
|
|
||||||
a = collider.shape().contains_local_point(&point![x, y]);
|
|
||||||
}
|
|
||||||
Vector2 { x, y }
|
|
||||||
};
|
|
||||||
|
|
||||||
let pos =
|
|
||||||
ship_pos + (Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos);
|
|
||||||
|
|
||||||
let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
|
||||||
|
|
||||||
particles.push(ParticleBuilder::from_content(
|
|
||||||
effect,
|
|
||||||
pos,
|
|
||||||
Rad::zero(),
|
|
||||||
Vector2 {
|
|
||||||
x: velocity.x,
|
|
||||||
y: velocity.y,
|
|
||||||
},
|
|
||||||
Vector2::zero(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ship_rot = util::rigidbody_rotation(r);
|
||||||
let engine_force = ship_rot * t;
|
let engine_force = ship_rot * t;
|
||||||
|
|
||||||
if self.controls.thrust {
|
if self.controls.thrust {
|
||||||
rigid_body.apply_impulse(
|
r.apply_impulse(
|
||||||
vector![engine_force.x, engine_force.y]
|
vector![engine_force.x, engine_force.y]
|
||||||
* self.ship.outfits.stat_sum().engine_thrust,
|
* self.ship.outfits.stat_sum().engine_thrust,
|
||||||
true,
|
true,
|
||||||
|
@ -276,13 +258,11 @@ impl ShipWorldObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.controls.right {
|
if self.controls.right {
|
||||||
rigid_body
|
r.apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * -100.0 * t, true);
|
||||||
.apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * -100.0 * t, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.controls.left {
|
if self.controls.left {
|
||||||
rigid_body
|
r.apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * 100.0 * t, true);
|
||||||
.apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * 100.0 * t, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in self.ship.outfits.iter_guns() {
|
for i in self.ship.outfits.iter_guns() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2, Zero};
|
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2};
|
||||||
use crossbeam::channel::Receiver;
|
use crossbeam::channel::Receiver;
|
||||||
use nalgebra::{point, vector};
|
use nalgebra::{point, vector};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
@ -80,9 +80,9 @@ impl<'a> World {
|
||||||
|
|
||||||
let pos = ship_pos + (Matrix2::from_angle(-ship_ang) * point.pos.to_vec());
|
let pos = ship_pos + (Matrix2::from_angle(-ship_ang) * point.pos.to_vec());
|
||||||
|
|
||||||
let spread: Rad<f32> = Deg(
|
let spread: Rad<f32> = Deg(rng.gen_range(
|
||||||
rng.gen_range(-projectile.content.angle_rng.0..=projectile.content.angle_rng.0)
|
-(projectile.content.angle_rng.0 / 2.0)..=projectile.content.angle_rng.0 / 2.0,
|
||||||
)
|
))
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let vel = ship_vel
|
let vel = ship_vel
|
||||||
|
@ -117,7 +117,11 @@ impl<'a> World {
|
||||||
|
|
||||||
self.projectiles.insert(
|
self.projectiles.insert(
|
||||||
collider.clone(),
|
collider.clone(),
|
||||||
ProjectileWorldObject::new(projectile, rigid_body, collider),
|
ProjectileWorldObject {
|
||||||
|
projectile,
|
||||||
|
rigid_body,
|
||||||
|
collider,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +133,7 @@ impl<'a> World {
|
||||||
projectile_h: ColliderHandle,
|
projectile_h: ColliderHandle,
|
||||||
ship_h: ColliderHandle,
|
ship_h: ColliderHandle,
|
||||||
) {
|
) {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
let projectile = self.projectiles.get(&projectile_h);
|
let projectile = self.projectiles.get(&projectile_h);
|
||||||
let ship = self.ships.get_mut(&ship_h);
|
let ship = self.ships.get_mut(&ship_h);
|
||||||
if projectile.is_none() || ship.is_none() {
|
if projectile.is_none() || ship.is_none() {
|
||||||
|
@ -168,22 +173,40 @@ impl<'a> World {
|
||||||
match &projectile.projectile.content.impact_effect {
|
match &projectile.projectile.content.impact_effect {
|
||||||
None => {}
|
None => {}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
let effect = ct.get_effect(*x);
|
let x = ct.get_effect(*x);
|
||||||
|
|
||||||
|
let velocity = {
|
||||||
let (_, sr) = self.get_ship_body(s).unwrap();
|
let (_, sr) = self.get_ship_body(s).unwrap();
|
||||||
let parent_velocity = util::rigidbody_velocity(pr);
|
|
||||||
let target_velocity =
|
let target_velocity =
|
||||||
sr.velocity_at_point(&nalgebra::Point2::new(pos.x, pos.y));
|
sr.velocity_at_point(&nalgebra::Point2::new(pos.x, pos.y));
|
||||||
|
let a = rng
|
||||||
|
.gen_range(-x.velocity_scale_parent_rng..=x.velocity_scale_parent_rng);
|
||||||
|
let b = rng
|
||||||
|
.gen_range(-x.velocity_scale_target_rng..=x.velocity_scale_target_rng);
|
||||||
|
|
||||||
particles.push(ParticleBuilder::from_content(
|
let velocity = ((x.velocity_scale_parent + a)
|
||||||
effect,
|
* util::rigidbody_velocity(pr))
|
||||||
pos,
|
+ ((x.velocity_scale_target + b)
|
||||||
Rad::from(-angle),
|
* Vector2 {
|
||||||
parent_velocity,
|
|
||||||
Vector2 {
|
|
||||||
x: target_velocity.x,
|
x: target_velocity.x,
|
||||||
y: target_velocity.y,
|
y: target_velocity.y,
|
||||||
},
|
});
|
||||||
));
|
|
||||||
|
Matrix2::from_angle(Rad(
|
||||||
|
rng.gen_range(-x.direction_rng.0..=x.direction_rng.0)
|
||||||
|
)) * velocity
|
||||||
|
};
|
||||||
|
|
||||||
|
particles.push(ParticleBuilder {
|
||||||
|
sprite: x.sprite,
|
||||||
|
pos: Point2 { x: pos.x, y: pos.y },
|
||||||
|
velocity,
|
||||||
|
angle: Rad::from(-angle)
|
||||||
|
+ Rad(rng.gen_range(-x.angle_rng.0..=x.angle_rng.0)),
|
||||||
|
angvel: Rad(x.angvel.0 + rng.gen_range(-x.angvel_rng.0..=x.angvel_rng.0)),
|
||||||
|
lifetime: x.lifetime + rng.gen_range(-x.lifetime_rng..=x.lifetime_rng),
|
||||||
|
size: x.size + rng.gen_range(-x.size_rng..=x.size_rng),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -329,15 +352,21 @@ impl<'a> World {
|
||||||
let velocity = (x.velocity_scale_parent + a) * vel;
|
let velocity = (x.velocity_scale_parent + a) * vel;
|
||||||
|
|
||||||
velocity
|
velocity
|
||||||
|
//Matrix2::from_angle(Rad(
|
||||||
|
// rng.gen_range(-x.direction_rng.0..=x.direction_rng.0)
|
||||||
|
//)) * velocity
|
||||||
};
|
};
|
||||||
|
|
||||||
particles.push(ParticleBuilder::from_content(
|
particles.push(ParticleBuilder {
|
||||||
x,
|
sprite: x.sprite,
|
||||||
pos,
|
pos: Point2 { x: pos.x, y: pos.y },
|
||||||
Rad::from(-angle),
|
|
||||||
velocity,
|
velocity,
|
||||||
Vector2::zero(),
|
angle: Rad::from(-angle)
|
||||||
));
|
+ x.angle + Rad(rng.gen_range(-x.angle_rng.0..=x.angle_rng.0)),
|
||||||
|
angvel: Rad(x.angvel.0 + rng.gen_range(-x.angvel_rng.0..=x.angvel_rng.0)),
|
||||||
|
lifetime: x.lifetime + rng.gen_range(-x.lifetime_rng..=x.lifetime_rng),
|
||||||
|
size: x.size + rng.gen_range(-x.size_rng..=x.size_rng),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue