将矩形向外扩张圆半径r来进行碰撞检测
主要可以分为以下两个阶段进行碰撞:
1. 将需要检测的长方形,在上下左右4个方向均向外扩张,扩张的长度为圆半径r,如果扩张后得到新的长方形内包含了圆心坐标,则认为两物体具备碰撞的可能(反之则无碰撞的可能)。
2. 在满足条件1的情况下,如果圆心坐标在原长方形以外、扩张后的长方形的左上、左下、右上、右下四个角处,且圆内没有包含长方形最近的顶点,则认为两物体没有碰撞。
示例代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HitTest
{
class Program
{
static void Main(string[] args)
{
Console.Read();
}
}
/// <summary>
/// 矩形碰撞器
/// </summary>
public class RectCollider
{
//定义左下角为(minX, minY)
public int minX;
public int minY;
//定义右上角为(maxX, maxY)
public int maxX;
public int maxY;
//判断某点是否在矩形内
public bool CheckHit(int x, int y)
{
return x >= minX && x <= maxX && y >= minY && y <= maxY;
}
public bool CheckHit(RectCollider rect)
{
//水平方向存在重叠
if (rect.maxX >= minX && rect.minX <= maxX)
{
//垂直方向存在重叠
if (rect.maxY >= minY && rect.minY <= maxY)
return true;
}
return false;
}
//判断矩形与圆形是否发生碰撞
public bool CheckHit(CircleCollider circle)
{
//判断圆心是否在原矩形内
if (this.CheckHit(circle.x, circle.y))
return true;
//扩展矩形区
RectCollider rect_b = new RectCollider();
rect_b.minX = minX - circle.r;
rect_b.minY = minY - circle.r;
rect_b.maxX = maxX + circle.r;
rect_b.maxY = maxY + circle.r;
//判断圆心是否在扩展矩形内
if (!rect_b.CheckHit(circle.x, circle.y))
return false;//无碰撞可能
//判断矩形左下角是否在圆内
if (AtLeftBottom(circle.x, circle.y))
return circle.CheckHit(minX, minY);
//判断矩形左上角是否在圆内
else if (AtLeftTop(circle.x, circle.y))
return circle.CheckHit(minX, maxY);
//判断矩形的右下角是否在圆内
else if (AtRightBottom(circle.x, circle.y))
return circle.CheckHit(maxX, minY);
//判断矩形右上角是否在圆内
else if (AtRightTop(circle.x, circle.y))
return circle.CheckHit(maxX, maxY);
return true;
}
//判断某个点是否在矩形的左下方
public bool AtLeftBottom(int x, int y)
{
return x < minX && y < minY;
}
//判断某个点是否在矩形的左上方
public bool AtLeftTop(int x, int y)
{
return x < minX && y > maxY;
}
//判断某个点是否在矩形的右下方
public bool AtRightBottom(int x, int y)
{
return x > maxX && y < minY;
}
//判断某个点是否在矩形的右上方
public bool AtRightTop(int x, int y)
{
return x > maxX && y > maxY;
}
}
/// <summary>
/// 圆形碰撞器
/// </summary>
public class CircleCollider
{
public int x;
public int y;
public int r;
//判断某点是否在圆内
public bool CheckHit(int x, int y)
{
int d = (this.x - x) * (this.x - x) + (this.y - y) * (this.y - y);
return d <= r * r;
}
//判断圆形是否与矩形发生了碰撞
public bool CheckHit(RectCollider rect)
{
return rect.CheckHit(this);
}
//判断圆形是否与圆形发生了碰撞
public bool CheckHit(CircleCollider circle)
{
int dx = x - circle.x;
int dy = y - circle.y;
int distSqr = dx * dx + dy * dy;
int drSqr = (r + circle.r) * (r + circle.r);
return distSqr < drSqr;
}
}
}