提问人:Dreadward07 提问时间:11/9/2023 最后编辑:Dreadward07 更新时间:11/11/2023 访问量:48
Verlet 集成冲突求解器不工作 C++ SFML
Verlet Integration Collision Solver Not working C++ SFML
问:
我一直在用SFML编写一个简单的物理引擎,并且一直在使用Verlet Integration。在编写一个好的碰撞检测器时,我遇到了一个相当大的障碍。我一直在使用这个 github 作为大多数碰撞代码的来源。由于我的代码设置方式,我不得不进行一些调整,但在大多数情况下,想法是相同的。然而,每当两个球体碰撞时,它们都不会像预期的那样弹跳和滚动,它们只是相互粘附,根本不像实际的球体那样行动。
下面是与实际碰撞检查相关的代码部分
void updateCollisions()
{
// Runs through all objects and pushes them apart if they're to close together
for (int i = 0; i < physBalls.size(); i++)
{
PhysicsBall& physball_1 = physBalls[i];
for (int k{ i + 1 }; k < physBalls.size(); k++)
{
PhysicsBall& physball_2 = physBalls[k];
sf::Vector2f collision_axis = physball_1.getPosition() - physball_2.getPosition();
const float dist2 = (collision_axis.x * collision_axis.x) + (collision_axis.y * collision_axis.y);
const float mindist = physball_1.getRadius() + physball_2.getRadius();
if (dist2 < mindist * mindist)
{
const float dist = sqrt(dist2);
const sf::Vector2f n = collision_axis / dist;
const float delta = 0.5f * (dist - mindist);
physball_1.setPosition((physball_1.getPosition() - n * delta * 0.5f));
physball_2.setPosition((physball_2.getPosition() + n * delta * 0.5f));
}
}
}
}
下面是与 Physicsball 类和 Simulation 类相关的所有代码:
#pragma once
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/Audio.hpp>
#include <iostream>
class PhysicsBall
{
private:
sf::CircleShape physball;
float radius;
sf::Vector2f position;
sf::Vector2f prevposition;
sf::Vector2f accel;
//Creates our Physics Ball
void initPhysBall(sf::Vector2f startPos, sf::Vector2f prevPos, float rad)
{
this->radius = rad;
this->position = startPos;
this->prevposition = prevPos;
this->physball.setOrigin(sf::Vector2f(radius, radius));
this->physball.setPosition(startPos);
this->physball.setRadius(this->radius);
this->physball.setFillColor(sf::Color(255, 255, 255, 255));
}
public:
//Constructors and Deconstructors
PhysicsBall(sf::Vector2f startPos, sf::Vector2f prevPos,float rad)
{
initPhysBall(startPos, prevPos, rad);
}
~PhysicsBall()
{
}
//Accessors
sf::Vector2f getPosition()
{
return this->physball.getPosition();
}
float getRadius()
{
return this->physball.getRadius();
}
sf::Vector2f getVelocity()
{
return this->position - this->prevposition;
}
void setPosition(sf::Vector2f pos)
{
this->physball.setPosition(pos);
this->position = pos;
}
//Update Functions
//Moves the ball
void updatePhysBall(float dt)
{
this->physball.setPosition(position);
const sf::Vector2f velocity = this->position - this->prevposition;
this->prevposition = this->position;
this->position = this->position + velocity + this->accel * dt * dt;
}
// Accelerators
void accelerate(sf::Vector2f acc)
{
this->accel += acc;
}
//Render Function
void render(sf::RenderTarget & target)
{
target.draw(this->physball);
}
};
class Simulation
{
private:
sf::RenderWindow* window;
sf::VideoMode videoMode;
sf::Event event;
sf::Clock deltaclock;
float dt;
sf::Vector2i mousePosWindow;
sf::Vector2f mousePosView;
sf::Vector2f mouseStartPos;
sf::Vector2f mousePrevPos;
bool mouseHeldDown;
std::vector<PhysicsBall> physBalls;
sf::Vector2f gravity = sf::Vector2f(0.f, 1000.f);
//Initialize Functions
void initVariables()
{
this->window = nullptr;
}
//Creates Window
void initWindow()
{
this->videoMode.width = 640;
this->videoMode.height = 480;
this->window = new sf::RenderWindow(this->videoMode, "Verlet Integration", sf::Style::Close);
this->window->setFramerateLimit(60);
}
public:
//Vector math functions
float Vec2fDist(sf::Vector2f vec1)
{
return std::sqrt(
(vec1.x * vec1.x) + (vec1.y * vec1.y)
);
}
//Update functions
float calculateDeltaTime()
{
return this->deltaclock.getElapsedTime().asSeconds();
}
//Gets Input
void pollevent()
{
while (this->window->pollEvent(this->event))
{
switch (this->event.type)
{
case sf::Event::Closed:
this->window->close();
break;
case sf::Event::KeyPressed:
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
this->window->close();
break;
}
case sf::Event::MouseButtonPressed:
this->mousePrevPos = mousePosView;
break;
case sf::Event::MouseButtonReleased:
this->mouseStartPos = mousePosView;
spawnPhysBall();
break;
}
}
}
//Creates a physics ball and adds it to a vector
void spawnPhysBall()
{
if (sf::Event::MouseButtonReleased)
{
PhysicsBall physball(mouseStartPos, ((mouseStartPos - mousePrevPos) * 0.01f) + mousePrevPos, 50.f);
physBalls.push_back(physball);
}
}
void updateMousePosistion()
{
//Updates mouse posistion as a Vector2
this->mousePosWindow = sf::Mouse::getPosition(*this->window);
this->mousePosView = this->window->mapPixelToCoords(this->mousePosWindow);
}
//Preforms all the update functions.
void update()
{
this->dt = this->calculateDeltaTime();
this->updateMousePosistion();
this->pollevent();
this->updateCollisions();
for (auto& physball : this->physBalls)
{
updatePhysPos(physball, dt);
updateAcceleration(physball, gravity);
updateApplyConstriants(physball);
}
this->deltaclock.restart();
}
//Updates Position
void updatePhysPos(PhysicsBall &physball, float delta)
{
physball.updatePhysBall(delta);
}
//Updates acceleration.
void updateAcceleration(PhysicsBall &physball, sf::Vector2f acc)
{
physball.accelerate(acc);
}
//Screen collision checks
void updateApplyConstriants(PhysicsBall &physball)
{
const float friction = 0.75f;
if (physball.getPosition().x + physball.getRadius() > videoMode.width)
{
physball.setPosition(
sf::Vector2f((videoMode.width-physball.getRadius()), physball.getPosition().y + (physball.getVelocity().y * friction))
);
}
if (physball.getPosition().y + physball.getRadius() > videoMode.height)
{
physball.setPosition(
sf::Vector2f(physball.getPosition().x + (physball.getVelocity().x * friction), (videoMode.height - physball.getRadius()))
);
}
if (physball.getPosition().x - physball.getRadius() < 0.f)
{
physball.setPosition(
sf::Vector2f(physball.getRadius(), physball.getPosition().y + (physball.getVelocity().y * friction))
);
}
if (physball.getPosition().y - physball.getRadius() < 0.f)
{
physball.setPosition(
sf::Vector2f(physball.getPosition().x + (physball.getVelocity().x * friction), physball.getRadius())
);
}
}
void updateCollisions()
{
// Runs through all objects and pushes them apart if they're to close together
for (int i = 0; i < physBalls.size(); i++)
{
PhysicsBall& physball_1 = physBalls[i];
for (int k{ i + 1 }; k < physBalls.size(); k++)
{
PhysicsBall& physball_2 = physBalls[k];
sf::Vector2f vel = physball_1.getPosition() - physball_2.getPosition();
const float dist2 = (vel.x * vel.x) + (vel.y * vel.y);
const float mindist = physball_1.getRadius() + physball_2.getRadius();
if (dist2 < mindist * mindist)
{
const float dist = sqrt(dist2);
const sf::Vector2f n = vel / dist;
const float delta = 0.5f * (dist - mindist);
physball_1.setPosition(physball_1.getPosition() - n * (delta * 0.5f));
physball_2.setPosition(physball_2.getPosition() + n * (delta * 0.5f));
}
}
}
}
//Render Functions
//Main render function
void render()
{
this->window->clear();
for (auto physball : this->physBalls)
{
physball.render(*this->window);
}
this->window->display();
}
//
//Gets whether or not the window is open
const bool running()
{
return this->window->isOpen();
}
//Constructors and deconstructors
Simulation()
{
initVariables();
initWindow();
}
~Simulation()
{
delete this->window;
}
};
任何帮助将不胜感激!
我试图在 SFML 中创建一个 Verlet 集成引擎,但每当它们碰撞时,球体就会消失。
答:
评论