在Canvas中進行碰撞偵測,大家往往直接採用遊戲引擎(Cocos2d-JS、Egret)或實體引擎(Box2D)內建的碰撞偵測功能,好奇的你有思考過它們的內部運作機制嗎?以下將針對基本的碰撞偵測技術進行解說:
1、基於矩形的碰撞檢測所謂碰撞偵測就是判斷物體間是否發生重疊,這裡我們假設討論的碰撞體都是矩形物體。下面範例中我們將建立兩個rect物件A和B(以下簡稱A,B),其中A位置固定,B跟隨滑鼠移動,當A,B重疊時控制台將提示intercect! !
1、創建Rect對象這裡我們新建Rect.js,建立Rect物件並為其新增原型方法draw,該方法將根據目前物件的屬性(位置、大小)繪製到傳入的畫布物件(context)中。
程式碼如下:
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函數可偵測滑鼠在傳入的文件節點(element)上的移動並傳回一個mouse物件(其中包含了滑鼠的x,y座標)。
程式碼如下:
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; offsetLeft; y -=element.offsetTop; mouse.x = x; mouse.y = y; },false); return mouse;} 3、碰撞檢測偵測A,B是否發生重疊,在討論是否發生重疊時我們可以先看看沒有重疊的四種情況,如下圖:
以下是對這四種狀態的判斷:
1、rectB.y+rectB.height < rectA.y
2、rectB.y > rectA.x +rectA.width
3、rectB.y > rectA.y + rectA.height
4、rectB.x+rectB.width < rectA.x
知道如何判斷沒有重疊的狀態,那麼發生重疊的狀態該如何判斷呢?沒錯取反! ,我們建立函數Interaect並加入到Init.js中,該函數傳入兩個Rect物件參數,當兩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.動畫循環新建animationjs,設定requestAnimationFrame()動畫函數。
在循環體中將做以下兩件事:
程式碼如下:
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、初始化
新Init.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、基於圓形的碰撞偵測說完矩形碰撞,我們再來聊聊圓形碰撞,同樣我們將創建兩個Circle物件A和B(以下簡稱A,B),其中A位置固定,B跟隨滑鼠移動,當A,B重疊時控制台將提示intercect! !
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、檢測圓形碰撞圓形間碰撞偵測可以簡單地透過兩圓心間距離與兩圓半徑總和的比較來做判斷,當兩圓心距離小於兩圓半徑總和時則發生碰撞。
如下圖:
所以我們首先要做的是計算出兩圓心間的距離,這裡我們將用到兩點間的距離公式,如下:
當取得兩圓心間的距離之後將與兩圓半徑總和比較,如果距離小於半徑總和則傳回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.動畫循環更新animation.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、初始化更新Init.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.檢測碰撞
和矩形偵測一樣,我們先來看看沒有發生碰撞的四種情況。
如下圖:
以下是對這四種狀態的判斷:
更新Interaect函數,將沒有重疊的狀態取反,向該函數傳入Rect對象和Circle對象,當Rect對象與Circle對象發生重疊將返回true。
程式碼如下:
function Intersect(Rect,Circle) { return !(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)} 2、動畫循環更新animation.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、初始化更新Init.js ,初始化Circle對象和Rect對象,最後開啟動畫循環。
程式碼如下:
window.onload = function () { canvas = document.getElementById('collCanvas'); context = canvas.getContext('2d'); Capturemouse(canvas); circle = new Circle(100,100,100); rectcan = new Rectcancanvas. width/2,canvas.height/2,100,100); drawAnimation();}以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。