cocos2d-x中的碰撞检测

时间:2021-02-02 04:56:58

今天在csdn看到一篇文章,写矩形与圆形的碰撞检测,借鉴了作者的检测思路,我把它用到了cocos2d-x中。

原文章的地址:点击打开链接

在cocos2d-x中已经提供了矩形与矩形的碰撞检测以及点与矩形的碰撞检测,如下:

检测矩形与矩形碰撞的函数:

bool intersectsRect(const CCRect &rect)
使用方法:
rect1.intersectsRect(rect2);

检测 点与矩形碰撞的函数:
bool containsPoint(const CCPoint &point)
使用方法:
rect.containsPoint(point); 

下面重点说矩形与圆形的碰撞检测:
PS:先说一下cocos2d-x中的矩形Rect,Rect的构造有四个参数,x, y, width, height,如下图所示
cocos2d-x中的碰撞检测

以圆心为原点新建一个坐标系,碰撞检测分两种情况:
1.整个矩形位于同一个象限中
怎么判断是否只在一个象限呢?看一对对角顶点是否位于同一象限就可以了,判断这两个顶点的x,y坐标是否同号即可。
检测四个顶点中若有至少一个顶点位于圆内,矩形和圆形就碰撞了;否则没有。
2.矩形位于两个或四个象限中(不会出现三个的情况)
这时候可以检测矩形与圆的外切正方形时候碰撞,它们的检测结果和矩形与圆的检测结果相同。

实现如下,会有必要的注释:
//
// CGCircle.h
// HelloCpp
//
// Created by Mike on 14-1-16.
//
//

#ifndef __HelloCpp__CGCircle__
#define __HelloCpp__CGCircle__

#include <iostream>
#include "cocos2d.h"
using namespace std;
using namespace cocos2d;

class CGCircle
{
private:
//float _radius; //半径
//Point _position; //圆心

public:
CC_SYNTHESIZE(float, _radius, Radius);
CC_SYNTHESIZE(Point, _position, Position);

CGCircle(float radius, Point position): _radius(radius), _position(position){};

bool isContainRect(Rect rect);
};

#endif /* defined(__HelloCpp__CGCircle__) */

////  CGCircle.cpp//  HelloCpp////  Created by Mike on 14-1-16.////#include "CGCircle.h"bool CGCircle::isContainRect(Rect rect){    bool _isContian = false;    Point orign = _position;  //圆心,新建坐标系的原点        //圆的外切正方形  Rect(x, y, width, heigth) x,y是原点,左下顶点    Rect square = Rect::Rect(_position.x - _radius, _position.y - _radius,                             2 * _radius, 2 * _radius);        do {        Point rectVertex0 = rect.origin; //左下        Point rectVertex1 = rect.origin + Point(rect.size.width, 0); //右下        Point rectVertex2 = rect.origin + Point(rect.size.width, rect.size.height); //右上        Point rectVertex3 = rect.origin + Point(0, rect.size.height); //左上        Point pos[] = {rectVertex0, rectVertex1, rectVertex2, rectVertex3};                if ((pos[1].x - orign.x) * (pos[3].x - orign.x) > 0 &&            (pos[1].y - orign.y) * (pos[3].y - orign.y) > 0)        {            //右下顶点和左上顶点在同一象限,说明整个矩形位于一个象限内 若各顶点至少有一个在圆内则相交            for (int i = 0; i < 4; i++) {                //判断矩形四个顶点是否至少有一个位于圆内                if (((pos[i].x - orign.x) * (pos[i].x - orign.x)                     + (pos[i].y - orign.y) * (pos[i].y - orign.y))                    <= _radius * _radius)                {                    goto next;                }            }        }                if (square.intersectsRect(rect)) {            goto next;        }                for (int i = 0; i < 4; i++) {            if (pos[i] == orign) {                goto next;            }        }                break;            next:        _isContian = true;    } while (0);        return _isContian;}

测试代码:
Size visibleSize = Director::getInstance()->getVisibleSize();
auto circleS = Sprite::create("circle.png");
circleS->setPosition(Point(visibleSize.width/2, visibleSize.height/2));
this->addChild(circleS, 0);

auto rectS = Sprite::create("rect.png");
rectS->setPosition(Point(circleS->getPositionX() - 100, circleS->getPositionY()));
this->addChild(rectS, 0);

CGCircle circle0 = CGCircle(circleS->getContentSize().width/2, circleS->getPosition());
Rect rect0 = Rect(rectS->getPositionX() - rectS->getContentSize().width/2,
rectS->getPositionY() - rectS->getContentSize().height/2,
rectS->getContentSize().width, rectS->getContentSize().height);
if (circle0.isContainRect(rect0)) {
CCLOG("circleS与rectS碰撞了");
}
else CCLOG("circleS与rectS未碰撞");


float radius = 30.0;
Point position = Point(300, 300);
CGCircle circle = CGCircle(radius, position);

Rect rect1 = Rect(280, 290, 10, 30);
if (circle.isContainRect(rect1))
{
CCLOG("矩形1与圆碰撞了");
}

Rect rect2 = Rect(210, 290, 10, 30);
if (! circle.isContainRect(rect2))
{
CCLOG("矩形2与圆未碰撞");
}
测试输出:
cocos2d: circleS与rectS未碰撞
cocos2d: 矩形1与圆碰撞了
cocos2d: 矩形2与圆未碰撞

如有问题,还请指正~