EasyX 碰撞检测

news2024/11/24 7:43:56

代码:

#define _UNICODE
#define UNICODE

#include <array>
#include <cmath>
#include <ctime>
#include <format>
#include <graphics.h>
#include <vector>

typedef struct tagRECTF {
	double left;
	double top;
	double right;
	double bottom;
} RECTF, * PRECTF, NEAR* NPRECTF, FAR* LPRECTF;

// 2D Vector
class Vec final {
public:
	Vec() : x({ 0, 0 }) {
	}
	Vec(std::array<double, 2> Init) : x(Init) {
	}

public:
	auto Length() noexcept -> double {
		return sqrt(pow(x[0], 2) + pow(x[1], 2));
	}
	auto Normalize() noexcept -> Vec {
		return (*this) / Length();
	}
	auto DotProduct(const Vec& Vector) noexcept -> double {
		return Vector.x[0] * x[0] + Vector.x[1] * x[1];
	}

public:
	auto operator*=(const Vec& Value) -> Vec& {
		for (auto position = size_t(0); position < 2; ++position) {
			x[position] *= Value.x[position];
		}

		return (*this);
	}
	auto operator/=(const Vec& Value) -> Vec& {
		for (auto position = size_t(0); position < 2; ++position) {
			x[position] /= Value.x[position];
		}

		return (*this);
	}
	auto operator+=(const Vec& Value) -> Vec& {
		for (auto position = size_t(0); position < 2; ++position) {
			x[position] += Value.x[position];
		}

		return (*this);
	}
	auto operator-=(const Vec& Value) -> Vec& {
		for (auto position = size_t(0); position < 2; ++position) {
			x[position] -= Value.x[position];
		}

		return (*this);
	}
	auto operator*=(const double& Value) -> Vec& {
		for (auto position = size_t(0); position < 2; ++position) {
			x[position] * Value;
		}

		return (*this);
	}
	auto operator/=(const double& Value) -> Vec& {
		for (auto position = size_t(0); position < 2; ++position) {
			x[position] / Value;
		}

		return (*this);
	}
	auto operator+=(const double& Value) -> Vec& {
		for (auto position = size_t(0); position < 2; ++position) {
			x[position] + Value;
		}

		return (*this);
	}
	auto operator-=(const double& Value) -> Vec& {
		for (auto position = size_t(0); position < 2; ++position) {
			x[position] - Value;
		}

		return (*this);
	}

public:
	friend auto operator/(const Vec& Left, const Vec& Right)->Vec;
	friend auto operator/(const Vec& Left, const double& Right)->Vec;
	friend auto operator*(const Vec& Left, const Vec& Right)->Vec;
	friend auto operator*(const Vec& Left, const double& Right)->Vec;
	friend auto operator+(const Vec& Left, const Vec& Right)->Vec;
	friend auto operator+(const Vec& Left, const double& Right)->Vec;
	friend auto operator-(const Vec& Left, const Vec& Right)->Vec;
	friend auto operator-(const Vec& Left, const double& Right)->Vec;

public:
	std::array<double, 2> x;
};

auto operator/(const Vec& Left, const Vec& Right) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] / Right.x[position];
	}

	return result;
}
auto operator/(const Vec& Left, const double& Right) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] / Right;
	}

	return result;
}
auto operator*(const Vec& Left, const Vec& Right) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] * Right.x[position];
	}

	return result;
}
auto operator*(const Vec& Left, const double& Right) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] * Right;
	}

	return result;
}
auto operator+(const Vec& Left, const Vec& Right) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] + Right.x[position];
	}

	return result;
}
auto operator+(const Vec& Left, const double& Right) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] + Right;
	}

	return result;
}
auto operator-(const Vec& Left, const Vec& Right) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] - Right.x[position];
	}

	return result;
}
auto operator-(const Vec& Left, const double& Right) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] - Right;
	}

	return result;
}

