@@ -0,0 +1,3 @@ | |||
[submodule "auto_ops"] | |||
path = auto_ops | |||
url = https://github.com/carbotaniuman/auto_ops.git |
@@ -83,6 +83,10 @@ version = "0.3.6" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
checksum = "c9ff149ed9780025acfdb36862d35b28856bb693ceb451259a7164442f22fdc3" | |||
[[package]] | |||
name = "auto_ops" | |||
version = "0.1.0" | |||
[[package]] | |||
name = "autocfg" | |||
version = "1.0.1" | |||
@@ -548,6 +552,7 @@ dependencies = [ | |||
name = "glc" | |||
version = "0.1.0" | |||
dependencies = [ | |||
"auto_ops", | |||
"gl", | |||
"imagefmt", | |||
"serde", | |||
@@ -11,6 +11,7 @@ default-members = [ | |||
] | |||
[patch.crates-io] | |||
auto_ops = { path = "./auto_ops" } | |||
gl = { path = "./gl" } | |||
glc = { path = "./glc" } | |||
space-crush-app = { path = "./space-crush-app" } | |||
@@ -0,0 +1 @@ | |||
Subproject commit 59ebf01379d09c0707d257c20efb21a3b1dc877b |
@@ -8,6 +8,7 @@ edition = "2018" | |||
default = [ ] | |||
[dependencies] | |||
auto_ops = "0.1" | |||
gl = { version = "0.1", features = [ "generate_global" ] } | |||
imagefmt = "4.0" | |||
serde = { version = "1.0", optional = true, features = [ "derive" ] } | |||
@@ -1,7 +1,7 @@ | |||
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; | |||
use std::f64::consts::PI; | |||
use std::ops::{Add, Div, Mul, Neg, Sub}; | |||
use auto_ops::impl_op_ex; | |||
#[cfg(feature = "serde")] | |||
use serde::{Deserialize, Serialize}; | |||
@@ -47,99 +47,59 @@ where | |||
Self::Rad(value) => Self::Rad(value.abs()), | |||
} | |||
} | |||
} | |||
impl<T> Angle<T> | |||
where | |||
T: Float, | |||
{ | |||
pub fn sin(self) -> T { | |||
T::sin(self.into_rad().into_inner()) | |||
} | |||
pub fn cos(self) -> T { | |||
T::cos(self.into_rad().into_inner()) | |||
} | |||
/// Normalizes the angle to (-pi, pi] / (-180.0, 180.0] | |||
pub fn normalize(self) -> Self { | |||
match self { | |||
Self::Deg(value) => Self::Deg(normalize(value, T::new(-180.0), T::new(180.0))), | |||
Self::Rad(value) => Self::Rad(normalize(value, T::new(-PI), T::new(PI))), | |||
} | |||
} | |||
} | |||
impl<T> Neg for Angle<T> | |||
where | |||
T: Neg + Numeric, | |||
{ | |||
type Output = Angle<T>; | |||
fn neg(self) -> Self::Output { | |||
fn _neg(self) -> Self { | |||
match self { | |||
Self::Deg(value) => Self::Deg(-value), | |||
Self::Rad(value) => Self::Rad(-value), | |||
} | |||
} | |||
} | |||
impl<T> Add for Angle<T> | |||
where | |||
T: Add<T, Output = T> + Numeric, | |||
{ | |||
type Output = Angle<T>; | |||
fn add(self, v: Self) -> Self::Output { | |||
fn _add(self, other: &Self) -> Self { | |||
match self { | |||
Self::Deg(value) => Self::Deg(value + v.into_deg().into_inner()), | |||
Self::Rad(value) => Self::Rad(value + v.into_rad().into_inner()), | |||
Self::Deg(value) => Self::Deg(value + other.into_deg().into_inner()), | |||
Self::Rad(value) => Self::Rad(value * other.into_rad().into_inner()), | |||
} | |||
} | |||
} | |||
impl<T> Sub for Angle<T> | |||
where | |||
T: Sub<T, Output = T> + Numeric, | |||
{ | |||
type Output = Angle<T>; | |||
fn sub(self, v: Self) -> Self::Output { | |||
fn _mul(self, other: T) -> Self { | |||
match self { | |||
Self::Deg(value) => Self::Deg(value - v.into_deg().into_inner()), | |||
Self::Rad(value) => Self::Rad(value - v.into_rad().into_inner()), | |||
Self::Deg(value) => Self::Deg(value * other), | |||
Self::Rad(value) => Self::Rad(value * other), | |||
} | |||
} | |||
} | |||
impl<T> Mul<T> for Angle<T> | |||
impl<T> Angle<T> | |||
where | |||
T: Mul<T, Output = T> + Numeric, | |||
T: Float, | |||
{ | |||
type Output = Angle<T>; | |||
fn mul(self, factor: T) -> Self::Output { | |||
match self { | |||
Self::Deg(value) => Self::Deg(value * factor), | |||
Self::Rad(value) => Self::Rad(value * factor), | |||
} | |||
pub fn sin(self) -> T { | |||
T::sin(self.into_rad().into_inner()) | |||
} | |||
} | |||
impl<T> Div<T> for Angle<T> | |||
where | |||
T: Div<T, Output = T> + Numeric, | |||
{ | |||
type Output = Angle<T>; | |||
pub fn cos(self) -> T { | |||
T::cos(self.into_rad().into_inner()) | |||
} | |||
fn div(self, factor: T) -> Self::Output { | |||
/// Normalizes the angle to (-pi, pi] / (-180.0, 180.0] | |||
pub fn normalize(self) -> Self { | |||
match self { | |||
Self::Deg(value) => Self::Deg(value / factor), | |||
Self::Rad(value) => Self::Rad(value / factor), | |||
Self::Deg(value) => Self::Deg(normalize(value, T::new(-180.0), T::new(180.0))), | |||
Self::Rad(value) => Self::Rad(normalize(value, T::new(-PI), T::new(PI))), | |||
} | |||
} | |||
} | |||
impl_op_ex!(*|a: &f32, b: &Angle<f32>| -> Angle<f32> { b._mul(*a) }); | |||
impl_op_ex!(- <T: Numeric> |a: &Angle<T>| -> Angle<T> { a._neg() }); | |||
impl_op_ex!(+ <T: Numeric> |a: &Angle<T>, b: &Angle<T>| -> Angle<T> { a._add(b) }); | |||
impl_op_ex!(- <T: Numeric> |a: &Angle<T>, b: &Angle<T>| -> Angle<T> { a._add(&b._neg()) }); | |||
impl_op_ex!(* <T: Numeric> |a: &Angle<T>, b: &T| -> Angle<T> { a._mul(*b) }); | |||
impl_op_ex!(/ <T: Numeric> |a: &Angle<T>, b: &T| -> Angle<T> { a._mul(T::one() / *b) }); | |||
impl_op_ex!(+= <T: Numeric> |a: &mut Angle<T>, b: &Angle<T>| { *a = a._add(b); }); | |||
impl_op_ex!(-= <T: Numeric> |a: &mut Angle<T>, b: &Angle<T>| { *a = a._add(&b._neg()); }); | |||
impl<T, S> PartialEq<Angle<S>> for Angle<T> | |||
where | |||
T: Numeric + PartialEq<S>, | |||
@@ -3,8 +3,9 @@ | |||
use std::borrow::Borrow; | |||
use std::convert::{AsMut, AsRef}; | |||
use std::fmt::{Debug, Formatter, Result as FmtResult}; | |||
use std::ops::{Deref, DerefMut, Mul}; | |||
use std::ops::{Deref, DerefMut}; | |||
use auto_ops::impl_op_ex; | |||
#[cfg(feature = "serde")] | |||
use serde::{ | |||
de::{Deserializer, Error, MapAccess, SeqAccess, Visitor}, | |||
@@ -356,17 +357,9 @@ where | |||
} | |||
} | |||
impl<T, M> Mul<M> for Matrix3<T> | |||
where | |||
T: Float, | |||
M: Borrow<Matrix3<T>>, | |||
{ | |||
type Output = Self; | |||
fn mul(self, rhs: M) -> Self::Output { | |||
self.multiply(rhs.borrow()) | |||
} | |||
} | |||
impl_op_ex!(* <T: Float> |a: &Matrix3<T>, b: &Matrix3<T>| -> Matrix3<T> { a.multiply(b) }); | |||
impl_op_ex!(* <T: Float> |a: &Matrix3<T>, b: &Vector2<T>| -> Vector2<T> { a.transform(*b) }); | |||
impl_op_ex!(*= <T: Float> |a: &mut Vector2<T>, b: &Matrix3<T>| { *a = b.transform(*a); }); | |||
/* Matrix4 */ | |||
@@ -638,35 +631,8 @@ where | |||
} | |||
} | |||
macro_rules! impl_mul_mat4 { | |||
($input:ty, $output:ty, $func:ident) => { | |||
impl<T> Mul<$input> for Matrix4<T> | |||
where | |||
T: Float, | |||
{ | |||
type Output = $output; | |||
fn mul(self, rhs: $input) -> Self::Output { | |||
self.$func(rhs) | |||
} | |||
} | |||
impl<T> Mul<$input> for &Matrix4<T> | |||
where | |||
T: Float, | |||
{ | |||
type Output = $output; | |||
fn mul(self, rhs: $input) -> Self::Output { | |||
self.$func(rhs) | |||
} | |||
} | |||
}; | |||
} | |||
impl_mul_mat4!(Matrix4<T>, Matrix4<T>, multiply); | |||
impl_mul_mat4!(&Matrix4<T>, Matrix4<T>, multiply); | |||
impl_mul_mat4!(Vector4<T>, Vector4<T>, transform); | |||
impl_op_ex!(* <T: Float> |a: &Matrix4<T>, b: &Matrix4<T>| -> Matrix4<T> { a.multiply(b) }); | |||
impl_op_ex!(* <T: Float> |a: &Matrix4<T>, b: &Vector4<T>| -> Vector4<T> { a.transform(*b) }); | |||
#[cfg(test)] | |||
mod tests { | |||
@@ -2,8 +2,9 @@ | |||
use std::convert::{AsMut, AsRef}; | |||
use std::fmt::{Debug, Formatter, Result as FmtResult}; | |||
use std::ops::{Add, Deref, DerefMut, Mul, Neg, Sub}; | |||
use std::ops::{Deref, DerefMut}; | |||
use auto_ops::impl_op_ex; | |||
#[cfg(feature = "serde")] | |||
use serde::{ | |||
de::{Deserialize, Deserializer, Error}, | |||
@@ -296,74 +297,15 @@ where | |||
} | |||
} | |||
impl<T> Neg for Vector2<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn neg(self) -> Self::Output { | |||
Self { | |||
x: -self.x, | |||
y: -self.y, | |||
} | |||
} | |||
} | |||
impl<T> Add for Vector2<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn add(mut self, other: Self) -> Self::Output { | |||
self.x = self.x + other.x; | |||
self.y = self.y + other.y; | |||
self | |||
} | |||
} | |||
impl<T> Sub for Vector2<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn sub(mut self, other: Self) -> Self::Output { | |||
self.x = self.x - other.x; | |||
self.y = self.y - other.y; | |||
self | |||
} | |||
} | |||
impl<T> Mul for Vector2<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = T; | |||
#[inline] | |||
fn mul(self, rhs: Self) -> Self::Output { | |||
self.scalar(&rhs) | |||
} | |||
} | |||
impl<T> Mul<T> for Vector2<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn mul(self, rhs: T) -> Self::Output { | |||
self.multiply(rhs) | |||
} | |||
} | |||
impl_op_ex!(*|a: &f32, b: &Vector2f| -> Vector2f { b.multiply(*a) }); | |||
impl_op_ex!(- <T: Numeric> |a: &Vector2<T>| -> Vector2<T> { Vector2 { x: -a.x, y: -a.y } }); | |||
impl_op_ex!(+ <T: Numeric> |a: &Vector2<T>, b: &Vector2<T>| -> Vector2<T> { Vector2 { x: a.x + b.x, y: a.y + b.y } }); | |||
impl_op_ex!(- <T: Numeric> |a: &Vector2<T>, b: &Vector2<T>| -> Vector2<T> { Vector2 { x: a.x - b.x, y: a.y - b.y } }); | |||
impl_op_ex!(* <T: Numeric> |a: &Vector2<T>, b: &Vector2<T>| -> T { a.scalar(b) }); | |||
impl_op_ex!(* <T: Numeric> |a: &Vector2<T>, b: &T| -> Vector2<T> { a.multiply(*b) }); | |||
impl_op_ex!(/ <T: Numeric> |a: &Vector2<T>, b: &T| -> Vector2<T> { a.multiply(T::one() / *b) }); | |||
impl_op_ex!(+= <T: Numeric> |a: &mut Vector2<T>, b: &Vector2<T>| { a.x = a.x + b.x; a.y = a.y + b.y; }); | |||
impl_op_ex!(-= <T: Numeric> |a: &mut Vector2<T>, b: &Vector2<T>| { a.x = a.x - b.x; a.y = a.y - b.y; }); | |||
impl<T> From<Vector3<T>> for Vector2<T> | |||
where | |||
@@ -445,6 +387,16 @@ where | |||
y: self.y, | |||
} | |||
} | |||
#[inline] | |||
pub fn into_vec4(self) -> Vector4<T> { | |||
Vector4 { | |||
x: self.x, | |||
y: self.y, | |||
z: self.z, | |||
w: T::one(), | |||
} | |||
} | |||
} | |||
impl<T> Vector3<T> | |||
@@ -461,77 +413,15 @@ where | |||
} | |||
} | |||
impl<T> Neg for Vector3<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn neg(self) -> Self::Output { | |||
Self { | |||
x: -self.x, | |||
y: -self.y, | |||
z: -self.z, | |||
} | |||
} | |||
} | |||
impl<T> Add for Vector3<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn add(mut self, other: Self) -> Self::Output { | |||
self.x = self.x + other.x; | |||
self.y = self.y + other.y; | |||
self.z = self.z + other.z; | |||
self | |||
} | |||
} | |||
impl<T> Sub for Vector3<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn sub(mut self, other: Self) -> Self::Output { | |||
self.x = self.x - other.x; | |||
self.y = self.y - other.y; | |||
self.z = self.z - other.z; | |||
self | |||
} | |||
} | |||
impl<T> Mul for Vector3<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = T; | |||
#[inline] | |||
fn mul(self, rhs: Self) -> Self::Output { | |||
self.scalar(&rhs) | |||
} | |||
} | |||
impl<T> Mul<T> for Vector3<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn mul(self, rhs: T) -> Self::Output { | |||
self.multiply(rhs) | |||
} | |||
} | |||
impl_op_ex!(*|a: &f32, b: &Vector3f| -> Vector3f { b.multiply(*a) }); | |||
impl_op_ex!(- <T: Numeric> |a: &Vector3<T>| -> Vector3<T> { Vector3 { x: -a.x, y: -a.y, z: -a.z } }); | |||
impl_op_ex!(+ <T: Numeric> |a: &Vector3<T>, b: &Vector3<T>| -> Vector3<T> { Vector3 { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z } }); | |||
impl_op_ex!(- <T: Numeric> |a: &Vector3<T>, b: &Vector3<T>| -> Vector3<T> { Vector3 { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z } }); | |||
impl_op_ex!(* <T: Numeric> |a: &Vector3<T>, b: &Vector3<T>| -> T { a.scalar(b) }); | |||
impl_op_ex!(* <T: Numeric> |a: &Vector3<T>, b: &T| -> Vector3<T> { a.multiply(*b) }); | |||
impl_op_ex!(/ <T: Numeric> |a: &Vector3<T>, b: &T| -> Vector3<T> { a.multiply(T::one() / *b) }); | |||
impl_op_ex!(+= <T: Numeric> |a: &mut Vector3<T>, b: &Vector3<T>| { a.x = a.x + b.x; a.y = a.y + b.y; a.z = a.z + b.z; }); | |||
impl_op_ex!(-= <T: Numeric> |a: &mut Vector3<T>, b: &Vector3<T>| { a.x = a.x - b.x; a.y = a.y - b.y; a.z = a.z - b.z; }); | |||
impl<T> From<Vector2<T>> for Vector3<T> | |||
where | |||
@@ -665,52 +555,15 @@ where | |||
} | |||
} | |||
impl<T> Add for Vector4<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn add(self, other: Self) -> Self::Output { | |||
(self.into_vec3() + other.into_vec3(), T::one()).into() | |||
} | |||
} | |||
impl<T> Sub for Vector4<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn sub(self, other: Self) -> Self::Output { | |||
(self.into_vec3() - other.into_vec3(), T::one()).into() | |||
} | |||
} | |||
impl<T> Mul for Vector4<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = T; | |||
fn mul(self, rhs: Self) -> Self::Output { | |||
self.scalar(&rhs) | |||
} | |||
} | |||
impl<T> Mul<T> for Vector4<T> | |||
where | |||
T: Numeric, | |||
{ | |||
type Output = Self; | |||
#[inline] | |||
fn mul(self, rhs: T) -> Self::Output { | |||
self.multiply(rhs) | |||
} | |||
} | |||
impl_op_ex!(*|a: &f32, b: &Vector4f| -> Vector4f { b.multiply(*a) }); | |||
impl_op_ex!(- <T: Numeric> |a: &Vector4<T>| -> Vector4<T> { Vector4 { x: -a.x, y: -a.y, z: -a.z, w: a.w } }); | |||
impl_op_ex!(+ <T: Numeric> |a: &Vector4<T>, b: &Vector4<T>| -> Vector4<T> { (a.into_vec3() + b.into_vec3()).into_vec4() }); | |||
impl_op_ex!(- <T: Numeric> |a: &Vector4<T>, b: &Vector4<T>| -> Vector4<T> { (a.into_vec3() - b.into_vec3()).into_vec4() }); | |||
impl_op_ex!(* <T: Numeric> |a: &Vector4<T>, b: &Vector4<T>| -> T { a.scalar(b) }); | |||
impl_op_ex!(* <T: Numeric> |a: &Vector4<T>, b: &T| -> Vector4<T> { a.multiply(*b) }); | |||
impl_op_ex!(/ <T: Numeric> |a: &Vector4<T>, b: &T| -> Vector4<T> { a.multiply(T::one() / *b) }); | |||
impl_op_ex!(+= <T: Numeric> |a: &mut Vector4<T>, b: &Vector4<T>| { *a = (a.into_vec3() + b.into_vec3()).into_vec4(); }); | |||
impl_op_ex!(-= <T: Numeric> |a: &mut Vector4<T>, b: &Vector4<T>| { *a = (a.into_vec3() - b.into_vec3()).into_vec4(); }); | |||
impl<T> From<Vector2<T>> for Vector4<T> | |||
where | |||
@@ -65,7 +65,7 @@ impl<'a> System<'a> for Fleets { | |||
gl::enable(gl::BLEND); | |||
for (position, orbit) in (&positions, &orbits).join() { | |||
let fleet_id = continue_if_none!(orbit.fleets.get(player.index)); | |||
let fleet_id = continue_if_none!(orbit.fleets().get(player.index())); | |||
let fleet_id = continue_if_none!(fleet_id); | |||
let fleet = continue_if_none!(fleets.get(*fleet_id)); | |||
@@ -73,15 +73,15 @@ impl<'a> System<'a> for Fleets { | |||
gl::blend_equation(gl::FUNC_ADD); | |||
geometry.render_lines( | |||
Vector4f::new(0.5, 0.5, 0.5, 0.05), | |||
&create_circle(position.pos, orbit.min), | |||
&create_circle(position.pos(), orbit.min()), | |||
); | |||
geometry.render_lines( | |||
Vector4f::new(0.5, 0.5, 0.5, 0.05), | |||
&create_circle(position.pos, orbit.max), | |||
&create_circle(position.pos(), orbit.max()), | |||
); | |||
geometry.render_lines( | |||
Vector4f::new(0.5, 0.5, 0.5, 0.05), | |||
&create_circle(position.pos, SHIP_ORBIT_DISTANCE_MAX * orbit.max), | |||
&create_circle(position.pos(), SHIP_ORBIT_DISTANCE_MAX * orbit.max()), | |||
); | |||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | |||
@@ -91,11 +91,13 @@ impl<'a> System<'a> for Fleets { | |||
0, | |||
format!( | |||
"F:{}\nB:{}\nT:{}", | |||
fleet.count.fighter, fleet.count.bomber, fleet.count.transporter | |||
fleet.count().fighter, | |||
fleet.count().bomber, | |||
fleet.count().transporter | |||
), | |||
) | |||
.panic("Unable to update text") | |||
.render_offset(&camera.world_to_window(position.pos)); | |||
.render_offset(&camera.world_to_window(*position.pos())); | |||
} | |||
gl::blend_equation(gl::FUNC_ADD); | |||
@@ -103,7 +105,7 @@ impl<'a> System<'a> for Fleets { | |||
} | |||
} | |||
fn create_circle(p: Vector2f, r: f32) -> Vec<Vector2f> { | |||
fn create_circle(p: &Vector2f, r: f32) -> Vec<Vector2f> { | |||
let mut points = Vec::new(); | |||
for i in 0..=180 { | |||
@@ -33,25 +33,28 @@ impl<'a> System<'a> for Ships { | |||
gl::blend_func(gl::SRC_ALPHA, gl::ONE); | |||
for (position, velocity, ship) in (&positions, &velocities, &ships).join() { | |||
let ship_pos = position.pos; | |||
let ship_pos = position.pos(); | |||
geometry.render_lines( | |||
Vector4f::new(0.0, 0.0, 1.0, 0.2), | |||
&[ship_pos, ship_pos + velocity.dir * velocity.speed], | |||
&[*ship_pos, ship_pos + velocity.dir() * velocity.speed()], | |||
); | |||
geometry.render_lines( | |||
Vector4f::new(1.0, 0.0, 0.0, 0.2), | |||
&[ship_pos, ship_pos + ship.target_dir * 100.0], | |||
&[*ship_pos, ship_pos + ship.target_dir() * 100.0], | |||
); | |||
geometry.render_lines( | |||
Vector4f::new(1.0, 1.0, 1.0, 0.2), | |||
&[ship_pos, ship.target_pos], | |||
&[*ship_pos, *ship.target_pos()], | |||
); | |||
if let ShipObstacle::Known(obstacle) = ship.obstacle { | |||
let obstacle_pos = continue_if_none!(positions.get(obstacle)).pos; | |||
if let ShipObstacle::Known(obstacle) = ship.obstacle() { | |||
let obstacle_pos = continue_if_none!(positions.get(obstacle)).pos(); | |||
geometry.render_lines(Vector4f::new(0.0, 1.0, 0.0, 0.2), &[ship_pos, obstacle_pos]); | |||
geometry.render_lines( | |||
Vector4f::new(0.0, 1.0, 0.0, 0.2), | |||
&[*ship_pos, *obstacle_pos], | |||
); | |||
} | |||
} | |||
@@ -57,11 +57,10 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
matrix::Angle, | |||
vector::{Vector2f, Vector4f}, | |||
}; | |||
use smallvec::smallvec; | |||
use space_crush_common::{ | |||
components::{ | |||
Asteroid, AsteroidType, Fleet, FleetOwned, Obstacle, Orbit, OrbitOwned, Planet, Player, | |||
PlayerOwned, Position, Shape, Ship, ShipType, Velocity, | |||
PlayerOwned, Position, Ship, ShipType, Velocity, | |||
}, | |||
misc::{PersistWorld, Persistence}, | |||
}; | |||
@@ -71,13 +70,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
world | |||
.system_data::<WriteStorage<Player>>() | |||
.insert( | |||
player_id, | |||
Player { | |||
index: 0, | |||
color: Vector4f::new(0.0, 0.5, 1.0, 0.1), | |||
}, | |||
) | |||
.insert(player_id, Player::new(Vector4f::new(0.0, 0.5, 1.0, 0.1))) | |||
.unwrap(); | |||
let planets = (0..3) | |||
@@ -88,16 +81,9 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(PlayerOwned { owner: player_id }) | |||
.with(Position { | |||
pos: Vector2f::new(x, y), | |||
shape: Shape::Circle(250.0), | |||
}) | |||
.with(Orbit { | |||
min: 325.0, | |||
max: 425.0, | |||
fleets: smallvec![], | |||
}) | |||
.with(PlayerOwned::new(player_id)) | |||
.with(Position::circle(Vector2f::new(x, y), 250.0)) | |||
.with(Orbit::new(325.0, 425.0)) | |||
.with(Obstacle {}) | |||
.with(Planet {}) | |||
.build() | |||
@@ -114,31 +100,22 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(Position { | |||
pos: Vector2f::new(x, y), | |||
shape: Shape::Circle(100.0), | |||
}) | |||
.with(Orbit { | |||
min: 125.0, | |||
max: 175.0, | |||
fleets: smallvec![], | |||
}) | |||
.with(Position::circle(Vector2f::new(x, y), 100.0)) | |||
.with(Orbit::new(125.0, 175.0)) | |||
.with(Obstacle {}) | |||
.with(Asteroid { | |||
type_: match i_x * i_y { | |||
-1 => AsteroidType::Metal, | |||
1 => AsteroidType::Crystal, | |||
_ => unreachable!(), | |||
}, | |||
}) | |||
.with(Asteroid::new(match i_x * i_y { | |||
-1 => AsteroidType::Metal, | |||
1 => AsteroidType::Crystal, | |||
_ => unreachable!(), | |||
})) | |||
.build(); | |||
} | |||
let fleet_id = world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(PlayerOwned { owner: player_id }) | |||
.with(OrbitOwned { owner: planets[1] }) | |||
.with(PlayerOwned::new(player_id)) | |||
.with(OrbitOwned::new(planets[1])) | |||
.with(Fleet::default()) | |||
.build(); | |||
@@ -152,28 +129,19 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(PlayerOwned { owner: player_id }) | |||
.with(FleetOwned { owner: fleet_id }) | |||
.with(Position { | |||
pos: Vector2f::new(x, y), | |||
shape: Shape::Dot, | |||
}) | |||
.with(Velocity { | |||
dir: Vector2f::new(random::<f32>() - 0.5, random::<f32>() - 0.5).normalize(), | |||
speed: 100.0, | |||
}) | |||
.with(Ship { | |||
type_: match i % 3 { | |||
0 => ShipType::Fighter, | |||
1 => ShipType::Bomber, | |||
2 => ShipType::Transporter, | |||
_ => unreachable!(), | |||
}, | |||
agility: Angle::Deg(360.0), | |||
target_pos: Default::default(), | |||
target_dir: Default::default(), | |||
obstacle: Default::default(), | |||
}) | |||
.with(PlayerOwned::new(player_id)) | |||
.with(FleetOwned::new(fleet_id)) | |||
.with(Position::dot(Vector2f::new(x, y))) | |||
.with(Velocity::new( | |||
Vector2f::new(random::<f32>() - 0.5, random::<f32>() - 0.5).normalize(), | |||
100.0, | |||
)) | |||
.with(Ship::new(match i % 3 { | |||
0 => ShipType::Fighter, | |||
1 => ShipType::Bomber, | |||
2 => ShipType::Transporter, | |||
_ => unreachable!(), | |||
})) | |||
.build(); | |||
} | |||
} |
@@ -86,17 +86,17 @@ impl<'a> System<'a> for Asteroids { | |||
let _guard = BindGuard::new(&self.program); | |||
for (position, asteroid, owned) in (&position, &asteroid, owned.maybe()).join() { | |||
let p_x = position.pos.x; | |||
let p_y = position.pos.y; | |||
let s = position.shape.circle().unwrap_or(ASTEROID_SIZE); | |||
let p_x = position.pos().x; | |||
let p_y = position.pos().y; | |||
let s = position.shape().circle().unwrap_or(ASTEROID_SIZE); | |||
let _guard = match asteroid.type_ { | |||
let _guard = match asteroid.type_() { | |||
AsteroidType::Metal => BindGuard::new(&self.texture_metal), | |||
AsteroidType::Crystal => BindGuard::new(&self.texture_crystal), | |||
}; | |||
let c = match owned.and_then(|owned| player.get(owned.owner)) { | |||
Some(pv) => &pv.color, | |||
let c = match owned.and_then(|owned| player.get(owned.owner())) { | |||
Some(pv) => pv.color(), | |||
None => &PLAYER_COLOR_DEFAULT, | |||
}; | |||
@@ -194,12 +194,12 @@ impl FleetSelect { | |||
let pos = d.camera.view_to_world(d.input_state.mouse_pos); | |||
let selection = d.game_state.selection.take(); | |||
for (position, orbit) in (&d.positions, &d.orbits).join() { | |||
let r = orbit.max * orbit.max; | |||
if (position.pos - pos).length_sqr() <= r { | |||
let r = orbit.max() * orbit.max(); | |||
if (position.pos() - pos).length_sqr() <= r { | |||
let player_id = d.game_state.player_id; | |||
let player = player!(&d, player_id); | |||
let player_index = player.index; | |||
let fleet_id = continue_if_none!(orbit.fleets.get(player_index)); | |||
let player_index = player.index(); | |||
let fleet_id = continue_if_none!(orbit.fleets().get(player_index)); | |||
let fleet_id = *continue_if_none!(fleet_id); | |||
d.game_state.selection = match selection { | |||
@@ -225,7 +225,7 @@ impl FleetSelect { | |||
self.mouse_pos = d.input_state.mouse_pos; | |||
self.select_mode = SelectMode::Init(timeout); | |||
self.values_changed_once = false; | |||
self.set_count(selection.count, &fleet.count); | |||
self.set_count(selection.count, &fleet.count()); | |||
break; | |||
} | |||
@@ -282,12 +282,12 @@ impl FleetSelect { | |||
/* calculate values */ | |||
let selection = selection!(&d); | |||
let orbit_owned = orbit_owned!(&d, selection.fleet); | |||
let position = position!(&d, orbit_owned.owner); | |||
let position = position!(&d, orbit_owned.owner()); | |||
let fleet = fleet!(&d, selection.fleet); | |||
self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos; | |||
self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos(); | |||
self.zoom = d.camera.view().axis_x.as_vec3().length(); | |||
self.shape_size = position.shape.radius(); | |||
self.shape_size = position.shape().radius(); | |||
self.ring0 = self.shape_size + FLEET_SELECT_OFFSET / self.zoom; | |||
self.ring1 = self.ring0 + FLEET_SELECT_WIDTH / self.zoom; | |||
@@ -314,10 +314,10 @@ impl FleetSelect { | |||
x @ 0..=2 => { | |||
let mut count = selection.count; | |||
count[x] = usize::MAX; | |||
self.set_count(count, &fleet.count); | |||
self.set_count(count, fleet.count()); | |||
self.values[x] = 1.0; | |||
self.update_values(&fleet.count); | |||
self.update_values(fleet.count()); | |||
} | |||
_ => { | |||
self.count = ShipCount::all(); | |||
@@ -332,14 +332,14 @@ impl FleetSelect { | |||
match sector { | |||
x @ 0..=2 => { | |||
let mut count = selection.count; | |||
count[x] = (fleet.count[x] as f32 * value).round() as usize; | |||
self.set_count(count, &fleet.count); | |||
count[x] = (fleet.count()[x] as f32 * value).round() as usize; | |||
self.set_count(count, fleet.count()); | |||
self.values[x] = value; | |||
self.update_values(&fleet.count); | |||
self.update_values(fleet.count()); | |||
} | |||
_ => { | |||
self.count = fleet.count * value; | |||
self.count = *fleet.count() * value; | |||
self.values = value.into(); | |||
} | |||
} | |||
@@ -348,10 +348,10 @@ impl FleetSelect { | |||
x @ 0..=2 => { | |||
let mut count = selection.count; | |||
count[x] = 0; | |||
self.set_count(count, &fleet.count); | |||
self.set_count(count, fleet.count()); | |||
self.values[x] = 0.0; | |||
self.update_values(&fleet.count); | |||
self.update_values(fleet.count()); | |||
} | |||
_ => { | |||
self.count = Default::default(); | |||
@@ -361,7 +361,7 @@ impl FleetSelect { | |||
} | |||
/* update texts */ | |||
let c = self.count.merge(&fleet.count); | |||
let c = self.count.merge(fleet.count()); | |||
let _guard = self.cache.begin_update(); | |||
self.text_total | |||
.update(0, c.total().to_string()) | |||
@@ -436,13 +436,13 @@ impl FleetSelect { | |||
/* extract system data */ | |||
let selection = selection!(&d); | |||
let orbit_owned = orbit_owned!(&d, selection.fleet); | |||
let position = position!(&d, orbit_owned.owner); | |||
let position = position!(&d, orbit_owned.owner()); | |||
/* calculate shared values */ | |||
let size = self.ring1 + 50.0; | |||
let rings = Vector2f::new(self.ring0 / size, self.ring1 / size); | |||
let px = position.pos.x; | |||
let py = position.pos.y; | |||
let px = position.pos().x; | |||
let py = position.pos().y; | |||
let m = Matrix4f::new( | |||
Vector4f::new(size, 0.0, 0.0, 0.0), | |||
Vector4f::new(0.0, size, 0.0, 0.0), | |||
@@ -485,20 +485,20 @@ impl FleetSelect { | |||
if is_simple { | |||
self.text_total | |||
.color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | |||
.render_offset(&self.text_pos(self.marker, position.pos, d)); | |||
.render_offset(&self.text_pos(self.marker, *position.pos(), d)); | |||
} else { | |||
self.text_total | |||
.color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | |||
.render_offset(&self.text_pos((0.0, 1.0), position.pos, d)); | |||
.render_offset(&self.text_pos((0.0, 1.0), *position.pos(), d)); | |||
self.text_fighter | |||
.color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | |||
.render_offset(&self.text_pos((1.0, 0.0), position.pos, d)); | |||
.render_offset(&self.text_pos((1.0, 0.0), *position.pos(), d)); | |||
self.text_bomber | |||
.color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | |||
.render_offset(&self.text_pos((0.0, -1.0), position.pos, d)); | |||
.render_offset(&self.text_pos((0.0, -1.0), *position.pos(), d)); | |||
self.text_transporter | |||
.color(Vector4f::new(1.0, 1.0, 1.0, alpha)) | |||
.render_offset(&self.text_pos((-1.0, 0.0), position.pos, d)); | |||
.render_offset(&self.text_pos((-1.0, 0.0), *position.pos(), d)); | |||
} | |||
} | |||
@@ -84,12 +84,12 @@ impl<'a> System<'a> for Planets { | |||
let _guard = BindGuard::new(&self.texture); | |||
for (p, _, owned) in (&position, &planet, owned.maybe()).join() { | |||
let p_x = p.pos.x; | |||
let p_y = p.pos.y; | |||
let s = p.shape.circle().unwrap_or(PLANET_SIZE); | |||
let p_x = p.pos().x; | |||
let p_y = p.pos().y; | |||
let s = p.shape().circle().unwrap_or(PLANET_SIZE); | |||
let c = match owned.and_then(|owned| player.get(owned.owner)) { | |||
Some(pv) => &pv.color, | |||
let c = match owned.and_then(|owned| player.get(owned.owner())) { | |||
Some(pv) => &pv.color(), | |||
None => &PLAYER_COLOR_DEFAULT, | |||
}; | |||
@@ -90,21 +90,21 @@ impl<'a> System<'a> for Ships { | |||
let _guard = BindGuard::new(&self.program); | |||
for (p, v, ship, owned) in (&position, &velocity, &ship, owned.maybe()).join() { | |||
let _guard = match ship.type_ { | |||
let _guard = match ship.type_() { | |||
ShipType::Fighter => BindGuard::new(&self.texture_fighter), | |||
ShipType::Bomber => BindGuard::new(&self.texture_bomber), | |||
ShipType::Transporter => BindGuard::new(&self.texture_transporter), | |||
}; | |||
let c = match owned.and_then(|owned| player.get(owned.owner)) { | |||
Some(pv) => &pv.color, | |||
let c = match owned.and_then(|owned| player.get(owned.owner())) { | |||
Some(pv) => pv.color(), | |||
None => &PLAYER_COLOR_DEFAULT, | |||
}; | |||
let p_x = p.pos.x; | |||
let p_y = p.pos.y; | |||
let d_x = v.dir.x; | |||
let d_y = v.dir.y; | |||
let p_x = p.pos().x; | |||
let p_y = p.pos().y; | |||
let d_x = v.dir().x; | |||
let d_y = v.dir().y; | |||
let s = SHIP_SIZE; | |||
let m = Matrix4f::new( | |||
@@ -69,11 +69,11 @@ impl<'a> System<'a> for FleetControl { | |||
MouseEvent::ButtonDown(button) if button == &config.input.fleet_move_button => { | |||
let pos = camera.view_to_world(input_state.mouse_pos); | |||
for (position, orbit) in (&positions, &orbits).join() { | |||
let r = orbit.max * orbit.max; | |||
if (position.pos - pos).length_sqr() <= r { | |||
let r = orbit.max() * orbit.max(); | |||
if (position.pos() - pos).length_sqr() <= r { | |||
let player_id = game_state.player_id; | |||
let player = continue_if_none!(players.get(player_id)); | |||
let fleet_id = continue_if_none!(orbit.fleets.get(player.index)); | |||
let fleet_id = continue_if_none!(orbit.fleets().get(player.index())); | |||
let fleet_id = *continue_if_none!(fleet_id); | |||
self.target_fleet = Some(fleet_id); | |||
@@ -82,23 +82,24 @@ impl<'a> System<'a> for FleetControl { | |||
} | |||
} | |||
} | |||
#[allow(unused_variables)] // TODO | |||
MouseEvent::ButtonUp(button) if button == &config.input.fleet_move_button => { | |||
let selection = game_state.selection.take(); | |||
let target_fleet = continue_if_none!(self.target_fleet.take()); | |||
let mut selection = continue_if_none!(selection); | |||
let fleet = continue_if_none!(fleets.get(selection.fleet)); | |||
for (ship, fleet_owned, _) in (&ships, &mut fleet_owned, &fleet.owned).join() { | |||
match &ship.type_ { | |||
for (ship, fleet_owned, _) in (&ships, &mut fleet_owned, fleet.owned()).join() { | |||
match ship.type_() { | |||
ShipType::Fighter if selection.count.fighter > 0 => { | |||
fleet_owned.owner = target_fleet; | |||
// TODO fleet_owned.set_owner(target_fleet); | |||
selection.count.fighter -= 1; | |||
} | |||
ShipType::Bomber if selection.count.bomber > 0 => { | |||
fleet_owned.owner = target_fleet; | |||
// TODO fleet_owned.set_owner(target_fleet); | |||
selection.count.bomber -= 1; | |||
} | |||
ShipType::Transporter if selection.count.transporter > 0 => { | |||
fleet_owned.owner = target_fleet; | |||
// TODO fleet_owned.set_owner(target_fleet); | |||
selection.count.transporter -= 1; | |||
} | |||
_ => (), | |||
@@ -3,15 +3,27 @@ use specs::{Component, HashMapStorage}; | |||
#[derive(Clone, Debug, Serialize, Deserialize)] | |||
pub struct Asteroid { | |||
pub type_: Type, | |||
type_: Type, | |||
} | |||
#[derive(Clone, Debug, Serialize, Deserialize)] | |||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] | |||
pub enum Type { | |||
Metal, | |||
Crystal, | |||
} | |||
impl Asteroid { | |||
#[inline] | |||
pub fn new(type_: Type) -> Self { | |||
Self { type_ } | |||
} | |||
#[inline] | |||
pub fn type_(&self) -> Type { | |||
self.type_ | |||
} | |||
} | |||
impl Component for Asteroid { | |||
type Storage = HashMapStorage<Self>; | |||
} |
@@ -1,3 +1,5 @@ | |||
#![allow(dead_code)] | |||
use serde::{Deserialize, Serialize}; | |||
use specs::{ | |||
error::NoError, | |||
@@ -10,13 +12,13 @@ use crate::{components::ShipCount, misc::FlaggedStorage}; | |||
#[derive(Default, Debug, Clone)] | |||
pub struct Fleet { | |||
pub owned: BitSet, | |||
pub count: ShipCount, | |||
owned: BitSet, | |||
count: ShipCount, | |||
} | |||
#[derive(Copy, Clone, Debug)] | |||
pub struct Owned { | |||
pub owner: Entity, | |||
owner: Entity, | |||
} | |||
#[derive(Serialize, Deserialize)] | |||
@@ -24,10 +26,46 @@ pub struct OwnedData<M> { | |||
pub owner: M, | |||
} | |||
impl Fleet { | |||
#[inline] | |||
pub fn owned(&self) -> &BitSet { | |||
&self.owned | |||
} | |||
#[inline] | |||
pub(crate) fn owned_mut(&mut self) -> &mut BitSet { | |||
&mut self.owned | |||
} | |||
#[inline] | |||
pub fn count(&self) -> &ShipCount { | |||
&self.count | |||
} | |||
#[inline] | |||
pub(crate) fn count_mut(&mut self) -> &mut ShipCount { | |||
&mut self.count | |||
} | |||
} | |||
impl Component for Fleet { | |||
type Storage = HashMapStorage<Self>; | |||
} | |||
impl Owned { | |||
pub fn new(owner: Entity) -> Self { | |||
Self { owner } | |||
} | |||
pub fn owner(&self) -> Entity { | |||
self.owner | |||
} | |||
pub(crate) fn set_owner(&mut self, owner: Entity) { | |||
self.owner = owner; | |||
} | |||
} | |||
impl Component for Owned { | |||
type Storage = FlaggedStorage<Self, VecStorage<Self>>; | |||
} | |||
@@ -1,4 +1,5 @@ | |||
use serde::{Deserialize, Serialize}; | |||
use smallvec::smallvec; | |||
use smallvec::SmallVec; | |||
use specs::{ | |||
error::NoError, | |||
@@ -10,9 +11,9 @@ use crate::misc::FlaggedStorage; | |||
#[derive(Clone, Debug, Default)] | |||
pub struct Orbit { | |||
pub min: f32, | |||
pub max: f32, | |||
pub fleets: SmallVec<[Option<Entity>; 8]>, | |||
min: f32, | |||
max: f32, | |||
fleets: Fleets, | |||
} | |||
#[derive(Serialize, Deserialize)] | |||
@@ -24,7 +25,7 @@ pub struct OrbitData<M> { | |||
#[derive(Copy, Clone, Debug)] | |||
pub struct Owned { | |||
pub owner: Entity, | |||
owner: Entity, | |||
} | |||
#[derive(Serialize, Deserialize)] | |||
@@ -32,6 +33,39 @@ pub struct OwnedData<M> { | |||
pub owner: M, | |||
} | |||
type Fleets = SmallVec<[Option<Entity>; 8]>; | |||
impl Orbit { | |||
#[inline] | |||
pub fn new(min: f32, max: f32) -> Self { | |||
Self { | |||
min, | |||
max, | |||
fleets: smallvec![], | |||
} | |||
} | |||
#[inline] | |||
pub fn min(&self) -> f32 { | |||
self.min | |||
} | |||
#[inline] | |||
pub fn max(&self) -> f32 { | |||
self.max | |||
} | |||
#[inline] | |||
pub fn fleets(&self) -> &Fleets { | |||
&self.fleets | |||
} | |||
#[inline] | |||
pub(crate) fn fleets_mut(&mut self) -> &mut Fleets { | |||
&mut self.fleets | |||
} | |||
} | |||
impl Component for Orbit { | |||
type Storage = HashMapStorage<Self>; | |||
} | |||
@@ -71,6 +105,16 @@ where | |||
} | |||
} | |||
impl Owned { | |||
pub fn new(owner: Entity) -> Self { | |||
Self { owner } | |||
} | |||
pub fn owner(&self) -> Entity { | |||
self.owner | |||
} | |||
} | |||
impl Component for Owned { | |||
type Storage = FlaggedStorage<Self, HashMapStorage<Self>>; | |||
} | |||
@@ -8,13 +8,13 @@ use specs::{ | |||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||
pub struct Player { | |||
pub index: usize, | |||
pub color: Vector4f, | |||
index: usize, | |||
color: Vector4f, | |||
} | |||
#[derive(Copy, Clone, Debug)] | |||
pub struct Owned { | |||
pub owner: Entity, | |||
owner: Entity, | |||
} | |||
#[derive(Serialize, Deserialize)] | |||
@@ -22,10 +22,40 @@ pub struct OwnedData<M> { | |||
pub owner: M, | |||
} | |||
impl Player { | |||
#[inline] | |||
pub fn new(color: Vector4f) -> Self { | |||
Self { | |||
index: next_index(), | |||
color, | |||
} | |||
} | |||
#[inline] | |||
pub fn index(&self) -> usize { | |||
self.index | |||
} | |||
#[inline] | |||
pub fn color(&self) -> &Vector4f { | |||
&self.color | |||
} | |||
} | |||
impl Component for Player { | |||
type Storage = HashMapStorage<Self>; | |||
} | |||
impl Owned { | |||
pub fn new(owner: Entity) -> Self { | |||
Self { owner } | |||
} | |||
pub fn owner(&self) -> Entity { | |||
self.owner | |||
} | |||
} | |||
impl Component for Owned { | |||
type Storage = HashMapStorage<Self>; | |||
} | |||
@@ -55,3 +85,11 @@ where | |||
Ok(Owned { owner }) | |||
} | |||
} | |||
fn next_index() -> usize { | |||
use std::sync::atomic::{AtomicUsize, Ordering}; | |||
static NEXT_INDEX: AtomicUsize = AtomicUsize::new(0); | |||
NEXT_INDEX.fetch_add(1, Ordering::Relaxed) | |||
} |
@@ -4,8 +4,8 @@ use specs::{Component, VecStorage}; | |||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||
pub struct Position { | |||
pub pos: Vector2f, | |||
pub shape: Shape, | |||
pos: Vector2f, | |||
shape: Shape, | |||
} | |||
#[derive(Clone, Debug, Serialize, Deserialize)] | |||
@@ -14,6 +14,34 @@ pub enum Shape { | |||
Circle(f32), | |||
} | |||
impl Position { | |||
pub fn dot(pos: Vector2f) -> Self { | |||
Self { | |||
pos, | |||
shape: Shape::Dot, | |||
} | |||
} | |||
pub fn circle(pos: Vector2f, radius: f32) -> Self { | |||
Self { | |||
pos, | |||
shape: Shape::Circle(radius), | |||
} | |||
} | |||
pub fn pos(&self) -> &Vector2f { | |||
&self.pos | |||
} | |||
pub fn shape(&self) -> &Shape { | |||
&self.shape | |||
} | |||
pub(crate) fn pos_mut(&mut self) -> &mut Vector2f { | |||
&mut self.pos | |||
} | |||
} | |||
impl Component for Position { | |||
type Storage = VecStorage<Self>; | |||
} | |||
@@ -1,18 +1,22 @@ | |||
use std::cmp::min; | |||
use std::ops::{Index, IndexMut, Mul}; | |||
use glc::{matrix::Angle, vector::Vector2f}; | |||
use glc::vector::Vector2f; | |||
use serde::{Deserialize, Serialize}; | |||
use specs::{Component, Entity, VecStorage}; | |||
#[derive(Clone, Debug, Serialize, Deserialize)] | |||
pub struct Ship { | |||
pub type_: Type, | |||
pub agility: Angle<f32>, | |||
pub target_pos: Vector2f, | |||
pub target_dir: Vector2f, | |||
type_: Type, | |||
#[serde(skip)] | |||
obstacle: Obstacle, | |||
#[serde(skip)] | |||
pub obstacle: Obstacle, | |||
target_pos: Vector2f, | |||
#[serde(skip)] | |||
target_dir: Vector2f, | |||
} | |||
#[derive(Copy, Clone, Debug, PartialEq, Eq)] | |||
@@ -36,6 +40,49 @@ pub enum Type { | |||
Transporter, | |||
} | |||
impl Ship { | |||
#[inline] | |||
pub fn new(type_: Type) -> Self { | |||
Self { | |||
type_, | |||
obstacle: Default::default(), | |||
target_pos: Default::default(), | |||
target_dir: Default::default(), | |||
} | |||
} | |||
#[inline] | |||
pub fn type_(&self) -> Type { | |||
self.type_ | |||
} | |||
#[inline] | |||
pub fn target_pos(&self) -> &Vector2f { | |||
&self.target_pos | |||
} | |||
#[inline] | |||
pub fn target_dir(&self) -> &Vector2f { | |||
&self.target_dir | |||
} | |||
#[inline] | |||
pub(crate) fn set_target(&mut self, pos: Vector2f, dir: Vector2f) { | |||
self.target_pos = pos; | |||
self.target_dir = dir; | |||
} | |||
#[inline] | |||
pub fn obstacle(&self) -> Obstacle { | |||
self.obstacle | |||
} | |||
#[inline] | |||
pub(crate) fn set_obstacle(&mut self, value: Obstacle) { | |||
self.obstacle = value; | |||
} | |||
} | |||
impl Component for Ship { | |||
type Storage = VecStorage<Self>; | |||
} | |||
@@ -4,8 +4,26 @@ use specs::{Component, VecStorage}; | |||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||
pub struct Velocity { | |||
pub dir: Vector2f, | |||
pub speed: f32, | |||
dir: Vector2f, | |||
speed: f32, | |||
} | |||
impl Velocity { | |||
pub fn new(dir: Vector2f, speed: f32) -> Self { | |||
Self { dir, speed } | |||
} | |||
pub fn dir(&self) -> &Vector2f { | |||
&self.dir | |||
} | |||
pub fn dir_mut(&mut self) -> &mut Vector2f { | |||
&mut self.dir | |||
} | |||
pub fn speed(&self) -> f32 { | |||
self.speed | |||
} | |||
} | |||
impl Component for Velocity { | |||
@@ -71,18 +71,24 @@ impl<'a> System<'a> for FleetOwnedUpdate { | |||
for event in events { | |||
match event { | |||
ComponentEvent::Inserted(id, fleet_owned) => { | |||
self.fleet_ids.add(fleet_owned.owner.id()); | |||
self.fleet_ids.add(fleet_owned.owner().id()); | |||
self.fleet_owned_ids.add(*id); | |||
} | |||
ComponentEvent::Modified(id, fleet_owned) => { | |||
self.fleet_ids.add(fleet_owned.owner.id()); | |||
self.fleet_ids.add(fleet_owned.owner().id()); | |||
self.fleet_owned_ids.add(*id); | |||
*self.old_fleet_ids.entry(*id).or_insert(fleet_owned.owner) = fleet_owned.owner; | |||
*self | |||
.old_fleet_ids | |||
.entry(*id) | |||
.or_insert_with(|| fleet_owned.owner()) = fleet_owned.owner(); | |||
} | |||
ComponentEvent::Removed(id, fleet_owned) => { | |||
self.fleet_ids.add(fleet_owned.owner.id()); | |||
self.fleet_ids.add(fleet_owned.owner().id()); | |||
self.fleet_owned_ids.add(*id); | |||
*self.old_fleet_ids.entry(*id).or_insert(fleet_owned.owner) = fleet_owned.owner; | |||
*self | |||
.old_fleet_ids | |||
.entry(*id) | |||
.or_insert_with(|| fleet_owned.owner()) = fleet_owned.owner(); | |||
} | |||
} | |||
} | |||
@@ -92,18 +98,24 @@ impl<'a> System<'a> for FleetOwnedUpdate { | |||
let data = (&entities, &ships, &fleet_owned, &self.fleet_owned_ids); | |||
for (ship_id, ship, fleet_owned, _) in data.join() { | |||
let new_match = fleet_id == fleet_owned.owner; | |||
let new_match = fleet_id == fleet_owned.owner(); | |||
let old_match = match self.old_fleet_ids.get(&ship_id.id()) { | |||
Some(old_fleet_id) => fleet_id == *old_fleet_id, | |||
None => false, | |||
}; | |||
if old_match && !new_match { | |||
fleet_info.owned.remove(ship_id.id()); | |||
fleet_info.count[ship.type_] = fleet_info.count[ship.type_].saturating_sub(1); | |||
let count = fleet_info.count_mut(); | |||
let count = &mut count[ship.type_()]; | |||
*count = count.saturating_sub(1); | |||
fleet_info.owned_mut().remove(ship_id.id()); | |||
} else if !old_match && new_match { | |||
fleet_info.owned.add(ship_id.id()); | |||
fleet_info.count[ship.type_] += 1; | |||
let count = fleet_info.count_mut(); | |||
let count = &mut count[ship.type_()]; | |||
*count += 1; | |||
fleet_info.owned_mut().add(ship_id.id()); | |||
} | |||
} | |||
} | |||
@@ -32,7 +32,7 @@ impl<'a> System<'a> for Movement { | |||
.for_each(|(position, velocity)| { | |||
let delta = global.delta * global.world_speed; | |||
position.pos = position.pos + velocity.dir * velocity.speed * delta; | |||
*position.pos_mut() += velocity.dir() * velocity.speed() * delta; | |||
}); | |||
} | |||
} |
@@ -74,18 +74,24 @@ impl<'a> System<'a> for OrbitOwnedUpdate { | |||
for event in events { | |||
match event { | |||
ComponentEvent::Inserted(id, orbit_owned) => { | |||
self.orbit_ids.add(orbit_owned.owner.id()); | |||
self.orbit_ids.add(orbit_owned.owner().id()); | |||
self.orbit_owned_ids.add(*id); | |||
} | |||
ComponentEvent::Modified(id, orbit_owned) => { | |||
self.orbit_ids.add(orbit_owned.owner.id()); | |||
self.orbit_ids.add(orbit_owned.owner().id()); | |||
self.orbit_owned_ids.add(*id); | |||
*self.old_orbit_ids.entry(*id).or_insert(orbit_owned.owner) = orbit_owned.owner; | |||
*self | |||
.old_orbit_ids | |||
.entry(*id) | |||
.or_insert_with(|| orbit_owned.owner()) = orbit_owned.owner(); | |||
} | |||
ComponentEvent::Removed(id, orbit_owned) => { | |||
self.orbit_ids.add(orbit_owned.owner.id()); | |||
self.orbit_ids.add(orbit_owned.owner().id()); | |||
self.orbit_owned_ids.add(*id); | |||
*self.old_orbit_ids.entry(*id).or_insert(orbit_owned.owner) = orbit_owned.owner; | |||
*self | |||
.old_orbit_ids | |||
.entry(*id) | |||
.or_insert_with(|| orbit_owned.owner()) = orbit_owned.owner(); | |||
} | |||
} | |||
} | |||
@@ -100,20 +106,22 @@ impl<'a> System<'a> for OrbitOwnedUpdate { | |||
); | |||
for (fleet_id, orbit_owned, player_owned, _) in data.join() { | |||
let new_match = orbit_id == orbit_owned.owner; | |||
let new_match = orbit_id == orbit_owned.owner(); | |||
let old_match = match self.old_orbit_ids.get(&fleet_id.id()) { | |||
Some(old_orbit_id) => orbit_id == *old_orbit_id, | |||
None => false, | |||
}; | |||
let player_id = player_owned.owner.id() as usize; | |||
let player_id = player_owned.owner().id() as usize; | |||
if old_match && !new_match { | |||
if let Some(fleet) = orbit.fleets.get_mut(player_id) { | |||
if let Some(fleet) = orbit.fleets_mut().get_mut(player_id) { | |||
*fleet = None; | |||
} | |||
} else if !old_match && new_match { | |||
orbit.fleets.resize_with(player_id + 1, Default::default); | |||
orbit.fleets[player_id] = Some(fleet_id); | |||
orbit | |||
.fleets_mut() | |||
.resize_with(player_id + 1, Default::default); | |||
orbit.fleets_mut()[player_id] = Some(fleet_id); | |||
} | |||
} | |||
} | |||
@@ -139,24 +139,27 @@ impl Processor<'_> { | |||
position: &Position, | |||
fleet_owned: &FleetOwned, | |||
) { | |||
let fleet_id = fleet_owned.owner; | |||
let fleet_id = fleet_owned.owner(); | |||
let orbit_owned = return_if_none!(self.orbit_owned.get(fleet_id)); | |||
let orbit_id = orbit_owned.owner; | |||
let orbit_id = orbit_owned.owner(); | |||
let orbit = return_if_none!(self.orbits.get(orbit_id)); | |||
let orbit_pos = return_if_none!(self.positions.get(orbit_id)).pos; | |||
let ship_pos = position.pos; | |||
let target_pos = ship.target_pos; | |||
let target_dir = ship.target_dir; | |||
let orbit_pos = return_if_none!(self.positions.get(orbit_id)).pos(); | |||
let ship_pos = position.pos(); | |||
let target_pos = ship.target_pos(); | |||
let target_dir = ship.target_dir(); | |||
let orbit_to_target = target_pos - orbit_pos; | |||
let orbit_to_ship = ship_pos - orbit_pos; | |||
let mut ship_to_target = target_pos - position.pos; | |||
let mut ship_to_target = target_pos - ship_pos; | |||
let r_ship = orbit_to_ship.length_sqr(); | |||
let r_target = orbit_to_target.length_sqr(); | |||
let target_in_orbit = (r_target <= sqr(orbit.max)) && (r_target >= sqr(orbit.min)); | |||
let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit.max); | |||
let orbit_min = orbit.min(); | |||
let orbit_max = orbit.max(); | |||
let target_in_orbit = (r_target <= sqr(orbit_max)) && (r_target >= sqr(orbit_min)); | |||
let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max); | |||
let need_update = self.need_update.contains(id); | |||
let has_target = target_dir.length_sqr() != 0.0; | |||
@@ -164,9 +167,9 @@ impl Processor<'_> { | |||
/* check and update target posistion */ | |||
if need_update || !has_target || passed_target || ship_in_orbit != target_in_orbit { | |||
let target_pos = if ship_in_orbit && orbit.max > 0.0 { | |||
let target_pos = if ship_in_orbit && orbit_max > 0.0 { | |||
let orbit_to_ship_vec3 = Vector3f::new(orbit_to_ship.x, orbit_to_ship.y, 0.0); | |||
let ship_dir_vec3 = Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0); | |||
let ship_dir_vec3 = velocity.dir().into_vec3(); | |||
let dir = if orbit_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 { | |||
1.0 | |||
@@ -174,34 +177,35 @@ impl Processor<'_> { | |||
-1.0 | |||
}; | |||
let add = SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random(); | |||
let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X); | |||
let angle = angle + add * dir / orbit.max; | |||
let radius = orbit.min + (orbit.max - orbit.min) * random::<f32>(); | |||
let orbit_min = orbit.min(); | |||
let orbit_max = orbit.max(); | |||
let add = SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random::<f32>(); | |||
let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X) + add * dir / orbit_max; | |||
let radius = orbit_min + (orbit_max - orbit_min) * random::<f32>(); | |||
Vector2f::new( | |||
orbit_pos.x + radius * angle.cos(), | |||
orbit_pos.y + radius * angle.sin(), | |||
) | |||
} else { | |||
ship.obstacle = ShipObstacle::Search; | |||
ship.set_obstacle(ShipObstacle::Search); | |||
orbit_pos | |||
*orbit_pos | |||
}; | |||
ship.target_pos = target_pos; | |||
ship.target_dir = (target_pos - ship_pos).normalize(); | |||
ship.set_target(target_pos, (target_pos - ship_pos).normalize()); | |||
ship_to_target = target_pos - ship_pos; | |||
} | |||
/* check if obstacle is still valid */ | |||
if ship_in_orbit { | |||
ship.obstacle = ShipObstacle::Done; | |||
} else if let ShipObstacle::Known(obstacle) = ship.obstacle { | |||
ship.set_obstacle(ShipObstacle::Done); | |||
} else if let ShipObstacle::Known(obstacle) = ship.obstacle() { | |||
if let Some(position) = self.positions.get(obstacle) { | |||
let obstacle_orbit = self.orbits.get(obstacle).unwrap(); | |||
let obstacle_pos = position.pos; | |||
let obstacle_pos = position.pos(); | |||
let ship_to_obstacle = obstacle_pos - ship_pos; | |||
let obstacle_angle = ship_to_target | |||
@@ -210,22 +214,22 @@ impl Processor<'_> { | |||
.into_inner() | |||
.abs(); | |||
let orbit_sqr = obstacle_orbit.max * obstacle_orbit.max; | |||
let orbit_sqr = obstacle_orbit.max() * obstacle_orbit.max(); | |||
if (obstacle_angle > 90.0 && ship_to_obstacle.length_sqr() > orbit_sqr) | |||
|| obstacle_angle > 170.0 | |||
{ | |||
ship.obstacle = ShipObstacle::Search; | |||
ship.set_obstacle(ShipObstacle::Search); | |||
} | |||
} else { | |||
ship.obstacle = ShipObstacle::Search; | |||
ship.set_obstacle(ShipObstacle::Search); | |||
} | |||
} | |||
/* find obstacle */ | |||
if !ship_in_orbit && ship.obstacle == ShipObstacle::Search { | |||
if !ship_in_orbit && ship.obstacle() == ShipObstacle::Search { | |||
let mut dist_sqr = f32::MAX; | |||
for (e, position, _) in (self.entities, self.positions, self.obstacles).join() { | |||
let obstacle_pos = position.pos; | |||
let obstacle_pos = position.pos(); | |||
let ship_to_obstacle = obstacle_pos - ship_pos; | |||
if ship_to_target * ship_to_obstacle < 0.0 { | |||
@@ -235,31 +239,32 @@ impl Processor<'_> { | |||
let len_sqr = ship_to_obstacle.length_sqr(); | |||
if len_sqr < dist_sqr { | |||
dist_sqr = len_sqr; | |||
ship.obstacle = ShipObstacle::Known(e); | |||
ship.set_obstacle(ShipObstacle::Known(e)); | |||
} | |||
} | |||
if let ShipObstacle::Known(e) = ship.obstacle { | |||
if e == fleet_owned.owner { | |||
ship.obstacle = ShipObstacle::Done; | |||
if let ShipObstacle::Known(e) = ship.obstacle() { | |||
if e == fleet_owned.owner() { | |||
ship.set_obstacle(ShipObstacle::Done); | |||
} | |||
} | |||
} | |||
/* check the obstacle */ | |||
let mut expected_dir = ship_to_target; | |||
if let ShipObstacle::Known(obstacle) = ship.obstacle { | |||
if let ShipObstacle::Known(obstacle) = ship.obstacle() { | |||
let obstacle_pos = self.positions.get(obstacle).unwrap(); | |||
let obstacle_orbit = self.orbits.get(obstacle).unwrap(); | |||
let ship_to_obstacle = obstacle_pos.pos - ship_pos; | |||
let ship_to_obstacle = obstacle_pos.pos() - ship_pos; | |||
let orbit_min = obstacle_orbit.min(); | |||
let orbit_max = obstacle_orbit.max(); | |||
let orbit = ship_to_obstacle.length(); | |||
if orbit < obstacle_orbit.max { | |||
let orbit_min = obstacle_orbit.min; | |||
let orbit_max = obstacle_orbit.max; | |||
if orbit < orbit_max { | |||
let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x); | |||
let radius = obstacle_pos.shape.radius(); | |||
let radius = obstacle_pos.shape().radius(); | |||
let mut adjust_low = linear_step(orbit_min, radius, orbit); | |||
let adjust_high = 1.0 - linear_step(orbit_max, orbit_min, orbit); | |||
@@ -277,17 +282,13 @@ impl Processor<'_> { | |||
} | |||
/* update ship direction */ | |||
let angle = expected_dir.angle2(&velocity.dir); | |||
let angle = expected_dir.angle2(&velocity.dir()); | |||
if angle.into_inner().abs() > 0.0001 { | |||
let dir = angle.into_inner() / angle.abs().into_inner(); | |||
let agility = if ship_in_orbit { | |||
SHIP_ORBIT_AGILITY | |||
} else { | |||
ship.agility | |||
}; | |||
let agility = SHIP_ORBIT_AGILITY; | |||
let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner()); | |||
velocity.dir = Matrix3f::rotate(rot_speed * -dir * self.delta).transform(velocity.dir); | |||
*velocity.dir_mut() *= Matrix3f::rotate(rot_speed * -dir * self.delta); | |||
} | |||
} | |||
} |