球盒碰撞检测

Ball-Box Collision Detection

var canvas,cxt,h,w,mousePos;
var player= {
    x: 10,
    y: 10,
    height: 20,
    width: 20,
    color: 'black'
};

function init(){
    canvas= document.querySelector('#style');
    cxt= canvas.getContext('2d');
    h= canvas.height;
    w= canvas.width;
    createBalls(10);
    main();
}

function createBalls(c){
    ball= [];
    var i;
    for(i=0;i<c;i++){
        var k= {
            x: h/2,
            y: w/2,
            color: colorGenerate(),
            radius: 5+Math.round(30*Math.random()), 
            a: -5+Math.round(10*Math.random()),
            b: -5+Math.round(10*Math.random())
        }
        ball.push(k);
    }
}

function main(){
    cxt.clearRect(0,0,h,w);
    canvas.addEventListener('mousemove',function(evt){
        mousePos= getMousePos(canvas,evt);
    });
    createPlayer();
    draw(ball.length);
    ballAlive();
    move(ball.length);
    movePlayer();
    requestAnimationFrame(main);
}

function ballAlive(){
    cxt.save();
    cxt.font="30px Arial";
    if(ball.length==0) cxt.fillText("You Win",20,20);
    else cxt.fillText(ball.length,20,40);
    cxt.restore();
}

function getMousePos(canvas,evt){
    var rect= canvas.getBoundingClientRect();
    return{
        x: evt.clientX-rect.left,
        y: evt.clientY-rect.top
    }
}

function createPlayer(){
    cxt.save();
    cxt.translate(0,0);
    cxt.fillStyle= player.color;
    cxt.fillRect(player.x,player.y,player.height,player.width);
    cxt.restore();
}

function movePlayer(){
    if(mousePos !== undefined){
        player.x= mousePos.x;
        player.y= mousePos.y;
    }
}

function draw(d){
    var i;
    for(i=0;i<d;i++){
        cxt.save();
        cxt.translate(0,0);
        cxt.beginPath();
        cxt.fillStyle= ball[i].color;
        cxt.arc(ball[i].x,ball[i].y,ball[i].radius,0,2*Math.PI)
        cxt.fill();
        cxt.restore();
    }
}

function move(m){
    var i;
    for(i=0;i<m;i++){
        ball[i].x+= ball[i].a;
        ball[i].y+= ball[i].b;
        checkCollision(ball[i]);
        checkCollisionPlayer(ball[i],i);
    }
}

function checkCollision(n){
    if(n.x+n.radius>w){
        n.a= -n.a;
        n.x= w-n.radius;
    }
    else if(n.x-n.radius<0){
        n.a= -n.a;
        n.x= n.radius;
    }
    if(n.y+n.radius>h){
        n.b= -n.b;
        n.y= h-n.radius;
    }
    else if(n.y-n.radius<0){
        n.b= -n.b;
        n.y= n.radius;
    }
}

function checkCollisionPlayer(n,j){
    if(overlap(n.x,n.y,n.radius,player.x,player.y,player.height,player.width)){
        ball.splice(j,1);
    }
}

function overlap(cx,cy,r,px,py,ph,pw){
    var testX= cx;
    var testY= cy;
// THESE LINES ARE FOR MOVING THE BALLS TOWARDS THE PLAYER
    if(testX<px) testX=px;
    if(testX>(px+pw)) testX=px+pw;
    if(testY<py) testy=py;
    if(testY>(py+ph)) testY=py+ph;

    //DISTANCE FORMULA FOR CHECKING THE OVERLAPING BETWEEN THE BOX AND CIRCLE
    return((cx-px)*(cx-px)+(cy-py)*(cy-py)<r*r);
}

function colorGenerate(){
    var col= ['green','blue','pink','red','brown','yellow','black','orange','grey','golden'];
    var i= Math.round((col.length-1)*Math.random());  //RETURN VALUES FROM 0 TO 9
    return col[i];
}
 #style{
    border: 4px dotted green;
 }
<!DOCTYPE html>
<html lang= 'en-us'>
    <head>
        <title>Feed The Monster</title>
 
    </head>
    <body onload= 'init();'>
        <canvas id= 'style' height= '400' width= '400'>
            Your browser does not support canvas...
        </canvas>
    </body>
</html>

一旦玩家(盒子)和球之间发生第一次碰撞,我的代码就会出错。 唯一出错的部分是 splice() 函数。如果我评论 splice() 函数,那么代码不会显示任何错误。 但是,如果我在我的代码中使用 splice() 函数部分,那么它会在移动函数中显示错误,我不知道为什么会这样。 请帮助我...

这似乎与 move 函数中的循环有关。您使用代表 ball 数组长度的参数 m 来调用它 - 但是如果发生碰撞,在其中调用的函数 checkCollisionPlayer 可以从数组中移除一个球。这意味着数组现在更短了,所以每当您稍后在循环中尝试访问 ball[m-1] 上的 属性 时,您都会收到此错误。

