You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL矩形碰撞检测存异常间隙 checkCollisionRect()bug排查

矩形碰撞检测物体间隙问题

问题表现

  • 自研碰撞检测系统在运行阻挡穿透逻辑时,发生碰撞的两个矩形对象间会出现无规律细小间隙,正常碰撞接触状态下两物体不应存在空隙
  • 已定位问题出在矩形碰撞处理函数checkCollisionRect()

问题复现代码

#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>

#define or ||
#define and &&
#define pCharacter "%c \n"
#define pInteger "%d \n"
#define pFloat "%f \n"
#define pDouble "%lf \n"
#define pUnsighned "%u \n"
#define pString "%s \n"

/*
format string:| input type:
      %c      | character
      %d      | digit (integer)
      %f      | float
      %lf     | double
      %u      | unsigned
      %s      | string
*/

int width=1000; //Screen width
int height=500; //Screen height
int px=200; //Player pos x
int py=100; //Player pos y
float playerSpeed=5.0;

void drawRect(int tlx,int tly,int boxWidth,int boxHeight){
 glBegin(GL_POLYGON);
 glVertex2f(tlx,tly+boxHeight); //Bottom Left
 glVertex2f(tlx,tly); //Top Left
 glVertex2f(tlx+boxWidth,tly); //Top Right
 glVertex2f(tlx+boxWidth,tly+boxHeight); //Bottom Right
 glEnd();
}

void checkCollisionRect(x1,y1,w1,h1,x2,y2,w2,h2){
 if(x1>x2+w2 or x1+w1<x2 or y1>y2+h2 or y1+h1<y2){
  glColor3f(0,1,0);
 }
 else{
  glColor3f(1,0,0);
  if(x1<x2+w2 and x1+w1>x2 and y1<y2+h2){
   py-=playerSpeed;
   printf("top\n");
  }
  if(y1+h1>y2 and y1<y2+h2 and x1<x2+w2){
   px-=playerSpeed;
   printf("left\n");
  }
  if(x1<x2+w2 and x1+w1>x2 and y1+h1>y2){
   py+=playerSpeed;
   printf("bottom\n");
  }
  if(y1+h1>y2 and y1<y2+h2 and x1+w1>x2){
   px+=playerSpeed;
   printf("right\n");
  }
 }
}
    
void drawSquare(px,py,size){
 glPointSize(size);
 glBegin(GL_POINTS);
 glVertex2i(px,py);
 glEnd();
}

void Buttons(unsigned char key,int x,int y){
 if(key=='a'){px-=playerSpeed;}     
 if(key=='d'){px+=playerSpeed;} 
 if(key=='w'){py-=playerSpeed;}
 if(key=='s'){py+=playerSpeed;}
}               
 
void display(){
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 //-----------------------Draw----------------------
 checkCollisionRect(px,py,10,10,200,200,100,100);
 drawRect(200,200,100,100); //rect
 drawRect(px,py,10,10); //player
 //-------------------------------------------------
 glutSwapBuffers();
 glutPostRedisplay();
}

void init(){
 glClearColor(0.3,0.3,0.3,0);
 gluOrtho2D(0,width,height,0);
}

void main(int argc, char** argv){ 
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
 glutInitWindowSize(width,height);
 glutCreateWindow("OpenGL");
 init();
 glutDisplayFunc(display);
 glutKeyboardFunc(Buttons);
 glutMainLoop();
}

问题根因

现有checkCollisionRect()逻辑存在三个核心错误,直接导致间隙出现:

  1. 多方向同时响应错误:只要检测到碰撞,就会同时满足多个方向的判断条件,同时触发x、y轴多个方向的位置回退,多余的位移会把物体推离接触面
  2. 修正距离不合理:不管实际碰撞穿透深度是多少,统一固定回退5像素(playerSpeed的数值),当实际穿透深度小于5像素时,多推的距离就会形成可见间隙
  3. 代码规范问题:checkCollisionRect、drawSquare两个函数的形参未声明类型,C语言默认按int处理,后续如果改用浮点坐标会直接出现计算错误

修复方法

标准AABB碰撞响应的正确逻辑是:碰撞发生后只选重叠深度最小的轴做位置修正,修正距离刚好等于该轴的重叠深度,把物体推到刚好和障碍物贴合的位置即可。
修复后的碰撞检测函数参考:

// 补全形参类型,用浮点类型避免整数截断误差
void checkCollisionRect(float x1,float y1,float w1,float h1,float x2,float y2,float w2,float h2){
    // 无碰撞情况
    if(x1>x2+w2 or x1+w1<x2 or y1>y2+h2 or y1+h1<y2){
        glColor3f(0,1,0);
        return;
    }
    // 发生碰撞
    glColor3f(1,0,0);
    // 计算两个矩形的中心坐标
    float pCenterX = x1 + w1/2;
    float pCenterY = y1 + h1/2;
    float oCenterX = x2 + w2/2;
    float oCenterY = y2 + h2/2;
    // 计算x、y轴的重叠深度
    float overlapX = (w1 + w2)/2 - abs(pCenterX - oCenterX);
    float overlapY = (h1 + h2)/2 - abs(pCenterY - oCenterY);
    // 只修正重叠深度更小的轴
    if(overlapX < overlapY){
        // x轴方向修正
        if(pCenterX < oCenterX){
            px -= overlapX; // 从左侧碰撞,往左推刚好贴合
        }else{
            px += overlapX; // 从右侧碰撞,往右推刚好贴合
        }
    }else{
        // y轴方向修正
        if(pCenterY < oCenterY){
            py -= overlapY; // 从上方碰撞,往上推刚好贴合
        }else{
            py += overlapY; // 从下方碰撞,往下推刚好贴合
        }
    }
}

替换原有函数后,碰撞时物体就会刚好贴在障碍物表面,不会出现间隙,也不会出现多方向同时推物体的逻辑错误。


内容的提问来源于stack exchange,提问作者Saw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 10:06:20