auto operator/(const double& Right, const Vec& Left) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Right / Left.x[position];
	}

	return result;
}
auto operator*(const double& Right, const Vec& Left) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] * Right;
	}

	return result;
}
auto operator+(const double& Right, const Vec& Left) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Left.x[position] + Right;
	}

	return result;
}
auto operator-(const double& Right, const Vec& Left) -> Vec {
	Vec result;
	for (auto position = size_t(0); position < 2; ++position) {
		result.x[position] = Right - Left.x[position];
	}

	return result;
}

class Sprite {
public:
	Sprite() = default;

public:
	virtual auto Draw() -> void = 0;
	// Use SDF for collision judgement
	virtual auto SDF(const Vec& Point) -> double = 0;
	virtual auto GradientSDF(const Vec& Point) -> Vec = 0;
	virtual auto DealSDF(const double& SDF) -> double {
		return SDF;
	}
	virtual auto Particle() -> Vec = 0;
	virtual auto RelativeMove(const Vec& Position) -> void = 0;

public:
	auto Move(const double& X, const double& Y) -> void {
		auto width = boundingBox.right - boundingBox.left;
		auto height = boundingBox.bottom - boundingBox.top;

		boundingBox = { X, Y, X + width, Y + height };
	}

public:
	bool  lock = true;
	RECTF boundingBox{};
	Vec	  velocity;
};
class RoundSprite : public Sprite {
public:
	explicit RoundSprite(const double& Radius) : radius(Radius), Sprite() {
		boundingBox = { 0, 0, Radius * 2, Radius * 2 };
	}

public:
	auto Draw() -> void override {
		setfillcolor(WHITE);
		solidcircle(boundingBox.left + radius, boundingBox.top + radius, radius);
	}
	auto SDF(const Vec& Point) -> double override {
		Vec centre({ boundingBox.left + radius, boundingBox.top + radius });

		return (Point - centre).Length() - radius;
	}
	auto GradientSDF(const Vec& Point) -> Vec override {
		auto base = SDF(Point) + radius;
		Vec	 centre({ boundingBox.left + radius, boundingBox.top + radius });
		return Vec({ (Point.x[0] - centre.x[0]) / base, (Point.x[1] - centre.x[1]) / base });
	}
	auto DealSDF(const double& SDF) -> double override {
		return SDF - radius;
	}
	auto Particle() -> Vec override {
		return Vec({ boundingBox.left + radius, boundingBox.top + radius });
	}
	auto RelativeMove(const Vec& Position) -> void override {
		Move(Position.x[0] - radius, Position.x[1] - radius);
	}

public:
	double radius;
};
class LineSprite : public Sprite {
public:
	explicit LineSprite(const Vec& Point1, const Vec& Point2) : point1(Point1), point2(Point2) {
		boundingBox = { Point1.x[0], Point1.x[1], Point2.x[0], Point2.x[1] };
	}

public:
	auto Draw() -> void override {
		setlinecolor(WHITE);
		setlinestyle(PS_SOLID, 1);
		line(point1.x[0], point1.x[1], point2.x[0], point2.x[1]);
	}
	auto SDF(const Vec& Point) -> double override {
		Vec	   ap = Point - point1;
		Vec	   ab = point2 - point1;
		double h = ap.DotProduct(ab) / ab.DotProduct(ab);
		h = h >= 1.f ? 1.f : h;
		h = h <= 0.f ? 0.f : h;

		return (ap - h * ab).Length();
	}
	auto GradientSDF(const Vec& Point) -> Vec override {
		auto origin = SDF(Vec({ Point.x[0], Point.x[1] }));
		return Vec({ SDF(Vec({Point.x[0] + 0.0000000001, Point.x[1]})) - origin,
					SDF(Vec({Point.x[0], Point.x[1] + 0.0000000001})) - origin });
	}
	auto Particle() -> Vec override {
		return point1 + (point2 - point1) / 2;
	}
	auto RelativeMove(const Vec& Position) -> void override {
		auto width = boundingBox.right - boundingBox.left;
		auto height = boundingBox.bottom - boundingBox.top;
		point1 = Position;
		point2 = point1 + Vec({ width, height });
		Move(Position.x[0], Position.x[1]);
	}

public:
	Vec point1;
	Vec point2;
};

