关于C/C++游戏引擎如何判断碰撞(以SDL2为例)

本文介绍了在C/C++使用SDL2库实现游戏引擎时,如何进行多边形碰撞检测。通过讲解如何判断两个多边形是否相交,包括边重叠和射线交点个数的奇偶性判断,详细阐述了碰撞检测的原理和步骤。引用了其他博主的代码并提供了相关资源链接。

Version:alpha 2.4

Information:

代码摘自我自己的一个项目的一段代码

本文是类似日记形式,可以帮助需要的人,我在未来也会回来看(忘了时)

2022.3.18时我还只是12岁,许多公式不知道,故引用了网上许多博主的代码,原博客地址在注释内有所体现

这是建立在SDL2上的游戏引擎,这很低级,大佬勿喷

//精灵定义
class Spirit {
   
   
public:
    void SetPicture(SDL_Texture* image);
    void SetHitBox(const vector<SDL_LFPoint> hit_box);
    void SetDirection(double direction);
    void SetSize(double sz);
    void SetBaseDirection(double _basedir);
    double GetSize();
    void Move(double speed);
    void Update();
    void SetPostion(SDL_LFPoint pos);
    void SetRotatePoint(SDL_LFPoint pos);
    vector<SDL_LFPoint> GetHitBox();
    SDL_Texture* GetPicture();
    double GetDirection();
    SDL_LFPoint GetPos();
    bool Spirit::IsHitWith(const vector<SDL_LFPoint>);
    SDL_LFPoint GetRotatePoint();
    SDL_LFPoint GetPostion();
protected:
    vector<SDL_LFPoint> hitBox;
    vector<SDL_LFPoint> rotateHitBox;
    SDL_LFPoint place, rotatePoint;
    SDL_Texture* picture;
    double dir, basedir; //0~360
    double size = 1.0;//x0 ~ inf
};
以下是一些你可能需要的明白的东西
首先,我们使一个精灵的碰撞箱是一个多边形用"vector<SDL_LFPoint>"来存
(注:如果一个多边形是vector<SDL_LFPoint> poly, 则poly[x]与poly[(x + 1) % poly.size()]连边)
那么你就看懂了bool Spirit::IsHitWith(const vector<SDL_LFPoint> box);的定义,两个多边形碰撞箱是否碰撞
Spirit::rotateHitBox是经过旋转处理(SetDirection())后的碰撞箱
那么我们如下处理:
1.如果两个多边形有边重叠,则它们一定相交
2.如果一条直线向任意方向延伸出一条射线,则如果与另一多边形的交点个数为奇数则一个在另一个里边(如果刚好交点在顶点,则要去掉一次,不然就会多一次)
3.否则不相交
注:这适用于任意多边形(包括凹多边形)

这里使用了qq_41726230::is_intersect()来自https://blog.youkuaiyun.com/qq_41726230/article/details/105037871
和自己推的HitPoint2Line()
SDL_LFPoint HitPoint2Line(SDL_LFPoint a1, SDL_LFPoint b1, SDL_LFPoint a2, SDL_LFPoint b2) {
   
   
    /*
     * y=ax+b
     * x1 y1 x2 y2
     * y1=ax1+b
     * y2=ax2+b
     * y1-y2=a(x1-x2)
     * a=(y1-y2)/(x1-x2)
     * b=y1-a*x1
     */
    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;
    /*
     * y=fa1*x+fa2
     * y=fb1*x+fb2
     * x*(fa1-fb1)+(fa2-fb2)=0
     * x*(fa1-fb1)=fb2-fa2
     * x=(fb2-fa2)/(fa1-fb1)
    */
    double x = (fb2 - fa2) / (fa1 - fb1);
    double y = fa1 * x + fa2;
    return {
   
    x, y };
}

bool Spirit::IsHitWith(const vector<SDL_LFPoint> 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.
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值