Search code examples
c++game-physicsvelocity

Pool Game physics velocity calculation issue


Hi I am making a 3d pool game and I am currently at the state of applying collisions, I am using openGL and C++. I already have the collision written and it is working properly. The issue I have is related only to the velocity of the ball class and passing forces to other balls on collision.

I have a ball class that is used for all the balls including the cue ball. I have a drawBall() function:

void drawBall(Shader ourShader) {
    extern GLfloat deltaTime;
    a = F / radius;
    v = v + (a * deltaTime);
    ballPos = ballPos + (v*deltaTime) + (0.5f*a*deltaTime*deltaTime);
    collision();

    //F = glm::vec3(0.0f, 0.0f, 0.0f);
//ACTUAL DRAWING
    glBindVertexArray(VAO);
        glm::mat4 model;

        model = glm::translate(model, ballPos);
        model = glm::rotate(model, glm::radians(40.0f), glm::vec3(1.0f, 0.0f, 0.0f));
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

And a collision function:

void collision()  {
    extern vector <Ball> ballCollection;
    for (int i = 0; i < ballCollection.size(); i++) {
        if (glm::distance(ballCollection.at(i).ballPos, ballPos) <= (2 * radius)) {
            if (!glm::distance(ballCollection.at(i).ballPos, ballPos) == 0) {
                extern GLfloat forceAmount;
                if (isColliding == 0) {
                    glm::vec3 collPoint = glm::vec3((ballPos.x + ballCollection.at(i).ballPos.x) / 2, 0.0f, (ballPos.z + ballCollection.at(i).ballPos.z) / 2);
                    glm::vec3 collPointPerp = collPoint - ballPos;

                    glm::vec3 otherNew = collPointPerp;
                    glm::vec3 thisNew = glm::cross(collPointPerp, glm::vec3(0.0, 1.0, 0.0));

                    F = thisNew;
                    ballCollection.at(i).F = otherNew;

                    glm::vec3 newV;
                    glm::vec3 otherNewV;

                    newV.x = (v.x * (2 * ballCollection.at(i).radius * ballCollection.at(i).v.x)) / (radius + ballCollection.at(i).radius);
                    newV.z = (v.z * (2 * ballCollection.at(i).radius * ballCollection.at(i).v.z)) / (radius + ballCollection.at(i).radius);
                    newV.y = 0.0f;

                    otherNewV.x = (ballCollection.at(i).v.x * (2 * radius * v.x)) / (radius + ballCollection.at(i).radius);
                    otherNewV.z = (ballCollection.at(i).v.z * (2 * radius * v.z)) / (radius + ballCollection.at(i).radius);
                    otherNewV.y = 0.0f;



                    v.x = newV.x;
                    v.z = newV.z;

                    ballCollection.at(i).v.x = otherNewV.x;
                    ballCollection.at(i).v.z = otherNewV.z;



                }
                isColliding = 1;
                ballCollection.at(i).isColliding = 1;
            }
        }
    }
    isColliding = 0;

This calss is in a separate file, in my main cpp. This has a key_kallback function:

void do_movement()
{
glm::vec3  cameraRight = glm::normalize(glm::cross(cameraFront, cameraUp));
GLfloat cameraSpeed = 50.0f;

glm::vec3 aboveBall = glm::vec3(ballCollection.at(15).ballPos.x, ballCollection.at(15).ballPos.y + 20.0f, ballCollection.at(15).ballPos.z);
glm::vec3 cameraFwd = aboveBall - cameraPos;

//cout << cameraFwd.x << "," << cameraFwd.y << "," << cameraFwd.z << endl;
if (keys[GLFW_KEY_W])
    ballCollection.at(15).ballPos = ballCollection.at(15).ballPos + glm::vec3(0.0f, 0.0f, -0.1f);
if (keys[GLFW_KEY_S])
    ballCollection.at(15).ballPos = ballCollection.at(15).ballPos + glm::vec3(0.0f, 0.0f, 0.1f);
if (keys[GLFW_KEY_A])
    ballCollection.at(15).ballPos = ballCollection.at(15).ballPos + glm::vec3(-0.1f, 0.0f, 0.0f);
if (keys[GLFW_KEY_D])
    ballCollection.at(15).ballPos = ballCollection.at(15).ballPos + glm::vec3(0.1f, 0.0f, 0.0f);
if (keys[GLFW_KEY_SPACE]) {
    ballCollection.at(15).F = 10.0f*glm::normalize(cameraFwd);
}
if (keys[GLFW_KEY_E]) {
    ballCollection.at(15).F = -10.0f * glm::normalize(cameraFwd);
}

}

And then within the game loop:

        for (int i = 0; i < 16; i++) {

            ballCollection.at(i).drawBall(ourShader);
        }
        cameraPos = ballCollection.at(15).ballPos + glm::vec3(0.0f, 20.0f, 20.0f);
        do_movement();

My problem is that when I apply the force to the cue ball with space, since the F value keeps adding to v, my cue ball speed increases every frame. If I put F back to 0 after applying the force, I can't pass force to other balls, therefore their v is 0 and they don't move after collision.

Any help would be very appreciated, please comment if I there is extra information needed.

EDIT

I realized that I had an error in the collision calculation, it should be:

newV.x = (v.x + (2 * ballCollection.at(i).radius * ballCollection.at(i).v.x)) / (radius + ballCollection.at(i).radius);
newV.z = (v.z + (2 * ballCollection.at(i).radius * ballCollection.at(i).v.z)) / (radius + ballCollection.at(i).radius);
newV.y = 0.0f;

otherNewV.x = (ballCollection.at(i).v.x + (2 * radius * v.x)) / (radius + ballCollection.at(i).radius);
otherNewV.z = (ballCollection.at(i).v.z + (2 * radius * v.z)) / (radius + ballCollection.at(i).radius);
otherNewV.y = 0.0f;

Now, if I make F back to zero in the class after calculations, the ball moves with constant velocity which is fine for now. My issue now is that sometimes the collision works, sometimes the balls fly away, sometimes hitting the first ball is fine but if the second ball hits another one then its wrong again. I think this happens because they keep colliding and calculating their speed wrong, but I can't figure out how to set up a boolean to collide only once, anyone have any idea?

EDIT I managed to set up the boolean correctly now.


Solution

  • On collision, the force that should be applied to the other ball is the magnitude of the velocity vector. So if you pass in sqrt(v.x*v.x+v.y*v.y+v.z*v.z) as the initial force of the collision and set F to zero after applying the force like you stated, you should get the results you desire.