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)) {
17 void World::Update(float dt) {
18 constexpr float fricDyn = 0.75f;
19 constexpr float fricStat = 2.5f;
20 constexpr float dragFact = 0.05f;
22 for (Entity &e : entities) {
23 const Vector<float> gravity = ForceAt(e.pos, e.mass);
24 const Vector<float> drag = Rotate180(e.vel) * dragFact;
25 // TODO: drag should be inverse square. and not onmipresent
27 e.acc = (gravity + drag) / e.mass;
31 if (WorldCollision(e, at)) {
32 float speed = Length(e.vel);
33 Vector<float> normVel = e.vel / speed;
35 while (MassAt(e.pos) > 0) {
39 const Vector<float> normal = NormalAt(e.pos + normVel);
40 e.vel = Reflect(e.vel, normal);
41 speed = Length(e.vel);
42 normVel = e.vel / speed;
43 // some kind of friction, depends on angle to normal
44 speed *= (fricDyn * (std::abs(Dot(normVel, normal))));
45 if (speed > fricStat) {
47 e.vel = normVel * speed;
48 e.pos += normVel * steps;
50 e.vel = Vector<float>(0, 0);
57 bool World::WorldCollision(const Entity &e, Vector<float> &at) const {
58 if (InBounds(e.pos) && MassAt(e.pos) > 0) {
66 Vector<float> World::NormalAt(Vector<float> pos) const {
67 constexpr Vector<float> check[] = {
69 { 0.765367, -1.84776 },
70 { 1.41421, -1.41421 },
71 { 1.84776, -0.765367 },
73 { 1.84776, 0.765367 },
75 { 0.765367, 1.84776 },
77 { -0.765367, 1.84776 },
78 { -1.41421, 1.41421 },
79 { -1.84776, 0.765367 },
81 { -1.84776, -0.765367 },
82 { -1.41421, -1.41421 },
83 { -0.765367, -1.84776 },
86 for (auto v : check) {
87 if (MassAt(pos + v) == 0) {
94 //Vector<float> World::NormalAt(Vector<float> pos) const {
95 // Vector<int> begin(pos - Vector<float>(3, 3));
96 // Vector<int> end(pos + Vector<float>(3, 3));
98 // Vector<float> normal;
99 // for (Vector<int> cur(begin); cur.y < end.y; ++cur.y) {
100 // for (cur.x = begin.x; cur.x < end.x; ++cur.x) {
101 // if (IsSurface(cur) > 0) {
102 // const Vector<float> dir = pos - Vector<float>(cur);
103 // normal += Rotate90(dir);
108 // return Norm(normal);
111 bool World::IsSurface(Vector<int> pos) const {
112 return MassAt(pos) > 0 && (
113 MassAt(pos - Vector<int>(1, 0)) == 0 ||
114 MassAt(pos + Vector<int>(1, 0)) == 0 ||
115 MassAt(pos - Vector<int>(0, 1)) == 0 ||
116 MassAt(pos + Vector<int>(0, 1)) == 0);
120 Entity &World::AddEntity(const Entity &e) {
121 entities.emplace_back(e);
122 return entities.back();
126 // returns <1.37136364,1.37136734> for 1 mass at <0,0>
128 Vector<float> World::ForceAt(Vector<float> p1, float m1) const {
129 Vector<float> force(0, 0);
131 for (int i = 0; i < count; ++i) {
132 const Vector<float> p2(i % size.y, i / size.y);
133 if (p1 == p2) continue;
135 const Vector<float> diff(p2 - p1);
136 const Vector<float> dir(Norm(diff));
138 const float m2 = masses[i];
139 const float r2 = Dot(diff, diff);
141 const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame
150 // returns <1.37136674,1.37136662> for 1 mass at <0,0>
151 // (should be less prone to rounding loss, i.e. more accurate)
152 Vector<float> World::ForceAt(Vector<float> p1, float m1) const {
153 Vector<float> force(0, 0);
155 for (Vector<int> p2(0, 0); p2.y < size.y; ++p2.y) {
156 Vector<float> rowForce(0, 0);
157 for (p2.x = 0; p2.x < size.x; ++p2.x) {
158 const int i = Index(p2);
159 if (p1 == Vector<float>(p2)) continue;
161 const Vector<float> diff(Vector<float>(p2) - p1);
162 const Vector<float> dir(Norm(diff));
164 const float m2 = masses[i];
165 const float r2 = Dot(diff, diff);
167 const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame
169 rowForce += dir * mag;