简体   繁体   中英

Circle vs Square Collision Detection AND NEED TO RESPONSE in C++ | OpenGL. My problem just this “I need to keep the circle outside the square”

I am working on a 2D Circle vs Square Collision Detection. I did the test of collision detection between circle and square, It's ok, there is no problem with collision detection, just I need to keep the circle outside of the square when circle touch to the square. I want that the circle does not enter into the square, and the circle must stay outside of the square? How can I do that? How can I keep circle outside of the square?

Picture01 My problem just this "I just need to keep the circle outside of the square when they are touching each other" I made this collision detection test looking at this site => http://jeffreythompson.org/collision-detection/circle-rect.php , but in this tutorial there is not a response of the collision detetcion

Please explain to me writing as a code

Code:

#include "shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include<vector>
#include<cmath>
#include <math.h>
using namespace std;

GLfloat blueSquareWidth = 0.3f, blueSquareHeight = 0.2f;
std::vector<glm::vec3>      vertices;

float x, y, z, r = 0.1f;
int num_segments = 48;

void DrawCircle()
{
  for (int i = 0; i < num_segments; i++)
 {
     float theta = 2.0f * 3.1415926f * float(i) / float(num_segments);
     //get the current angle
     x = r * cosf(theta);
     y = r * sinf(theta);
     z = 0.0f;

     vertices.push_back(glm::vec3(x, y, z));
    } 
}

  GLfloat blueSquareVertices[] =
  {
    0.0f, blueSquareHeight, 0.0f,
    0.0f, 0.0f, 1.0f,

    0.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f,

    blueSquareWidth, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f,

    blueSquareWidth, blueSquareHeight, 0.0f,
    0.0f, 0.0f, 1.0f
 };

GLuint blueSqaureIndices[] =
{
 0, 1, 2,
 0, 2, 3
};

GLfloat rotationTime = 0.0f;

GLuint vbo[2], vao[2], ibo[2];

glm::vec3 blueSquarePosition(0.3f, 0.0f, 0.0f);
glm::vec3 spherePosition(0.660001f, 0.28f, 0.0f);

void inputKeys(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_TRUE)
{
    glfwSetWindowShouldClose(window, true);
}

if (glfwGetKey(window, GLFW_KEY_W) == GLFW_TRUE)
{
    blueSquarePosition.y += 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_TRUE)
{
    blueSquarePosition.y -= 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_TRUE)
{
    blueSquarePosition.x -= 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_TRUE)
{
    blueSquarePosition.x += 0.001f;
}

if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_TRUE)
{
    spherePosition.y += 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_TRUE)
{
    spherePosition.y -= 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_TRUE)
{
    spherePosition.x -= 0.001f;
}
else if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_TRUE)
{
    spherePosition.x += 0.001f;
  }
}

bool circleRect(GLFWwindow* window) 
{
// temporary variables to set edges for testing
float testX = spherePosition.x;
float testY = spherePosition.y;

// which edge is closest?
if (spherePosition.x < blueSquarePosition.x)         
{
    testX = blueSquarePosition.x;      // test left edge
}
else if (spherePosition.x > blueSquarePosition.x + blueSquareWidth) 
{
    testX = blueSquarePosition.x + blueSquareWidth;   // right edge
}

if (spherePosition.y < blueSquarePosition.y)         
{
    testY = blueSquarePosition.y;      // top edge
}
else if (spherePosition.y > blueSquarePosition.y + blueSquareHeight) 
{
    testY = blueSquarePosition.y + blueSquareHeight;   // bottom edge
}

// get distance from closest edges
float distX = spherePosition.x - testX;
float distY = spherePosition.y - testY;
float distance = sqrt((distX * distX) + (distY * distY));

// if the distance is less than the radius, collision!
if (distance<= r) 
{
    if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
    {
        // WHAT I NEED TO DO HERE
    }

    if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS)
    {
        // WHAT I NEED TO DO HERE
    }

    if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
    {
        // WHAT I NEED TO DO HERE
    }

    if (glfwGetKey(window, GLFW_KEY_BOTTOM) == GLFW_PRESS)
    {
        // WHAT I NEED TO DO HERE
    }

    return 1;
}

  return 0;
}



int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

GLFWwindow* window = glfwCreateWindow(800, 800, "Game Engine", NULL, 
 NULL);

if (!window)
{
    cout << "Failed to create a window" << endl;
    glfwTerminate();
    return -1;
}

glfwMakeContextCurrent(window);

if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
    cout << "Failed to initialize GLAD" << endl;
    return -1;
}

DrawCircle();

glGenBuffers(1, &vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(blueSquareVertices), blueSquareVertices, GL_STATIC_DRAW);

glGenVertexArrays(1, &vao[0]);
glBindVertexArray(vao[0]);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, 0);

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));

glGenBuffers(1, &ibo[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(blueSqaureIndices), blueSqaureIndices, GL_STATIC_DRAW);

glGenBuffers(1, &vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices.size(), &vertices[0], GL_STATIC_DRAW);

glGenVertexArrays(1, &vao[1]);
glBindVertexArray(vao[1]);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

Shader shader("vs2.glsl", "fs2.glsl");
shader.useShader();

while (!glfwWindowShouldClose(window))
{
    inputKeys(window);
    circleRect(window);

    glClearColor(0.6f, 0.8f, 0.8f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glm::mat4 blueSquareTransform(1.0f);
    blueSquareTransform = glm::translate(blueSquareTransform, 
    glm::vec3(blueSquarePosition));

    GLuint blueSquareTransformUniform = 
    glGetUniformLocation(shader.shader, "transform");
    glUniformMatrix4fv(blueSquareTransformUniform, 1, GL_FALSE, 
    glm::value_ptr(blueSquareTransform));

    glBindVertexArray(vao[0]);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glm::mat4 redSquareTransform(1.0f);
    redSquareTransform = glm::translate(redSquareTransform, 
    glm::vec3(spherePosition));


    GLuint redSquareTransformUniform = glGetUniformLocation(shader.shader, 
    "transform");
    glUniformMatrix4fv(redSquareTransformUniform, 1, GL_FALSE, 
    glm::value_ptr(redSquareTransform));

    glBindVertexArray(vao[1]);
    glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size());

    glfwSwapBuffers(window);
    glfwPollEvents();
   }
}

In order to perform collision detection and preventing penetration, you need

previous position

current position

The first issue is that at the "WHAT I NEED TO DO HERE" line, you already seem to miss the previous position. Once you have both, you need to do:

If current position collides, binary-search along the line from current to previous position where the switch occurs.

You need to be able to linear interpolate the position where 0 is previous and 1 is current.

Then, if you want to do nice, as opposed to just OK, you then compute a collision, update the direction and repeat for the remaining length.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM