物理引擎中的球彼此相移

问题描述 投票:0回答:1

我正在尝试用 C++ 编写一个简单的物理引擎;到目前为止,一切进展顺利,除了球本身之间的物理作用外,所有功能都按预期工作。在碰撞过程中,球有时会互相穿过。

#include <iostream>
#include <stdio.h>
#include <raylib.h>
#include <raymath.h>
#include <stdlib.h>
#include <time.h>
#include <chrono>
#include <list>

using namespace std;

class Ball {
public:
    Vector2 position;
    Vector2 velocity;
    float radius;
    Color color;
};

void updateBall(Ball &ball, float gravity, float frictionCoefficient, float deltaTime, float screenWidth, float screenHeight, float bounciness, std::list<Ball> &balls) {

    ball.velocity.y -= gravity;

    // Apply friction if the ball is at the top or bottom of the screen
    ball.velocity.x *= (ball.position.y >= screenHeight - ball.radius || ball.position.y <= ball.radius) ? frictionCoefficient : 1;

    // Update the ball's position based on its velocity
    ball.position.x += ball.velocity.x * deltaTime;
    ball.position.y += -ball.velocity.y * deltaTime;

    // Clamp the ball's position within the screen bounds
    ball.position.x = Clamp(ball.position.x, ball.radius, screenWidth - ball.radius);
    ball.position.y = Clamp(ball.position.y, ball.radius, screenHeight - ball.radius);

    // Check for collisions with screen edges and apply bounciness
    ball.velocity.x *= (ball.position.x == ball.radius || ball.position.x == screenWidth - ball.radius) ? -bounciness : 1;
    ball.velocity.y *= (ball.position.y == ball.radius || ball.position.y == screenHeight - ball.radius) ? -bounciness : 1;

    for (auto &otherBall : balls) {
        // Avoid checking the ball against itself
        if (&otherBall == &ball) {
            continue;
        }

        // Calculate the distance between the two balls
        float distance = Vector2Distance(ball.position, otherBall.position);

        // Check if a collision has occurred
        if (distance < (ball.radius + otherBall.radius)) {
            ball.velocity.x = -(ball.velocity.x);
            otherBall.velocity.x = -(otherBall.velocity.x);
            ball.velocity.y = -(ball.velocity.y);
            otherBall.velocity.y = -(otherBall.velocity.y);
        }
    }
}

Ball newBall(Vector2 position, Vector2 velocity, float radius, Color color) {
    Ball tempBall;
    tempBall.position = position;
    tempBall.velocity = velocity;
    tempBall.radius = radius;
    tempBall.color = color;
    return tempBall;
}

int main() {
    SetConfigFlags(FLAG_WINDOW_RESIZABLE);

    int screenWidth = 900;
    int screenHeight = 900;

    InitWindow(screenWidth, screenHeight, "cppPhysics");
    SetTargetFPS(120);

    const float gravity = 9.81f;
    const float frictionCoefficient = 0.981f;
    const float bounciness = 0.7f;

    Ball ballOne = newBall({100, 100}, {400, -450}, 60, WHITE);
    Ball ballTwo = newBall({50, 200}, {400, 450}, 45, BLUE);
    Ball ballThree = newBall({200, 50}, {300, -450}, 20, YELLOW);

    std::list<Ball> balls;
    balls.push_back(ballOne);
    balls.push_back(ballTwo);
    balls.push_back(ballThree);

    while (!WindowShouldClose()) {
        if (IsWindowResized()) {
            screenWidth = GetScreenWidth();
            screenHeight = GetScreenHeight();
        }
        float deltaTime = GetFrameTime();

        for (auto &ball : balls) {
            updateBall(ball, gravity, frictionCoefficient, deltaTime, screenWidth, screenHeight, bounciness, balls);
        }

        if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
            for (auto &ball : balls) {
                ball.velocity.y += 500;
                ball.velocity.x += 500;
            }
        }

        BeginDrawing();
        ClearBackground(BLACK);

        for (auto &ball : balls) {
            DrawCircleV(ball.position, ball.radius, ball.color);
        }

        EndDrawing();
    }

    CloseWindow();
    return 0;
}

注意:这里的代码被缩短了;我正在制作的实际程序使用鼠标点击和颜色值的随机值。

最理想的情况是,它们会彼此弹开(有点像它们离开地面的方式)。我已经尝试将代码移动到函数的开头,并在检测到碰撞时使函数中断。

c++ 2d physics raylib
1个回答
0
投票

你有量子跳跃球:

float deltaTime = GetFrameTime();
updateBall(ball, gravity, frictionCoefficient, deltaTime, screenWidth, screenHeight, bounciness, balls);

ball.position.x += ball.velocity.x * deltaTime;
ball.position.y += -ball.velocity.y * deltaTime;

在深入研究之前,您应该强烈考虑切换到固定增量物理:

accumulatedDelta += GetFrameTime(); // accumulatedDelta is a member value
while(accumulatedDelta > someConstant)
{
    updateBall(ball, gravity, frictionCoefficient, someConstant, screenWidth, screenHeight, bounciness, balls);  
    accumulatedDelta -= someConstant;
}

这会让你摆脱大部分的阶段性。它将使你的物理不再依赖于帧持续时间,如果你进入多人游戏,你的同步和决定论将使我更容易处理。

© www.soinside.com 2019 - 2024. All rights reserved.