怎么实现2D游戏的html盒子碰撞判定定

木其网络科技专业程序员代写
程序员学历擅长经验网店链接
硕士ASP.NET PHP 电子 通信设计 图像 编程 网络5年
本科C语言 C++面向对象 Java5年
本科Java Web项目 JSP Hibernate Struts Mysql5年
本系列文章由七十一雾央编写,转载请注明出处。
作者:七十一雾央 新浪微博:
& & & 在这个教程中主要内容是2D游戏,关于3D游戏,雾央也还在努力学习之中,等以后有时间,一定会把自己学到的知识分享给大家,所以这一节中主要讲解的就是2D游戏中的障碍物判定了,45度地图以后要有时间雾央会讲。
& & & 上一节中讲解了近似的矩形判定,这是一种比较常用的判定方式,很适合于两个移动的物体之间,比如很多跳跃类游戏中移动的台阶和人物之间的碰撞,但是在地图障碍物判定上就显得有些力不从心了。这一节雾央将会给大家讲解几种新的碰撞检测方法,对于新手朋友们可能内容略多,不过只要认真阅读,多思考思考,应该是不难理解的,如果有什么问题,欢迎大家留言讨论。
& & & & & 在玩游戏的时候,有些河流断崖等地方是不能通过的,高处跳跃落下的时候是不会穿过地平线的,石头挡着的地方是绝对不能路过的…………这些检测都属于地图障碍物判定的范围。
& & & 大家在开发游戏的时候,地图的结构类型不同,采用的障碍物判定一般也就不同,地图类型和障碍物检测联系密切,因此雾央会介绍一下不同地图类型可以采取的方法。
& & & 在介绍之前,雾央必须要说明一个前提:在雾央的教程里,做碰撞检测时,人物都是使用最小外接矩形进行的。大家当然可以逐像素进行,即遍历整个人物矩形,当检测到人物图形和背景图片在同一位置都具有像素且是障碍物的时候,即发生碰撞。这样去掉了人物图片透明处带来的误差,但是太过于低效,雾央觉得大家初学游戏没有必要追求这么高的精确度,同时也可以大大简化问题。
一、TileMap
& & & 现在在家的同学请回头看一下背后,嗯,什么诡异的事情都没有发生,呵呵,开个玩笑了。我们要看的其实是地面,大家看到的是不是像下面这样?
& & & 这个地面是雾央在网上找的一张图,大家想象一下,如果将其中的某些块瓷砖画上石头,画上树木、房屋等,在把瓷砖之间的分界线给隐藏起来,比如下面这样,那么它像什么?
& & & 应该说它就是一张2D游戏中的地图!
& & & 这种类型的地图叫“TileMap”,Tile就是瓷砖的意思,每一块瓷砖我们可以认为是一种地图元素,使用几种不同的地图元素,我们就可以拼出不同的地图,制造地图的过程一般通过地图编辑器进行,这种地图的特征就是网格形。
& & & 不知道大家还记不记得小时候在小霸王学习机上玩过的坦克大战?它支持自定义地图,那个部分如果拆分出来就是一个地图编辑器,我们可以选择土墙、钢铁墙、草丛、河流等很多种元素然后自己确定摆放位置,制造出一张地图来进行游戏,这就是TileMap,PS:雾央记得那时候最喜欢用钢铁墙将路封死,只留一个入口,然后守在哪里,呵呵。
& & & 这种地图比较简单,程序实现障碍物判定也很容易。因为我们用地图编辑器生成地图的时候,可以保存一个二维数组,指明某个方块的信息。在程序中读取这个二维数组,显示地图,进行障碍物判定。
& & & 在TileMap中进行障碍物判定是非常容易的事情,人物每次移动时,都检测前方是否是障碍物即可。人物的移动并不一定要是按网格移动,仍然是可以按像素移动的,当然按网格移动是最简单的,比如推箱子这种游戏。
& & & TileMap要求的就是障碍物比较规则,并且是网格大小的整数倍,否则就会出现比较假的情况。
& & & 下面给出一个TileMap的例子,看起来是不是很挫的感觉~~(╯﹏╰)b
& & & 下面的图像也是通过TileMap实现的,看起来是不是好了很多?
& & & TileMap对于游戏在表现力上强烈的需求,灵活的操作性来说有点力不从心,制造出的地图很多看起来都有四四方方的感觉,因此最适合于简单休闲的小游戏,比如坦克大战,推箱子,泡泡堂等,在有些大型游戏中也可能会使用到。但是TileMap也有自己独特的优点,仅仅使用几种有限的图元就可以组合出无穷多的各异的地图,并且很省内存空间,毕竟只需要加载几种小图元即可,比如说在沙漠、草原等整个场景风格近似的地图等。某种程度上来说,TileMap是把像素放大了几十倍,相比于逐像素处理来说,现在只需要按网格处理了,因此更便于操作。
二、横版台阶地图
& & & 雾央也不知道那种普普通通常见的地图叫什么,就暂且叫做横版台阶地图好了。这里雾央说的是那种障碍物可以随意摆放的地图,并不要求处在特定网格中,这样在游戏中的灵活性也就高了许多。比如下面这种
& & & 在这样的地图中,要实现障碍判定,有多种方式。
& & & 一种可行的是记录下每个台阶所在的矩形区域坐标范围,然后在程序中判断,情况同TileMap差不了太多,都比较简单可行,但是可能需要遍历每个台阶,比较麻烦。
& & & 另一种通过蒙版图进行,这个要方便了很多,但是有一个很大的缺憾,要求障碍物固定,对于那些移动的台阶就无能为力,或者需要额外添加判定。
& & & 雾央首先介绍一下蒙版图的概念,举个例子大家就明白了。
& & & 比如下面是一张背景图片
& & & 下面这张图就是它的蒙版图
& & & 大家应该明白了吧?就是将图中的障碍物地方用黑色表示,可以通行的地方用白色表示。那么我们在程序中只需要判定人物要移动到的位置是不是黑色,如果是黑色就不可以通过,否则就可以经过了。事实上可以认为,它是一种特殊的TileMap,只不过每个Tile的大小是一个像素,每个Tile用1表示可以通过,0表示不可通行而已。
& & & 明白了这个原理后,雾央相信写成代码应该不是难事,大家可以自己尝试下,雾央待会会附上使用蒙版图判定的详细代码,在障碍物判定上,同样分水平方向和垂直方向,雾央只会以垂直方向示例,水平方向同理,留待大家自己完成。
& & & 对了,大家之前一直使用的是CImage贴图,这个类功能很强大,它的一个成员函数GetPixel(x,y)可以获取xy处的像素,返回值为COLORREF类型, 它是32-bit 整型数值,代表了一种颜色。你可以使用 RGB 宏生成颜色变量来和它进行比较,注意x的范围是0到width,y的范围是0到height,包括起始点,但不包括终点,超过范围是会弹出错误框框的哦。在雾央的程序里面,是没有对人物离开地图范围进行判定的,所以大家如果操纵人物离开了窗口范围,再进行上下移动是会看到错误框的,这个由大家自己加上,比较简单。
& & & 判断是否可以通行的代码可以如同下面这样:
//是否可以通行的判断
bool CChildView::CanPass()
//水平方向的雾央省略了,留给大家自己完成
if(MyHero.direct==LEFT || MyHero.direct==RIGHT )
for(int x=MyHero.x;x&MyHero.x+MyHero.x++)
//检测的宽度是人物的宽度
//雾央在这里偷了个懒,只检测了人物下一时刻要到达的位置,即MyHero.y-5处
//万一障碍物很薄,只有2个像素宽之类的,就会失效
//主要是因为以后人物的移动方式不会是这种位移直接增加的方式,所以雾央在这里主要是介绍一下思想
//在流畅动画那一节中,雾央会重新讲解,以后会给出新的demo
if(MyHero.direct==UP)
//方向向上时
if(m_bgblack.GetPixel(x,MyHero.y-5)==RGB(0,0,0))
//遇到黑色像素返回false
else if(MyHero.direct==DOWN)
//方向向下时
//向下时,记得加上人物的宽度,因为人物的xy位置是它的左上角坐标
if(m_bgblack.GetPixel(x,MyHero.y+MyHero.height+5)==RGB(0,0,0))
//遇到黑色像素返回false
& & 现在我们来看看运行的效果吧
& & 向上走,走不了啊 &
& & 那往下走吧,还是走不了。。。
& & 呼,写到这里,雾央发现已经比以前写的内容似乎都要多,不知道大家觉得怎么样?雾央本来还打算讲解一下游戏中斜坡的情况,有时间还想讲解一下45度地图的情况,现在看来只好放到下一讲去了,那之前说好的流畅动画等又得往后推一推了,~~(╯﹏╰)b。
三、源代码
// ChildView.h : CChildView 类的接口
#pragma once
#define SNOW_NUMBER 100
//雪花例子的数量
// CChildView 窗口
class CChildView : public CWnd
CChildView();
//人物结构体
struct charcter
//保存人物的图像
//保存人物的位置
//人物的方向
//运动到第几张图片
//图片的宽度和高度,用于碰撞判定
//保存客户区大小
//背景图片
CImage m_ //背景蒙版图
CDC m_cacheDC;
CBitmap m_cacheCB//缓冲位图
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual ~CChildView();
// 生成的消息映射函数
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
bool CanPass();
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//-----------------------------------【程序说明】----------------------------------------------
// 【MFC游戏开发】笔记十 障碍判定进阶 配套源代码
// VS2010环境
// 更多内容请访问雾央CSDN博客 http://blog.csdn.net/u/article/category/1497651
// 雾央的新浪微博: @七十一雾央
//------------------------------------------------------------------------------------------------
// ChildView.cpp : CChildView 类的实现
#include &stdafx.h&
#include &GameMFC.h&
#include &ChildView.h&
#include &mmsystem.h&
#pragma comment(lib,&winmm.lib&)//导入声音头文件库
#ifdef _DEBUG
#define new DEBUG_NEW
//定时器的名称用宏比较清楚
#define TIMER_PAINT 1
#define TIMER_HEROMOVE 2
//四个方向
#define DOWN 0
#define LEFT 1
#define RIGHT 2
#define UP 3
//窗口大小
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
// CChildView
CChildView::CChildView()
CChildView::~CChildView()
mciSendString(&stop bgMusic &,NULL,0,NULL);
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_KEYDOWN()
ON_WM_LBUTTONDOWN()
ON_WM_TIMER()
ON_WM_CREATE()
END_MESSAGE_MAP()
//将png贴图透明
void TransparentPNG(CImage *png)
for(int i = 0; i &png-&GetWidth(); i++)
for(int j = 0; j &png-&GetHeight(); j++)
unsigned char* pucColor = reinterpret_cast&unsigned char *&(png-&GetPixelAddress(i , j));
pucColor[0] = pucColor[0] * pucColor[3] / 255;
pucColor[1] = pucColor[1] * pucColor[3] / 255;
pucColor[2] = pucColor[2] * pucColor[3] / 255;
// CChildView 消息处理程序
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast&HBRUSH&(COLOR_WINDOW+1), NULL);
//-----------------------------------游戏数据初始化部分-------------------------
//加载背景
m_bg.Load(&bg.png&);
m_bgblack.Load(&bgblack.png&);
//加载英雄图片
MyHero.character.Load(&heroMove.png&);
TransparentPNG(&MyHero.character);
MyHero.width=80;
MyHero.height=80;
//初始化英雄状态
MyHero.direct=UP;
MyHero.frame=0;
//设置英雄初始位置
MyHero.x=80;
MyHero.y=400;
//打开音乐文件
mciSendString(&open background.mp3 alias bgMusic &, NULL, 0, NULL);
mciSendString(&play bgMusic repeat&, NULL, 0, NULL);
return TRUE;
void CChildView::OnPaint()
//获取窗口DC指针
CDC *cDC=this-&GetDC();
//获取窗口大小
GetClientRect(&m_client);
//创建缓冲DC
m_cacheDC.CreateCompatibleDC(NULL);
m_cacheCBitmap.CreateCompatibleBitmap(cDC,m_client.Width(),m_client.Height());
m_cacheDC.SelectObject(&m_cacheCBitmap);
//————————————————————开始绘制——————————————————————
//贴背景,现在贴图就是贴在缓冲DC:m_cache中了
m_bg.Draw(m_cacheDC,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
MyHero.character.Draw(m_cacheDC,MyHero.x,MyHero.y,80,80,
MyHero.frame*80,MyHero.direct*80,80,80);
//最后将缓冲DC内容输出到窗口DC中
cDC-&BitBlt(0,0,m_client.Width(),m_client.Height(),&m_cacheDC,0,0,SRCCOPY);
//————————————————————绘制结束—————————————————————
//在绘制完图后,使窗口区有效
ValidateRect(&m_client);
//释放缓冲DC
m_cacheDC.DeleteDC();
//释放对象
m_cacheCBitmap.DeleteObject();
//释放窗口DC
ReleaseDC(cDC);
//是否可以通行的判断
bool CChildView::CanPass()
//水平方向的雾央省略了,留给大家自己完成
if(MyHero.direct==LEFT || MyHero.direct==RIGHT )
for(int x=MyHero.x;x&MyHero.x+MyHero.x++)
//检测的宽度是人物的宽度
//雾央在这里偷了个懒,只检测了人物下一时刻要到达的位置,即MyHero.y-5处
//万一障碍物很薄,只有2个像素宽之类的,就会失效
//主要是因为以后人物的移动方式不会是这种位移直接增加的方式,所以雾央在这里主要是介绍一下思想
//在流畅动画那一节中,雾央会重新讲解,以后会给出新的demo
if(MyHero.direct==UP)
//方向向上时
if(m_bgblack.GetPixel(x,MyHero.y-5)==RGB(0,0,0))
//遇到黑色像素返回false
else if(MyHero.direct==DOWN)
//方向向下时
//向下时,记得加上人物的宽度,因为人物的xy位置是它的左上角坐标
if(m_bgblack.GetPixel(x,MyHero.y+MyHero.height+5)==RGB(0,0,0))
//遇到黑色像素返回false
//按键响应函数
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
//nChar表示按下的键值
switch(nChar)
//游戏中按下的键当然应该不区分大小写了
MyHero.direct=RIGHT;
MyHero.x+=5;
MyHero.direct=LEFT;
MyHero.x-=5;
MyHero.direct=UP;
if(CanPass())
MyHero.y-=5;
MyHero.direct=DOWN;
if(CanPass())
MyHero.y+=5;
//鼠标左键单击响应函数
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
char bufPos[50];
sprintf(bufPos,&你单击了点X:%d,Y:%d&,point.x,point.y);
AfxMessageBox(bufPos);
//定时器响应函数
void CChildView::OnTimer(UINT_PTR nIDEvent)
switch(nIDEvent)
case TIMER_PAINT:OnPaint();
//若是重绘定时器,就执行OnPaint函数
case TIMER_HEROMOVE:
//控制人物移动的定时器
MyHero.frame++;
//每次到了间隔时间就将图片换为下一帧
if(MyHero.frame==4)
//到最后了再重头开始
MyHero.frame=0;
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
在此添加您专用的创建代码
//创建一个10毫秒产生一次消息的定时器
SetTimer(TIMER_PAINT,10,NULL);
//创建人物行走动画定时器
SetTimer(TIMER_HEROMOVE,100,NULL);
& & 雾央今天听到一首很好听的歌,吴琼的《故人叹》,就作为背景音乐了,希望大家喜欢咯。
& &《MFC游戏开发》笔记十到这里就结束了,更多精彩请关注下一篇。如果您觉得文章对您有帮助的话,请留下您的评论,点个赞,能看到你们的留言是我最高兴的事情,因为这让我知道我正在帮助曾和我一样迷茫的少年,你们的支持就是我继续写下去的动力,愿我们一起学习,共同努力,复兴国产游戏。
& & &对于文章的疏漏或错误,欢迎大家的指出。
阅读(...) 评论()
木其网络科技专业程序员代写
程序员学历擅长经验网店链接
硕士ASP.NET PHP 电子 通信设计 图像 编程 网络5年
本科C语言 C++面向对象 Java5年
本科Java Web项目 JSP Hibernate Struts Mysql5年这几天放寒假了,时间也多了起来,当然又有时间搞搞程序了。哈哈~昨天在开发我的塔防游戏时突然发现人物实际攻击范围比规定的范围小,按理说应该是一样大的,但偏偏不是,我被这个问题搞得糊里糊涂的,一直没想出问题所在。最后询问了一个程序高手——我哥哥。他虽然是搞C++的,但听了我代码解释中有检测圆形碰撞时,他立刻就发现了问题,他告诉我,敌人可以看作是方块,而攻击范围是圆的,如果把敌人弄成圆形进行碰撞检测那必然不准,应该检测矩形和圆形碰撞才行。我听了之后恍然大悟,但是lufylegend中没有这个功能,怎么办呢?我第一想法是对lufy说说,让他老人家实现吧。当我点开Google Talk准备发起对话时,突然又想到一来要是lufy老人家去实现,那要等到猴年马月去了,况且lufy前辈琐事缠身,要是我总是给他提意见不帮忙解决,他老人家是不是想打我啊……最后我还是决定自己来实现吧。但是我没搞过这方面的研究,没有经验,所以一开始有点懵,于是就去Google了一下,发现还真有人讲过,于是就点开看了,不知道是我理解能力不好还是文章写得差(估计都是我理解能力不好……)我看了半晌没看懂,呜呼,无法可想,我当时就失望了。但是文章下面有段C代码,于是我把它移植到js上来,运行了一下,感觉效果还不错,于是就马上跑到github上把代码上传给lufy了,并做了一个demo,并在Google Talk上提醒了lufy叫他老人家测试,结果lufy拿到代码一测试就发现了bug。我X,不愧是大神啊……没有办法,只有另谋出路了。今早起来,哎呀,天气不错啊,成都好久没有这么爽的天气了。只见空气清新,阳光和煦,真是外出骑车的好机会啊!于是我便和家人一块儿跑到外面溜达了一圈。边走边想矩形和圆形碰撞的事。半天想不明白,呜呼,我只好在路上问了问哥哥。哥哥果然是高手,他想了一会儿便说出了重点,给了我启发。于是回到家,我便马上打开电脑,进行了实验,结果还成功了。当然,按照以往我的习惯,这次小小“发明”也当然也要分享给大家啦~(以上事情均发生在1月11日和1月12日,所以lufy看到文章开头不要以为走错家门了……)上面说到了我的塔防游戏,现在已经完工得差不多了~大家可以看看它的一些介绍:&,顺便发几张截图,给大伙提提兴趣。废话写了一大堆,接下来还是来看看矩形和圆形碰撞实现过程吧。一,原理介绍这回有点复杂,不过看懂了还是很好理解的。当然,我不敢保证这种算法在任何情况下都会起效果,如果有同学测试时,发现出现错误,请及时联系我。我们首先来建立一个以圆心为原点的坐标系:然后要检测碰撞就只有两种情况了。情况一,矩形全部都在一个象限内,如图:当然,图中只是举个例子,不一定是只在第二象限,任何一个象限都行,只要是矩形全在该象限。这种情况比较好解决,首先,我们计算出矩形每个角的坐标,然后用勾股定律依次算出这个角到圆心的距离是否小于或者等于半径。设这个角与圆心横坐标之差为d1,纵坐标之差为d2,半径为r,公式表达如下:如果有一个角满足要求说明产生碰撞,返回true。但是有朋友懵了,怎么判断矩形是不是在一个象限内呢?很简单,只要判断这个矩形左上角和右下角是否在同一个象限内就可以了。于是我们得写个函数来实现判断某两个角是否在同一象限。函数代码如下:function isSameQuadrant(cood,objA,objB){
var coodX = cood.x;
var coodY = cood.y;
var xoA = objA.x
,yoA = objA.y
,xoB = objB.x
,yoB = objB.y;
if(xoA-coodX&0 && xoB-coodX&0){
if((yoA-coodY&0 && yoB-coodY&0) || (yoA-coodY&0 && yoB-coodY&0)){
}else if(xoA-coodX&0 && xoB-coodX&0){
if((yoA-coodY&0 && yoB-coodY&0) || (yoA-coodY&0 && yoB-coodY&0)){
}这个函数原本是准备写到lufylegend中LMath静态类中的,参数原本是LPoint对象,但是这里可以用json,因为LPoint里的x,y属性可以写到json里,函数也就同样取得出值了。函数参数介绍:[cood创建的坐标系原点坐标, objA第一个点坐标, objB第二个点坐标] 这几个参数均为json对象,格式为:{x:点的x坐标, y:点的y坐标}函数中的代码还是很好理解的,就是判断一下两个点的x坐标都分别减去原点x坐标,看得出的数正负符号是否相同,然后又用同样的办法算出y轴上的符号是否相同,如果都相同就在同一象限。有了这个函数,剩下得就好办了,直接代入开头给出的公式进行计算即可。情况二,矩形跨度两个象限或者两个象限以上这种情况更好办,我们就可以直接把圆看作一个边长为2r正方形,然后用矩形碰撞算法检测正方形和矩形的碰撞,如下图所示:矩形碰撞的算法是什么呢?很easy,如图:如果要横向判断碰撞的话,判断(x1-x2)的绝对值是否小于或者等于w1/2+w2/2,如果是则横向则有碰撞。纵向判断是一样的,判断(y1-y2)的绝对值是否小于或等于h1/2+h2/2即可。有了这些算法,我们就可以实现情况2了。二,Javascript版算法&测试代码先上代码吧:function hitTestRectArc(rectObj,arcObj,rectVec,arcR){
var rw = rectObj.getWidth()
,rh = rectObj.getHeight()
,ar = arcObj.getWidth()*0.5
,rx = rectObj.x
,ry = rectObj.y
,ax = arcObj.x
,ay = arcObj.y;
if(typeof rectVec != UNDEFINED){
rx += (rw - rectVec[0])*0.5;
ry += (rh - rectVec[1])*0.5;
rw = rectVec[0];
rh = rectVec[1];
if(typeof arcR != UNDEFINED){
ax += (ar - arcR);
ay += (ar - arcR);
ar = arcR;
var rcx = rx+rw*0.5,rcy = ry+rh*0.5;
var rltx = rx
,rlty = ry
,rlbx = rx
,rlby = ry+rh
,rrtx = rx+rw
,rrty = ry
,rrbx = rx+rw
,rrby = ry+
isSameQuadrant(
{x:ax,y:ay},
{x:rltx,y:rlty},
{x:rrbx,y:rrby}
var dX1 = Math.abs(ax-rltx),dY1 = Math.abs(ay-rlty);
var dX2 = Math.abs(ax-rlbx),dY2 = Math.abs(ay-rlby);
var dX3 = Math.abs(ax-rrtx),dY3 = Math.abs(ay-rrty);
var dX4 = Math.abs(ax-rrbx),dY4 = Math.abs(ay-rrby);
(((dX1*dX1) + (dY1*dY1)) &= (ar*ar))
||(((dX2*dX2) + (dY2*dY2)) &= (ar*ar))
||(((dX3*dX3) + (dY3*dY3)) &= (ar*ar))
||(((dX4*dX4) + (dY4*dY4)) &= (ar*ar))
var result =
var squareX = ax
,squareY = ay
,squareW = ar*2
,squareH = squareW;
(Math.abs(squareX-rcx) &= (squareW+rw)*0.5)
&&(Math.abs(squareY-rcy) &= (squareH+rh)*0.5)
}由于是为lufylegend设计的函数,所以参数为&[ rectObj矩形对象(LSprite或者LShape对象), arcObj圆形对象(LSprite或者LShape对象), rectVec矩形规定大小(可不填), arcR圆形半径(可不填)] 当然,或许些朋友不懂这几行代码:var rw = rectObj.getWidth()
,rh = rectObj.getHeight()
,ar = arcObj.getWidth()*0.5
,rx = rectObj.x
,ry = rectObj.y
,ax = arcObj.x
,ay = arcObj.y;好吧,我告诉你,这里用到的是lufylegend中LSprite和LShape,这两个类有x、y属性,还有获取宽度和高度的getWidth()和getHeight(),这里看不懂没关系,你知道是取高度和宽度还有x,y坐标的就行了。当然你要深究,那就看看lufylegend.js的API文档吧:&,以下测试代码也用到了lufylegend.js,据说这个引擎是个不错的引擎,想了解的同学,去官方网站看看吧:&或者看看我的文章,大多数是讲解有关lufylegend开发的。示例代码:init(50,&mylegend&,500,250,main);
function main(){
LGlobal.setDebug(true);
var back = new LSprite();
back.graphics.drawRect(5,&green&,[0,0,LStage.width,LStage.height],true,&lightblue&);
addChild(back);
var cObj = new LSprite();
cObj.x = 200;
cObj.y = 120;
cObj.graphics.drawArc(0,&&,[0,0,50,0,2*Math.PI],true,&red&);
back.addChild(cObj);
var rObj = new LSprite();
rObj.x = 250;
rObj.y = 70;
rObj.alpha = 0.8;
rObj.graphics.drawRect(0,&&,[0,0,100,100],true,&green&);
back.addChild(rObj);
trace(hitTestRectArc(rObj,cObj));
back.addEventListener(LMouseEvent.MOUSE_DOWN,function(e){
rObj.x = e.offsetX-rObj.getWidth()*0.5;
rObj.y = e.offsetY-rObj.getHeight()*0.5;
trace(hitTestRectArc(rObj,cObj));
测试链接:三,C++版C++版我用的是Qt,所以大家运行要在Qt creator里编译运行。HitTestAlg.h里的代码:#ifndef HITTESTALG_H
#define HITTESTALG_H
#include &math.h&
#include &QPoint&
#include &QRect&
class CMath
static int pow(int base, int powerOf)
return (int)::pow((double)base, (double)powerOf);
static int sqrt(int n)
return (int)::sqrt((double)n);
static int abs(int n)
n = n & 0 ? -n :
static int distance(const QPoint& pt1, const QPoint& pt2)
return CMath::sqrt(CMath::pow(CMath::abs(pt1.x() - pt2.x()), 2) + CMath::pow(CMath::abs(pt1.y() - pt2.y()), 2));
class CArc
protected:
QPoint m_ptC
CArc() : m_nRadius(0), m_ptCenter(0, 0){}
CArc(const CArc& arc) : m_nRadius(arc.radius()), m_ptCenter(arc.center()){}
CArc(int radius, QPoint center) : m_nRadius(radius), m_ptCenter(center){}
CArc(int radius, int centerX, int centerY) : m_nRadius(radius), m_ptCenter(centerX, centerY){}
void setRadius(int radius){m_nRadius =}
int radius() const {return m_nR}
void setCenter(const QPoint& center){m_ptCenter =}
void setCenter(int centerX, int centerY){m_ptCenter = QPoint(centerX, centerY);}
QPoint center() const {return m_ptC}
QRect rect() const {return QRect(center().x() - radius(), center().y() - radius(), 2 * radius(), 2 * radius());}
class CHitTestAlg
protected:
QRect m_rtR
CArc m_arA
protected:
bool locatedSameQuadrant() const
bool bRes =
int nRectLeft = m_rtRect.left(), nRectTop = m_rtRect.top(), nRectRight = m_rtRect.right(), nRectBottom = m_rtRect.bottom();
int nArcCenterX = m_arArc.center().x(), nArcCenterY = m_arArc.center().y();
if((nRectLeft - nArcCenterX &= 0 && nRectRight - nArcCenterX &= 0 && nRectTop - nArcCenterY &= 0 && nRectBottom - nArcCenterY &= 0)
|| (nRectLeft - nArcCenterX &= 0 && nRectRight - nArcCenterX &= 0 && nRectTop - nArcCenterY &= 0 && nRectBottom - nArcCenterY &= 0)
|| (nRectLeft - nArcCenterX &= 0 && nRectRight - nArcCenterX &= 0 && nRectTop - nArcCenterY &= 0 && nRectBottom - nArcCenterY &= 0)
|| (nRectLeft - nArcCenterX &= 0 && nRectRight - nArcCenterX &= 0 && nRectTop - nArcCenterY &= 0 && nRectBottom - nArcCenterY &= 0)
bool hitTestRect() const
QRect rtArc = m_arArc.rect();
bool bRes =
if(CMath::abs(m_rtRect.center().x() - rtArc.center().x()) &= CMath::abs((m_rtRect.width() + rtArc.width()) / 2)
&& CMath::abs(m_rtRect.center().y() - rtArc.center().y()) &= CMath::abs((m_rtRect.height() + rtArc.height()) / 2)
bool hitTestAngleArc() const
bool bRes =
QPoint ptRectTopLeft = m_rtRect.topLeft(), ptRectTopRight = m_rtRect.topRight()
, ptRectBottomLeft = m_rtRect.bottomLeft(), ptRectBottomRight = m_rtRect.bottomRight()
, ptArcCenter = m_arArc.center();
int nArcRadius = m_arArc.radius();
if(CMath::distance(ptRectTopLeft, ptArcCenter) &= nArcRadius
|| CMath::distance(ptRectTopRight, ptArcCenter) &= nArcRadius
|| CMath::distance(ptRectBottomLeft, ptArcCenter) &= nArcRadius
|| CMath::distance(ptRectBottomRight, ptArcCenter) &= nArcRadius
CHitTestAlg(const QRect& rect, const CArc& arc) : m_rtRect(rect), m_arArc(arc){}
~CHitTestAlg(){}
bool hitTest() const
bool bRes =
if(locatedSameQuadrant()){
bRes = hitTestAngleArc();
bRes = hitTestRect();
#endif // HITTESTALG_H
mainwindow.h里的代码:#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include &QWidget&
#include &HitTestAlg.h&
class MainWindow : public QWidget
protected:
protected:
virtual void mouseReleaseEvent(QMouseEvent *mouseEvent);
virtual void paintEvent(QPaintEvent *paintEvent);
MainWindow(QWidget *parent = 0);
~MainWindow();
#endif // MAINWINDOW_H
mainwindow.cpp里的代码:#include &QDebug&
#include &QMouseEvent&
#include &QBrush&
#include &QPainter&
#include &mainwindow.h&
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
, m_rtRect(0, 0, 100, 50)
, m_arArc(50, 200, 200)
, m_bHit(false)
QWidget::showMaximized();
MainWindow::~MainWindow()
void MainWindow::mouseReleaseEvent(QMouseEvent *mouseEvent)
if(mouseEvent){
QPoint ptPos = mouseEvent-&pos();
rtRect.setX(ptPos.x() - m_rtRect.width() / 2);
rtRect.setY(ptPos.y() - m_rtRect.height() / 2);
rtRect.setWidth(m_rtRect.width());
rtRect.setHeight(m_rtRect.height());
m_rtRect = rtR
m_bHit = CHitTestAlg(m_rtRect, m_arArc).hitTest();
QWidget::update();
void MainWindow::paintEvent(QPaintEvent *paintEvent)
Q_UNUSED(paintEvent)
QPainter xPainter(this);
xPainter.save();
QBrush xB xBrush.setColor(Qt::red); xBrush.setStyle(Qt::SolidPattern);
QPen xP xPen.setColor(Qt::black); xPen.setStyle(Qt::SolidLine);
xPainter.setBrush(xBrush);
xPainter.setPen(xPen);
xPainter.drawEllipse(m_arArc.center(), m_arArc.radius(), m_arArc.radius());
xPainter.restore();
xPainter.save();
QBrush xB xBrush.setColor(Qt::darkGreen); xBrush.setStyle(Qt::SolidPattern);
QPen xP xPen.setColor(Qt::black); xPen.setStyle(Qt::SolidLine);
xPainter.setBrush(xBrush);
xPainter.setPen(xPen);
xPainter.drawRect(m_rtRect);
xPainter.restore();
xPainter.save();
QString sContent = QString(&Hit Test: %1&).arg(m_bHit ? &true& : &false&);
QFont ftFont(&Tahoma&, 12, QFont::DemiBold, true);
xPainter.setFont(ftFont);
xPainter.drawText(20, m_arArc.rect().bottom() + 30, sContent);
xPainter.restore();
main.cpp里的代码:#include &QApplication&
#include &mainwindow.h&
int main(int argc, char *argv[])
QApplication a(argc, argv);
return a.exec();
原理和js版是一样的,就不多解释了,在下面我会放出所有代码。C++版运行demo如下:Qt做的界面感觉还是不错的,哈哈~~源代码下载:本文就到此为止,以上就是本篇所有内容,欢迎大家交流。----------------------------------------------------------------欢迎大家转载我的文章。转载请注明:转自欢迎继续关注我的博客
本文已收录于以下专栏:
相关文章推荐
碰撞器由来
1.系统默认会给每个对象(GameObject)添加一个碰撞组件(ColliderComponent),一些背景对象则可以取消资格组件。
2.在unity3d中,能检测碰撞发生的方式有两种...
判断是两个形状是否相交(一)-SAT分离轴理论原文地址简介分离轴理论,简称SAT(SeparatingAxisTheoremSeparating Axis Theorem),是一个判断两个凸多边形是否...
人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..
简介:分离轴理论,简称SAT(Separating AxisTheorem),是一个判断两个凸多边形是否碰撞的理论。此理论可以用于找到最小的渗透向量(感觉应该是模最小的),此向量在物理模拟和其他很多应...
Unity 使用物理射线(Physics.Raycast),实现扇形(Fan-Shaped)区域碰撞检测。
参考之前的制作简单UI: Unity 有限状态机(Finite State Machin...
首先要说的就是:怎么实现一个自定义的滚动条
主要步骤:
1. 定义两个div,一大一小,让小div在大div上滚动
2. 利用拖拽原理使小div可以滚动,这里拖拽的时候,只是改变小div的l...
一个简单的碰撞检测例子,检测div1是否和div2发生碰撞,当div1碰到div2时,改变div2的颜色,看测试图
看一下分析图:
当div1在div2的上边线(t2)以上的区...
点和矩形碰撞
[java] view
plaincopyprint?
     *  
    &#16...
几乎所有的3D游戏都离不开碰撞检测——无论是各物体之间的碰撞检测,还是物体与场景之间的碰撞检测。在真实世界中,你是很自然地不能穿墙而过的,所以很多人在玩各种3D游戏的时候自然而然的忽视了碰撞检测这一过...
本文翻译自@sevenson的文章Separating Axis Theorem (SAT) Explanation 。原文作者用的是ActionScript 3来编写算法,不过文中主要讲述的还是算法...
他的最新文章
讲师:董西成
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 多物体互相碰撞判定 的文章

 

随机推荐