I'm using macroquad.
Here is a minimal example:
use macroquad::prelude::*;
use macroquad::rand::{gen_range};
fn resolve_circle_circle_collision(circle1: &mut Circle, circle2: &mut Circle) {
let direction = circle1.pos - circle2.pos; // Direction vector
let min_distance = circle1.radius + circle2.radius; // Minimum distance (sum of radii)
let distance = circle1.pos.distance(circle2.pos); // Current distance between centers
if distance < min_distance && distance > 0.0 { // Check if the current distance is less than the minimum distance
let overlap = min_distance - distance; // Calculate intersection, solves the problem of jerking during collision
let displacement = direction.normalize_or_zero() * overlap / 2.; // Calculate how much to move in the direction
circle1.pos += displacement * get_frame_time(); // Move smoothly because frame time is used
}
}
In essence, the direction vector multiplied by the frame time gives the desired effect:
displacement * get_frame_time()
However, if you add mouse movement to the equation:
circle1.pos += direction * circle1.velocity * get_frame_time();
Then everything breaks, I don't know what to do with it anymore.. In the original, I added an interpolation factor in the range [0; 1] which increases by N * frame time.
And it turns out displacement * factor
- it works, but not ideal. Apparently my gaps in knowledge do not allow me to see an obvious solution to the problem, if there is one. P.S.: I can record a video if needed
Full example:
fn resolve_circle_circle_collision(circle1: &mut Circle, circle2: &mut Circle) {
let direction = circle1.pos - circle2.pos; // Direction vector
let min_distance = circle1.radius + circle2.radius; // Minimum distance (sum of radii)
let distance = circle1.pos.distance(circle2.pos); // Current distance between centers
if distance < min_distance && distance > 0.0 { // Check if the current distance is less than the minimum distance
let overlap = min_distance - distance; // Calculate intersection, solves the problem of jerking during collision
let displacement = direction.normalize_or_zero() * overlap / 2.; // Calculate how much to move in the direction
circle1.pos += displacement * get_frame_time(); // Move smoothly because frame time is used
}
}
struct Circle {
pos: Vec2,
radius: f32,
velocity: f32
}
struct Rect {
pos: Vec2,
dimensions: Vec2
}
#[macroquad::main("Collisions")]
async fn main() {
let mut camera = Camera2D {
..Camera2D::default()
};
let mut circles = vec![];
for _ in 0..20 {
circles.push(vec2(gen_range(-500., 500.), gen_range(-500., 500.)));
}
let mut player = Circle {
pos: Vec2::ZERO - 0.1,
radius: 100.,
velocity: 300.
};
let mut player2 = Circle {
pos: Vec2::ZERO,
radius: 100.,
velocity: 300.
};
let mut rect = Rect {
pos: vec2(0., 0.),
dimensions: vec2(300., 100.),
};
loop {
clear_background(WHITE);
camera.zoom = vec2(ZOOM / screen_width(), ZOOM / screen_height());
set_camera(&camera);
for c in &circles {
draw_circle(c.x, c.y, 60., RED);
}
let mouse = camera.screen_to_world(vec2(mouse_position().0, mouse_position().1));
let direction = (mouse - player.pos).normalize_or_zero();
resolve_circle_circle_collision(&mut player, &mut player2);
player.pos += direction * player.velocity * get_frame_time();
draw_rectangle(rect.pos.x, rect.pos.y, rect.dimensions.x, rect.dimensions.y, GREEN);
// draw_rectangle(player.pos.x, player.pos.y, player.dimensions.x, player.dimensions.y, GREEN);
draw_circle(player.pos.x, player.pos.y, player.radius, PURPLE);
draw_circle(player2.pos.x, player2.pos.y, player2.radius, PURPLE);
set_default_camera();
draw_text(&get_fps().to_string(), screen_width() - 50., 30.0, 30.0, BLUE);
next_frame().await;
}
}