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

JavaScript射线投射碰撞异常问题排查求助

穿墙射线投射碰撞异常排查求助

我正在实现穿墙射线投射功能,每条射线包含碰撞对象(objectHIT)和交点坐标(pointIntersectionXY)信息。目前已完成射线投射,但碰撞效果并非总能符合预期,反复检查代码仍未定位问题。已确认碰撞计算函数生成的listCollision中,交点坐标及其他属性均准确无误,现将相关函数代码附上,请求协助排查问题:

代码注释说明

  • listCollision[射线索引][被碰撞对象]:存储每条射线的所有碰撞点信息
  • VisaoLimitada[射线索引]:存储每条射线的起点与终点坐标
limitDistance(listCollision, visaoLimitada) {   
            
    for (let i = 0; i < this.laser; i++) {
        var distanciaV = { 
            x1: visaoLimitada[i].x1, 
            y1: visaoLimitada[i].y1, 
            x2: visaoLimitada[i].x2, 
            y2: visaoLimitada[i].y2 
        };
        
        var originDistance = this.distanceC(distanciaV.x1, distanciaV.x2, distanciaV.y1, distanciaV.y2); // 计算射线全长
    
        for (let j = 0; j < listCollision[i].length; j++) {
            var distanciaAtingida = { 
                x1: distanciaV.x1, 
                y1: distanciaV.y1, 
                x2: listCollision[i][j].x, 
                y2: listCollision[i][j].y 
            };
        
            var objectDistance = this.distanceC(distanciaAtingida.x1, distanciaAtingida.x2, distanciaAtingida.y1, distanciaAtingida.y2);
    
            if(objectDistance < originDistance){
                visaoLimitada[i] = distanciaAtingida;
                originDistance = visaoLimitada[i]; // 用于查找更近的下一个对象
            }
        }
    }
    return visaoLimitada;
}

calculateViewport(FOV){

    var intervaloX = (this.player[3].x - this.player[1].x)/this.laser;
    var intervaloY = (this.player[3].y - this.player[1].y)/(this.laser-1);
    
    // 游戏循环中先调用calculateViewport()初始化射线为直线,再传入listCollisions更新碰撞后的射线坐标
    if(FOV == null || this.isEmpty(FOV) == 1){
        for(let i = 0; i < this.laser; i++){    
            this.visao[i].x1 = this.player[1].x + 1*Math.cos(this.radians(this.aX)) + i * intervaloX;
            this.visao[i].y1 = this.player[1].y + 1*Math.sin(this.radians(this.aX)) + i * intervaloY;
            this.visao[i].x2 = this.player[1].x + this.distanceView*Math.cos(this.radians(this.aX)) + i * intervaloX;
            this.visao[i].y2 = this.player[1].y + this.distanceView*Math.sin(this.radians(this.aX)) + i * intervaloY;
        }
    }
    else{
        this.visao = this.limitDistance(FOV, this.visao);
    }
}

核心问题排查与修正建议

  1. originDistance变量更新错误
    原代码中找到更近的碰撞点后,错误地将visaoLimitada[i](坐标对象)赋值给了存储距离数值的originDistance,导致后续距离比较完全失效。修正为更新为当前碰撞点的距离值:

    if(objectDistance < originDistance){
        visaoLimitada[i] = distanciaAtingida;
        originDistance = objectDistance; // 替换为当前近点的距离值
    }
    
  2. 射线起点偏移可能引发的问题
    calculateViewport中射线起点x1/y1的计算额外添加了1*Math.cos(...)和1*Math.sin(...),如果这个1是无意义的偏移,会导致射线起点偏离玩家位置,进而影响碰撞距离计算的准确性。建议验证该偏移的必要性,若无需则移除。

  3. intervaloY分母的边界问题
    当射线数量this.laser为1时,(this.laser-1)会导致除以0的错误。建议统一分母为this.laser,或添加边界判断避免异常:

    var intervaloY = (this.player[3].y - this.player[1].y)/(this.laser > 1 ? this.laser-1 : 1);
    
  4. 碰撞点未排序的潜在隐患
    若listCollision[i]中的碰撞点未按距离从近到远排序,当前遍历逻辑虽然能找到最近点,但效率较低。建议在生成listCollision时先对每条射线的碰撞点按距离排序,减少无效比较。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 07:56:04