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