use emerald::{
nalgebra::Point2, render_settings::RenderSettings, rendering::components::ColorRect, *,
};
use rapier2d::prelude::{RevoluteJointBuilder, RigidBodyType};
const RES_WIDTH: f32 = 960.0;
const RES_HEIGHT: f32 = 540.0;
struct Controller;
#[derive(Clone)]
struct Velocity {
pub dx: f32,
pub dy: f32,
}
pub fn main() {
let mut settings = GameSettings::default();
let render_settings = RenderSettings {
resolution: (RES_WIDTH as u32, RES_HEIGHT as u32),
..Default::default()
};
settings.render_settings = render_settings;
emerald::start(
Box::new(PhysicsJointsExample {
world: World::new(),
}),
settings,
)
}
pub struct PhysicsJointsExample {
world: World,
}
impl PhysicsJointsExample {}
impl Game for PhysicsJointsExample {
fn initialize(&mut self, mut emd: Emerald) {
self.world.physics().set_gravity(Vector2::new(0.0, -9.8));
let mut body_handles = Vec::new();
let numk = 1;
let numi = 10;
let shift = 15.0;
for k in 0..numk {
for i in 0..numi {
let fk = k as f32;
let fi = i as f32;
let status = if i == 0 && k == 0 {
RigidBodyType::Dynamic
} else {
RigidBodyType::Dynamic
};
let (entity, child_handle) = self
.world
.spawn_with_body(
(
Transform::from_translation((fk * shift, -fi * shift)),
ColorRect::new(WHITE, 10, 10),
),
RigidBodyBuilder::new(status),
)
.unwrap();
if i == 0 && k == 0 {
self.world
.insert(entity, (Controller {}, Velocity { dx: 0.0, dy: 0.0 }))
.ok();
}
self.world
.physics()
.build_collider(child_handle, ColliderBuilder::ball(0.4));
if i > 0 {
let parent_handle = *body_handles.last().unwrap();
let joint = RevoluteJointBuilder::new().local_anchor2(Point2::new(0.0, shift));
self.world
.physics()
.build_joint(parent_handle, child_handle, joint, true);
}
if k > 0 {
let parent_index = body_handles.len() - numi;
let parent_handle = body_handles[parent_index];
let joint = RevoluteJointBuilder::new().local_anchor2(Point2::new(-shift, 0.0));
self.world
.physics()
.build_joint(parent_handle, child_handle, joint, true);
}
body_handles.push(child_handle);
}
}
}
fn update(&mut self, mut emd: Emerald) {
let delta = emd.delta();
let mouse = emd.input().mouse();
let mouse_translation = screen_translation_to_world_translation(
(RES_WIDTH as u32, RES_HEIGHT as u32),
&mouse.translation,
&mut self.world,
);
let speed = 10.0;
for (_, (velocity, transform)) in self
.world
.query::<(&mut Velocity, &mut Transform)>()
.with::<&Controller>()
.iter()
{
let diff = mouse_translation - transform.translation;
velocity.dx = diff.x * speed;
velocity.dy = diff.y * speed;
}
velocity_system(&mut self.world, delta).unwrap();
self.world.physics().step(delta);
}
fn draw(&mut self, mut emd: Emerald) {
emd.graphics().begin().unwrap();
emd.graphics().draw_world(&mut self.world).unwrap();
emd.graphics().render().unwrap();
}
}
fn velocity_system(world: &mut World, delta: f32) -> Result<(), EmeraldError> {
let mut velocity_updates = Vec::new();
for (id, (velocity, body, pos)) in world
.query::<(&Velocity, &RigidBodyHandle, &Transform)>()
.iter()
{
velocity_updates.push((id, velocity.clone(), body.clone(), pos.clone()));
}
let mut kinematic_updates = Vec::new();
for update in velocity_updates {
let id = update.0;
let velocity = update.1;
let body_handle = update.2;
let pos = update.3;
if let Some(body) = world.physics().rigid_body_mut(body_handle) {
if body.is_kinematic() {
kinematic_updates.push((id, velocity.clone(), pos));
}
if body.is_dynamic() {
body.set_linvel(Vector2::new(velocity.dx, velocity.dy), true);
}
}
}
for (id, velocity, _pos) in kinematic_updates {
if let Ok(mut transform) = world.get::<&mut Transform>(id.clone()) {
transform.translation.x += velocity.dx * delta;
transform.translation.y += velocity.dy * delta;
}
}
Ok(())
}