Html 5 Canvasアニメーションベース衝突検出の実現

13964 ワード

Canvasで衝突検出を行う場合、ゲームエンジン(Cocos 2 d-JS、Egret)や物理エンジン(Box 2 D)に内蔵された衝突検出機能を直接採用することが多いのですが、内部の仕組みを考えたことがありますか?次に、基本的な衝突検出技術について説明します.
1、矩形による衝突検出
衝突検出とは,物体間に重複が生じるか否かを判断することであり,ここで議論する衝突体は矩形物体であると仮定する.次の例では、2つのrectオブジェクトAとB(以下、A、Bと略称する)を作成します.ここで、Aの位置が固定され、Bがマウスに従って移動し、A、Bが重なるとコンソールがintercectをプロンプトします.
1、Rectオブジェクトの作成
ここに新しいレコードを作ります.jsは、Rectオブジェクトを作成し、現在のオブジェクトのプロパティ(位置、サイズ)に基づいて、入力されたキャンバスオブジェクト(context)に描画されるプロトタイプメソッドdrawを追加します.
コードは次のとおりです.
function Rect(x,y,width,height) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
}
 
Rect.prototype.draw = function(context){
    context.save();
    context.translate(this.x,this.y);
    context.fillRect(0,0,this.width,this.height);
    context.restore();
}

2、マウスの位置を取る
Bはマウスに従って移動する必要があるので、キャンバスの現在の位置を検出する必要があります.Capturemouse関数を作成して、入力されたドキュメントノード上のマウスの移動を検出し、マウスのx,y座標を含むmouseオブジェクトを返します.
コードは次のとおりです.
function Capturemouse (element) {
    var mouse={x:null,y:null};
    element.addEventListener('mousemove',function (event) {
        var x, y;
        if(event.pageX || event.pageY){
            x = event.pageX;
            y = event.pageY;
        }else{
            x = event.clientX+document.body.scrollLeft+
                document.documentElement.scrollLeft;
            y = event.clientY+document.body.scrollTop+
                document.documentElement.scrollTop;
        }
        x -=element.offsetLeft;
        y -=element.offsetTop;
        mouse.x = x;
        mouse.y = y;
    },false);
    return mouse;
}

3、衝突検出
A,Bが重複しているかどうかを検出し、重複していないかどうかを議論する際に、以下の図を参照してください.
以下はこの4つの状態に対する判断です.
1、rectB.y+rectB.height < rectA.y2、rectB.y > rectA.x +rectA.width3、rectB.y > rectA.y + rectA.height4、rectB.x+rectB.width < rectA.x
重なっていない状態をどう判断するか知っていますが、重なっている状態をどう判断すればいいのでしょうか.間違いなく「取反」!、関数Interaectを作成してInitに追加します.jsでは、この関数は2つのRectオブジェクトパラメータを入力し、2つのRectオブジェクトが重なるとtrueを返します.
コードは次のとおりです.
function Intersect(rectA,rectB) {
    return !(rectB.y+rectB.height < rectA.y || rectB.y > rectA.x +rectA.width ||
        rectB.y > rectA.y + rectA.height|| rectB.x+rectB.width < rectA.x)
}

4、アニメーションサイクル
新しいアニメーションjsを作成し、requestAnimationFrame()アニメーション関数を設定します.
サイクルでは、次の2つのことを行います.
現在のcanvasの内容をクリアし、次のフレームを描く準備をします.A,Bが重なるかどうかを検出し,重なるとコンソールにinteract!!!現在のcanvas上のマウスの移動を検出し、マウスの位置をBの位置プロパティに更新します.新しい位置プロパティに基づいてAを再描画します.B(もちろん、Aの位置は更新されませんが、ループごとにcanvasが空になるので再描画する必要があります)のコードは次のとおりです.
function drawAnimation() {
    window.requestAnimationFrame(drawAnimation);
    context.clearRect(0, 0, canvas.width, canvas.height);
    if(Intersect(rectA,rectB)){
     console.log('interact!!!!');
    }
    if(mouse.x){
        rectB.x = mouse.x;
        rectB.y = mouse.y;
    }
    rectA.draw(context);
    rectB.draw(context);
}

3、初期化
新規作成jsは、canvas要素を取得し、マウスの移動検出をバインドし、RectオブジェクトAとBを初期化し、最後にアニメーションループをオンにします.
コードは次のとおりです.
window.onload = function () {
    canvas = document.getElementById('collCanvas');
    context = canvas.getContext('2d');
    Capturemouse(canvas);
    rectA = new Rect(canvas.width/2,canvas.height/2,100,100);
    rectB = new Rect(100,100,100,100);
    drawAnimation();
}