class SpriteManager {
public:
	SpriteManager() = default;

public:
	auto UpdateSprite() -> void {
		for (auto& sprite : spriteList) {
			if (!sprite->lock) {
				for (auto& other : spriteList) {
					if (&other == &sprite) {
						continue;
					}
					auto spritePoint = sprite->Particle();
					auto sdf = sprite->DealSDF(other->SDF(spritePoint));
					if (sdf <= 0.001) {
						// Normal vector
						auto normal = other->GradientSDF(spritePoint).Normalize();
						auto newPosition = spritePoint + normal * abs(sdf);
						// Fix the position
						sprite->RelativeMove(newPosition);

						// Fix the speed
						if (sprite->velocity.DotProduct(normal) < 0) {
							Vec NVelocity = sprite->velocity.DotProduct(normal) * normal;
							Vec TVelocity = sprite->velocity - NVelocity;
							Vec newNVelocity = (0.f - NVelocity);
							Vec newTVelocity = max(1.f - (NVelocity.Length() / TVelocity.Length()), 1.f) * TVelocity;
							sprite->velocity = newNVelocity + newTVelocity;
						}
					}
				}
			}
		}
		for (auto& sprite : spriteList) {
			auto newPosition =
				Vec({ static_cast<double>(sprite->boundingBox.left), static_cast<double>(sprite->boundingBox.top) }) +
				sprite->velocity * timingTick;
			sprite->Move(newPosition.x[0], newPosition.x[1]);
		}

		cleardevice();

		for (auto& sprite : spriteList) {
			sprite->Draw();
		}
	}

public:
	double				  timingTick = 1.f;
	std::vector<Sprite*> spriteList;
};

int main() {
	initgraph(640, 480);

	SpriteManager manager;
	auto		  roundSprite1 = new RoundSprite(20.f);
	auto		  roundSprite2 = new RoundSprite(60.f);
	auto		  roundSprite3 = new RoundSprite(70.f);
	auto		  roundSprite4 = new RoundSprite(20.f);
	auto		  roundSprite5 = new RoundSprite(20.f);
	auto		  roundSprite6 = new RoundSprite(20.f);
	auto		  border1 = new LineSprite(Vec({ 0, 0 }), Vec({ static_cast<double>(getwidth()), 0 }));
	auto		  border2 = new LineSprite(Vec({ 0, 0 }), Vec({ 0, static_cast<double>(getheight()) }));
	auto		  border3 = new LineSprite(Vec({ static_cast<double>(getwidth()), 0 }),
		Vec({ static_cast<double>(getwidth()), static_cast<double>(getheight()) }));
	auto		  border4 = new LineSprite(Vec({ 0, static_cast<double>(getheight()) }),
		Vec({ static_cast<double>(getwidth()), static_cast<double>(getheight()) }));
	auto		  lineSprite = new LineSprite(Vec({ 70, 390 }), Vec({ 100, 190 }));
	manager.spriteList.push_back(roundSprite1);
	manager.spriteList.push_back(lineSprite);
	manager.spriteList.push_back(border1);
	manager.spriteList.push_back(border2);
	manager.spriteList.push_back(border3);
	manager.spriteList.push_back(border4);
	manager.spriteList.push_back(roundSprite2);
	manager.spriteList.push_back(roundSprite3);
	manager.spriteList.push_back(roundSprite4);
	manager.spriteList.push_back(roundSprite5);
	manager.spriteList.push_back(roundSprite6);
	roundSprite2->Move(180.f, 80.f);
	roundSprite3->Move(380.f, 180.f);
	roundSprite4->Move(300.f, 120.f);
	roundSprite5->Move(400.f, 320.f);
	roundSprite1->Move(20.f, 20.f);
	roundSprite1->velocity.x = { 1.5f, 0.6f };
	roundSprite4->velocity.x = { -1.7f, 1.3f };
	roundSprite5->velocity.x = { -1.5f, -2.3f };
	roundSprite6->velocity.x = { 3.f, -2.3f };
	roundSprite4->lock = false;
	roundSprite1->lock = false;
	roundSprite5->lock = false;
	roundSprite6->lock = false;

	BeginBatchDraw();

	settextcolor(GREEN);

	auto fpsCount = int(0);
	auto fps = int(0);
	auto time = clock();
	while (true) {
		manager.UpdateSprite();

		if (clock() - time >= 1000) {
			fpsCount = fps;
			fps = 0;
			time = clock();
		}

		++fps;

		FlushBatchDraw();

		Sleep(2);
	}

	return 0;
}

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1984738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

