canvas 碰撞检测问题?

我通过中心点距离来判断与哪个元素进行碰撞检测,现在问题是对于wall上方的碰撞检测不起效果

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <canvas id="canvas" width="500" height="500"></canvas>
</body>
<script>
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext('2d');

    var hero = {
        height: 50,
        width: 30,
        x: 10,
        y: 10,
        speed: 150,
    }

    var wall = [
        {
            height: 100,
            width: 200,
            x: 100,
            y: 100,
        },
        {
            height: 50,
            width: 50,
            x: 300,
            y: 300,
        }
    ];

    function drawWall() {
        ctx.save();
        ctx.fillStyle = "#FFA500";
        for (let i = 0; i < wall.length; i++) {
            ctx.fillRect(wall[i].x, wall[i].y, wall[i].width, wall[i].height);
        }
        ctx.restore();
    }
    function drawHero() {
        ctx.save();
        ctx.fillStyle = "skyblue";
        ctx.fillRect(hero.x, hero.y, hero.width, hero.height);
        ctx.restore();
    }

    function draw() {
        ctx.clearRect(0, 0, 500, 500);
        drawHero();
        drawWall();
    }
    draw();

    // 移动
    var keyDown = {};
    var then = Date.now();
    var collision = {
        top: false,
        left: false,
        bottom: false,
        right: false,
    };

    addEventListener('keydown', function (e) {
        keyDown[e.keyCode] = true;
    }, false)

    addEventListener('keyup', function (e) {
        delete keyDown[e.keyCode]
    }, false)

    function move(time) {
        if (87 in keyDown) {  //W
            if (collision.top == true) {
                hero.y -= 0
            } else {
                hero.y -= hero.speed * time
            }
        }
        if (65 in keyDown) {  //A
            if (collision.left == true) {
                hero.x -= 0
            } else {
                hero.x -= hero.speed * time
            }
        }
        if (83 in keyDown) {  //S
            if (collision.bottom == true) {
                hero.y += 0
            } else {
                hero.y += hero.speed * time
            }
        }
        if (68 in keyDown) {  //D
            if (collision.right == true) {
                hero.y += 0
            } else {
                hero.x += hero.speed * time;
            }
        }
    }

    function collisionDetection(hero, wall) {

        // collision.top = false;
        // collision.left = false;
        // collision.bottom = false;
        // collision.right = false;

        if (hero.x <= wall.x) {
            if (hero.x + hero.width + 2 >= wall.x && hero.y + hero.height > wall.y && hero.y < wall.y + wall.height) {
                collision.right = true;
                direction = '右';
            } else {
                collision.right = false;
                direction = ' ';
            }
        }
        if (hero.x >= wall.x + wall.width) {
            if (hero.x - 2 <= wall.x + wall.width && hero.y + hero.height > wall.y && hero.y < wall.y + wall.height) {
                collision.left = true;
                direction = '左';
            } else {
                collision.left = false;
                direction = ' ';
            }
        }
        if (hero.y + hero.height < wall.y) {
            if (hero.x - 2 <= wall.x + wall.width && hero.x + hero.width + 2 >= wall.x && hero.y + hero.height + 2 >= wall.y) {
                collision.bottom = true;
                direction = '下';
            } else {
                collision.bottom = false;
                direction = ' ';
            }
        }
        if (hero.y > wall.y + wall.height) {
            if (hero.x - 2 <= wall.x + wall.width && hero.x + hero.width + 2 >= wall.x && hero.y <= wall.y + wall.height + 2) {
                collision.top = true;
                direction = '上';
            } else {
                collision.top = false;
                direction = ' ';
            }
        }

        console.log(collision.left, collision.top, collision.right, collision.bottom)
    }
    
    // 查找和hero最近的元素,并判断碰撞检测
    function distance() {
        let arr = [];
        for (let i = 0; i < wall.length; i++) {
            let herox = heroy = wallx = wally = ax = ay = az = 0;
            herox = hero.x + hero.width / 2;
            heroy = hero.y + hero.height / 2;
            wallx = wall[i].x + wall[i].width / 2;
            wally = wall[i].y + wall[i].height / 2;
            ax = Math.abs(wallx - herox);
            ay = Math.abs(wally - heroy);
            az = Math.sqrt(ax * ax + ay * ay);
            let data = { index: i, num: az };
            arr.push(data);
        }
        let bIndex = arr.sort((a, b) => { return a.num - b.num })[0].index;
        collisionDetection(hero, wall[bIndex]);
    }

    function moveTime() {
        var now = Date.now();
        var deleta = now - then;
        let time = deleta / 1000;
        move(time);
        draw();
        distance();
        then = now;
        requestAnimationFrame(moveTime);
    }
    moveTime();
    // 移动


</script>
<style>
    #canvas {
        border: 1px solid #000;
    }
</style>

</html>
阅读 1.4k
1 个回答
if (87 in keyDown) {  //W
    if (collision.top == true) {
        hero.y -= 0
    } else {
        hero.y -= hero.speed * time
        // 上移后应该把下侧的碰撞修改为false
        collision.bottom = false
    }
}
// 先外部定义一个lastbIndex记录上一次的bIndex,
// 新计算出的bIndex与上一次的lastbIndex比较, 不同则为墙发生了变化
// 墙发生了变化, 则碰撞状态需要重置
let bIndex = arr.sort((a, b) => { return a.num - b.num })[0].index;
        
if (bIndex != lastbIndex) {
    lastbIndex = bIndex
    collision = {
        top: false,
        left: false,
        bottom: false,
        right: false,
    };
}

通过中心点距离来判断与哪个元素进行碰撞检测也有问题, 如下图.
hero中心点与2号墙中心点更近, 但是发生碰撞的墙却是1号墙
image.png

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题