我相信有很多不同的方法可以解决这个问题。我能想到的最简单的方法(我已经成功地将其用于制作浏览器游戏)是,不是在碰撞时直接从数组中删除球,而是在它们上设置 属性 以将它们标记为 "deleted".然后在循环的末尾添加一个 "cleanup" 函数,以将数组过滤为仅包含未标记为已删除的数组。这可确保您循环的每个对象都实际存在,同时仍会动态更改长度以反映游戏状态。

var canvas,cxt,h,w,mousePos;
var player= {
    x: 10,
    y: 10,
    height: 20,
    width: 20,
    color: 'black'
};

function init(){
    canvas= document.querySelector('#style');
    cxt= canvas.getContext('2d');
    h= canvas.height;
    w= canvas.width;
    createBalls(10);
    main();
}

function createBalls(c){
    ball= [];
    var i;
    for(i=0;i<c;i++){
        var k= {
            x: h/2,
            y: w/2,
            color: colorGenerate(),
            radius: 5+Math.round(30*Math.random()), 
            a: -5+Math.round(10*Math.random()),
            b: -5+Math.round(10*Math.random())
        }
        ball.push(k);
    }
}

function main(){
    cxt.clearRect(0,0,h,w);
    canvas.addEventListener('mousemove',function(evt){
        mousePos= getMousePos(canvas,evt);
    });
    createPlayer();
    draw(ball.length);
    ballAlive();
    move(ball);
    movePlayer();
    requestAnimationFrame(main);
}

function ballAlive(){
    cxt.save();
    cxt.font="30px Arial";
    if(ball.length==0) cxt.fillText("You Win",20,20);
    else cxt.fillText(ball.length,20,40);
    cxt.restore();
}

function getMousePos(canvas,evt){
    var rect= canvas.getBoundingClientRect();
    return{
        x: evt.clientX-rect.left,
        y: evt.clientY-rect.top
    }
}

function createPlayer(){
    cxt.save();
    cxt.translate(0,0);
    cxt.fillStyle= player.color;
    cxt.fillRect(player.x,player.y,player.height,player.width);
    cxt.restore();
}

function movePlayer(){
    if(mousePos !== undefined){
        player.x= mousePos.x;
        player.y= mousePos.y;
    }
}

function draw(d){
    var i;
    for(i=0;i<d;i++){
        cxt.save();
        cxt.translate(0,0);
        cxt.beginPath();
        cxt.fillStyle= ball[i].color;
        cxt.arc(ball[i].x,ball[i].y,ball[i].radius,0,2*Math.PI)
        cxt.fill();
        cxt.restore();
    }
}

function move(m){
    var i;
    for(i=0;i<m.length;i++){
        ball[i].x+= ball[i].a;
        ball[i].y+= ball[i].b;
        checkCollision(ball[i]);
        checkCollisionPlayer(ball[i],i);
    }
}

function checkCollision(n){
    if(n.x+n.radius>w){
        n.a= -n.a;
        n.x= w-n.radius;
    }
    else if(n.x-n.radius<0){
        n.a= -n.a;
        n.x= n.radius;
    }
    if(n.y+n.radius>h){
        n.b= -n.b;
        n.y= h-n.radius;
    }
    else if(n.y-n.radius<0){
        n.b= -n.b;
        n.y= n.radius;
    }
}

function checkCollisionPlayer(n,j){
    if(overlap(n.x,n.y,n.radius,player.x,player.y,player.height,player.width)){
        ball.splice(j,1);
    }
}

function overlap(cx,cy,r,px,py,ph,pw){
    var testX= cx;
    var testY= cy;
// THESE LINES ARE FOR MOVING THE BALLS TOWARDS THE PLAYER
    if(testX<px) testX=px;
    if(testX>(px+pw)) testX=px+pw;
    if(testY<py) testy=py;
    if(testY>(py+ph)) testY=py+ph;

    //DISTANCE FORMULA FOR CHECKING THE OVERLAPING BETWEEN THE BOX AND CIRCLE
    return((cx-px)*(cx-px)+(cy-py)*(cy-py)<r*r);
}

function colorGenerate(){
    var col= ['green','blue','pink','red','brown','yellow','black','orange','grey','golden'];
    var i= Math.round((col.length-1)*Math.random());  //RETURN VALUES FROM 0 TO 9
    return col[i];
}
#style{
        border: 4px dotted green;
 }
<!DOCTYPE html>
<html lang= 'en-us'>
    <head>
        <title>Feed The Monster</title>
 
    </head>
    <body onload= 'init();'>
        <canvas id= 'style' height= '400' width= '400'>
            Your browser does not support canvas...
        </canvas>
    </body>
    </html>

如果您在 move() 函数中将数组作为参数而不是数组的长度传递,那么您的代码将完美运行。