You Only Look Once:Unified, Real-Time Object Detection 论文阅读

论文名&#xff1a;You Only Look Once:Unified, Real-Time Object Detection 论文作者&#xff1a;Joseph Redmon et.al. 期刊/会议名&#xff1a;CVPR 2016 发表时间&#xff1a;2016-5 ​论文地址&#xff1a;https://arxiv.org/pdf/1506.02640 1.摘要 我们提出了一种新的目…

论文辅导 | 结合变种残差模型和 Transformer 的城市公路短时交通流预测

辅导文章 模型描述 城市公路交通流的预测受到历史交通流量和相邻车道交通流量的影响&#xff0c;蕴含了复杂的时空特征。针对传统交通流预测模型卷积长短时记忆网络(ConvLSTM)进行交通流预测时&#xff0c;未将时空特征分开提取而造成的提取不充分、特征信息混淆和特征信息缺失…

视频融合技术

三维视频融合技术遵循数字孪生多源数据融合的原则&#xff0c;比视频窗口、矩阵更加直观高效&#xff0c;省去了人脑理解空间的时间&#xff0c;可有效提升数字孪生城市在物联感知操作、虚实融合交互等方面的能力&#xff0c;动静一体、虚实结合&#xff0c;让三维场景“动起来…

常见的SQL注入

联合查询 如下&#xff0c;要求我们传入一个id值过去。传参?id1&#xff0c;当我们输入id1和id2时&#xff0c;页面中name值和password的值会发生变化&#xff0c;说明此时我们输入的数据和数据库有交互并且将数据显示在屏幕上了 输入?id1&#xff0c;页面发生报错&#xf…

手机联网如何设置动态ip

在现代社会&#xff0c;手机已成为我们日常生活中不可或缺的一部分&#xff0c;无论是工作、学习还是娱乐&#xff0c;都离不开网络的支持。而在手机联网的过程中&#xff0c;IP地址的分配方式显得尤为重要。动态IP地址因其灵活性和安全性&#xff0c;成为了许多用户的首选。那…

电子合同怎么制作?9款常用电子合同软件

文章将介绍了以下9个工具&#xff1a;e签宝、文书宝、签通云、快签宝、法天使、Zycus iContract、airSlate WorkFlow、Lightico、KeepSolid Sign。 在数字化快速发展的今天&#xff0c;电子合同成为了业务操作中不可或缺的一部分&#xff0c;但许多人仍然面临如何有效创建和管理…

Redis vs Memcached:Redis的三大优势

Redis vs Memcached&#xff1a;Redis的三大优势 1. 数据类型2. 数据持久化能力3. 高性能与灵活性 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1. 数据类型 Redis&#xff1a;支持多样化的数据类型&#xff0c;包括字符串&#xff08;S…

前端性能优化-回流与重绘

前言 本文总结回流与重绘相关的知识点 回流与重绘的基本概念 重绘&#xff08;Repaint&#xff09;&#xff1a; 当元素样式发生改变&#xff0c;但不影响其几何属性的时候&#xff0c;浏览器只需要重新绘制这个元素&#xff0c;这个过程被称为重绘。 回流&#xff08;Refl…

Linux_监测CPU和内存

通过TOP持续获取进程的CPU和内存消耗&#xff0c;并写入到表格 # 配置进程名 processvm-agent # 配置次数 number100 # 配置间隔时间 time5 # csv结果文件 filecm_$(date %s).csv echo "%CPU,%MEM">${file} pid$(ps -aux | grep ${process} | awk -F {OFS"…

debug\moc\mocinclude.tmp dose not exist

先把jom禁用&#xff0c;然后清理工程&#xff0c;重新编译&#xff0c;编译通过后再重新打开jom

MybatisPlus的主键策略

