RigidCircle.h
"공" 객체를 찍어낼 클래스를 포함한 헤더
#pragma once
#include "Game2D.h"
namespace jm
{
class RigidCircle
{
public:
vec2 pos;
vec2 vel;
RGB color = Colors::hotpink;
float radius = 0.1f;
float mass = 1.0f;
public:
void draw()
{
beginTransformation();
{
translate(pos);
drawFilledCircle(color, radius - 1e-3f);
setLineWidth(2.0f);
drawWiredCircle(Colors::black, radius);
}
endTransformation();
}
void update(const float & dt)
{
static const vec2 gravity = vec2(0.0f, -9.8f);
static const float coef_res = 0.7f; // coefficient of restitution
static const float coef_friction = 0.99f; // friction (not physical)
// numerical integration
vel += gravity * dt;
pos += vel * dt;
// wall collision, friction
if (1.0f - pos.x <= radius) // right wall
{
pos.x = 1.0f - radius;
if (vel.x >= 0.0f)
vel.x *= -1.0f * coef_res;
}
if (pos.x <= -1.0f + radius) // left wall
{
pos.x = -1.0f + radius;
if (vel.x <= 0.0f)
vel.x *= -1.0f * coef_res;
}
if (pos.y <= -1.0f + radius) // ground
{
pos.y = -1.0f + radius;
if (vel.y <= 0.0f)
vel.y *= -1.0f * coef_res;
vel.x *= coef_friction;
}
}
};
}
Vector2.h
여기서 함수 앞 "T"는 template으로 자료형을 값에 맞게 정해주는 기능이다.
이 강의에서는 float값을 사용하므로 float형으로 스칼라 값을 리턴될 것이다.
<Vector.h>
T getDotProduct(const Vector2<T>& v) const // 매개변수로 받은 벡터와의 내적
{
return x * v.x + y * v.y;
}
T getMagnitude() // 벡터의 크기
{
return std::sqrt(x * x + y * y);
}
main
#include "Game2D.h"
#include "Examples/PrimitivesGallery.h"
#include "RandomNumberGenerator.h"
#include "RigidCircle.h"
#include <vector>
#include <memory>
namespace jm
{
class Example : public Game2D
{
public:
RigidCircle rb0, rb1;
Example()
: Game2D()
{
reset();
}
void reset()
{
// 두 공의 멤버 값들 초기화
rb0.pos = vec2(-0.8f, 0.3f);
rb0.vel = vec2(5.0f, 0.0f);
rb0.color = Colors::hotpink;
rb0.radius = 0.1f;
rb0.mass = 1.0f; //
rb1.pos = vec2(0.8f, 0.3f);
rb1.vel = vec2(-5.0f, 0.0f);
rb1.color = Colors::yellow;
rb1.radius = 0.15f;
rb1.mass = rb0.mass * std::pow(rb1.radius / rb0.radius, 2.0f);
}
void drawWall() // 벽을 그린다.
{
setLineWidth(5.0f);
drawLine(Colors::blue, { -1.0f, -1.0f }, Colors::blue, { 1.0f, -1.0f });
drawLine(Colors::blue, { 1.0f, -1.0f }, Colors::blue, { 1.0f, 1.0f });
drawLine(Colors::blue, { -1.0f, -1.0f }, Colors::blue, { -1.0f, 1.0f });
}
void update() override
{
const float dt = getTimeStep() * 0.4f;
const float epsilon = 0.5f; // 반발계수
// physics update
rb0.update(dt);
rb1.update(dt);
// check collision between two rigid bodies
const float distance = (rb0.pos - rb1.pos).getMagnitude();
if (distance <= rb0.radius + rb1.radius) // 충돌했을 때
{
// compute impulse
const auto vel_rel = rb0.vel - rb1.vel; // 상대 속도 구하기
const auto normal = (rb0.pos - rb1.pos) / (rb0.pos - rb1.pos).getMagnitude(); // 노말 벡터 구하기 n1
if (vel_rel.getDotProduct(normal) < 0.0f) // approaching, 두 개의 공이 가까워지고 있을 때만 충격량 계산
{
const auto impulse = normal * -(1.0f + epsilon) * vel_rel.getDotProduct(normal) /
((1.0f / rb0.mass) + (1.0f / rb1.mass));
// update velocities of two bodies
rb0.vel += impulse / rb0.mass; // 🔴원의 새로운 속도
rb1.vel -= impulse / rb1.mass; // 🟡원의 새로운 속도
}
}
// draw
drawWall();
rb0.draw();
rb1.draw();
// reset button
if (isKeyPressedAndReleased(GLFW_KEY_R)) reset();
}
};
}
int main(void)
{
jm::Example().run();
return 0;
}
'공부 일지 > C++' 카테고리의 다른 글
[C++] 3.3 질량-용수철 시스템 (0) | 2023.12.12 |
---|---|
[C++] 3.1 공 튕기기 시뮬레이션 (0) | 2023.10.03 |
[C++] 2.6 싱글톤 패턴 singleton pattern (0) | 2023.09.20 |
[C++] 2.5 명령 패턴 command pattern (0) | 2023.09.20 |
[C++] 2.4 공장 패턴 factory pattern (0) | 2023.09.16 |