代码:
#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 judgementvirtual 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 vectorauto normal = other->GradientSDF(spritePoint).Normalize();auto newPosition = spritePoint + normal * abs(sdf);// Fix the positionsprite->RelativeMove(newPosition);// Fix the speedif (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;
}
运行结果: