在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()动画函数。

在循环体中将做以下两件事:

  1. “清空”当前canvas中内容,为绘制下一帧做准备。
  2. 检测A,B是否发生重叠,若重叠则在控制台输出interact!!!
  3. 检测当前鼠标在canvas上的移动并将鼠标位置更新到B的位置属性中。
  4. 根据新的位置属性重新绘制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、检测碰撞

和矩形检测一样,我们先看看没有发生碰撞的四种情况。

如下图:

以下是对这四种状态的判断:

  1. Circle.y + Circle.radius < Rect.y
  2. Circle.x - Circle.radius > Rect.x + Rect.width
  3. Circle.y - Circle.radius > Rect.y + Rect.height
  4. 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();
}

Canvas动画基础之碰撞检测的更多相关文章

  1. Html5 Canvas动画基础碰撞检测的实现

    在Canvas中进行碰撞检测,大家往往直接采用游戏引擎(Cocos2d-JS.Egret)或物理引擎(Box2D)内置的碰撞检测功能,好奇的你有思考过它们的内部运行机制吗?下面将针对基本的碰撞检测技术 ...

  2. canvas动画基础

    setInterval( function(){ render( context ); update(); } , ); window.requestAnimFrame = (function() { ...

  3. 炫丽的倒计时效果Canvas绘图与动画基础

    前言 想要在自己做的网页中,加入canvas动画效果,但是发现模板各种调整不好,觉得还是要对canvas有所了解,才可以让自己的网页变得狂拽炫酷吊炸天! 一.绘制基础 1 <!DOCTYPE h ...

  4. 【30分钟学完】canvas动画|游戏基础(2):从零开始画画

    前言 上篇主要是理论的概述,本篇会多些实践,来讲讲canvas的基础用法,并包含一些基础三角函数的应用,推荐没有canvas基础的朋友阅读,熟悉的朋友可以跳过. 本人能力有限,欢迎牛人共同讨论,批评指 ...

  5. canvas系列教程07-canvas动画基础1

    上面我们玩了一个图表,大家学好结构,然后在那个基础上去扩展各种图表,慢慢就可以形成自己的图表库了.也可以多看看一些国外的图表库简单的版本,分析分析,读代码对提高用处很大.我说了canvas两大主流用途 ...

  6. JavaScript动画基础:canvas绘制简单动画

    动画是将静止的画面变为动态的艺术.实现由静止到动态,主要是靠人眼的视觉残留效应.视觉残留也叫视觉暂留现象,物体在快速运动时, 当人眼所看到的影像消失后,人眼仍能继续保留其影像0.1~0.4秒左右的图像 ...

  7. 《FLASH CC 2015 CANVAS 中文教程》——1、导出canvas动画,文件结构浅析

    注::如果你对 FLASH 这个软件操作不够熟悉,建议你可以先看看FLASH动画之类的书. :FLASH CC 在文中直接简称为CC. :以下所以文章中所说的快捷键 如果你按了不起作用,请检查是否有其 ...

  8. 《Programming WPF》翻译 第8章 1.动画基础

    原文:<Programming WPF>翻译 第8章 1.动画基础 动画包括在一段时间内改变用户界面的某些可见的特征,如它的大小.位置或颜色.你可以做到这一点,非常困难的通过创建一个tim ...

  9. [js高手之路] html5 canvas动画教程 - 实时获取鼠标的当前坐标

    有了前面的canvas基础之后,现在开始就精彩了,后面写的canvas教程都是属于综合应用,前面已经写了常用的canvas基础知识,参考链接如下: [js高手之路] html5 canvas系列教程 ...

随机推荐

  1. 【最新】破解微信小程序,获取微信小程序源码,破解微信wxapkg,仅需5秒

    一个后端第一次接触iview,就简单写了个网站. 之前看到有人发解析wx小程序源码包的软件,但是因为微信的升级,之前的办法已经不行了.现在重新改了js文件,适配了最新的版本. 之前微信wxapkg包获 ...

  2. git之rebase、merge和cherry pick的区别(面试常问)

    git flow图例镇楼 merge 这个简单,初学者常用.比如主分支是Dev,最新版本是01.然后小明基于此,搞了个feature 分支A,业务:打酱油.然后在上面多次提交,完成功能迭代开发,如A1 ...

  3. 02 (OC)* ViewController 的声明周期

    一. UIViewController 的 生命周期 代码 示例 #pragma mark --- life circle // 非storyBoard(xib或非xib)都走这个方法 - (inst ...

  4. spring集成mybatis-plus

    一.mybatis-plus 使用mybatis-plus可以轻松实现通用crue.通用service,不用再在xml.dao.service里写增删改查的代码(需要写特殊方法的时候可以按原先的来), ...

  5. 引用、浅拷贝及深拷贝 到 Map、Set(含对象assign、freeze方法、WeakMap、WeakSet及数组map、reduce等等方法)

    从引用聊到深浅拷贝,从深拷贝过渡到ES6新数据结构Map及Set,再到另一个map即Array.map()和与其类似的Array.flatMap(),中间会有其他相关话题,例如Object.freez ...

  6. 转:int整数除以int整数一定得到的是int整数(易忽视)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u014053368/article/de ...

  7. App的功能测试要点

    一 UI测试 (1)界面(菜单.窗口.按钮)布局.风格是否满足客户要求,文字和图片组合是否美观,操作是否友好. (2)清晰.简洁.美观.响应.一致 (3)图形测试.内容测试.导航测试    (图形包括 ...

  8. Spring常犯的十大错误,你踩过吗?

    1.错误一:太过关注底层 我们正在解决这个常见错误,是因为 "非我所创" 综合症在软件开发领域很是常见.症状包括经常重写一些常见的代码,很多开发人员都有这种症状. 虽然理解特定库的 ...

  9. 23种设计模式之责任链模式(Chain of Responsibility Pattern)

    责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行为型模式. ...

  10. ORM组件LogORM使用指北

    LogORM是一个对数据库进行对象关系映射的ORM组件.当对数据库进行增删改操作时,组件会自动进行日志记录. 该组件支持.Net平台和.NetCore平台,支持SQL Server.Oracle.My ...