簡體   English   中英

2d html5 畫布碰撞,操作方法

[英]2d html5 canvas collision, howto

正如標題所暗示的那樣,我遇到了對象碰撞問題...我目前正在使用 JavaScript 開發 2d Html5 畫布游戲。 我知道如何防止“玩家”對象超出游戲畫布的寬度/高度,並且我知道當玩家與對象(例如電源或敵人或其他任何東西)碰撞時如何做一些事情,但我只是不知道如何制作“固體”物體,意思是當玩家碰到固體物體時,玩家只是停下來,不能穿過固體物體。

這就是我現在所擁有的(並非所有代碼只是我覺得相關的,如果它太多/太少,抱歉。:

  var canvasPlayer = document.getElementById('canvasPlayer');
var ctxPlayer = canvasPlayer.getContext('2d');
var canvasWalls = document.getElementById('canvasWalls');
var ctxWalls = canvasWalls.getContext('2d');

function checkKeyDown(e) {
        var keyID = (e.keyCode) || e.which;
        if (keyID === 38 || keyID === 87)   { // up arrow OR W key
        if (!player1.isDownKey && !player1.isLeftKey && !player1.isRightKey) {
        player1.isUpKey = true;
        e.preventDefault();
        } }
        if (keyID === 39 || keyID === 68)   { //right arrow OR D key
        if (!player1.isDownKey && !player1.isLeftKey && !player1.isUpKey) {
        player1.isRightKey = true;
        e.preventDefault();
        } }
        if (keyID === 40 || keyID === 83)   {//down arrow OR S key
        if (!player1.isUpKey && !player1.isLeftKey && !player1.isRightKey) {
        player1.isDownKey = true;
        e.preventDefault();
        } }
        if (keyID === 37 || keyID === 65)   {//left arrow OR A key
        if (!player1.isDownKey && !player1.isUpKey && !player1.isRightKey) {
        player1.isLeftKey = true;
        e.preventDefault();
        }
        }
    }

    Walls.prototype.draw = function (){
        ctxWalls.drawImage(imgSprite,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
        this.checkHitPlayer();
        };
    Walls.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;
            }
    }; 

這是有效的...除了嘗試向上或向左移動時,玩家可能只移動 2-3 個像素,因此向左或向上移動需要 3 個向左或向上箭頭。 玩家也可以直接穿過牆壁,這不是我想要的。 如果我包含太多或不夠的代碼,任何幫助都非常抱歉。 哦,我還忘了說這款游戲是一款益智游戲,而且我已經將它設置為玩家一次只能向一個方向移動直到撞牆。

如果你只是想讓你的玩家在碰到牆時停下來,你可以應用一些數學:

例如:假設您的播放器是一個 10 像素 x 10 像素的矩形,右牆的 X 位置是 200。

矩形右側的 X 位置計算如下:

var playerRightSide = player.x + player.width;

您可以像這樣測試玩家是否已經到達牆壁:

if( playerRightSide >= 200 )

如果用戶試圖將他們的玩家推到牆外,您可以使用玩家 X 位置將玩家保持在牆的左側。

if( playerRightSide >= 200 ) { player.x = 190; }  

190 是牆的 X 位置 (200) 減去玩家的寬度 (10)。

如果您有興趣進行更高級的碰撞測試,請進一步閱讀。

許多基本的游戲碰撞可以分為 3 種類型:

  • 圓與圓碰撞
  • 矩形與矩形碰撞
  • 矩形與圓形碰撞

這是如何檢測這些常見沖突中的每一個的說明。

假設您定義了一個圓,如下所示:

var circle1={
    x:30,
    y:30,
    r:10
};

假設你定義了一個這樣的矩形:

var rect1={
    x:20,
    y:100,
    w:20,
    h:20
};

您可以像這樣檢測圓形與圓形的碰撞......

在此處輸入圖片說明

...使用此 Circle vs Circle 碰撞測試代碼:

    // return true if the 2 circles are colliding
    // c1 and c2 are circles as defined above

    function CirclesColliding(c1,c2){
        var dx=c2.x-c1.x;
        var dy=c2.y-c1.y;
        var rSum=c1.r+c2.r;
        return(dx*dx+dy*dy<=rSum*rSum);
    }

您可以像這樣檢測矩形與矩形的碰撞......

在此處輸入圖片說明

...使用此矩形與矩形碰撞測試代碼:

    // return true if the 2 rectangles are colliding
    // r1 and r2 are rectangles as defined above

    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);
    }

您可以像這樣檢測矩形與圓形碰撞...

在此處輸入圖片說明