2、円形による衝突検出
長方形の衝突と言って、円形の衝突について話しましょう.同じように、A位置が固定され、Bがマウスに従って移動し、A、Bが重なるとコンソールがintercectを提示する2つのCircleオブジェクトAとB(以下、A、Bと略称します)を作成します.
1、circleオブジェクトの作成
function Circle(x,y,radius) {
    this.x = x;
    this.y = y;
    this.radius = radius;
}
 
Circle.prototype.draw = function(context){
    context.save();
    context.translate(this.x,this.y);
    context.beginPath();
    context.arc(0,0,this.radius,0,Math.PI*2,false);
    context.fill();
    context.restore();
}

2、円形衝突の検出
円形間衝突検出は、両円心間距離と両円半径の和の比較により簡単に判断することができ、両円心距離が両円半径の和より小さい場合に衝突が発生する.
次の図を示します.
まず、2つの円心間の距離を計算する必要があります.ここでは、2点間の距離式を使用します.以下のようにします.
2つの円心間の距離を取得すると、2つの円半径の和と比較され、距離が半径の和より小さい場合はtrueが返されます.
Interaect関数を更新します.
コードは次のとおりです.
function Intersect(circleA,circleB) {
    var dx = circleA.x-circleB.x;
    var dy = circleA.y-circleB.y;
    var distance = Math.sqrt(dx*dx+dy*dy);
    return distance < (circleA.radius + circleB.radius);
}

3、アニメーションサイクル
更新するjs,ここではRectオブジェクトをCircleオブジェクトに置き換えます.
コードは次のとおりです.
function drawAnimation() {
    window.requestAnimationFrame(drawAnimation);
    context.clearRect(0, 0, canvas.width, canvas.height);
    if(Intersect(circleA,circleB)){
     console.log('interact!!!!');
    }
    if(mouse.x){
        circleB.x = mouse.x;
        circleB.y = mouse.y;
    }
    circleA.draw(context);
    circleB.draw(context);
}

4、初期化
更新jsは、CircleオブジェクトAとBを初期化し、最後にアニメーションループをオンにします.
コードは次のとおりです.
window.onload = function () {
    canvas = document.getElementById('collCanvas');
    context = canvas.getContext('2d');
    Capturemouse(canvas);
    circleA = new Circle(canvas.width/2,canvas.height/2,100);
    circleB = new Circle(100,100,100);
    drawAnimation();
}

3、矩形と円形間の衝突検出に基づく
前述の説明は、単一形状間の衝突検出ですが、矩形と円形間の衝突を検出します.
1、衝突検出
矩形検出と同様に,衝突が発生していない4つの状況を先に見た.
次の図を示します.
以下はこの4つの状態に対する判断です.
Circle.y + Circle.radius < Rect.y
Circle.x - Circle.radius > Rect.x + Rect.width
Circle.y - Circle.radius > Rect.y + Rect.height
Circle.x + Circle.radius < Rect.x
  Interaect  ,        “  ”,      Rect   Circle  , Rect   Circle         true。

コードは次のとおりです.
function Intersect(Rect,Circle){return!(Circle.y+Circle.radiusRect.x+Rect.width||Circle.y-Circle.radius>Rect.y+Rect.height||Circle.x+Circle.radius更新するjs,ここではcircleオブジェクトをマウスの動きに従い,固定位置のrectオブジェクトとの衝突を検出する.
コードは次のとおりです.
function drawAnimation() {
    window.requestAnimationFrame(drawAnimation);
    context.clearRect(0, 0, canvas.width, canvas.height);
    if(Intersect(rect,circle)){
     console.log('interact!!!!');
    }
    if(mouse.x){
        circle.x = mouse.x;
        circle.y = mouse.y;
    }
    circle.draw(context);
    rect.draw(context);
}

3、初期化
更新jsは、CircleオブジェクトとRectオブジェクトを初期化し、最後にアニメーションループを開きます.
コードは次のとおりです.
window.onload = function () {
    canvas = document.getElementById('collCanvas');
    context = canvas.getContext('2d');
    Capturemouse(canvas);
    circle = new Circle(100,100,100);
    rect = new Rect(canvas.width/2,canvas.height/2,100,100);
    drawAnimation();
}

 
多くの人が先端や中期に接触したばかりの頃、いくつかの問題とボトルネック期に遭遇すると信じています.例えば、しばらく勉強しても方向感がないか、堅持できないか、一人で勉強するのは退屈で問題があっても、どのように解決するか分かりません.これに対して私はいくつかの資料を整理して私の文章が好きで、もっと多くのベテランの大牛と一緒に討論して勉強したいならば私の学習交流群907694362に参加することを歓迎します