在Canvas上进行碰撞检测,大多直接采用游戏引擎(Cocos2d-JS,Egret )和物理引擎(Box2D )内置的碰撞检测功能,好奇的你有没有想过它们的内部工作机制下面介绍基本的碰撞检测技术。
1、基于矩形的碰撞检测
碰撞检测是指判断物体之间是否重叠,这里假设讨论的碰撞体都是矩形物体。 下面的示例创建两个rect对象a和b (以下称为a、b ) : 其中,a的位置是固定的,b跟随鼠标的移动。 a、b重叠时控制台为intercect!
1、创建Rect对象
在此处,我们将创建新的Rect.js,创建Rect对象,并添加原型方法draw。 此方法根据当前对象的特性(位置、大小)绘制在导入的画布对象context中。
代码如下所示。
函数rect (x,y,width,height ) {
this.x=x;
this.y=y;
this.width=width;
this.height=height;
}
rect.prototype.draw=function{
context.save (;
context.translate(this.x,this.y );
context.fillrect (0,0,this.width,this.height );
context.restore (;
}
2、获取鼠标位置
因为b需要跟随鼠标的移动,所以需要检测鼠标在画布上的当前位置。 创建Capturemouse函数来检测鼠标在传递的文档节点element上的移动,并返回一个包含鼠标x、y坐标的mouse对象。
代码如下所示。
functioncapturemouse{
var mouse={x:null,y:null};
element.addevent监听器(' mousemove ',function ) (event )。
var x,y;
event.pagex|| event.pagey {
x=event.pageX;
y=event.pageY;
}else{
x=event.clientx document.body.scroll left
document.documentelement.scroll left;
y=event.clienty document.body.scroll top
document.documentelement.scroll top;
}
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。
代码如下所示。
函数间隔(rectB,rectB ) {
返回! (rectb.y rectb.height recta.y|| rectb.y recta.xrecta.width|| )
rectb.y recta.y recta.height|| rectb.xrectb.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();
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。