use log::debug;
use nalgebra::{vector, Vector2};
use rapier2d_f64::prelude::{
ColliderBuilder, ColliderSet, RigidBodyBuilder, RigidBodyHandle, RigidBodySet,
};
use starkingdoms_protocol::planet::PlanetType;
use std::collections::HashMap;
use crate::entity::{get_entity_id, Entities, Entity, EntityId};
use crate::orbit::constants::{
EARTH_MASS, EARTH_RADIUS, MOON_APOAPSIS, MOON_MASS, MOON_PERIAPSIS, MOON_RADIUS,
};
use crate::orbit::orbit::{calculate_point_on_orbit, calculate_world_position_of_orbit};
use crate::{manager::ClientHandlerMessage, SCALE};
pub const GRAVITY: f64 = 0.02;
#[derive(Clone, Debug)]
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: HashMap<String, Planet>,
}
impl Planets {
pub fn get_planet(&self, planet_id: &str) -> Option<&Planet> {
self.planets.get(planet_id)
}
pub fn get_planet_mut(&mut self, planet_id: &str) -> Option<&mut Planet> {
self.planets.get_mut(planet_id)
}
pub async fn make_planet(
_planet_id: &str,
planet_type: PlanetType,
mass: f64,
radius: f64,
position: (f64, f64),
rigid_body_set: &mut RigidBodySet,
collider_set: &mut ColliderSet,
) -> (EntityId, Entity) {
let collider = ColliderBuilder::ball(radius / SCALE).build();
let body = RigidBodyBuilder::kinematic_position_based()
.translation(vector![position.0 / SCALE, position.1 / SCALE])
.dominance_group(127)
.additional_mass(0.0);
let body_handle = rigid_body_set.insert(body);
collider_set.insert_with_parent(collider, body_handle, rigid_body_set);
let entity_id = get_entity_id();
(
entity_id,
Entity::Planet(Planet {
planet_type,
body_handle,
position: (position.0 / SCALE, position.1 / SCALE),
radius: radius / SCALE,
mass,
}),
)
}
pub async fn create_planets(
rigid_body_set: &mut RigidBodySet,
collider_set: &mut ColliderSet,
entities: &mut Entities,
) -> Vec<EntityId> {
let mut planet_ids: Vec<EntityId> = Vec::new();
let (earth_id, entity) = Planets::make_planet(
"earth",
PlanetType::Earth,
EARTH_MASS,
EARTH_RADIUS,
(100.0, 100.0),
rigid_body_set,
collider_set,
)
.await;
entities.insert(earth_id, entity);
planet_ids.push(earth_id);
let moon_start_point;
if let Entity::Planet(earth) = entities.get(&earth_id).unwrap() {
moon_start_point = calculate_world_position_of_orbit(
calculate_point_on_orbit(MOON_PERIAPSIS, MOON_APOAPSIS, 0.0),
vector![earth.position.0, earth.position.1],
);
} else {
moon_start_point = vector![0., 0.];
}
let (moon_id, moon) = Planets::make_planet(
"moon",
PlanetType::Moon,
MOON_MASS,
MOON_RADIUS,
(moon_start_point[0], moon_start_point[1]),
rigid_body_set,
collider_set,
)
.await;
entities.insert(moon_id, moon);
planet_ids.push(moon_id);
planet_ids
}
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,
y: planet.position.1 * SCALE,
radius: planet.radius * SCALE, // DO NOT * SCALE - THIS VALUE IS NOT SCALED! YES IT IS
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)
}
}