百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

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

xsobi 2024-12-01 05:38 1 浏览

在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();
}

相关推荐

好用的云函数!后端低代码接口开发,零基础编写API接口

前言在开发项目过程中,经常需要用到API接口,实现对数据库的CURD等操作。不管你是专业的PHP开发工程师,还是客户端开发工程师,或者是不懂编程但懂得数据库SQL查询,又或者是完全不太懂技术的人,通过...

快速上手:Windows 平台上 cURL 命令的使用方法

在工作流程中,为了快速验证API接口有效性,团队成员经常转向直接执行cURL命令的方法。这种做法不仅节省时间,而且促进了团队效率的提升。对于使用Windows系统的用户来说,这里有一套详细...

使用 Golang net/http 包:基础入门与实战

简介Go的net/http包是构建HTTP服务的核心库,功能强大且易于使用。它提供了基本的HTTP客户端和服务端支持,可以快速构建RESTAPI、Web应用等服务。本文将介绍ne...

#小白接口# 使用云函数,人人都能编写和发布自己的API接口

你只需编写简单的云函数,就可以实现自己的业务逻辑,发布后就可以生成自己的接口给客户端调用。果创云支持对云函数进行在线接口编程,进入开放平台我的接口-在线接口编程,设计一个新接口,设计和配置好接口参...

极度精神分裂:我家没有墙面开关,但我虚拟出来了一系列开关

本内容来源于@什么值得买APP,观点仅代表作者本人|作者:iN在之前和大家说过,在iN的家里是没有墙面开关的。...

window使用curl命令的注意事项 curl命令用法

cmd-使用curl命令的注意点前言最近在cmd中使用curl命令来测试restapi,发现有不少问题,这里记录一下。在cmd中使用curl命令的注意事项json不能由单引号包括起来json...

Linux 系统curl命令使用详解 linuxctrl

curl是一个强大的命令行工具,用于在Linux系统中进行数据传输。它支持多种协议,包括HTTP、HTTPS、FTP等,用于下载或上传数据,执行Web请求等。curl命令的常见用法和解...

Tornado 入门:初学者指南 tornados

Tornado是一个功能强大的PythonWeb框架和异步网络库。它最初是为了处理实时Web服务中的数千个同时连接而开发的。它独特的Web服务器和框架功能组合使其成为开发高性能Web...

PHP Curl的简单使用 php curl formdata

本文写给刚入PHP坑不久的新手们,作为工具文档,方便用时查阅。CURL是一个非常强大的开源库,它支持很多种协议,例如,HTTP、HTTPS、FTP、TELENT等。日常开发中,我们经常会需要用到cur...

Rust 服务器、服务和应用程序:7 Rust 中的服务器端 Web 应用简介

本章涵盖使用Actix提供静态网页...

我给 Apache 顶级项目提了个 Bug apache顶级项目有哪些

这篇文章记录了给Apache顶级项目-分库分表中间件ShardingSphere提交Bug的历程。说实话,这是一次比较曲折的Bug跟踪之旅。10月28日,我们在GitHub上提...

linux文件下载、服务器交互(curl)

基础环境curl命令描述...

curl简单使用 curl sh

1.curl--help#查看关键字2.curl-A“(添加user-agent<name>SendUser-Agent<name>toserver)”...

常用linux命令:curl 常用linux命令大全

//获取网页内容//不加任何选项使用curl时,默认会发送GET请求来获取内容到标准输出$curlhttp://www.baidu.com//输出<!DOCTYPEh...

三十七,Web渗透提高班之hack the box在线靶场注册及入门知识

一.注册hacktheboxHackTheBox是一个在线平台,允许测试您的渗透技能和代码,并与其他类似兴趣的成员交流想法和方法。它包含一些不断更新的挑战,并且模拟真实场景,其风格更倾向于CT...