use nalgebra::{Vector2, vector};
use rapier2d_f64::prelude::{RigidBodyHandle, RigidBodySet, ColliderBuilder, RigidBodyBuilder, ColliderSet};
use starkingdoms_protocol::planet::PlanetType;
use crate::{SCALE, manager::ClientHandlerMessage};
//const GRAVITY: f64 = 0.001;
const GRAVITY: f64 = 0.00006674;
#[derive(Clone)]
pub struct Planet {
pub planet_type: PlanetType,
pub body_handle: RigidBodyHandle,
pub position: (f64, f64),
pub radius: f64,
pub mass: f64
}
impl Planet {
pub fn gravity(&self, position: (f64, f64), mass: f64) -> (f64, f64) {
let distance = ((position.0 - self.position.0).powi(2) + (position.1 - self.position.1).powi(2)).sqrt();
let force = GRAVITY * ((self.mass * mass) / distance * distance);
let mut direction = Vector2::new(self.position.0 - position.0, self.position.1 - position.1);
direction.set_magnitude(force);
(direction.x, direction.y)
}
}
#[derive(Default, Clone)]
pub struct Planets {
pub planets: Vec<Planet>,
}
impl Planets {
pub fn make_planet(planets: &mut Vec<Planet>, planet_type: PlanetType, mass: f64, radius: f64, position: (f64, f64), rigid_body_set: &mut RigidBodySet, collider_set: &mut ColliderSet) {
let collider = ColliderBuilder::ball(radius / SCALE)
.build();
let body = RigidBodyBuilder::fixed()
.translation(vector![position.0, position.1])
.additional_mass(0.0);
let body_handle = rigid_body_set.insert(body);
collider_set.insert_with_parent(collider, body_handle, rigid_body_set);
planets.push(Planet {
planet_type,
body_handle,
position,
radius,
mass,
});
}
pub fn new(rigid_body_set: &mut RigidBodySet, collider_set: &mut ColliderSet) -> Planets {
let mut planets = Vec::new();
Planets::make_planet(
&mut planets,
PlanetType::Earth,
2000.0,
1000.0,
(100.0, 100.0),
rigid_body_set,
collider_set,
);
Planets { planets }
}
pub fn to_protocol(&self) -> ClientHandlerMessage {
let mut planets = vec![];
for planet in self.planets.clone() {
// TODO: Adjust codegen to use f64
planets.push(starkingdoms_protocol::planet::Planet {
planet_type: planet.planet_type.into(),
x: (planet.position.0 * SCALE) as f32,
y: (planet.position.1 * SCALE) as f32,
radius: planet.radius as f32, // DO NOT * SCALE
special_fields: Default::default(),
});
}
ClientHandlerMessage::PlanetData {
planets
}
}
pub fn gravity(&self, position: (f64, f64), mass: f64) -> (f64, f64) {
let mut direction = Vector2::zeros();
for planet in self.planets.clone() {
let planet_grav = planet.gravity(position, mass);
direction.x = planet_grav.0;
direction.y = planet_grav.1;
}
(direction.x, direction.y)
}
}