ASSIGN_ID(默认策略) 生成唯一的值&#xff0c;包含数字&#xff0c;表对应字段类型bigint或者varchar类型 ASSIGN_UUID() 生成唯一的值&#xff0c;包含数字和字母&#xff0c;表对应字段类型varchar类型 AUTO 主键自动增长效果&#xff0c;和表字段auto_increment INPUT …

养猫劝退?猫咪浮毛太多难清理?宠物空气净化器一招搞定

受不了了&#xff0c;真的很想把家里的猫孩子丢出去&#xff01;平日实在是太能掉毛了&#xff0c;赶上换毛季更夸张&#xff0c;家里都要被猫毛淹没了。这些还能靠多加打扫卫生清理掉&#xff0c;可空气中的浮毛真是束手无策。对于我这种过敏性鼻炎患者&#xff0c;一旦空气中…

FSRCNN论文读后感

本文的主要目的是在尽可能保持恢复质量不变的情况下&#xff0c;提高模型的处理速度&#xff0c;以将其投入实际应用。&#xff08;注意&#xff1a;本文只要是针对大尺寸图像&#xff0c;但实验结果证明&#xff0c;FRSNN模型对于小尺寸图像的处理速度也比SRCNN快&#xff0c;…

鸿蒙应用开发之GridRow和GridCol容器

在不同屏幕上布局是一个比较困难的问题,因为屏幕大小不一样,导致内容布局会比较混乱。所以提出一种网络的方式来布局,即使屏幕大小改变了,但是布局行列数不变,那么内容就不会混乱。使用组件GridRow来管理行,使用组件GridCol管理列。 先来看一下组件GridRow的定义: Grid…

VSCode在windows系统下使用conda虚拟环境配置

如何解决CondaError: Run ‘conda init‘ before ‘conda activate‘_condaerror: run conda init before conda activat-CSDN博客 首先检查自己的anaconda是否是添加到整个的环境变量里了 打开cmd如果conda和python都能够识别那么就是配置成功了 然后看插件是否安装&#xf…

在 cPanel 和 WHM 中配置域名重定向

在处理HTTP请求时&#xff0c;服务器会返回页面内容&#xff0c;这一过程依赖于域名和IP地址的正确配置。手动配置IP和域名非常复杂&#xff0c;但cPanel & WHM的网页界面让日常的网络服务器管理变得轻而易举。例如&#xff0c;Hostease提供的服务器解决方案&#xff0c;支…

3DCoat v2023 激活版下载与安装教程 (数字雕刻程序)

前言 3DCoat 是一款数字雕塑软件&#xff0c;由乌克兰开发。该软件专注于游戏模型的细节设计&#xff0c;集三维模型实时纹理绘制和细节雕刻功能为一身&#xff0c;可以加速细节设计流程&#xff0c;在更短的时间内创造出更多的内容。 一、下载地址 下载链接&#xff1a;分享…

想实现ubuntu搭建sqli-labs靶场

目录 首先前期的nginx和php部署完成​编辑​编辑 Xftp导入sqli-labs 遇到了的问题 它提示我们请检查db-creds.inc 去尝试解决这个问题 尝试修改MySQL root密码 修改db-creds.inc配置 再次尝试依旧失败 思考&#xff1a;会不会是MySQL版本过高的原因 重新下载MySQL5.7.…

优思学院|精益管理的指导思想给企业带来了什么启示?

很多企业和管理者以为&#xff0c;多即是好&#xff0c;尽量加快生产&#xff0c;提升库存&#xff0c;库存越多&#xff0c;安全性越高&#xff0c;尽量迫使员工多做工作&#xff0c;他们的工作越多&#xff0c;效率就越高&#xff0c;凡此种种都是在精益思想诞生前的人们对营…

B站宋红康JAVA基础视频教程个人笔记chapter04

文章目录 1.IDEA安装好后的一些设置和学习1.1关于IDEA内部jdk版本的设置1.2 一些样式以及快捷键的常用设置&#xff08;强烈推荐&#xff09; 2.工程与模块管理3.如何彻底的卸载IDEA 1.IDEA安装好后的一些设置和学习 1.1关于IDEA内部jdk版本的设置 1.File—>Project Struc…