3 #include "../graphics/const.h"
8 World::World(Vector<int> size)
10 , count(size.x * size.y)
11 , masses(count, 1000000000.0f)
12 , colors(count, Color(0x7F, 0x7F, 0x7F))
18 void World::Update(float dt) {
19 constexpr float fricDyn = 0.75f;
20 constexpr float fricStat = 2.5f;
21 constexpr float dragFact = 0.05f;
23 for (Entity &e : entities) {
24 const Vector<float> gravity = ForceAt(e.pos, e.mass);
25 const Vector<float> drag = Rotate180(e.vel) * dragFact;
26 // TODO: drag should be inverse square. and not onmipresent
28 e.acc = (gravity + drag) / e.mass;
32 if (WorldCollision(e, at)) {
33 float speed = Length(e.vel);
34 Vector<float> normVel = e.vel / speed;
36 while (MassAt(e.pos) > 0) {
40 const Vector<float> normal = NormalAt(e.pos + normVel);
41 e.vel = Reflect(e.vel, normal);
42 speed = Length(e.vel);
43 normVel = e.vel / speed;
44 // some kind of friction, depends on angle to normal
45 speed *= (fricDyn * (std::abs(Dot(normVel, normal))));
46 if (speed > fricStat) {
48 e.vel = normVel * speed;
49 e.pos += normVel * steps;
51 e.vel = Vector<float>(0, 0);
58 bool World::WorldCollision(const Entity &e, Vector<float> &at) const {
59 if (InBounds(e.pos) && MassAt(e.pos) > 0) {
67 Vector<float> World::NormalAt(Vector<float> pos) const {
68 constexpr Vector<float> check[] = {
70 { 0.765367, -1.84776 },
71 { 1.41421, -1.41421 },
72 { 1.84776, -0.765367 },
74 { 1.84776, 0.765367 },
76 { 0.765367, 1.84776 },
78 { -0.765367, 1.84776 },
79 { -1.41421, 1.41421 },
80 { -1.84776, 0.765367 },
82 { -1.84776, -0.765367 },
83 { -1.41421, -1.41421 },
84 { -0.765367, -1.84776 },
87 for (auto v : check) {
88 if (MassAt(pos + v) == 0) {
95 //Vector<float> World::NormalAt(Vector<float> pos) const {
96 // Vector<int> begin(pos - Vector<float>(3, 3));
97 // Vector<int> end(pos + Vector<float>(3, 3));
99 // Vector<float> normal;
100 // for (Vector<int> cur(begin); cur.y < end.y; ++cur.y) {
101 // for (cur.x = begin.x; cur.x < end.x; ++cur.x) {
102 // if (IsSurface(cur) > 0) {
103 // const Vector<float> dir = pos - Vector<float>(cur);
104 // normal += Rotate90(dir);
109 // return Norm(normal);
112 bool World::IsSurface(Vector<int> pos) const {
113 return MassAt(pos) > 0 && (
114 MassAt(pos - Vector<int>(1, 0)) == 0 ||
115 MassAt(pos + Vector<int>(1, 0)) == 0 ||
116 MassAt(pos - Vector<int>(0, 1)) == 0 ||
117 MassAt(pos + Vector<int>(0, 1)) == 0);
121 Entity &World::AddEntity(const Entity &e) {
122 entities.emplace_back(e);
123 return entities.back();
127 // returns <1.37136364,1.37136734> for 1 mass at <0,0>
129 Vector<float> World::ForceAt(Vector<float> p1, float m1) const {
130 Vector<float> force(0, 0);
132 for (int i = 0; i < count; ++i) {
133 const Vector<float> p2(i % size.y, i / size.y);
134 if (p1 == p2) continue;
136 const Vector<float> diff(p2 - p1);
137 const Vector<float> dir(Norm(diff));
139 const float m2 = masses[i];
140 const float r2 = Dot(diff, diff);
142 const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame
151 // returns <1.37136674,1.37136662> for 1 mass at <0,0>
152 // (should be less prone to rounding loss, i.e. more accurate)
153 Vector<float> World::ForceAt(Vector<float> p1, float m1) const {
154 Vector<float> force(0, 0);
156 for (Vector<int> p2(0, 0); p2.y < size.y; ++p2.y) {
157 Vector<float> rowForce(0, 0);
158 for (p2.x = 0; p2.x < size.x; ++p2.x) {
159 const int i = Index(p2);
160 if (p1 == Vector<float>(p2)) continue;
162 const Vector<float> diff(Vector<float>(p2) - p1);
163 const Vector<float> dir(Norm(diff));
165 const float m2 = masses[i];
166 const float r2 = Dot(diff, diff);
168 const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame
170 rowForce += dir * mag;