box);的定义,两个多边形碰撞箱是否碰撞
Spirit::rotateHitBox是经过旋转处理(SetDirection())后的碰撞箱
那么我们如下处理:
1.如果两个多边形有边重叠,则它们一定相交
2.如果一条直线向任意方向延伸出一条射线,则如果与另一多边形的交点个数为奇数则一个在另一个里边(如果刚好交点在顶点,则要去掉一次,不然就会多一次)
3.否则不相交
注:这适用于任意多边形(包括凹多边形)
这里使用了qq_41726230::is_intersect()来自https://blog.csdn.net/qq_41726230/article/details/105037871
和自己推的HitPoint2Line()
SDL_LFPoint HitPoint2Line(SDL_LFPoint a1, SDL_LFPoint b1, SDL_LFPoint a2, SDL_LFPoint b2) {
double fa1 = (a1.y - b1.y) / (a1.x - b1.x);
double fa2 = a1.y - fa1 * a1.x;
double fb1 = (a2.y - b2.y) / (a2.x - b2.x);
double fb2 = a2.y - fb1 * a2.x;
double x = (fb2 - fa2) / (fa1 - fb1);
double y = fa1 * x + fa2;
return { x, y };
}
bool Spirit::IsHitWith(const vector box) {
if (box.empty() || this->hitBox.empty()) return false;
for (int i = 0; i < this->hitBox.size(); i++) {
qq_41726230::line la(
this->rotateHitBox[i].x * this->size + this->place.x, this->rotateHitBox[i].y * this->size + this->place.y,
this->rotateHitBox[i == this->rotateHitBox.size() - 1 ? 0 : i + 1].x * this->size + this->place.x,
this->rotateHitBox[i == this->rotateHitBox.size() - 1 ? 0 : i + 1].y * this->size + this->place.y
);
for (int j = 0; j < box.size(); j++) {
qq_41726230::line lb(
box[j].x, box[j].y,
box[j == box.size() - 1 ? 0 : j + 1].x,
box[j == box.size() - 1 ? 0 : j + 1].y
);
if (qq_41726230::is_intersect(la, lb)) {
return true;
}
}
}
//判断我是不是在他里面
qq_41726230::line l1(this->rotateHitBox[0].x * this->size + this->place.x, this->rotateHitBox[0].y * this->size + this->place.y, -100, -100);
int cnt[1] = {};
for (int j = 0; j < box.size(); j++) {
qq_41726230::line lb(
box[j].x, box[j].y,
box[j == box.size() - 1 ? 0 : j + 1].x,
box[j == box.size() - 1 ? 0 : j + 1].y
);
int a = 0, b = 0;
if (qq_41726230::is_intersect(l1, lb)) cnt[0]++;
auto pos = HitPoint2Line({ l1.xa, l1.ya }, { l1.xb, l1.yb }, { lb.xa, lb.ya }, { lb.xb, lb.yb });
if (pos.x == lb.xa && pos.y == lb.ya) {
cnt[0]--;
}
}
if (cnt[0] & 1) {
return true;
}
//判断他是不是在我里面
cnt[0] = 0;
qq_41726230::line l6(box[0].x, box[0].y, -100, -100);
for (int i = 0; i < this->hitBox.size(); i++) {
qq_41726230::line la(
this->rotateHitBox[i].x * this->size + this->place.x, this->rotateHitBox[i].y * this->size + this->place.y,
this->rotateHitBox[i == this->rotateHitBox.size() - 1 ? 0 : i + 1].x * this->size + this->place.x,
this->rotateHitBox[i == this->rotateHitBox.size() - 1 ? 0 : i + 1].y * this->size + this->place.y
);
if (qq_41726230::is_intersect(l6, la)) cnt[0]++;
auto pos = HitPoint2Line({ l6.xa, l6.ya }, { l6.xb, l6.yb }, { la.xa, la.ya }, { la.xb, la.yb });
if (pos.x == la.xa && pos.y == la.ya) {
cnt[0]--;
}
}
if (cnt[0] & 1) {
return true;
}
//都不是
return false;
}
此处使用了kevin_org的文章https://blog.csdn.net/QIJINGBO123/article/details/100850088
Spirit::SetDirection(double direction);用于旋转
将hitBox转成rotateHitBox,围绕着的点在SetRotatePoint()中定义
过程:
旋转整个多边形=将多边形的每个顶点旋转
CalcRotatePoint()用于计算点的旋转
void Spirit::SetDirection(double direction) {
this->rotateHitBox.clear();
for (int i = 0; i < this->hitBox.size(); i++) {
this->rotateHitBox.push_back(CalcRotatePoint(this->hitBox[i], this->rotatePoint, direction));
}
this->dir = direction;
}
SDL_LFPoint CalcRotatePoint(const SDL_LFPoint& pos, const SDL_LFPoint& rpos, const double& direction) {
SDL_LFPoint res;
//thanks kevin_org for https://blog.csdn.net/QIJINGBO123/article/details/100850088
res.x = (pos.x - rpos.x) * cos(direction * 3.141593 / 180.0) - (pos.y - rpos.y) * sin(direction * 3.141593 / 180.0) + rpos.x;
res.y = (pos.x - rpos.x) * sin(direction * 3.141593 / 180.0) + (pos.y - rpos.y) * cos(direction * 3.141593 / 180.0) + rpos.y;
return res;
}
剩下的就自己看吧
对了,这只是此项目的大概10%不到,所以它无法编译,仅供参考
//Math.h
#pragma once
#include "Structure.h"
#include
#include
#include
#include
using namespace std;
//http://blog.sina.com.cn/s/blog_5d5c80840101bnhw.html
namespace ZH_CN_ZGY {
extern pair PointToSegDistEx(double x, double y, double x1, double y1, double x2, double y2);
}
extern SDL_LFPoint PointToPolygonDistPos(SDL_LFPoint p, vector polygon);
extern SDL_LFPoint HitPoint2Line(SDL_LFPoint a1, SDL_LFPoint b1, SDL_LFPoint a2, SDL_LFPoint b2);
namespace mirro {
extern double Tri(SDL_LFPoint p1, SDL_LFPoint p2);
}
extern SDL_LFPoint CirclePointCalc(double r, double angle, SDL_LFPoint mid);
//Math.cpp
#include "Math.h"
pair ZH_CN_ZGY::PointToSegDistEx(double x, double y, double x1, double y1, double x2, double y2) {
double cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1);
if (cross <= 0) return { sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)), {x1, y1} };
double d2 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
if (cross >= d2) return { sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)), {x2, y2} };
double r = cross / d2;
double px = x1 + (x2 - x1) * r;
double py = y1 + (y2 - y1) * r;
//bug fixed
//return sqrt((x - px) * (x - px) + (py - y1) * (py - y1));
return { sqrt((x - px) * (x - px) + (py - y) * (py - y)), {px, py} };
}
SDL_LFPoint PointToPolygonDistPos(SDL_LFPoint p, vector polygon) {
double result_dis = 1e10;
SDL_LFPoint result;
for (int i = 0; i < polygon.size(); i++) {
SDL_LFPoint a = polygon[i];
SDL_LFPoint b = polygon[(i + 1) % polygon.size()];
auto ret = ZH_CN_ZGY::PointToSegDistEx(p.x, p.y, a.x, a.y, b.x, b.y);
if (ret.first < result_dis) {
result_dis = ret.first;
result = ret.second;
}
}
return result;
}
SDL_LFPoint HitPoint2Line(SDL_LFPoint a1, SDL_LFPoint b1, SDL_LFPoint a2, SDL_LFPoint b2) {
double fa1 = (a1.y - b1.y) / (a1.x - b1.x);
double fa2 = a1.y - fa1 * a1.x;
double fb1 = (a2.y - b2.y) / (a2.x - b2.x);
double fb2 = a2.y - fb1 * a2.x;
double x = (fb2 - fa2) / (fa1 - fb1);
double y = fa1 * x + fa2;
return { x, y };
}
//https://bbs.csdn.net/topics/391814854
namespace mirro {
double Tri(SDL_LFPoint p1, SDL_LFPoint p2) {//形参是Point类的对象p1,p2
double angle;
if (p1.x == p2.x && p1.y < p2.y)
return 90.0;//如果x坐标相等,p1的y值小于p2的y值,则方位角是90
if (p1.x == p2.x && p1.y > p2.y)
return 270.0;//如果x坐标相等,p1的y值大于p2的y值,则方位角是270
if (p1.y == p2.y && p1.x < p2.x)
return 0.0;//如果y坐标相等,p1的x值小于p2的x值,则方位角是180
if (p1.y == p2.y && p1.x > p2.x)
return 180.0;//如果y坐标相等,p1的x值大于p2的x值,则方位角是180
angle = atan((p1.y - p2.y) / (p1.x - p2.x)) * (180.0 / M_PI); //得到弧度制的角
if (p1.x < p2.x && p1.y < p2.y)
return angle; //标准情况下正常输出。
if (p1.x > p2.x)
return 180.0 + angle;//angle正负都有可能。
if (p1.x < p2.x && p1.y > p2.y)
return 360.0 + angle;//angle是负值。
return -999;
}
}
SDL_LFPoint CirclePointCalc(double r, double angle, SDL_LFPoint mid) {
return {
mid.x + r * cos((angle - 90) * M_PI / 180.0),
mid.y + r * sin((angle - 90) * M_PI / 180.0)
};
}
//Structure.h
#pragma once
struct SDL_LFPoint {
double x, y;
};
struct SDL_LFRect {
double x, y, w, h;
};
//Spirit.h
#pragma once
#include "Structure.h"
#include "Math.h"
#include
#include
#include
在CSDN上发布,原文链接:https://dscs2009.blog.luogu.org/guan-yu-cc-you-hu-yin-qing-ru-he-pan-duan-peng-zhuang-yi-sdl2-wei-li-post 这本来就是我写的,自己转载。