如何正确地从每一侧(顶部,左侧,底部,右侧)创建2d对象碰撞

时间:2013-07-29 19:34:49

标签: javascript html5 html5-canvas 2d collision

只为不想阅读大量文字的人添加此内容,至少阅读本文并查看图片以了解我的问题;
我在“玩家”和“物体”之间设置了碰撞,因此当“玩家”击中“物体”的“左”时,“玩家”被置于“物体”的“左”。 (这就是我要的)。但我希望玩家能够击中物体的任何一侧(“顶部”,“左侧”,“右侧”,“底部”)并进行适当放置。 Block collision example image 所以看看上面的图像,基本上我试图在黑色方块和其他对象之间创建碰撞。黑色方块是“玩家”对象,灰色方块是数字“墙”对象,红色方块是“下一级”对象。 我已经完成了这个,但它有点混乱,当涉及到移动墙壁物体时,玩家碰撞不再像我希望的那样工作。 所以无论如何这里是我的“墙”代码:

var canvasWalls1 = document.getElementById('canvasWalls');
var ctxWalls1 = canvasWalls.getContext('2d');
var walls1 = new Walls1();
var imgSprite = new Image();
imgSprite.src = 'sprite.png';
imgSprite.addEventListener('load',init,false);

WallLeft.prototype.draw = function (){
    ctxWalls1.drawImage(imgSprite,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
this.checkHitPlayer();
};
WallLeft.prototype.checkHitPlayer = function() {
if (this.drawX > player1.drawX &&
this.drawX <= player1.drawX + player1.width &&
this.drawY >= player1.drawY &&
this.drawY < player1.drawY + player1.height) {
player1.isUpKey = false;
player1.isDownKey = false;
player1.isRightKey = false;
player1.isLeftKey = false;
player1.drawX = this.drawX - player1.width - 0.05;
player1.drawY = this.drawY - 0.05;      }
}; 

我刚刚为wall1,2,3,...等复制了相同的代码。我确信有更好的方法可以做到这一点,如果有人可以提出更好的方法吗?我尝试在两个不同的地方绘制相同的精灵,但无法弄清楚如何正确实现这一点。我有不同“墙”对象的主要原因是因为我需要根据“玩家”与“墙”对象碰撞的位置在不同的位置绘制“玩家”对象。 如果玩家从左侧飞入player1.drawX = walls1.drawX - player width。 但如果玩家从顶部飞来,player1.drawY = walls1.drawY + player1.height。 我需要所有碰撞能够在任何“墙”对象上发生的原因,是因为每当“玩家”对象到达“完成”时我就会重新使用所有“墙”对象。 如果我知道一个更好的系统,也许我可以继续使用我的碰撞系统。无论如何,当“玩家”击中“完成”对象时会发生什么:

Finish.prototype.checkHitPlayer = function() {
if (this.drawX >= player1.drawX &&
this.drawX <= player1.drawX + player1.width &&
this.drawY >= player1.drawY &&
this.drawY <= player1.drawY + player1.height) {
increaseLevel();
} };
function increaseLevel() {
Level+=1;
if (Level===2) {
drawlevel2(); }
function drawlevel2()
{
player1.drawX = 288;
player1.drawY = 160;
walls1.drawX = 448;
walls1.drawY = 160;
walls2.drawX = 416;
walls2.drawY = 320;
walls3.drawX = 192;
walls3.drawY = 288;
finish1.drawX = 224
finish1.drawY = 96;
}

我再次完成了“玩家”和“墙壁”之间的碰撞,但只是为每个“墙”创建了一个单独的功能,当我想在不同的地方画出“墙”时,它不起作用。 我很抱歉,如果这看起来很多,我试着只包括相关的代码。非常感谢任何帮助/建议。

3 个答案:

答案 0 :(得分:1)

检测所有4个边的矩形碰撞

enter image description here

给定如下定义的矩形对象:

var player={x:0,y:0, w:20,h:20};

var barrier={x:100,y:100, w:50,h:50};

您可以使用此功能测试2个矩形是否从任何一侧发生碰撞

// return true if the 2 rectangles are colliding

function RectsColliding(r1,r2){
        return !(r1.x>r2.x+r2.w || r1.x+r1.w<r2.x || r1.y>r2.y+r2.h || r1.y+r1.h<r2.y);
}

你可以这样调用这个函数:

// test if the player and barrier are colliding

if( RectsColliding(player,barrier){
       console.log(‘BANG’);
}else{
       console.log(‘Congrats…No collision’);
}

即使你有很多屏障对象,也很容易检查碰撞

var CollisionOccured=false;

for(var i=0;i<barriers.length;i++){
    if(RectsColliding(desiredPlayer,barriers[i])){
        CollisionOccured=true;
    }
} 

return(CollisionOccured);

这是代码和小提琴:http://jsfiddle.net/m1erickson/sJfbd/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; padding:20px; }
    canvas{border:1px solid red;}
</style>

<script>
    $(function(){

        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");

        var defaultFill="lightgray";
        var defaultStroke="skyblue";

        ctx.fillStyle=defaultFill;
        ctx.strokeStyle=defaultStroke;

        var player={x:0,y:0, w:20,h:20, fill:"black",stroke:"black"};

        console.log(player.fill);

        var barriers=[];
        barriers.push({x:50 ,y:100, w:40,h:30});
        barriers.push({x:200,y:230, w:20,h:20});
        barriers.push({x:150,y:100, w:20,h:20});
        barriers.push({x:150,y:200, w:20,h:20});
        barriers.push({x:240,y:25,  w:10,h:150});

        drawAll();


        function drawAll(){
            ctx.clearRect(0,0,canvas.width,canvas.height);
            for(var i=0;i<barriers.length;i++){
                drawRect(barriers[i]);
            }
            drawRect(player,player.fill,player.stroke);
        }


        function drawRect(r,fill,stroke){
            ctx.beginPath();
            ctx.rect(r.x,r.y,r.w,r.h);
            ctx.closePath();
            ctx.fillStyle=fill||defaultFill;
            ctx.fill();
            ctx.strokeStyle=stroke||defaultStroke;
            ctx.stroke();
        }


        function movePlayer(desiredMoveX,desiredMoveY){

            // calculate where the player would like to be
            var desiredPlayer={
                x:player.x+desiredMoveX,
                y:player.y+desiredMoveY,
                w:player.w,
                h:player.h,
                fill:"black",
                stroke:"black"
            }

            // to start, set the move to be allowed
            var allowMove=true;

            // check every barrier for collisions
            for(var i=0;i<barriers.length;i++){
                // if the desiredPlayer has collided with a barrier
                // set the allowMove flag to false
                if(RectsColliding(desiredPlayer,barriers[i])){
                    allowMove=false;
                }
            }

            // if the move is allowed, return the desiredPlayer position
            // if the move is not allowed, return the old player position
            if(allowMove){
                player=desiredPlayer;
                player.stroke="black";
            }else{
                player.stroke="red";
            }

            // redraw the screen
            drawAll();

        }


        // return true if the 2 rectangles are colliding
        function RectsColliding(r1,r2){
            return !(r1.x>r2.x+r2.w || r1.x+r1.w<r2.x || r1.y>r2.y+r2.h || r1.y+r1.h<r2.y);
        }


        $(document).bind("keydown",function(event) {

            switch(event.which){
                case 37:
                    movePlayer(-1,0);
                    break;
                case 39:
                    movePlayer(1,0);
                    break;
                case 38:
                    movePlayer(0,-1);
                    break;
                case 40:
                    movePlayer(0,1);
                    break;
                default:
                    break;
            }

        });


    }); // end $(function(){});
</script>

</head>

<body>
    <p>Use arrowkeys to move player (black box)</p>
    <p>Player's outline will become red if hitting barrier</p>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

答案 1 :(得分:0)

您可以检查屏幕x / y坐标,以及每个可碰撞对象的高度和宽度。

如果你的对手x / y在一定的范围内,则应该触发碰撞。

(但这只适用于街区)

我找到了一个可能有帮助的小提琴:

http://jsbin.com/imofat/660/edit

答案 2 :(得分:0)

所以我想出了一个适合我想做的方法。我不能用类似的东西 (player1.x >= wall1.x && player1.Y===walls1.Y)或类似的东西因为当它归结为在玩家的不同侧面上有4个物体时...玩家的X值必须高于墙壁而低于另一个。与Y值相同。 (这也使它变得不稳定。)无论如何,这里是我使用的:

Player.prototype.checkHitWall = function() {
this.TopY = this.drawY; this.BottomY = this.drawY + this.height; this.LeftX = this.drawX; this.RightX = this.drawX + this.width;
if (this.LeftX===walls1.x + walls1.width - 16 && this.drawY===walls1.y) //If player  flys in from the RIGHT of wall1
{
player1.isUpKey = false; player1.isDownKey = false; player1.isRightKey = false; player1.isLeftKey = false;
upkey = false;
rightkey = false;
downkey = false;
leftkey = true;
this.drawX = walls1.x + walls1.width;
this.drawY = walls1.y;

然后我添加了一些功能,当玩家撞墙或游戏重启时,使leftkey = false。对于任何想知道-16的人来说,那是墙壁宽度的一半,所以玩家必须打到墙的中心才能放在墙边,因为我有fps(我猜不管怎样)你永远不会看到玩家进入墙体对象,所以看起来玩家看起来像是完美地击中墙壁。 -16的原因是当玩家试图左右移动时,墙壁完全位于玩家上方,墙壁不会发现碰撞。