...使用此矩形與圓形碰撞測試代碼:

    // return true if the rectangle and circle are colliding
    // rect and circle are a rectangle and a circle as defined above

    function RectCircleColliding(rect,circle){
        var dx=Math.abs(circle.x-(rect.x+rect.w/2));
        var dy=Math.abs(circle.y-(rect.y+rect.y/2));

        if( dx > circle.r+rect.w2 ){ return(false); }
        if( dy > circle.r+rect.h2 ){ return(false); }

        if( dx <= rect.w ){ return(true); }
        if( dy <= rect.h ){ return(true); }

        var dx=dx-rect.w;
        var dy=dy-rect.h
        return(dx*dx+dy*dy<=circle.r*circle.r);
    }

例如,您可以使用這些碰撞測試來響應玩家觸摸強化方塊:

    // create a circular player object
    // that's located at [30,30] and has a radius of 10px

    var player={x:30,y:30,r:10};


    // create a rectangular power-up at position [200,30]

    var powerup={x:200, y:30, w:20, h:20};


    // Let's say the user keys the player to coordinate [200,35] 
    // (touching the power-up)

    player.x = 220;
    player.y = 35;


    // you can test if the circular player is touching the rectangular power-up

    if( RectCircleColliding(powerup,player)  ) {

        // the player has collided with the power-up, give bonus power!

        player.power += 100;

    }

這是代碼和小提琴: http : //jsfiddle.net/m1erickson/u6t48/

<!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");

        window.requestAnimFrame = (function(callback) {
          return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
          function(callback) {
            window.setTimeout(callback, 1000 / 60);
          };
        })();

        ctx.fillStyle="lightgray";
        ctx.strokeStyle="skyblue";

        // top collision circle vs circle
        var circle1={x:30,y:30,r:10};
        var circle2={x:70,y:40,r:10};
        var circle3={x:100,y:30,r:10};
        var direction1=1;

        // middle collision rect vs rect
        var rect1={x:20,y:100,w:20,h:20};
        var rect2={x:50,y:110,w:20,h:20};
        var rect3={x:90,y:100,w:20,h:20};
        var direction2=1;

        // bottom collision rect vs circle
        var circle4={x:30,y:200,r:10};
        var rect4={x:50,y:205,w:20,h:20};
        var circle5={x:100,y:200,r:10};
        var direction3=1;


        function drawAll(){
            ctx.clearRect(0,0,canvas.width,canvas.height);
            drawCircle(circle1);
            drawCircle(circle2);
            drawCircle(circle3);
            drawCircle(circle4);
            drawCircle(circle5);
            drawRect(rect1);
            drawRect(rect2);
            drawRect(rect3);
            drawRect(rect4);
        }

        function drawCircle(c){
            ctx.beginPath();
            ctx.arc(c.x,c.y,c.r,0,Math.PI*2,false);
            ctx.closePath();
            ctx.fill();
            ctx.stroke();
        }

        function drawRect(r){
            ctx.beginPath();
            ctx.rect(r.x,r.y,r.w,r.h);
            ctx.closePath();
            ctx.fill();
            ctx.stroke();
        }

        // return true if the 2 circles are colliding
        function CirclesColliding(c1,c2){
            var dx=c2.x-c1.x;
            var dy=c2.y-c1.y;
            var rSum=c1.r+c2.r;
            return(dx*dx+dy*dy<=rSum*rSum);
        }

        // 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);
        }

        // return true if the rectangle and circle are colliding
        function RectCircleColliding(rect,circle){
            var dx=Math.abs(circle.x-(rect.x+rect.w/2));
            var dy=Math.abs(circle.y-(rect.y+rect.h/2));

            if( dx > circle.r+rect.w/2 ){ return(false); }
            if( dy > circle.r+rect.h/2 ){ return(false); }

            if( dx <= rect.w ){ return(true); }
            if( dy <= rect.h ){ return(true); }

            var dx=dx-rect.w;
            var dy=dy-rect.h
            return(dx*dx+dy*dy<=circle.r*circle.r);
        }

        var fps = 15;
        function animate() {
            setTimeout(function() {
                requestAnimFrame(animate);

                // circle vs circle
                circle2.x = circle2.x+direction1;
                if( CirclesColliding(circle2,circle1) || CirclesColliding(circle2,circle3)  ){ 
                    direction1=-direction1; 
                }

                // rect vs rect
                rect2.x = rect2.x+direction2;
                if( RectsColliding(rect2,rect1) || RectsColliding(rect2,rect3) ){
                    direction2=-direction2;
                }

                // rect vs circle
                rect4.x = rect4.x+direction3;
                if( RectCircleColliding(rect4,circle4) || RectCircleColliding(rect4,circle5) ){
                    direction3=-direction3;
                }

                drawAll();

            }, 1000 / fps);
        }

        animate();

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

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM