Removed cgmath
parent
c656a2768d
commit
d014e085d5
|
@ -90,15 +90,6 @@ version = "1.0.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355"
|
checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "approx"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "approx"
|
name = "approx"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -276,16 +267,6 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cgmath"
|
|
||||||
version = "0.18.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317"
|
|
||||||
dependencies = [
|
|
||||||
"approx 0.4.0",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
@ -641,12 +622,12 @@ name = "galactica"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cgmath",
|
|
||||||
"galactica-content",
|
"galactica-content",
|
||||||
"galactica-playeragent",
|
"galactica-playeragent",
|
||||||
"galactica-render",
|
"galactica-render",
|
||||||
"galactica-system",
|
"galactica-system",
|
||||||
"galactica-util",
|
"galactica-util",
|
||||||
|
"nalgebra",
|
||||||
"pollster",
|
"pollster",
|
||||||
"rand",
|
"rand",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
|
@ -658,10 +639,11 @@ name = "galactica-content"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cgmath",
|
|
||||||
"galactica-packer",
|
"galactica-packer",
|
||||||
|
"galactica-util",
|
||||||
"image",
|
"image",
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
|
"rapier2d",
|
||||||
"serde",
|
"serde",
|
||||||
"toml",
|
"toml",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
|
@ -684,9 +666,9 @@ name = "galactica-playeragent"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cgmath",
|
|
||||||
"galactica-content",
|
"galactica-content",
|
||||||
"galactica-util",
|
"galactica-util",
|
||||||
|
"nalgebra",
|
||||||
"pollster",
|
"pollster",
|
||||||
"rapier2d",
|
"rapier2d",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
|
@ -699,7 +681,6 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cgmath",
|
|
||||||
"galactica-content",
|
"galactica-content",
|
||||||
"galactica-packer",
|
"galactica-packer",
|
||||||
"galactica-playeragent",
|
"galactica-playeragent",
|
||||||
|
@ -707,6 +688,7 @@ dependencies = [
|
||||||
"galactica-util",
|
"galactica-util",
|
||||||
"glyphon",
|
"glyphon",
|
||||||
"image",
|
"image",
|
||||||
|
"nalgebra",
|
||||||
"rand",
|
"rand",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winit",
|
"winit",
|
||||||
|
@ -716,7 +698,6 @@ dependencies = [
|
||||||
name = "galactica-system"
|
name = "galactica-system"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cgmath",
|
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"galactica-content",
|
"galactica-content",
|
||||||
"galactica-playeragent",
|
"galactica-playeragent",
|
||||||
|
@ -1181,7 +1162,7 @@ version = "0.32.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa"
|
checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx 0.5.1",
|
"approx",
|
||||||
"matrixmultiply",
|
"matrixmultiply",
|
||||||
"nalgebra-macros",
|
"nalgebra-macros",
|
||||||
"num-complex",
|
"num-complex",
|
||||||
|
@ -1465,7 +1446,7 @@ version = "0.13.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "104ae65232e20477a98f9f1e75ca9850eae24a2ea846a2b1a0af03ad752136ce"
|
checksum = "104ae65232e20477a98f9f1e75ca9850eae24a2ea846a2b1a0af03ad752136ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx 0.5.1",
|
"approx",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"downcast-rs",
|
"downcast-rs",
|
||||||
|
@ -1620,7 +1601,7 @@ version = "0.17.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f94d294a9b96694c14888dd0e8ce77620dcc4f2f49264109ef835fa5e2285b84"
|
checksum = "f94d294a9b96694c14888dd0e8ce77620dcc4f2f49264109ef835fa5e2285b84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx 0.5.1",
|
"approx",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-vec",
|
"bit-vec",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
|
@ -1818,7 +1799,7 @@ version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae"
|
checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx 0.5.1",
|
"approx",
|
||||||
"num-complex",
|
"num-complex",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"paste",
|
"paste",
|
||||||
|
|
|
@ -61,8 +61,6 @@ nalgebra = "0.32.3"
|
||||||
crossbeam = "0.8.3"
|
crossbeam = "0.8.3"
|
||||||
pollster = "0.3"
|
pollster = "0.3"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
# TODO: migrate to nalgebra
|
|
||||||
cgmath = "0.18.0"
|
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
walkdir = "2.4.0"
|
walkdir = "2.4.0"
|
||||||
toml = "0.8.8"
|
toml = "0.8.8"
|
||||||
|
|
|
@ -18,11 +18,12 @@ workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
galactica-packer = { workspace = true }
|
galactica-packer = { workspace = true }
|
||||||
|
galactica-util = { workspace = true }
|
||||||
|
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
toml = { workspace = true }
|
toml = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
cgmath = { workspace = true }
|
|
||||||
walkdir = { workspace = true }
|
walkdir = { workspace = true }
|
||||||
nalgebra = { workspace = true }
|
nalgebra = { workspace = true }
|
||||||
image = { workspace = true }
|
image = { workspace = true }
|
||||||
|
rapier2d = { workspace = true }
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use cgmath::Rad;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{handle::SpriteHandle, Content, ContentBuildContext, EffectHandle};
|
use crate::{handle::SpriteHandle, Content, ContentBuildContext, EffectHandle};
|
||||||
|
|
||||||
pub(crate) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use cgmath::Deg;
|
use galactica_util::to_radians;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{Content, ContentBuildContext, EffectHandle};
|
use crate::{Content, ContentBuildContext, EffectHandle};
|
||||||
|
@ -75,10 +74,10 @@ pub(crate) mod syntax {
|
||||||
size_rng: self.size_rng.unwrap_or(0.0),
|
size_rng: self.size_rng.unwrap_or(0.0),
|
||||||
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: to_radians(self.angle.unwrap_or(0.0) / 2.0),
|
||||||
angle_rng: self.angle_rng.unwrap_or(0.0) / 2.0,
|
angle_rng: to_radians(self.angle_rng.unwrap_or(0.0) / 2.0),
|
||||||
angvel: Deg(self.angvel.unwrap_or(0.0)).into(),
|
angvel: to_radians(self.angvel.unwrap_or(0.0)),
|
||||||
angvel_rng: self.angvel_rng.unwrap_or(0.0),
|
angvel_rng: to_radians(self.angvel_rng.unwrap_or(0.0)),
|
||||||
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),
|
||||||
|
@ -141,14 +140,14 @@ pub struct Effect {
|
||||||
/// Random lifetime variation
|
/// Random lifetime variation
|
||||||
pub lifetime_rng: f32,
|
pub lifetime_rng: f32,
|
||||||
|
|
||||||
/// The angle this particle points once spawned
|
/// The angle this particle points once spawned, in radians
|
||||||
pub angle: Rad<f32>,
|
pub angle: f32,
|
||||||
|
|
||||||
/// Random angle variation
|
/// Random angle variation, in radians
|
||||||
pub angle_rng: f32,
|
pub angle_rng: f32,
|
||||||
|
|
||||||
/// How fast this particle spins
|
/// How fast this particle spins, in radians/sec
|
||||||
pub angvel: Rad<f32>,
|
pub angvel: f32,
|
||||||
|
|
||||||
/// Random angvel variation
|
/// Random angvel variation
|
||||||
pub angvel_rng: f32,
|
pub angvel_rng: f32,
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use cgmath::Rad;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
handle::SpriteHandle, Content, ContentBuildContext, EffectHandle, OutfitHandle, OutfitSpace,
|
handle::SpriteHandle, Content, ContentBuildContext, EffectHandle, OutfitHandle, OutfitSpace,
|
||||||
|
@ -11,7 +9,7 @@ use crate::{
|
||||||
pub(crate) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use crate::{effect, part::outfitspace, ContentBuildContext};
|
use crate::{effect, part::outfitspace, ContentBuildContext};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use cgmath::Deg;
|
use galactica_util::to_radians;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
// Raw serde syntax structs.
|
// Raw serde syntax structs.
|
||||||
// These are never seen by code outside this crate.
|
// These are never seen by code outside this crate.
|
||||||
|
@ -91,7 +89,7 @@ pub(crate) mod syntax {
|
||||||
|
|
||||||
// Divide by 2, so the angle matches the angle of the fire cone.
|
// Divide by 2, so the angle matches the angle of the fire cone.
|
||||||
// This should ALWAYS be done in the content parser.
|
// This should ALWAYS be done in the content parser.
|
||||||
angle_rng: Deg(self.projectile.angle_rng / 2.0).into(),
|
angle_rng: to_radians(self.projectile.angle_rng / 2.0).into(),
|
||||||
impact_effect,
|
impact_effect,
|
||||||
expire_effect,
|
expire_effect,
|
||||||
collider: self.projectile.collider,
|
collider: self.projectile.collider,
|
||||||
|
@ -214,8 +212,8 @@ pub struct Projectile {
|
||||||
/// The force this projectile applies
|
/// The force this projectile applies
|
||||||
pub force: f32,
|
pub force: f32,
|
||||||
|
|
||||||
/// The angle variation of this projectile.
|
/// The angle variation of this projectile, in radians
|
||||||
pub angle_rng: Rad<f32>,
|
pub angle_rng: f32,
|
||||||
|
|
||||||
/// The particle this projectile will spawn when it hits something
|
/// The particle this projectile will spawn when it hits something
|
||||||
pub impact_effect: Option<EffectHandle>,
|
pub impact_effect: Option<EffectHandle>,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::{collections::HashMap, hash::Hash};
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use cgmath::Point2;
|
use galactica_util::to_radians;
|
||||||
use nalgebra::{point, Point};
|
use nalgebra::{Point2, Rotation2, Vector2};
|
||||||
|
use rapier2d::geometry::{Collider, ColliderBuilder};
|
||||||
|
use std::{collections::HashMap, fmt::Debug, hash::Hash};
|
||||||
|
|
||||||
use crate::{handle::SpriteHandle, Content, ContentBuildContext, EffectHandle, OutfitSpace};
|
use crate::{handle::SpriteHandle, Content, ContentBuildContext, EffectHandle, OutfitSpace};
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ pub struct Ship {
|
||||||
pub hull: f32,
|
pub hull: f32,
|
||||||
|
|
||||||
/// Collision shape for this ship
|
/// Collision shape for this ship
|
||||||
pub collision: Collision,
|
pub collider: CollisionDebugWrapper,
|
||||||
|
|
||||||
/// Remove later
|
/// Remove later
|
||||||
pub aspect: f32,
|
pub aspect: f32,
|
||||||
|
@ -137,11 +137,15 @@ pub struct Ship {
|
||||||
pub damage: ShipDamage,
|
pub damage: ShipDamage,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collision shape for this ship
|
/// Hack to give `Collider` a fake debug method.
|
||||||
#[derive(Debug, Clone)]
|
/// Pretend this is transparent, get the collider with .0.
|
||||||
pub struct Collision {
|
#[derive(Clone)]
|
||||||
pub points: Vec<Point<f32, 2>>,
|
pub struct CollisionDebugWrapper(pub Collider);
|
||||||
pub indices: Vec<[u32; 2]>,
|
|
||||||
|
impl Debug for CollisionDebugWrapper {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
"CollisionDebugWrapper".fmt(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An engine point on a ship.
|
/// An engine point on a ship.
|
||||||
|
@ -150,7 +154,7 @@ pub struct Collision {
|
||||||
pub struct EnginePoint {
|
pub struct EnginePoint {
|
||||||
/// This engine point's position, in game units,
|
/// This engine point's position, in game units,
|
||||||
/// relative to the ship's center.
|
/// relative to the ship's center.
|
||||||
pub pos: Point2<f32>,
|
pub pos: Vector2<f32>,
|
||||||
|
|
||||||
/// The size of the flare that should be drawn
|
/// The size of the flare that should be drawn
|
||||||
/// at this point, measured as height in game units.
|
/// at this point, measured as height in game units.
|
||||||
|
@ -165,7 +169,7 @@ pub struct GunPoint {
|
||||||
|
|
||||||
/// This gun point's position, in game units,
|
/// This gun point's position, in game units,
|
||||||
/// relative to the ship's center.
|
/// relative to the ship's center.
|
||||||
pub pos: Point2<f32>,
|
pub pos: Vector2<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for GunPoint {}
|
impl Eq for GunPoint {}
|
||||||
|
@ -281,9 +285,8 @@ impl crate::Build for Ship {
|
||||||
.to_handle(build_context, ct)
|
.to_handle(build_context, ct)
|
||||||
.with_context(|| format!("while loading ship `{}`", ship_name))?,
|
.with_context(|| format!("while loading ship `{}`", ship_name))?,
|
||||||
count: e.count,
|
count: e.count,
|
||||||
pos: e.pos.map(|p| Point2 {
|
pos: e.pos.map(|p| {
|
||||||
x: p[0] * (size / 2.0) * aspect,
|
Point2::new(p[0] * (size / 2.0) * aspect, p[1] * size / 2.0)
|
||||||
y: p[1] * size / 2.0,
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -302,9 +305,11 @@ impl crate::Build for Ship {
|
||||||
format!("while loading ship `{}`", ship_name)
|
format!("while loading ship `{}`", ship_name)
|
||||||
})?,
|
})?,
|
||||||
count: g.count,
|
count: g.count,
|
||||||
pos: g.pos.map(|p| Point2 {
|
pos: g.pos.map(|p| {
|
||||||
x: p[0] * (size / 2.0) * aspect,
|
Point2::new(
|
||||||
y: p[1] * size / 2.0,
|
p[0] * (size / 2.0) * aspect,
|
||||||
|
p[1] * size / 2.0,
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -342,9 +347,8 @@ impl crate::Build for Ship {
|
||||||
.to_handle(build_context, ct)
|
.to_handle(build_context, ct)
|
||||||
.with_context(|| format!("while loading ship `{}`", ship_name))?,
|
.with_context(|| format!("while loading ship `{}`", ship_name))?,
|
||||||
frequency: e.frequency,
|
frequency: e.frequency,
|
||||||
pos: e.pos.map(|p| Point2 {
|
pos: e.pos.map(|p| {
|
||||||
x: p[0] * (size / 2.0) * aspect,
|
Point2::new(p[0] * (size / 2.0) * aspect, p[1] * size / 2.0)
|
||||||
y: p[1] * size / 2.0,
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -367,13 +371,49 @@ impl crate::Build for Ship {
|
||||||
for g in ship.guns {
|
for g in ship.guns {
|
||||||
guns.push(GunPoint {
|
guns.push(GunPoint {
|
||||||
idx: guns.len() as u32,
|
idx: guns.len() as u32,
|
||||||
pos: Point2 {
|
|
||||||
x: g.x * size * aspect / 2.0,
|
// Angle adjustment, since sprites point north
|
||||||
y: g.y * size / 2.0,
|
// and 0 degrees is east in the game
|
||||||
},
|
pos: Rotation2::new(to_radians(-90.0))
|
||||||
|
* Vector2::new(g.x * size * aspect / 2.0, g.y * size / 2.0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build rapier2d collider
|
||||||
|
let collider = {
|
||||||
|
let indices: Vec<[u32; 2]> = (0..ship.collision.len())
|
||||||
|
.map(|x| {
|
||||||
|
// Auto-generate mesh lines:
|
||||||
|
// [ [0, 1], [1, 2], ..., [n, 0] ]
|
||||||
|
let next = if x == ship.collision.len() - 1 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
x + 1
|
||||||
|
};
|
||||||
|
[x as u32, next as u32]
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let points: Vec<Point2<f32>> = ship
|
||||||
|
.collision
|
||||||
|
.iter()
|
||||||
|
.map(|x| {
|
||||||
|
// Angle adjustment: rotate collider to match sprite
|
||||||
|
// (Sprites (and their colliders) point north, but 0 is east in the game world)
|
||||||
|
// We apply this pointwise so that local points inside the collider work as we expect.
|
||||||
|
//
|
||||||
|
// If we don't, rapier2 will compute local points pre-rotation,
|
||||||
|
// which will break particle placement on top of ships (i.e, collapse effects)
|
||||||
|
Rotation2::new(to_radians(-90.0))
|
||||||
|
* Point2::new(x[0] * (size / 2.0) * aspect, x[1] * size / 2.0)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ColliderBuilder::convex_decomposition(&points[..], &indices[..])
|
||||||
|
.mass(ship.mass)
|
||||||
|
.build()
|
||||||
|
};
|
||||||
|
|
||||||
ct.ships.push(Self {
|
ct.ships.push(Self {
|
||||||
aspect,
|
aspect,
|
||||||
collapse,
|
collapse,
|
||||||
|
@ -391,35 +431,14 @@ impl crate::Build for Ship {
|
||||||
.engines
|
.engines
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| EnginePoint {
|
.map(|e| EnginePoint {
|
||||||
pos: Point2 {
|
pos: Vector2::new(e.x * size * aspect / 2.0, e.y * size / 2.0),
|
||||||
x: e.x * size * aspect / 2.0,
|
|
||||||
y: e.y * size / 2.0,
|
|
||||||
},
|
|
||||||
size: e.size,
|
size: e.size,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
||||||
guns,
|
guns,
|
||||||
|
|
||||||
collision: Collision {
|
collider: CollisionDebugWrapper(collider),
|
||||||
indices: (0..ship.collision.len())
|
|
||||||
.map(|x| {
|
|
||||||
// Auto-generate mesh lines:
|
|
||||||
// [ [0, 1], [1, 2], ..., [n, 0] ]
|
|
||||||
let next = if x == ship.collision.len() - 1 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
x + 1
|
|
||||||
};
|
|
||||||
[x as u32, next as u32]
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
points: ship
|
|
||||||
.collision
|
|
||||||
.iter()
|
|
||||||
.map(|x| point![x[0] * (size / 2.0) * aspect, x[1] * size / 2.0])
|
|
||||||
.collect(),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use cgmath::{Deg, Point3, Rad};
|
use galactica_util::to_radians;
|
||||||
|
use nalgebra::{Point2, Point3};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -115,8 +116,8 @@ pub struct SystemObject {
|
||||||
/// relative to the system's center (0, 0).
|
/// relative to the system's center (0, 0).
|
||||||
pub pos: Point3<f32>,
|
pub pos: Point3<f32>,
|
||||||
|
|
||||||
/// This object's sprite's angle.
|
/// This object's sprite's angle, in radians
|
||||||
pub angle: Rad<f32>,
|
pub angle: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function for resolve_position, never called on its own.
|
/// Helper function for resolve_position, never called on its own.
|
||||||
|
@ -169,16 +170,12 @@ fn resolve_position(
|
||||||
};
|
};
|
||||||
let r = resolve_coordinates(&objects, &three, cycle_detector)?;
|
let r = resolve_coordinates(&objects, &three, cycle_detector)?;
|
||||||
let plane = Polar {
|
let plane = Polar {
|
||||||
center: (r.x, r.y).into(),
|
center: Point2::new(r.x, r.y),
|
||||||
radius: p.radius,
|
radius: p.radius,
|
||||||
angle: Deg(p.angle).into(),
|
angle: to_radians(p.angle),
|
||||||
}
|
}
|
||||||
.to_cartesian();
|
.to_cartesian();
|
||||||
Ok(Point3 {
|
Ok(Point3::new(plane.x, plane.y, p.z))
|
||||||
x: plane.x,
|
|
||||||
y: plane.y,
|
|
||||||
z: p.z,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +213,7 @@ impl crate::Build for System {
|
||||||
pos: resolve_position(&system.object, &obj, cycle_detector)
|
pos: 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,
|
||||||
angle: Deg(obj.angle.unwrap_or(0.0)).into(),
|
angle: to_radians(obj.angle.unwrap_or(0.0)),
|
||||||
handle: SystemObjectHandle {
|
handle: SystemObjectHandle {
|
||||||
system_handle,
|
system_handle,
|
||||||
body_index: 0,
|
body_index: 0,
|
||||||
|
|
|
@ -1,18 +1,23 @@
|
||||||
use cgmath::{Angle, Point2, Rad, Vector2};
|
use nalgebra::{Point2, Vector2};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Polar {
|
pub struct Polar {
|
||||||
|
/// The center of this polar coordinate
|
||||||
pub center: Point2<f32>,
|
pub center: Point2<f32>,
|
||||||
|
|
||||||
|
/// The radius of this polar coordinate
|
||||||
pub radius: f32,
|
pub radius: f32,
|
||||||
pub angle: Rad<f32>,
|
|
||||||
|
/// In radians
|
||||||
|
pub angle: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Polar {
|
impl Polar {
|
||||||
pub fn to_cartesian(self) -> Point2<f32> {
|
pub fn to_cartesian(self) -> Point2<f32> {
|
||||||
let v = Vector2 {
|
let v = Vector2::new(
|
||||||
x: self.radius * self.angle.sin(),
|
self.radius * self.angle.sin(),
|
||||||
y: self.radius * self.angle.cos(),
|
self.radius * self.angle.cos(),
|
||||||
};
|
);
|
||||||
|
|
||||||
return self.center + v;
|
return self.center + v;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,4 +32,4 @@ winit = { workspace = true }
|
||||||
wgpu = { workspace = true }
|
wgpu = { workspace = true }
|
||||||
pollster = { workspace = true }
|
pollster = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
cgmath = { workspace = true }
|
nalgebra = { workspace = true }
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use cgmath::Point2;
|
|
||||||
use galactica_content::{Content, FactionHandle, OutfitHandle, ShipHandle, SystemHandle};
|
use galactica_content::{Content, FactionHandle, OutfitHandle, ShipHandle, SystemHandle};
|
||||||
use galactica_playeragent::PlayerAgent;
|
use galactica_playeragent::PlayerAgent;
|
||||||
use galactica_system::data::ShipPersonality;
|
use galactica_system::data::ShipPersonality;
|
||||||
|
@ -6,6 +5,7 @@ use galactica_system::phys::{
|
||||||
ParticleBuilder, PhysSim, PhysSimShipHandle, PhysStepResources, Wrapper,
|
ParticleBuilder, PhysSim, PhysSimShipHandle, PhysStepResources, Wrapper,
|
||||||
};
|
};
|
||||||
use galactica_util::timing::Timing;
|
use galactica_util::timing::Timing;
|
||||||
|
use nalgebra::Point2;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ impl<'a> Game {
|
||||||
ShipHandle { index: 0 },
|
ShipHandle { index: 0 },
|
||||||
FactionHandle { index: 0 },
|
FactionHandle { index: 0 },
|
||||||
ShipPersonality::Player,
|
ShipPersonality::Player,
|
||||||
Point2 { x: 0.0, y: 0.0 },
|
Point2::new(0.0, 0.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let s = self.state.systemsim.get_ship_mut(&player).unwrap();
|
let s = self.state.systemsim.get_ship_mut(&player).unwrap();
|
||||||
|
@ -66,7 +66,7 @@ impl<'a> Game {
|
||||||
ShipHandle { index: 0 },
|
ShipHandle { index: 0 },
|
||||||
FactionHandle { index: 1 },
|
FactionHandle { index: 1 },
|
||||||
ShipPersonality::Point,
|
ShipPersonality::Point,
|
||||||
Point2 { x: 100.0, y: 0.0 },
|
Point2::new(100.0, 0.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let s = systemsim.get_ship_mut(&a).unwrap();
|
let s = systemsim.get_ship_mut(&a).unwrap();
|
||||||
|
@ -78,8 +78,8 @@ impl<'a> Game {
|
||||||
&ct,
|
&ct,
|
||||||
ShipHandle { index: 0 },
|
ShipHandle { index: 0 },
|
||||||
FactionHandle { index: 0 },
|
FactionHandle { index: 0 },
|
||||||
ShipPersonality::Point,
|
ShipPersonality::Dummy,
|
||||||
Point2 { x: 0.0, y: 120.0 },
|
Point2::new(0.0, 120.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let s = systemsim.get_ship_mut(&a).unwrap();
|
let s = systemsim.get_ship_mut(&a).unwrap();
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
mod game;
|
mod game;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use cgmath::Point2;
|
|
||||||
use galactica_content::{Content, SystemHandle};
|
use galactica_content::{Content, SystemHandle};
|
||||||
use galactica_playeragent::{PlayerAgent, PlayerStatus};
|
use galactica_playeragent::{PlayerAgent, PlayerStatus};
|
||||||
use galactica_render::RenderInput;
|
use galactica_render::RenderInput;
|
||||||
use galactica_system::{
|
use galactica_system::{data::ShipState, phys::PhysSimShipHandle};
|
||||||
data::ShipState,
|
|
||||||
phys::{util, PhysSimShipHandle},
|
|
||||||
};
|
|
||||||
use galactica_util::constants::ASSET_CACHE;
|
use galactica_util::constants::ASSET_CACHE;
|
||||||
|
use nalgebra::Vector2;
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
@ -92,7 +89,7 @@ fn main() -> Result<()> {
|
||||||
let r =
|
let r =
|
||||||
&game.get_state().systemsim.get_rigid_body(o.rigid_body);
|
&game.get_state().systemsim.get_rigid_body(o.rigid_body);
|
||||||
if let Some(r) = r {
|
if let Some(r) = r {
|
||||||
Some(util::rigidbody_position(r))
|
Some(*r.translation())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -100,19 +97,16 @@ fn main() -> Result<()> {
|
||||||
ShipState::UnLanding { .. } => {
|
ShipState::UnLanding { .. } => {
|
||||||
let pos =
|
let pos =
|
||||||
o.data.get_state().unlanding_position(&content).unwrap();
|
o.data.get_state().unlanding_position(&content).unwrap();
|
||||||
Some(Point2 { x: pos.x, y: pos.y })
|
Some(Vector2::new(pos.x, pos.y))
|
||||||
}
|
}
|
||||||
ShipState::Landing { .. } => {
|
ShipState::Landing { .. } => {
|
||||||
let pos =
|
let pos =
|
||||||
o.data.get_state().landing_position(&content).unwrap();
|
o.data.get_state().landing_position(&content).unwrap();
|
||||||
Some(Point2 { x: pos.x, y: pos.y })
|
Some(Vector2::new(pos.x, pos.y))
|
||||||
}
|
}
|
||||||
ShipState::Landed { target } => {
|
ShipState::Landed { target } => {
|
||||||
let b = content.get_system_object(*target);
|
let b = content.get_system_object(*target);
|
||||||
Some(Point2 {
|
Some(Vector2::new(b.pos.x, b.pos.y))
|
||||||
x: b.pos.x,
|
|
||||||
y: b.pos.y,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShipState::Dead => None,
|
ShipState::Dead => None,
|
||||||
|
|
|
@ -24,5 +24,5 @@ winit = { workspace = true }
|
||||||
wgpu = { workspace = true }
|
wgpu = { workspace = true }
|
||||||
pollster = { workspace = true }
|
pollster = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
cgmath = { workspace = true }
|
nalgebra = { workspace = true }
|
||||||
rapier2d = { workspace = true }
|
rapier2d = { workspace = true }
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use cgmath::Point2;
|
use nalgebra::Vector2;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Camera {
|
pub struct Camera {
|
||||||
/// Camera center
|
/// Camera center
|
||||||
pub pos: Point2<f32>,
|
pub pos: Vector2<f32>,
|
||||||
|
|
||||||
/// Camera zoom
|
/// Camera zoom
|
||||||
/// (How many game units tall is the viewport?)
|
/// (How many game units tall is the viewport?)
|
||||||
|
@ -16,7 +16,7 @@ pub struct Camera {
|
||||||
impl Camera {
|
impl Camera {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos: (0.0, 0.0).into(),
|
pos: Vector2::new(0.0, 0.0),
|
||||||
zoom: 500.0,
|
zoom: 500.0,
|
||||||
aspect: 1.0,
|
aspect: 1.0,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use cgmath::Point2;
|
use nalgebra::Vector2;
|
||||||
|
|
||||||
pub struct PlayerStatus {
|
pub struct PlayerStatus {
|
||||||
pub pos: Option<Point2<f32>>,
|
pub pos: Option<Vector2<f32>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ galactica-system = { workspace = true }
|
||||||
galactica-playeragent = { workspace = true }
|
galactica-playeragent = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
cgmath = { workspace = true }
|
nalgebra = { workspace = true }
|
||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
image = { workspace = true }
|
image = { workspace = true }
|
||||||
winit = { workspace = true }
|
winit = { workspace = true }
|
||||||
|
|
|
@ -41,8 +41,8 @@ fn transform_vertex(obj: ObjectData, vertex_position: vec2<f32>, sprite_index: u
|
||||||
|
|
||||||
// Apply rotation
|
// Apply rotation
|
||||||
pos = mat2x2(
|
pos = mat2x2(
|
||||||
vec2(cos(obj.angle), sin(obj.angle)),
|
vec2(cos(obj.angle - 1.5708), sin(obj.angle - 1.5708)),
|
||||||
vec2(-sin(obj.angle), cos(obj.angle))
|
vec2(-sin(obj.angle - 1.5708), cos(obj.angle - 1.5708))
|
||||||
) * pos;
|
) * pos;
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,8 +81,8 @@ fn transform_vertex(obj: ObjectData, vertex_position: vec2<f32>, sprite_index: u
|
||||||
|
|
||||||
// Apply parent's rotation
|
// Apply parent's rotation
|
||||||
pos = mat2x2(
|
pos = mat2x2(
|
||||||
vec2(cos(parent.angle), sin(parent.angle)),
|
vec2(cos(parent.angle - 1.5708), sin(parent.angle - 1.5708)),
|
||||||
vec2(-sin(parent.angle), cos(parent.angle))
|
vec2(-sin(parent.angle - 1.5708), cos(parent.angle - 1.5708))
|
||||||
) * pos;
|
) * pos;
|
||||||
|
|
||||||
// Correct for screen aspect, preserving height
|
// Correct for screen aspect, preserving height
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use cgmath::Point2;
|
|
||||||
use galactica_content::{Content, SystemHandle};
|
use galactica_content::{Content, SystemHandle};
|
||||||
use galactica_playeragent::PlayerAgent;
|
use galactica_playeragent::PlayerAgent;
|
||||||
use galactica_system::phys::{ParticleBuilder, PhysSim};
|
use galactica_system::phys::{ParticleBuilder, PhysSim};
|
||||||
use galactica_util::timing::Timing;
|
use galactica_util::timing::Timing;
|
||||||
use glyphon::{FontSystem, SwashCache, TextAtlas, TextRenderer};
|
use glyphon::{FontSystem, SwashCache, TextAtlas, TextRenderer};
|
||||||
|
use nalgebra::Vector2;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wgpu::BufferAddress;
|
use wgpu::BufferAddress;
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
@ -13,7 +13,7 @@ use crate::{globaluniform::GlobalUniform, vertexbuffer::VertexBuffer};
|
||||||
/// Bundles parameters passed to a single call to GPUState::render
|
/// Bundles parameters passed to a single call to GPUState::render
|
||||||
pub struct RenderInput<'a> {
|
pub struct RenderInput<'a> {
|
||||||
/// Camera position, in world units
|
/// Camera position, in world units
|
||||||
pub camera_pos: Point2<f32>,
|
pub camera_pos: Vector2<f32>,
|
||||||
|
|
||||||
/// Player ship data
|
/// Player ship data
|
||||||
pub player: &'a PlayerAgent,
|
pub player: &'a PlayerAgent,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! GPUState routines for drawing items in a systemsim
|
//! GPUState routines for drawing items in a systemsim
|
||||||
|
|
||||||
use bytemuck;
|
use bytemuck;
|
||||||
use cgmath::{EuclideanSpace, InnerSpace, Point2, Point3, Rad, Vector2};
|
use galactica_system::data::ShipState;
|
||||||
use galactica_system::{data::ShipState, phys::util};
|
use galactica_util::{constants::OBJECT_SPRITE_INSTANCE_LIMIT, to_radians};
|
||||||
use galactica_util::constants::OBJECT_SPRITE_INSTANCE_LIMIT;
|
use nalgebra::{Point2, Point3, Vector2};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
globaluniform::ObjectData,
|
globaluniform::ObjectData,
|
||||||
|
@ -29,14 +29,10 @@ impl GPUState {
|
||||||
|
|
||||||
ShipState::Collapsing { .. } | ShipState::Flying => {
|
ShipState::Collapsing { .. } | ShipState::Flying => {
|
||||||
let r = state.systemsim.get_rigid_body(ship.rigid_body).unwrap();
|
let r = state.systemsim.get_rigid_body(ship.rigid_body).unwrap();
|
||||||
let pos = util::rigidbody_position(&r);
|
let pos = *r.translation();
|
||||||
ship_pos = Point3 {
|
ship_pos = Point3::new(pos.x, pos.y, 1.0);
|
||||||
x: pos.x,
|
let ship_rot = r.rotation();
|
||||||
y: pos.y,
|
ship_ang = ship_rot.angle();
|
||||||
z: 1.0,
|
|
||||||
};
|
|
||||||
let ship_rot = util::rigidbody_rotation(r);
|
|
||||||
ship_ang = -ship_rot.angle(Vector2 { x: 0.0, y: 1.0 }); // TODO: inconsistent angles. Fix!
|
|
||||||
ship_cnt = state.ct.get_ship(ship.data.get_content());
|
ship_cnt = state.ct.get_ship(ship.data.get_content());
|
||||||
}
|
}
|
||||||
ShipState::Landing {
|
ShipState::Landing {
|
||||||
|
@ -48,14 +44,11 @@ impl GPUState {
|
||||||
} => {
|
} => {
|
||||||
let target = state.ct.get_system_object(*target);
|
let target = state.ct.get_system_object(*target);
|
||||||
|
|
||||||
let diff = Point2 {
|
let diff = Point2::new(target.pos.x, target.pos.y) - from_position;
|
||||||
x: target.pos.x,
|
|
||||||
y: target.pos.y,
|
|
||||||
} - from_position;
|
|
||||||
|
|
||||||
ship_pos = ship.data.get_state().landing_position(state.ct).unwrap();
|
ship_pos = ship.data.get_state().landing_position(state.ct).unwrap();
|
||||||
|
|
||||||
let target_angle = -diff.angle(Vector2 { x: 0.0, y: 1.0 });
|
let target_angle = diff.angle(&Vector2::new(1.0, 0.0));
|
||||||
|
|
||||||
ship_ang = from_angle + ((target_angle - from_angle) * 1f32.min(elapsed / 1.0));
|
ship_ang = from_angle + ((target_angle - from_angle) * 1f32.min(elapsed / 1.0));
|
||||||
ship_cnt = state.ct.get_ship(ship.data.get_content());
|
ship_cnt = state.ct.get_ship(ship.data.get_content());
|
||||||
|
@ -65,7 +58,7 @@ impl GPUState {
|
||||||
to_angle, elapsed, ..
|
to_angle, elapsed, ..
|
||||||
} => {
|
} => {
|
||||||
ship_pos = ship.data.get_state().unlanding_position(state.ct).unwrap();
|
ship_pos = ship.data.get_state().unlanding_position(state.ct).unwrap();
|
||||||
ship_ang = Rad(0.0) + ((to_angle - Rad(0.0)) * 1f32.min(elapsed / 1.0));
|
ship_ang = 0.0 + ((to_angle - 0.0) * 1f32.min(elapsed / 1.0));
|
||||||
ship_cnt = state.ct.get_ship(ship.data.get_content());
|
ship_cnt = state.ct.get_ship(ship.data.get_content());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,11 +66,8 @@ impl GPUState {
|
||||||
// Position adjusted for parallax
|
// Position adjusted for parallax
|
||||||
// TODO: adjust parallax for zoom?
|
// TODO: adjust parallax for zoom?
|
||||||
// 1.0 is z-coordinate, which is constant for ships
|
// 1.0 is z-coordinate, which is constant for ships
|
||||||
let pos: Point2<f32> = (Point2 {
|
let pos: Point2<f32> =
|
||||||
x: ship_pos.x,
|
(Point2::new(ship_pos.x, ship_pos.y) - state.camera_pos) / ship_pos.z;
|
||||||
y: ship_pos.y,
|
|
||||||
} - state.camera_pos.to_vec())
|
|
||||||
/ ship_pos.z;
|
|
||||||
|
|
||||||
// Game dimensions of this sprite post-scale.
|
// Game dimensions of this sprite post-scale.
|
||||||
// Post-scale width or height, whichever is larger.
|
// Post-scale width or height, whichever is larger.
|
||||||
|
@ -104,7 +94,7 @@ impl GPUState {
|
||||||
xpos: ship_pos.x,
|
xpos: ship_pos.x,
|
||||||
ypos: ship_pos.y,
|
ypos: ship_pos.y,
|
||||||
zpos: ship_pos.z,
|
zpos: ship_pos.z,
|
||||||
angle: ship_ang.0,
|
angle: ship_ang,
|
||||||
size: ship_cnt.size,
|
size: ship_cnt.size,
|
||||||
parent: 0,
|
parent: 0,
|
||||||
is_child: 0,
|
is_child: 0,
|
||||||
|
@ -142,10 +132,17 @@ impl GPUState {
|
||||||
&self.state.global_uniform.object_buffer,
|
&self.state.global_uniform.object_buffer,
|
||||||
ObjectData::SIZE * self.state.vertex_buffers.object_counter as u64,
|
ObjectData::SIZE * self.state.vertex_buffers.object_counter as u64,
|
||||||
bytemuck::cast_slice(&[ObjectData {
|
bytemuck::cast_slice(&[ObjectData {
|
||||||
|
// Note that we adjust the y-coordinate for half-height,
|
||||||
|
// not the x-coordinate, even though our ships point east
|
||||||
|
// at 0 degrees. This is because this is placed pre-rotation,
|
||||||
|
// and the parent rotation adjustment in our object shader
|
||||||
|
// automatically accounts for this.
|
||||||
xpos: engine_point.pos.x,
|
xpos: engine_point.pos.x,
|
||||||
ypos: engine_point.pos.y - engine_point.size / 2.0,
|
ypos: engine_point.pos.y - engine_point.size / 2.0,
|
||||||
zpos: 1.0,
|
zpos: 1.0,
|
||||||
angle: 0.0,
|
// We still need an adjustment here, though,
|
||||||
|
// since engine sprites point north (with exhaust towards the south)
|
||||||
|
angle: to_radians(90.0),
|
||||||
size: engine_point.size,
|
size: engine_point.size,
|
||||||
parent: idx as u32,
|
parent: idx as u32,
|
||||||
is_child: 1,
|
is_child: 1,
|
||||||
|
@ -183,15 +180,15 @@ impl GPUState {
|
||||||
) {
|
) {
|
||||||
for p in state.systemsim.iter_projectiles() {
|
for p in state.systemsim.iter_projectiles() {
|
||||||
let r = state.systemsim.get_rigid_body(p.rigid_body).unwrap();
|
let r = state.systemsim.get_rigid_body(p.rigid_body).unwrap();
|
||||||
let proj_pos = util::rigidbody_position(&r);
|
let proj_pos = *r.translation();
|
||||||
let proj_rot = util::rigidbody_rotation(r);
|
let proj_rot = r.rotation();
|
||||||
let proj_ang = -proj_rot.angle(Vector2 { x: 1.0, y: 0.0 });
|
let proj_ang = proj_rot.angle();
|
||||||
let proj_cnt = &p.content; // TODO: don't clone this?
|
let proj_cnt = &p.content; // TODO: don't clone this?
|
||||||
|
|
||||||
// Position adjusted for parallax
|
// Position adjusted for parallax
|
||||||
// TODO: adjust parallax for zoom?
|
// TODO: adjust parallax for zoom?
|
||||||
// 1.0 is z-coordinate, which is constant for ships
|
// 1.0 is z-coordinate, which is constant for projectiles
|
||||||
let pos: Point2<f32> = (proj_pos - state.camera_pos.to_vec()) / 1.0;
|
let pos = (proj_pos - state.camera_pos) / 1.0;
|
||||||
|
|
||||||
// Game dimensions of this sprite post-scale.
|
// Game dimensions of this sprite post-scale.
|
||||||
// Post-scale width or height, whichever is larger.
|
// Post-scale width or height, whichever is larger.
|
||||||
|
@ -218,7 +215,7 @@ impl GPUState {
|
||||||
xpos: proj_pos.x,
|
xpos: proj_pos.x,
|
||||||
ypos: proj_pos.y,
|
ypos: proj_pos.y,
|
||||||
zpos: 1.0,
|
zpos: 1.0,
|
||||||
angle: proj_ang.0,
|
angle: proj_ang,
|
||||||
size: 0f32.max(proj_cnt.size + p.size_rng),
|
size: 0f32.max(proj_cnt.size + p.size_rng),
|
||||||
parent: 0,
|
parent: 0,
|
||||||
is_child: 0,
|
is_child: 0,
|
||||||
|
@ -255,11 +252,7 @@ impl GPUState {
|
||||||
|
|
||||||
for o in &system.objects {
|
for o in &system.objects {
|
||||||
// Position adjusted for parallax
|
// Position adjusted for parallax
|
||||||
let pos: Point2<f32> = (Point2 {
|
let pos: Point2<f32> = (Point2::new(o.pos.x, o.pos.y) - state.camera_pos) / o.pos.z;
|
||||||
x: o.pos.x,
|
|
||||||
y: o.pos.y,
|
|
||||||
} - state.camera_pos.to_vec())
|
|
||||||
/ o.pos.z;
|
|
||||||
|
|
||||||
// Game dimensions of this sprite post-scale.
|
// Game dimensions of this sprite post-scale.
|
||||||
// Post-scale width or height, whichever is larger.
|
// Post-scale width or height, whichever is larger.
|
||||||
|
@ -286,7 +279,7 @@ impl GPUState {
|
||||||
xpos: o.pos.x,
|
xpos: o.pos.x,
|
||||||
ypos: o.pos.y,
|
ypos: o.pos.y,
|
||||||
zpos: o.pos.z,
|
zpos: o.pos.z,
|
||||||
angle: o.angle.0,
|
angle: o.angle,
|
||||||
size: o.size,
|
size: o.size,
|
||||||
parent: 0,
|
parent: 0,
|
||||||
is_child: 0,
|
is_child: 0,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use bytemuck;
|
use bytemuck;
|
||||||
use cgmath::Point2;
|
|
||||||
use galactica_util::constants::PARTICLE_SPRITE_INSTANCE_LIMIT;
|
use galactica_util::constants::PARTICLE_SPRITE_INSTANCE_LIMIT;
|
||||||
use glyphon::Resolution;
|
use glyphon::Resolution;
|
||||||
|
use nalgebra::Point2;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use wgpu;
|
use wgpu;
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ impl super::GPUState {
|
||||||
bytemuck::cast_slice(&[ParticleInstance {
|
bytemuck::cast_slice(&[ParticleInstance {
|
||||||
position: [i.pos.x, i.pos.y],
|
position: [i.pos.x, i.pos.y],
|
||||||
velocity: i.velocity.into(),
|
velocity: i.velocity.into(),
|
||||||
angle: i.angle.0,
|
angle: i.angle,
|
||||||
angvel: i.angvel.0,
|
angvel: i.angvel,
|
||||||
size: i.size,
|
size: i.size,
|
||||||
sprite_index: i.sprite.get_index(),
|
sprite_index: i.sprite.get_index(),
|
||||||
created: input.current_time,
|
created: input.current_time,
|
||||||
|
@ -106,8 +106,8 @@ impl super::GPUState {
|
||||||
|
|
||||||
// Game coordinates (relative to camera) of ne and sw corners of screen.
|
// Game coordinates (relative to camera) of ne and sw corners of screen.
|
||||||
// Used to skip off-screen sprites.
|
// Used to skip off-screen sprites.
|
||||||
let clip_ne = Point2::from((-self.state.window_aspect, 1.0)) * input.camera_zoom;
|
let clip_ne = Point2::new(-self.state.window_aspect, 1.0) * input.camera_zoom;
|
||||||
let clip_sw = Point2::from((self.state.window_aspect, -1.0)) * input.camera_zoom;
|
let clip_sw = Point2::new(self.state.window_aspect, -1.0) * input.camera_zoom;
|
||||||
|
|
||||||
// TODO: sorting. We don't need to sort ships, but we do need to sort system objects by z-level
|
// TODO: sorting. We don't need to sort ships, but we do need to sort system objects by z-level
|
||||||
// (which we don't yet draw)
|
// (which we don't yet draw)
|
||||||
|
|
|
@ -21,8 +21,7 @@ mod vertexbuffer;
|
||||||
pub use anchoredposition::PositionAnchor;
|
pub use anchoredposition::PositionAnchor;
|
||||||
pub use datastructs::RenderInput;
|
pub use datastructs::RenderInput;
|
||||||
pub use gpustate::GPUState;
|
pub use gpustate::GPUState;
|
||||||
|
use nalgebra::Matrix4;
|
||||||
use cgmath::Matrix4;
|
|
||||||
|
|
||||||
/// Shader entry points
|
/// Shader entry points
|
||||||
pub(crate) const SHADER_MAIN_VERTEX: &'static str = "vertex_main";
|
pub(crate) const SHADER_MAIN_VERTEX: &'static str = "vertex_main";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use cgmath::{Point2, Point3, Vector2, Vector3};
|
|
||||||
use galactica_content::Content;
|
use galactica_content::Content;
|
||||||
|
use nalgebra::{Point2, Point3, Vector2, Vector3};
|
||||||
use rand::{self, Rng};
|
use rand::{self, Rng};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -40,20 +40,17 @@ impl Starfield {
|
||||||
let sz = ct.get_config().starfield_size as f32 / 2.0;
|
let sz = ct.get_config().starfield_size as f32 / 2.0;
|
||||||
self.stars = (0..ct.get_config().starfield_count)
|
self.stars = (0..ct.get_config().starfield_count)
|
||||||
.map(|_| StarfieldStar {
|
.map(|_| StarfieldStar {
|
||||||
pos: Point3 {
|
pos: Point3::new(
|
||||||
x: rng.gen_range(-sz..=sz),
|
rng.gen_range(-sz..=sz),
|
||||||
y: rng.gen_range(-sz..=sz),
|
rng.gen_range(-sz..=sz),
|
||||||
z: rng.gen_range(
|
rng.gen_range(
|
||||||
ct.get_config().starfield_min_dist..=ct.get_config().starfield_max_dist,
|
ct.get_config().starfield_min_dist..=ct.get_config().starfield_max_dist,
|
||||||
),
|
),
|
||||||
},
|
),
|
||||||
size: rng.gen_range(
|
size: rng.gen_range(
|
||||||
ct.get_config().starfield_min_size..ct.get_config().starfield_max_size,
|
ct.get_config().starfield_min_size..ct.get_config().starfield_max_size,
|
||||||
),
|
),
|
||||||
tint: Vector2 {
|
tint: Vector2::new(rng.gen_range(0.0..=1.0), rng.gen_range(0.0..=1.0)),
|
||||||
x: rng.gen_range(0.0..=1.0),
|
|
||||||
y: rng.gen_range(0.0..=1.0),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
|
@ -62,52 +59,48 @@ impl Starfield {
|
||||||
let sz = ct.get_config().starfield_size as f32;
|
let sz = ct.get_config().starfield_size as f32;
|
||||||
|
|
||||||
// Compute window size in starfield tiles
|
// Compute window size in starfield tiles
|
||||||
let mut nw_tile: Point2<i32> = {
|
let mut nw_tile = {
|
||||||
// Game coordinates (relative to camera) of nw corner of screen.
|
// Game coordinates (relative to camera) of nw corner of screen.
|
||||||
let clip_nw = Point2::from((state.window_aspect, 1.0)) * ct.get_config().zoom_max;
|
let clip_nw = Point2::new(state.window_aspect, 1.0) * ct.get_config().zoom_max;
|
||||||
|
|
||||||
// Parallax correction.
|
// Parallax correction.
|
||||||
// Also, adjust v for mod to work properly
|
// Also, adjust v for mod to work properly
|
||||||
// (v is centered at 0)
|
// (v is centered at 0)
|
||||||
let v: Point2<f32> = clip_nw * ct.get_config().starfield_min_dist;
|
let v: Point2<f32> = clip_nw * ct.get_config().starfield_min_dist;
|
||||||
let v_adj: Point2<f32> = (v.x + (sz / 2.0), v.y + (sz / 2.0)).into();
|
let v_adj = Point2::new(v.x + (sz / 2.0), v.y + (sz / 2.0));
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
// Compute m = fmod(x, sz)
|
// Compute m = fmod(x, sz)
|
||||||
let m: Vector2<f32> = (
|
let m = Vector2::new(
|
||||||
(v_adj.x - (v_adj.x / sz).floor() * sz) - (sz / 2.0),
|
(v_adj.x - (v_adj.x / sz).floor() * sz) - (sz / 2.0),
|
||||||
(v_adj.y - (v_adj.y / sz).floor() * sz) - (sz / 2.0)
|
(v_adj.y - (v_adj.y / sz).floor() * sz) - (sz / 2.0)
|
||||||
).into();
|
);
|
||||||
|
|
||||||
// Now, remainder and convert to "relative tile" coordinates
|
// Now, remainder and convert to "relative tile" coordinates
|
||||||
// ( where (0,0) is center tile, (0, 1) is north, etc)
|
// ( where (0,0) is center tile, (0, 1) is north, etc)
|
||||||
let rel = (v - m) / sz;
|
let rel = (v - m) / sz;
|
||||||
|
|
||||||
// relative coordinates of north-east tile
|
// relative coordinates of north-east tile
|
||||||
(rel.x.round() as i32, rel.y.round() as i32).into()
|
Point2::new(rel.x.round() as i32, rel.y.round() as i32)
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need to cover the window with stars,
|
// We need to cover the window with stars,
|
||||||
// but we also need a one-wide buffer to account for motion.
|
// but we also need a one-wide buffer to account for motion.
|
||||||
nw_tile += Vector2::from((1, 1));
|
nw_tile += Vector2::new(1, 1);
|
||||||
|
|
||||||
// Truncate tile grid to buffer size
|
// Truncate tile grid to buffer size
|
||||||
// (The window won't be full of stars if our instance limit is too small)
|
// (The window won't be full of stars if our instance limit is too small)
|
||||||
while ((nw_tile.x * 2 + 1) * (nw_tile.y * 2 + 1) * ct.get_config().starfield_count as i32)
|
while ((nw_tile.x * 2 + 1) * (nw_tile.y * 2 + 1) * ct.get_config().starfield_count as i32)
|
||||||
> ct.get_config().starfield_instance_limit as i32
|
> ct.get_config().starfield_instance_limit as i32
|
||||||
{
|
{
|
||||||
nw_tile -= Vector2::from((1, 1));
|
nw_tile -= Vector2::new(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all tiles to buffer
|
// Add all tiles to buffer
|
||||||
self.instance_count = 0; // Keep track of buffer index
|
self.instance_count = 0; // Keep track of buffer index
|
||||||
for x in (-nw_tile.x)..=nw_tile.x {
|
for x in (-nw_tile.x)..=nw_tile.x {
|
||||||
for y in (-nw_tile.y)..=nw_tile.y {
|
for y in (-nw_tile.y)..=nw_tile.y {
|
||||||
let offset = Vector3 {
|
let offset = Vector3::new(sz * x as f32, sz * y as f32, 0.0);
|
||||||
x: sz * x as f32,
|
|
||||||
y: sz * y as f32,
|
|
||||||
z: 0.0,
|
|
||||||
};
|
|
||||||
for s in &self.stars {
|
for s in &self.stars {
|
||||||
state.queue.write_buffer(
|
state.queue.write_buffer(
|
||||||
&state.vertex_buffers.starfield.instances,
|
&state.vertex_buffers.starfield.instances,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use cgmath::{Deg, InnerSpace, Point2, Rad, Vector2};
|
use galactica_system::data::ShipState;
|
||||||
use galactica_system::{data::ShipState, phys::util};
|
use galactica_util::{constants::UI_SPRITE_INSTANCE_LIMIT, to_radians};
|
||||||
use galactica_util::constants::UI_SPRITE_INSTANCE_LIMIT;
|
use nalgebra::{Point2, Vector2};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
datastructs::RenderState,
|
datastructs::RenderState,
|
||||||
|
@ -15,7 +15,7 @@ pub(super) struct Radar {
|
||||||
impl Radar {
|
impl Radar {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
last_player_position: Point2 { x: 0.0, y: 0.0 },
|
last_player_position: Point2::new(0.0, 0.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ impl Radar {
|
||||||
.get_state()
|
.get_state()
|
||||||
.landing_position(&input.ct)
|
.landing_position(&input.ct)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.last_player_position = Point2 { x: pos.x, y: pos.y }
|
self.last_player_position = Point2::new(pos.x, pos.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
ShipState::UnLanding { .. } => {
|
ShipState::UnLanding { .. } => {
|
||||||
|
@ -56,15 +56,12 @@ impl Radar {
|
||||||
.get_state()
|
.get_state()
|
||||||
.unlanding_position(&input.ct)
|
.unlanding_position(&input.ct)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.last_player_position = Point2 { x: pos.x, y: pos.y }
|
self.last_player_position = Point2::new(pos.x, pos.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
ShipState::Landed { target } => {
|
ShipState::Landed { target } => {
|
||||||
let landed_body = input.ct.get_system_object(*target);
|
let landed_body = input.ct.get_system_object(*target);
|
||||||
self.last_player_position = Point2 {
|
self.last_player_position = Point2::new(landed_body.pos.x, landed_body.pos.y);
|
||||||
x: landed_body.pos.x,
|
|
||||||
y: landed_body.pos.y,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
ShipState::Flying | ShipState::Collapsing { .. } => {
|
ShipState::Flying | ShipState::Collapsing { .. } => {
|
||||||
let player_body = input
|
let player_body = input
|
||||||
|
@ -72,7 +69,7 @@ impl Radar {
|
||||||
.get_rigid_body(player_ship.rigid_body)
|
.get_rigid_body(player_ship.rigid_body)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
self.last_player_position = util::rigidbody_position(player_body)
|
self.last_player_position = (*player_body.translation()).into();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,10 +103,7 @@ impl Radar {
|
||||||
let system = input.ct.get_system(input.current_system);
|
let system = input.ct.get_system(input.current_system);
|
||||||
for o in &system.objects {
|
for o in &system.objects {
|
||||||
let size = (o.size / o.pos.z) / (radar_range * system_object_scale);
|
let size = (o.size / o.pos.z) / (radar_range * system_object_scale);
|
||||||
let p = Point2 {
|
let p = Point2::new(o.pos.x, o.pos.y);
|
||||||
x: o.pos.x,
|
|
||||||
y: o.pos.y,
|
|
||||||
};
|
|
||||||
let d = (p - self.last_player_position) / radar_range;
|
let d = (p - self.last_player_position) / radar_range;
|
||||||
// Add half the blip sprite's height to distance
|
// Add half the blip sprite's height to distance
|
||||||
let m = d.magnitude() + (size / (2.0 * radar_size));
|
let m = d.magnitude() + (size / (2.0 * radar_size));
|
||||||
|
@ -133,12 +127,10 @@ impl Radar {
|
||||||
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
||||||
bytemuck::cast_slice(&[UiInstance {
|
bytemuck::cast_slice(&[UiInstance {
|
||||||
anchor: PositionAnchor::NwC.to_int(),
|
anchor: PositionAnchor::NwC.to_int(),
|
||||||
position: (Point2 {
|
position: (Point2::new(radar_size / 2.0 + 10.0, radar_size / -2.0 - 10.0)
|
||||||
x: radar_size / 2.0 + 10.0,
|
+ (d * (radar_size / 2.0)))
|
||||||
y: radar_size / -2.0 - 10.0,
|
|
||||||
} + (d * (radar_size / 2.0)))
|
|
||||||
.into(),
|
.into(),
|
||||||
angle: o.angle.0,
|
angle: o.angle,
|
||||||
size,
|
size,
|
||||||
color: [0.5, 0.5, 0.5, 1.0],
|
color: [0.5, 0.5, 0.5, 1.0],
|
||||||
sprite_index: planet_sprite.get_index(),
|
sprite_index: planet_sprite.get_index(),
|
||||||
|
@ -171,7 +163,7 @@ impl Radar {
|
||||||
};
|
};
|
||||||
let ship = input.ct.get_ship(s.data.get_content());
|
let ship = input.ct.get_ship(s.data.get_content());
|
||||||
let size = (ship.size * ship.sprite.aspect) * ship_scale;
|
let size = (ship.size * ship.sprite.aspect) * ship_scale;
|
||||||
let p = util::rigidbody_position(r);
|
let p: Point2<f32> = (*r.translation()).into();
|
||||||
let d = (p - self.last_player_position) / radar_range;
|
let d = (p - self.last_player_position) / radar_range;
|
||||||
let m = d.magnitude() + (size / (2.0 * radar_size));
|
let m = d.magnitude() + (size / (2.0 * radar_size));
|
||||||
if m < hide_range {
|
if m < hide_range {
|
||||||
|
@ -179,12 +171,10 @@ impl Radar {
|
||||||
if size < 2.0 {
|
if size < 2.0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let angle = util::rigidbody_rotation(r).angle(Vector2 { x: 0.0, y: 1.0 });
|
let angle = r.rotation().angle();
|
||||||
|
|
||||||
let position = Point2 {
|
let position = Point2::new(radar_size / 2.0 + 10.0, radar_size / -2.0 - 10.0)
|
||||||
x: radar_size / 2.0 + 10.0,
|
+ (d * (radar_size / 2.0));
|
||||||
y: radar_size / -2.0 - 10.0,
|
|
||||||
} + (d * (radar_size / 2.0));
|
|
||||||
|
|
||||||
// Enforce buffer limit
|
// Enforce buffer limit
|
||||||
// TODO: cleaner solution. don't do this everywhere.
|
// TODO: cleaner solution. don't do this everywhere.
|
||||||
|
@ -200,7 +190,7 @@ impl Radar {
|
||||||
bytemuck::cast_slice(&[UiInstance {
|
bytemuck::cast_slice(&[UiInstance {
|
||||||
anchor: PositionAnchor::NwC.to_int(),
|
anchor: PositionAnchor::NwC.to_int(),
|
||||||
position: position.into(),
|
position: position.into(),
|
||||||
angle: -angle.0, // TODO: consistent angles
|
angle: -angle, // TODO: consistent angles
|
||||||
size,
|
size,
|
||||||
color,
|
color,
|
||||||
sprite_index: ship_sprite.get_index(),
|
sprite_index: ship_sprite.get_index(),
|
||||||
|
@ -211,10 +201,10 @@ impl Radar {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw viewport frame
|
// Draw viewport frame
|
||||||
let d = Vector2 {
|
let d = Vector2::new(
|
||||||
x: (input.camera_zoom / 2.0) * state.window_aspect,
|
(input.camera_zoom / 2.0) * state.window_aspect,
|
||||||
y: input.camera_zoom / 2.0,
|
input.camera_zoom / 2.0,
|
||||||
} / radar_range;
|
) / radar_range;
|
||||||
let m = d.magnitude();
|
let m = d.magnitude();
|
||||||
let d = d * (radar_size / 2.0);
|
let d = d * (radar_size / 2.0);
|
||||||
let color = [0.3, 0.3, 0.3, 1.0];
|
let color = [0.3, 0.3, 0.3, 1.0];
|
||||||
|
@ -233,10 +223,10 @@ impl Radar {
|
||||||
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
||||||
bytemuck::cast_slice(&[UiInstance {
|
bytemuck::cast_slice(&[UiInstance {
|
||||||
anchor: PositionAnchor::NwNw.to_int(),
|
anchor: PositionAnchor::NwNw.to_int(),
|
||||||
position: Point2 {
|
position: Point2::new(
|
||||||
x: (radar_size / 2.0 + 10.0) - d.x,
|
(radar_size / 2.0 + 10.0) - d.x,
|
||||||
y: (radar_size / -2.0 - 10.0) + d.y,
|
(radar_size / -2.0 - 10.0) + d.y,
|
||||||
}
|
)
|
||||||
.into(),
|
.into(),
|
||||||
angle: 0.0,
|
angle: 0.0,
|
||||||
size,
|
size,
|
||||||
|
@ -251,12 +241,12 @@ impl Radar {
|
||||||
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
||||||
bytemuck::cast_slice(&[UiInstance {
|
bytemuck::cast_slice(&[UiInstance {
|
||||||
anchor: PositionAnchor::NwSw.to_int(),
|
anchor: PositionAnchor::NwSw.to_int(),
|
||||||
position: Point2 {
|
position: Point2::new(
|
||||||
x: (radar_size / 2.0 + 10.0) - d.x,
|
(radar_size / 2.0 + 10.0) - d.x,
|
||||||
y: (radar_size / -2.0 - 10.0) - d.y,
|
(radar_size / -2.0 - 10.0) - d.y,
|
||||||
}
|
)
|
||||||
.into(),
|
.into(),
|
||||||
angle: Rad::from(Deg(90.0)).0,
|
angle: to_radians(90.0),
|
||||||
size,
|
size,
|
||||||
color,
|
color,
|
||||||
sprite_index: sprite.get_index(),
|
sprite_index: sprite.get_index(),
|
||||||
|
@ -269,12 +259,12 @@ impl Radar {
|
||||||
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
||||||
bytemuck::cast_slice(&[UiInstance {
|
bytemuck::cast_slice(&[UiInstance {
|
||||||
anchor: PositionAnchor::NwSe.to_int(),
|
anchor: PositionAnchor::NwSe.to_int(),
|
||||||
position: Point2 {
|
position: Point2::new(
|
||||||
x: (radar_size / 2.0 + 10.0) + d.x,
|
(radar_size / 2.0 + 10.0) + d.x,
|
||||||
y: (radar_size / -2.0 - 10.0) - d.y,
|
(radar_size / -2.0 - 10.0) - d.y,
|
||||||
}
|
)
|
||||||
.into(),
|
.into(),
|
||||||
angle: Rad::from(Deg(180.0)).0,
|
angle: to_radians(180.0),
|
||||||
size,
|
size,
|
||||||
color,
|
color,
|
||||||
sprite_index: sprite.get_index(),
|
sprite_index: sprite.get_index(),
|
||||||
|
@ -287,12 +277,12 @@ impl Radar {
|
||||||
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
UiInstance::SIZE * state.vertex_buffers.ui_counter,
|
||||||
bytemuck::cast_slice(&[UiInstance {
|
bytemuck::cast_slice(&[UiInstance {
|
||||||
anchor: PositionAnchor::NwNe.to_int(),
|
anchor: PositionAnchor::NwNe.to_int(),
|
||||||
position: Point2 {
|
position: Point2::new(
|
||||||
x: (radar_size / 2.0 + 10.0) + d.x,
|
(radar_size / 2.0 + 10.0) + d.x,
|
||||||
y: (radar_size / -2.0 - 10.0) + d.y,
|
(radar_size / -2.0 - 10.0) + d.y,
|
||||||
}
|
)
|
||||||
.into(),
|
.into(),
|
||||||
angle: Rad::from(Deg(270.0)).0,
|
angle: to_radians(270.0),
|
||||||
size,
|
size,
|
||||||
color,
|
color,
|
||||||
sprite_index: sprite.get_index(),
|
sprite_index: sprite.get_index(),
|
||||||
|
@ -302,15 +292,14 @@ impl Radar {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrow to center of system
|
// Arrow to center of system
|
||||||
let q = Point2 { x: 0.0, y: 0.0 } - self.last_player_position;
|
let q = Point2::new(0.0, 0.0) - self.last_player_position;
|
||||||
let m = q.magnitude();
|
let m = q.magnitude();
|
||||||
if m > 200.0 {
|
if m > 200.0 {
|
||||||
let player_angle = q.angle(Vector2 { x: 0.0, y: 1.0 });
|
let player_angle = q.angle(&Vector2::new(0.0, 1.0));
|
||||||
|
|
||||||
let position: Point2<f32> = Point2 {
|
let position: Point2<f32> =
|
||||||
x: radar_size / 2.0 + 10.0,
|
Point2::new(radar_size / 2.0 + 10.0, radar_size / -2.0 - 10.0)
|
||||||
y: radar_size / -2.0 - 10.0,
|
+ ((q.normalize() * 0.865) * (radar_size / 2.0));
|
||||||
} + ((q.normalize() * 0.865) * (radar_size / 2.0));
|
|
||||||
|
|
||||||
if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT {
|
if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT {
|
||||||
// TODO: no panic, handle this better.
|
// TODO: no panic, handle this better.
|
||||||
|
@ -323,7 +312,7 @@ impl Radar {
|
||||||
bytemuck::cast_slice(&[UiInstance {
|
bytemuck::cast_slice(&[UiInstance {
|
||||||
anchor: PositionAnchor::NwC.to_int(),
|
anchor: PositionAnchor::NwC.to_int(),
|
||||||
position: position.into(),
|
position: position.into(),
|
||||||
angle: -player_angle.0,
|
angle: -player_angle,
|
||||||
size: 10.0,
|
size: 10.0,
|
||||||
color: [1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)],
|
color: [1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)],
|
||||||
sprite_index: arrow_sprite.get_index(),
|
sprite_index: arrow_sprite.get_index(),
|
||||||
|
|
|
@ -24,5 +24,4 @@ galactica-playeragent = { workspace = true }
|
||||||
rapier2d = { workspace = true }
|
rapier2d = { workspace = true }
|
||||||
nalgebra = { workspace = true }
|
nalgebra = { workspace = true }
|
||||||
crossbeam = { workspace = true }
|
crossbeam = { workspace = true }
|
||||||
cgmath = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle, SystemObjectHandle};
|
||||||
|
use nalgebra::{Point2, Point3};
|
||||||
|
use rand::{rngs::ThreadRng, Rng};
|
||||||
use std::{collections::HashMap, time::Instant};
|
use std::{collections::HashMap, time::Instant};
|
||||||
|
|
||||||
use super::{OutfitSet, ShipPersonality};
|
use super::{OutfitSet, ShipPersonality};
|
||||||
use cgmath::{InnerSpace, Point2, Point3, Rad};
|
|
||||||
use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle, SystemObjectHandle};
|
|
||||||
use rand::{rngs::ThreadRng, Rng};
|
|
||||||
|
|
||||||
/// Ship state machine.
|
/// Ship state machine.
|
||||||
/// Any ship we keep track of is in one of these states.
|
/// Any ship we keep track of is in one of these states.
|
||||||
|
@ -38,8 +38,8 @@ pub enum ShipState {
|
||||||
/// The point, in world coordinates, where we started
|
/// The point, in world coordinates, where we started
|
||||||
from_position: Point2<f32>,
|
from_position: Point2<f32>,
|
||||||
|
|
||||||
/// The ship's angle when we started landing
|
/// The ship's angle when we started landing, in radians
|
||||||
from_angle: Rad<f32>,
|
from_angle: f32,
|
||||||
|
|
||||||
/// The planet we're landing on
|
/// The planet we're landing on
|
||||||
target: SystemObjectHandle,
|
target: SystemObjectHandle,
|
||||||
|
@ -57,8 +57,8 @@ pub enum ShipState {
|
||||||
/// The point, in world coordinates, to which we're going
|
/// The point, in world coordinates, to which we're going
|
||||||
to_position: Point2<f32>,
|
to_position: Point2<f32>,
|
||||||
|
|
||||||
/// The angle we'll be at when we arrive
|
/// The angle we'll be at when we arrive, in radians
|
||||||
to_angle: Rad<f32>,
|
to_angle: f32,
|
||||||
|
|
||||||
/// The planet we're taking off from
|
/// The planet we're taking off from
|
||||||
from: SystemObjectHandle,
|
from: SystemObjectHandle,
|
||||||
|
@ -104,10 +104,7 @@ impl ShipState {
|
||||||
} => Some({
|
} => Some({
|
||||||
let target = ct.get_system_object(*target);
|
let target = ct.get_system_object(*target);
|
||||||
|
|
||||||
let diff = Point2 {
|
let diff = Point2::new(target.pos.x, target.pos.y) - from_position;
|
||||||
x: target.pos.x,
|
|
||||||
y: target.pos.y,
|
|
||||||
} - from_position;
|
|
||||||
let diff = diff - diff.normalize() * (target.size / 2.0) * 0.8;
|
let diff = diff - diff.normalize() * (target.size / 2.0) * 0.8;
|
||||||
|
|
||||||
// TODO: improve animation
|
// TODO: improve animation
|
||||||
|
@ -120,11 +117,11 @@ impl ShipState {
|
||||||
|
|
||||||
let pos = from_position + (diff * (elapsed / total));
|
let pos = from_position + (diff * (elapsed / total));
|
||||||
|
|
||||||
Point3 {
|
Point3::new(
|
||||||
x: pos.x,
|
pos.x,
|
||||||
y: pos.y,
|
pos.y,
|
||||||
z: 1.0 + ((target.pos.z - 1.0) * (elapsed / total)),
|
1.0 + ((target.pos.z - 1.0) * (elapsed / total)),
|
||||||
}
|
)
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -142,11 +139,7 @@ impl ShipState {
|
||||||
} => Some({
|
} => Some({
|
||||||
let from = ct.get_system_object(*from);
|
let from = ct.get_system_object(*from);
|
||||||
|
|
||||||
let diff = to_position
|
let diff = to_position - Point2::new(from.pos.x, from.pos.y);
|
||||||
- Point2 {
|
|
||||||
x: from.pos.x,
|
|
||||||
y: from.pos.y,
|
|
||||||
};
|
|
||||||
//let diff = diff - diff.normalize() * (target.size / 2.0) * 0.8;
|
//let diff = diff - diff.normalize() * (target.size / 2.0) * 0.8;
|
||||||
|
|
||||||
// TODO: improve animation
|
// TODO: improve animation
|
||||||
|
@ -157,16 +150,13 @@ impl ShipState {
|
||||||
// TODO: time by distance
|
// TODO: time by distance
|
||||||
// TODO: keep momentum
|
// TODO: keep momentum
|
||||||
|
|
||||||
let pos = Point2 {
|
let pos = Point2::new(from.pos.x, from.pos.y) + (diff * (elapsed / total));
|
||||||
x: from.pos.x,
|
|
||||||
y: from.pos.y,
|
|
||||||
} + (diff * (elapsed / total));
|
|
||||||
|
|
||||||
Point3 {
|
Point3::new(
|
||||||
x: pos.x,
|
pos.x,
|
||||||
y: pos.y,
|
pos.y,
|
||||||
z: from.pos.z + ((1.0 - from.pos.z) * (elapsed / total)),
|
from.pos.z + ((1.0 - from.pos.z) * (elapsed / total)),
|
||||||
}
|
)
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -232,7 +222,7 @@ impl ShipData {
|
||||||
&mut self,
|
&mut self,
|
||||||
target: SystemObjectHandle,
|
target: SystemObjectHandle,
|
||||||
from_position: Point2<f32>,
|
from_position: Point2<f32>,
|
||||||
from_angle: Rad<f32>,
|
from_angle: f32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match self.state {
|
match self.state {
|
||||||
ShipState::Flying => {
|
ShipState::Flying => {
|
||||||
|
@ -257,7 +247,7 @@ impl ShipData {
|
||||||
ShipState::Landed { target } => {
|
ShipState::Landed { target } => {
|
||||||
self.state = ShipState::UnLanding {
|
self.state = ShipState::UnLanding {
|
||||||
to_position,
|
to_position,
|
||||||
to_angle: Rad(1.0),
|
to_angle: 1.0,
|
||||||
from: target,
|
from: target,
|
||||||
total: 5.0,
|
total: 5.0,
|
||||||
elapsed: 0.0,
|
elapsed: 0.0,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use cgmath::{Deg, InnerSpace};
|
|
||||||
use galactica_content::Relationship;
|
use galactica_content::Relationship;
|
||||||
|
use nalgebra::{Rotation2, Vector2};
|
||||||
use rapier2d::{dynamics::RigidBodySet, geometry::ColliderHandle};
|
use rapier2d::{dynamics::RigidBodySet, geometry::ColliderHandle};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use crate::data::ShipState;
|
||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{
|
||||||
objects::{PhysSimShip, ShipControls},
|
objects::{PhysSimShip, ShipControls},
|
||||||
util, PhysStepResources,
|
PhysStepResources,
|
||||||
},
|
},
|
||||||
ShipControllerStruct,
|
ShipControllerStruct,
|
||||||
};
|
};
|
||||||
|
@ -37,8 +37,8 @@ impl ShipControllerStruct for PointShipController {
|
||||||
|
|
||||||
let my_ship = ships.get(&this_ship).unwrap();
|
let my_ship = ships.get(&this_ship).unwrap();
|
||||||
let this_rigidbody = rigid_bodies.get(my_ship.rigid_body).unwrap();
|
let this_rigidbody = rigid_bodies.get(my_ship.rigid_body).unwrap();
|
||||||
let my_position = util::rigidbody_position(this_rigidbody);
|
let my_position = this_rigidbody.translation();
|
||||||
let my_rotation = util::rigidbody_rotation(this_rigidbody);
|
let my_rotation = this_rigidbody.rotation();
|
||||||
let my_angvel = this_rigidbody.angvel();
|
let my_angvel = this_rigidbody.angvel();
|
||||||
let my_faction = res.ct.get_faction(my_ship.data.get_faction());
|
let my_faction = res.ct.get_faction(my_ship.data.get_faction());
|
||||||
|
|
||||||
|
@ -59,13 +59,13 @@ impl ShipControllerStruct for PointShipController {
|
||||||
|
|
||||||
// Find the closest target
|
// Find the closest target
|
||||||
let mut closest_enemy_position = match hostile_ships.next() {
|
let mut closest_enemy_position = match hostile_ships.next() {
|
||||||
Some(c) => util::rigidbody_position(c),
|
Some(c) => c.translation(),
|
||||||
None => return Some(controls), // Do nothing if no targets are available
|
None => return Some(controls), // Do nothing if no targets are available
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut d = (my_position - closest_enemy_position).magnitude();
|
let mut d = (my_position - closest_enemy_position).magnitude();
|
||||||
for r in hostile_ships {
|
for r in hostile_ships {
|
||||||
let p = util::rigidbody_position(r);
|
let p = r.translation();
|
||||||
let new_d = (my_position - p).magnitude();
|
let new_d = (my_position - p).magnitude();
|
||||||
if new_d < d {
|
if new_d < d {
|
||||||
d = new_d;
|
d = new_d;
|
||||||
|
@ -73,13 +73,12 @@ impl ShipControllerStruct for PointShipController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let angle_delta: Deg<f32> = (my_rotation)
|
let angle = (closest_enemy_position - my_position).angle(&Vector2::new(1.0, 0.0));
|
||||||
.angle(closest_enemy_position - my_position)
|
let angle_delta = my_rotation.angle_to(&Rotation2::new(angle).into());
|
||||||
.into();
|
|
||||||
|
|
||||||
if angle_delta < Deg(0.0) && my_angvel > -0.3 {
|
if angle_delta < 0.0 && my_angvel > -0.3 {
|
||||||
controls.right = true;
|
controls.right = true;
|
||||||
} else if angle_delta > Deg(0.0) && my_angvel < 0.3 {
|
} else if angle_delta > 0.0 && my_angvel < 0.3 {
|
||||||
controls.left = true;
|
controls.left = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ pub mod objects;
|
||||||
mod particlebuilder;
|
mod particlebuilder;
|
||||||
mod stepresources;
|
mod stepresources;
|
||||||
mod systemsim;
|
mod systemsim;
|
||||||
pub mod util;
|
|
||||||
mod wrapper;
|
mod wrapper;
|
||||||
|
|
||||||
pub use particlebuilder::*;
|
pub use particlebuilder::*;
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Rad, Vector2, Zero};
|
|
||||||
use galactica_content::{CollapseEvent, Ship};
|
use galactica_content::{CollapseEvent, Ship};
|
||||||
use nalgebra::point;
|
use nalgebra::{Point2, Vector2};
|
||||||
use rand::{rngs::ThreadRng, Rng};
|
use rand::{rngs::ThreadRng, Rng};
|
||||||
use rapier2d::{dynamics::RigidBody, geometry::Collider};
|
use rapier2d::{dynamics::RigidBody, geometry::Collider};
|
||||||
|
|
||||||
use super::super::{util, ParticleBuilder, PhysStepResources};
|
use super::super::{ParticleBuilder, PhysStepResources};
|
||||||
use crate::data::ShipData;
|
use crate::data::ShipData;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -32,9 +31,9 @@ impl ShipCollapseSequence {
|
||||||
while !a {
|
while !a {
|
||||||
y = self.rng.gen_range(-1.0..=1.0) * ship.size / 2.0;
|
y = self.rng.gen_range(-1.0..=1.0) * ship.size / 2.0;
|
||||||
x = self.rng.gen_range(-1.0..=1.0) * ship.size * ship.sprite.aspect / 2.0;
|
x = self.rng.gen_range(-1.0..=1.0) * ship.size * ship.sprite.aspect / 2.0;
|
||||||
a = collider.shape().contains_local_point(&point![x, y]);
|
a = collider.shape().contains_local_point(&Point2::new(x, y));
|
||||||
}
|
}
|
||||||
Vector2 { x, y }
|
Vector2::new(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Step this sequence `t` seconds
|
/// Step this sequence `t` seconds
|
||||||
|
@ -46,9 +45,8 @@ impl ShipCollapseSequence {
|
||||||
collider: &mut Collider,
|
collider: &mut Collider,
|
||||||
) {
|
) {
|
||||||
let ship_content = res.ct.get_ship(ship_data.get_content());
|
let ship_content = res.ct.get_ship(ship_data.get_content());
|
||||||
let ship_pos = util::rigidbody_position(rigid_body);
|
let ship_pos = rigid_body.translation();
|
||||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
let ship_rot = rigid_body.rotation();
|
||||||
let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 });
|
|
||||||
|
|
||||||
let (total, elapsed) = ship_data.get_state().collapse_state().unwrap();
|
let (total, elapsed) = ship_data.get_state().collapse_state().unwrap();
|
||||||
// How much time has passed since step() was last called
|
// How much time has passed since step() was last called
|
||||||
|
@ -71,25 +69,22 @@ impl ShipCollapseSequence {
|
||||||
let effect = res.ct.get_effect(spawner.effect);
|
let effect = res.ct.get_effect(spawner.effect);
|
||||||
|
|
||||||
for _ in 0..spawner.count as usize {
|
for _ in 0..spawner.count as usize {
|
||||||
let pos = if let Some(pos) = spawner.pos {
|
let pos: Vector2<f32> = if let Some(pos) = spawner.pos {
|
||||||
pos.to_vec()
|
Vector2::new(pos.x, pos.y)
|
||||||
} else {
|
} else {
|
||||||
self.random_in_ship(ship_content, collider)
|
self.random_in_ship(ship_content, collider)
|
||||||
};
|
};
|
||||||
let pos = ship_pos
|
let pos = ship_pos + (ship_rot * 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 =
|
||||||
|
rigid_body.velocity_at_point(&Point2::new(pos.x, pos.y));
|
||||||
|
|
||||||
res.particles.push(ParticleBuilder::from_content(
|
res.particles.push(ParticleBuilder::from_content(
|
||||||
effect,
|
effect,
|
||||||
pos,
|
pos.into(),
|
||||||
Rad::zero(),
|
0.0,
|
||||||
Vector2 {
|
velocity,
|
||||||
x: velocity.x,
|
Vector2::new(0.0, 0.0),
|
||||||
y: velocity.y,
|
|
||||||
},
|
|
||||||
Vector2::zero(),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,21 +116,21 @@ impl ShipCollapseSequence {
|
||||||
|
|
||||||
if self.rng.gen_range(0.0..=1.0) <= p_add {
|
if self.rng.gen_range(0.0..=1.0) <= p_add {
|
||||||
let pos = if let Some(pos) = spawner.pos {
|
let pos = if let Some(pos) = spawner.pos {
|
||||||
pos.to_vec()
|
Vector2::new(pos.x, pos.y)
|
||||||
} else {
|
} else {
|
||||||
self.random_in_ship(ship_content, collider)
|
self.random_in_ship(ship_content, collider)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Position, adjusted for ship rotation
|
// Position, adjusted for ship rotation
|
||||||
let pos = ship_pos + Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos;
|
let pos = ship_pos + (ship_rot * pos);
|
||||||
let vel = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
let vel = rigid_body.velocity_at_point(&Point2::new(pos.x, pos.y));
|
||||||
|
|
||||||
res.particles.push(ParticleBuilder {
|
res.particles.push(ParticleBuilder {
|
||||||
sprite: effect.sprite,
|
sprite: effect.sprite,
|
||||||
pos,
|
pos: pos.into(),
|
||||||
velocity: Vector2 { x: vel.x, y: vel.y },
|
velocity: vel,
|
||||||
angle: Rad::zero(),
|
angle: 0.0,
|
||||||
angvel: Rad::zero(),
|
angvel: 0.0,
|
||||||
lifetime: effect.lifetime,
|
lifetime: effect.lifetime,
|
||||||
size: effect.size,
|
size: effect.size,
|
||||||
fade: 0.0,
|
fade: 0.0,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Rad, Vector2, Zero};
|
|
||||||
use galactica_content::{Content, FactionHandle, ShipHandle};
|
use galactica_content::{Content, FactionHandle, ShipHandle};
|
||||||
use nalgebra::{point, vector};
|
use nalgebra::{point, vector, Rotation2, Vector2};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
dynamics::{RigidBody, RigidBodyHandle},
|
dynamics::{RigidBody, RigidBodyHandle},
|
||||||
|
@ -10,7 +9,7 @@ use rapier2d::{
|
||||||
use crate::data::{ShipData, ShipPersonality, ShipState};
|
use crate::data::{ShipData, ShipPersonality, ShipState};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::{util, ParticleBuilder, PhysStepResources},
|
super::{ParticleBuilder, PhysStepResources},
|
||||||
collapse::ShipCollapseSequence,
|
collapse::ShipCollapseSequence,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,9 +113,9 @@ impl PhysSimShip {
|
||||||
collider: &mut Collider,
|
collider: &mut Collider,
|
||||||
) {
|
) {
|
||||||
let ship_content = res.ct.get_ship(self.data.get_content());
|
let ship_content = res.ct.get_ship(self.data.get_content());
|
||||||
let ship_pos = util::rigidbody_position(&rigid_body);
|
let ship_pos = rigid_body.translation();
|
||||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
let ship_rot = rigid_body.rotation();
|
||||||
let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 });
|
let ship_ang = ship_rot.angle();
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
if self.data.get_hull() <= ship_content.damage.hull {
|
if self.data.get_hull() <= ship_content.damage.hull {
|
||||||
|
@ -125,7 +124,7 @@ impl PhysSimShip {
|
||||||
let effect = res.ct.get_effect(e.effect);
|
let effect = res.ct.get_effect(e.effect);
|
||||||
|
|
||||||
let pos = if let Some(pos) = e.pos {
|
let pos = if let Some(pos) = e.pos {
|
||||||
pos.to_vec()
|
Vector2::new(pos.x, pos.y)
|
||||||
} else {
|
} else {
|
||||||
// Pick a random point inside this ship's collider
|
// Pick a random point inside this ship's collider
|
||||||
let mut y = 0.0;
|
let mut y = 0.0;
|
||||||
|
@ -138,29 +137,24 @@ impl PhysSimShip {
|
||||||
/ 2.0;
|
/ 2.0;
|
||||||
a = collider.shape().contains_local_point(&point![x, y]);
|
a = collider.shape().contains_local_point(&point![x, y]);
|
||||||
}
|
}
|
||||||
Vector2 { x, y }
|
Vector2::new(x, y)
|
||||||
};
|
};
|
||||||
|
|
||||||
let pos =
|
let pos = ship_pos + (Rotation2::new(ship_ang) * 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]);
|
let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||||
|
|
||||||
res.particles.push(ParticleBuilder::from_content(
|
res.particles.push(ParticleBuilder::from_content(
|
||||||
effect,
|
effect,
|
||||||
pos,
|
pos.into(),
|
||||||
Rad::zero(),
|
0.0,
|
||||||
Vector2 {
|
velocity,
|
||||||
x: velocity.x,
|
Vector2::new(0.0, 0.0),
|
||||||
y: velocity.y,
|
|
||||||
},
|
|
||||||
Vector2::zero(),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let engine_force = ship_rot * res.t;
|
let engine_force = ship_rot * (Vector2::new(1.0, 0.0) * res.t);
|
||||||
|
|
||||||
if self.controls.thrust {
|
if self.controls.thrust {
|
||||||
rigid_body.apply_impulse(
|
rigid_body.apply_impulse(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use cgmath::{Matrix2, Point2, Rad, Vector2};
|
|
||||||
use galactica_content::{Effect, SpriteHandle};
|
use galactica_content::{Effect, SpriteHandle};
|
||||||
|
use nalgebra::{Point2, Rotation2, Vector2};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
/// Instructions to create a new particle
|
/// Instructions to create a new particle
|
||||||
|
@ -14,11 +14,11 @@ pub struct ParticleBuilder {
|
||||||
/// This particle's velocity, in world coordinates
|
/// This particle's velocity, in world coordinates
|
||||||
pub velocity: Vector2<f32>,
|
pub velocity: Vector2<f32>,
|
||||||
|
|
||||||
/// This particle's angle
|
/// This particle's angle, in radians
|
||||||
pub angle: Rad<f32>,
|
pub angle: f32,
|
||||||
|
|
||||||
/// This particle's angular velocity (rad/sec)
|
/// This particle's angular velocity (rad/sec)
|
||||||
pub angvel: Rad<f32>,
|
pub angvel: f32,
|
||||||
|
|
||||||
/// This particle's lifetime, in seconds
|
/// This particle's lifetime, in seconds
|
||||||
pub lifetime: f32,
|
pub lifetime: f32,
|
||||||
|
@ -36,7 +36,7 @@ impl ParticleBuilder {
|
||||||
pub fn from_content(
|
pub fn from_content(
|
||||||
effect: &Effect,
|
effect: &Effect,
|
||||||
pos: Point2<f32>,
|
pos: Point2<f32>,
|
||||||
parent_angle: Rad<f32>,
|
parent_angle: f32,
|
||||||
parent_velocity: Vector2<f32>,
|
parent_velocity: Vector2<f32>,
|
||||||
target_velocity: Vector2<f32>,
|
target_velocity: Vector2<f32>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -51,21 +51,18 @@ impl ParticleBuilder {
|
||||||
let velocity = ((effect.velocity_scale_parent + a) * parent_velocity)
|
let velocity = ((effect.velocity_scale_parent + a) * parent_velocity)
|
||||||
+ ((effect.velocity_scale_target + b) * target_velocity);
|
+ ((effect.velocity_scale_target + b) * target_velocity);
|
||||||
|
|
||||||
Matrix2::from_angle(Rad(
|
Rotation2::new(rng.gen_range(-effect.direction_rng..=effect.direction_rng)) * velocity
|
||||||
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 {
|
let angvel = if effect.angvel_rng == 0.0 {
|
||||||
effect.angvel
|
effect.angvel
|
||||||
} else {
|
} else {
|
||||||
Rad(effect.angvel.0 + rng.gen_range(-effect.angvel_rng..=effect.angvel_rng))
|
effect.angvel + rng.gen_range(-effect.angvel_rng..=effect.angvel_rng)
|
||||||
};
|
};
|
||||||
let angle = if effect.angle_rng == 0.0 {
|
let angle = if effect.angle_rng == 0.0 {
|
||||||
parent_angle + effect.angle
|
parent_angle + effect.angle
|
||||||
} else {
|
} else {
|
||||||
parent_angle + effect.angle + Rad(rng.gen_range(-effect.angle_rng..=effect.angle_rng))
|
parent_angle + effect.angle + rng.gen_range(-effect.angle_rng..=effect.angle_rng)
|
||||||
};
|
};
|
||||||
|
|
||||||
ParticleBuilder {
|
ParticleBuilder {
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2, Zero};
|
|
||||||
use galactica_content::{
|
use galactica_content::{
|
||||||
Content, FactionHandle, GunPoint, OutfitHandle, ProjectileCollider, Relationship, ShipHandle,
|
Content, FactionHandle, GunPoint, OutfitHandle, ProjectileCollider, Relationship, ShipHandle,
|
||||||
SystemHandle, SystemObjectHandle,
|
SystemHandle, SystemObjectHandle,
|
||||||
};
|
};
|
||||||
use galactica_playeragent::PlayerAgent;
|
use galactica_playeragent::PlayerAgent;
|
||||||
use nalgebra::{point, vector};
|
use nalgebra::{point, vector, Point2, Rotation2, Vector2};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet},
|
dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet},
|
||||||
geometry::{ColliderBuilder, ColliderHandle, ColliderSet},
|
geometry::{ColliderBuilder, ColliderHandle, ColliderSet},
|
||||||
pipeline::ActiveEvents,
|
pipeline::ActiveEvents,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, f32::consts::PI};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::data::{ShipPersonality, ShipState};
|
use crate::data::{ShipPersonality, ShipState};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
controller::ShipController,
|
controller::ShipController,
|
||||||
objects::{PhysProjectile, PhysSimShip},
|
objects::{PhysProjectile, PhysSimShip},
|
||||||
util, ParticleBuilder, PhysStepResources,
|
ParticleBuilder, PhysStepResources,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: replace with a more generic handle
|
// TODO: replace with a more generic handle
|
||||||
|
@ -71,11 +70,8 @@ impl<'a> PhysSim {
|
||||||
let ship = self.ships.get_mut(&collider).unwrap();
|
let ship = self.ships.get_mut(&collider).unwrap();
|
||||||
|
|
||||||
let r = self.rigid_body_set.get(ship.rigid_body).unwrap();
|
let r = self.rigid_body_set.get(ship.rigid_body).unwrap();
|
||||||
ship.data.land_on(
|
ship.data
|
||||||
target,
|
.land_on(target, (*r.translation()).into(), r.rotation().angle());
|
||||||
util::rigidbody_position(r),
|
|
||||||
-util::rigidbody_rotation(r).angle(Vector2 { x: 0.0, y: 1.0 }),
|
|
||||||
);
|
|
||||||
|
|
||||||
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
|
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
|
||||||
r.set_enabled(false);
|
r.set_enabled(false);
|
||||||
|
@ -93,10 +89,7 @@ impl<'a> PhysSim {
|
||||||
let obj = ship.data.get_state().landed_on().unwrap();
|
let obj = ship.data.get_state().landed_on().unwrap();
|
||||||
let obj = ct.get_system_object(obj);
|
let obj = ct.get_system_object(obj);
|
||||||
|
|
||||||
let target_pos = Point2 {
|
let target_pos = Point2::new(obj.pos.x + 100.0, obj.pos.y + 100.0);
|
||||||
x: obj.pos.x + 100.0,
|
|
||||||
y: obj.pos.y + 100.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
ship.data.unland(target_pos);
|
ship.data.unland(target_pos);
|
||||||
|
|
||||||
|
@ -164,8 +157,9 @@ impl<'a> PhysSim {
|
||||||
|
|
||||||
if destory_projectile {
|
if destory_projectile {
|
||||||
let pr = self.rigid_body_set.get(projectile.rigid_body).unwrap();
|
let pr = self.rigid_body_set.get(projectile.rigid_body).unwrap();
|
||||||
let v = util::rigidbody_velocity(pr).normalize() * projectile.content.force;
|
let v =
|
||||||
let pos = util::rigidbody_position(pr);
|
pr.velocity_at_point(pr.center_of_mass()).normalize() * projectile.content.force;
|
||||||
|
let pos = *pr.translation();
|
||||||
let _ = pr;
|
let _ = pr;
|
||||||
|
|
||||||
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
|
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
|
||||||
|
@ -173,8 +167,8 @@ impl<'a> PhysSim {
|
||||||
|
|
||||||
// Borrow again, we can only have one at a time
|
// Borrow again, we can only have one at a time
|
||||||
let pr = self.rigid_body_set.get(projectile.rigid_body).unwrap();
|
let pr = self.rigid_body_set.get(projectile.rigid_body).unwrap();
|
||||||
let pos = util::rigidbody_position(pr);
|
let pos = *pr.translation();
|
||||||
let angle = util::rigidbody_rotation(pr).angle(Vector2 { x: 1.0, y: 0.0 });
|
let angle = pr.rotation().angle();
|
||||||
|
|
||||||
match &projectile.content.impact_effect {
|
match &projectile.content.impact_effect {
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -182,19 +176,16 @@ impl<'a> PhysSim {
|
||||||
let effect = res.ct.get_effect(*x);
|
let effect = res.ct.get_effect(*x);
|
||||||
let r = ship.rigid_body;
|
let r = ship.rigid_body;
|
||||||
let sr = self.get_rigid_body(r).unwrap();
|
let sr = self.get_rigid_body(r).unwrap();
|
||||||
let parent_velocity = util::rigidbody_velocity(pr);
|
let parent_velocity = pr.velocity_at_point(pr.center_of_mass());
|
||||||
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));
|
||||||
|
|
||||||
res.particles.push(ParticleBuilder::from_content(
|
res.particles.push(ParticleBuilder::from_content(
|
||||||
effect,
|
effect,
|
||||||
pos,
|
pos.into(),
|
||||||
-angle,
|
-angle,
|
||||||
parent_velocity,
|
parent_velocity,
|
||||||
Vector2 {
|
target_velocity,
|
||||||
x: target_velocity.x,
|
|
||||||
y: target_velocity.y,
|
|
||||||
},
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -228,15 +219,8 @@ impl PhysSim {
|
||||||
position: Point2<f32>,
|
position: Point2<f32>,
|
||||||
) -> PhysSimShipHandle {
|
) -> PhysSimShipHandle {
|
||||||
let ship_content = ct.get_ship(handle);
|
let ship_content = ct.get_ship(handle);
|
||||||
let cl = ColliderBuilder::convex_decomposition(
|
let cl = ship_content.collider.0.clone();
|
||||||
&ship_content.collision.points[..],
|
// TODO: additonal ship mass from outfits and cargo
|
||||||
&ship_content.collision.indices[..],
|
|
||||||
)
|
|
||||||
// Rotate collider to match sprite
|
|
||||||
// (Collider starts pointing east, sprite starts pointing north.)
|
|
||||||
.rotation(PI / -2.0)
|
|
||||||
.mass(ship_content.mass);
|
|
||||||
// TODO: only build colliders once
|
|
||||||
|
|
||||||
let rb = RigidBodyBuilder::dynamic()
|
let rb = RigidBodyBuilder::dynamic()
|
||||||
.angular_damping(ship_content.angular_drag)
|
.angular_damping(ship_content.angular_drag)
|
||||||
|
@ -247,7 +231,7 @@ impl PhysSim {
|
||||||
let ridid_body = self.rigid_body_set.insert(rb.build());
|
let ridid_body = self.rigid_body_set.insert(rb.build());
|
||||||
let collider =
|
let collider =
|
||||||
self.collider_set
|
self.collider_set
|
||||||
.insert_with_parent(cl.build(), ridid_body, &mut self.rigid_body_set);
|
.insert_with_parent(cl, ridid_body, &mut self.rigid_body_set);
|
||||||
|
|
||||||
self.ship_behaviors.insert(
|
self.ship_behaviors.insert(
|
||||||
collider,
|
collider,
|
||||||
|
@ -379,34 +363,31 @@ impl PhysSim {
|
||||||
|
|
||||||
let ship = self.ships.get(&collider).unwrap();
|
let ship = self.ships.get(&collider).unwrap();
|
||||||
let rigid_body = self.get_rigid_body(ship.rigid_body).unwrap();
|
let rigid_body = self.get_rigid_body(ship.rigid_body).unwrap();
|
||||||
let ship_pos = util::rigidbody_position(rigid_body);
|
let ship_pos = rigid_body.translation();
|
||||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
let ship_rot = rigid_body.rotation();
|
||||||
let ship_vel = util::rigidbody_velocity(rigid_body);
|
let ship_ang = ship_rot.angle();
|
||||||
let ship_ang = ship_rot.angle(Vector2 { x: 0.0, y: 1.0 });
|
let ship_vel = rigid_body.velocity_at_point(rigid_body.center_of_mass());
|
||||||
|
|
||||||
let pos = ship_pos + (Matrix2::from_angle(-ship_ang) * gun_point.pos.to_vec());
|
let pos = ship_pos + (ship_rot * gun_point.pos);
|
||||||
|
|
||||||
let outfit = res.ct.get_outfit(outfit);
|
let outfit = res.ct.get_outfit(outfit);
|
||||||
let outfit = outfit.gun.as_ref().unwrap();
|
let outfit = outfit.gun.as_ref().unwrap();
|
||||||
|
|
||||||
let spread: Rad<f32> =
|
let spread = rng.gen_range(-outfit.projectile.angle_rng..=outfit.projectile.angle_rng);
|
||||||
Deg(rng.gen_range(-outfit.projectile.angle_rng.0..=outfit.projectile.angle_rng.0))
|
|
||||||
.into();
|
|
||||||
|
|
||||||
let vel = ship_vel
|
let vel = ship_vel
|
||||||
+ (Matrix2::from_angle(-ship_ang + spread)
|
+ (Rotation2::new(ship_ang + spread)
|
||||||
* Vector2 {
|
* Vector2::new(
|
||||||
x: 0.0,
|
outfit.projectile.speed
|
||||||
y: outfit.projectile.speed
|
|
||||||
+ rng.gen_range(
|
+ rng.gen_range(
|
||||||
-outfit.projectile.speed_rng..=outfit.projectile.speed_rng,
|
-outfit.projectile.speed_rng..=outfit.projectile.speed_rng,
|
||||||
),
|
),
|
||||||
});
|
0.0,
|
||||||
|
));
|
||||||
|
|
||||||
let rigid_body = RigidBodyBuilder::kinematic_velocity_based()
|
let rigid_body = RigidBodyBuilder::kinematic_velocity_based()
|
||||||
.translation(vector![pos.x, pos.y])
|
.translation(vector![pos.x, pos.y])
|
||||||
.rotation(-ship_ang.0)
|
.rotation(ship_ang)
|
||||||
.linvel(vector![vel.x, vel.y])
|
.linvel(vel)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let collider = match &outfit.projectile.collider {
|
let collider = match &outfit.projectile.collider {
|
||||||
|
@ -487,9 +468,9 @@ impl PhysSim {
|
||||||
None => {}
|
None => {}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
let x = res.ct.get_effect(*x);
|
let x = res.ct.get_effect(*x);
|
||||||
let pos = util::rigidbody_position(&pr);
|
let pos = *pr.translation();
|
||||||
let vel = util::rigidbody_velocity(&pr);
|
let vel = pr.velocity_at_point(pr.center_of_mass());
|
||||||
let angle = util::rigidbody_rotation(&pr).angle(Vector2 { x: 1.0, y: 0.0 });
|
let angle = pr.rotation().angle();
|
||||||
|
|
||||||
let velocity = {
|
let velocity = {
|
||||||
let a = rng
|
let a = rng
|
||||||
|
@ -502,10 +483,10 @@ impl PhysSim {
|
||||||
|
|
||||||
res.particles.push(ParticleBuilder::from_content(
|
res.particles.push(ParticleBuilder::from_content(
|
||||||
x,
|
x,
|
||||||
pos,
|
pos.into(),
|
||||||
-angle,
|
-angle,
|
||||||
velocity,
|
velocity,
|
||||||
Vector2::zero(),
|
Vector2::new(0.0, 0.0),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
//! Conversion utilities
|
|
||||||
|
|
||||||
use cgmath::{Point2, Vector2};
|
|
||||||
use nalgebra;
|
|
||||||
use rapier2d::dynamics::RigidBody;
|
|
||||||
|
|
||||||
// TODO: Migrate to nalgebra fully, remove these converters
|
|
||||||
|
|
||||||
/// Convert a rigidbody position to a position in game coordinates
|
|
||||||
pub fn rigidbody_position(r: &RigidBody) -> cgmath::Point2<f32> {
|
|
||||||
Point2 {
|
|
||||||
x: r.translation()[0],
|
|
||||||
y: r.translation()[1],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert a rigidbody rotation to a rotation in game coordinates
|
|
||||||
pub fn rigidbody_rotation(r: &RigidBody) -> Vector2<f32> {
|
|
||||||
Vector2 {
|
|
||||||
x: r.rotation().re,
|
|
||||||
y: r.rotation().im,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert a rigidbody velocity to a velocity in game coordinates
|
|
||||||
pub fn rigidbody_velocity(r: &RigidBody) -> cgmath::Vector2<f32> {
|
|
||||||
let v = r.velocity_at_point(&nalgebra::Point2::new(
|
|
||||||
r.translation()[0],
|
|
||||||
r.translation()[1],
|
|
||||||
));
|
|
||||||
Vector2 { x: v.x, y: v.y }
|
|
||||||
}
|
|
|
@ -4,3 +4,8 @@
|
||||||
|
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod timing;
|
pub mod timing;
|
||||||
|
|
||||||
|
/// Convert an angle in degrees to radians
|
||||||
|
pub fn to_radians(degrees: f32) -> f32 {
|
||||||
|
return (degrees / 360.0) * std::f32::consts::TAU;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue