在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; 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()动画函数。
在循环体中将做以下两件事:
- “清空”当前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、初始化
新建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、检测碰撞
和矩形检测一样,我们先看看没有发生碰撞的四种情况。
如下图:
以下是对这四种状态的判断:
- 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.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); rect = new Rect(canvas.width/2,canvas.height/2,100,100); drawAnimation(); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新日志
- 英雄联盟六个龙魂是哪六个 英雄联盟六个龙魂介绍一览
- 《忆蚀》Subliminal:揭秘后室之谜,路知行献声Weplay文化展
- 初始之部制作人气漫画改编游戏《我家大师兄脑子有坑》参展2024WePlay
- 《异环》「奇点测试」定档11.28 超自然都市轻喜剧即将放送!
- 16层乐队.2024-大快朵颐【摩登天空】【FLAC分轨】
- 群星.1988-电视金曲巡礼【EMI百代】【WAV+CUE】
- 群星.1992-电视金曲巡礼VOL.2【EMI百代】【WAV+CUE】
- 廖昌永《情缘HQ》头版限量[低速原抓WAV+CUE]
- 蔡琴《老歌》头版限量编号MQA-24K金碟[低速原抓WAV+CUE]
- 李嘉《国语转调》3CD[WAV+CUE]
- 谭咏麟《爱的根源 MQA-UHQCD》2022头版限量编号 [WAV+CUE][1G]
- 江洋 《江洋原创琵琶作品专辑》[320K/MP3][118.08MB]
- 江洋 《江洋原创琵琶作品专辑》[FLAC/分轨][228.33MB]
- 《战舰世界》语音包文件夹位置介绍
- 《CSGO》送好友皮肤方法介绍