Каким образом можно сделать обработку коллизий более плавной?

Вот минимальный пример кода: 

```rust
fn resolve_circle_circle_collision(circle1: &mut Circle, circle2: &mut Circle) {
    let direction = circle1.pos - circle2.pos; // Вектор направления
    let min_distance = circle1.radius + circle2.radius; // Минимальная дистанция (сумма радиусов)
    let distance = circle1.pos.distance(circle2.pos); // Текущая дистанция между центрами

    if distance < min_distance && distance > 0.0 { // Проверяем, меньше ли текущая дистанция минимальной
        let overlap = min_distance - distance; // Вычисляем пересечение, чтобы избежать дёрганий при коллизии
        let displacement = direction.normalize_or_zero() * overlap / 2.; // Определяем величину смещения по направлению

        circle1.pos += displacement * get_frame_time(); // Плавное движение с учётом времени кадра
    }
}
```

Суть в том, что вектор направления, умноженный на время кадра, даёт необходимый эффект: 
```rust
displacement * get_frame_time()
```

Тем не менее, если добавить движение за мышью в уравнение: 
```rust
circle1.pos += direction * circle1.velocity * get_frame_time();
```
то возникает проблема. Я не могу решить её, хотя в оригинале у меня присутствует фактор интерполяции в диапазоне [0; 1], который увеличивается на N * время кадра. В итоге получается 
```rust
displacement * factor
```
— это работает, но не идеально. 

Я подозреваю, что мои недостаточные знания мешают мне увидеть очевидное решение этой проблемы, если оно существует. 

P.S.: Если нужно, могу записать видео; дайте знать в комментариях.
  • 14 января 2025 г. 8:03
Ответы на вопрос 2
Для достижения более плавной обработки коллизий в вашей системе, можно использовать несколько подходов, чтобы избежать дёрганий при столкновении и обеспечивать более естественное взаимодействие объектов. Вот несколько идей, которые могут помочь:

### 1. Использование временной интерполяции

Если у вас есть фактор интерполяции, вы можете основывать позицию коллизий на предыдущем кадре по сравнению с текущим, что позволит добиться более плавного движения. Вместо того, чтобы непосредственно двигать объект, вы могли бы рассмотреть возможность использования вспомогательной переменной для хранения промежуточного состояния:

```rust
let previous_pos_circle1 = circle1.pos;
circle1.pos += direction * circle1.velocity * get_frame_time();
```

Затем вы можете использовать `previous_pos_circle1` для расчета смещения и интерполировать к конечной позиции.

### 2. Векторное сглаживание

Использование векторного сглаживания позволяет вам "прижимать" объекты друг к другу, если они пересекаются. Вместо того чтобы сразу перемещать их на смещение, можно применять сглаживание:

```rust
let smoothing_factor = 0.5; // Регулируйте по необходимости
let displacement = direction.normalize_or_zero() * (overlap * smoothing_factor);

circle1.pos += displacement * get_frame_time();
circle2.pos -= displacement * get_frame_time();
```

Этот метод позволяет занижать смещение и сильно уменьшает риск "заедания" объектов.

### 3. Учет времени и скорости

Если нужно учитывать скорость и динамичное взаимодействие, вы можете применять метод, который расчёт нового положения объекта нагружает не только смещением, но и текущей скоростью:

```rust
let movement = direction * circle1.velocity * get_frame_time();
let displacement = (movement + direction.normalize_or_zero() * (overlap / 2.0)) * factor;

circle1.pos += displacement;
```

Здесь вы комбинируете движение от физики и смещение из-за коллизии, но учитываете скоростной вектор.

### 4. Устойчивые приоритеты

Если у вас много объектов, вы можете ввести приоритеты столкновения, ожидая, что если один из объектов имеет худшую скорость, он будет двигаться меньшим смещением. Тогда вы можете смягчить силу перемещения для разных объектов на основе их скорости:

```rust
let factor = if circle1.velocity.length() > circle2.velocity.length() {
    0.5
} else {
    1.0
};
```

### 5. Использование разрешающих векторов

Если вы получите больше информации о "пройдённом расстоянии" и векторы столкновения выстраиваются с учётом предыдущего состояния, метод разрешающих векторов реализуется более гладко. Это может помочь более точно смоделировать, как объекты реагируют друг на друга.

Постарайтесь комбинировать эти методы, чтобы достичь наилучшего результата, и поэкспериментируйте с факторами, чтобы лучше скомпоновать ваши объекты.
Что-то я пока не могу понять в целом вашей логики моделирования. Если вы обрабатываете коллизии, то где обработка движений? Где обработка скоростей? Почему коллизия приводит к изменению сразу позиции, а не velocity? Столкновение должно поменять вектора velocity у столкнувшихся кругов, а уже логика моделирования движения должна менять позицию для каждого кадра. Тогда и движение за мышью можно будет выразить просто как воздействие внешней силы ("магнитится" к мыши), т.е. как некоторый вектор ускорения, т.е. как некоторую дельту к velocity на каждом интервале моделирования.
Похожие вопросы