]> git.localhorst.tv Git - gworm.git/blob - src/world/World.cpp
dcac95eb72708791b37b15f4a29a76035aa0e503
[gworm.git] / src / world / World.cpp
1 #include "World.h"
2
3 #include "../graphics/const.h"
4
5
6 namespace gworm {
7
8 World::World(Vector<int> size)
9 : size(size)
10 , count(size.x * size.y)
11 , masses(count, 1000000000.0f)
12 , colors(count, Color(0x7F, 0x7F, 0x7F)) {
13
14 }
15
16
17 void World::Update(float dt) {
18         constexpr float fricDyn = 0.75f;
19         constexpr float fricStat = 2.5f;
20         constexpr float dragFact = 0.05f;
21
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
26
27                 e.acc = (gravity + drag) / e.mass;
28                 e.Update(dt);
29
30                 Vector<float> at;
31                 if (WorldCollision(e, at)) {
32                         float speed = Length(e.vel);
33                         Vector<float> normVel = e.vel / speed;
34                         float steps = 0;
35                         while (MassAt(e.pos) > 0) {
36                                 e.pos -= normVel;
37                                 steps += 1.0f;
38                         }
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) {
46                                 speed -= fricStat;
47                                 e.vel = normVel * speed;
48                                 e.pos += normVel * steps;
49                         } else {
50                                 e.vel = Vector<float>(0, 0);
51                         }
52                 }
53         }
54 }
55
56
57 bool World::WorldCollision(const Entity &e, Vector<float> &at) const {
58         if (InBounds(e.pos) && MassAt(e.pos) > 0) {
59                 at = e.pos;
60                 return true;
61         } else {
62                 return false;
63         }
64 }
65
66 Vector<float> World::NormalAt(Vector<float> pos) const {
67         constexpr Vector<float> check[] = {
68                 {  0,        -2        },
69                 {  0.765367, -1.84776  },
70                 {  1.41421,  -1.41421  },
71                 {  1.84776,  -0.765367 },
72                 {  2,         0        },
73                 {  1.84776,   0.765367 },
74                 {  1.41421,   1.41421  },
75                 {  0.765367,  1.84776  },
76                 {  0,         2        },
77                 { -0.765367,  1.84776  },
78                 { -1.41421,   1.41421  },
79                 { -1.84776,   0.765367 },
80                 { -2,         0        },
81                 { -1.84776,  -0.765367 },
82                 { -1.41421,  -1.41421  },
83                 { -0.765367, -1.84776  },
84         };
85         Vector<float> normal;
86         for (auto v : check) {
87                 if (MassAt(pos + v) == 0) {
88                         normal += v;
89                 }
90         }
91         return Norm(normal);
92 }
93
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));
97 //
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);
104 //                      }
105 //              }
106 //      }
107 //
108 //      return Norm(normal);
109 //}
110
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);
117 }
118
119
120 Entity &World::AddEntity(const Entity &e) {
121         entities.emplace_back(e);
122         return entities.back();
123 }
124
125
126 // returns <1.37136364,1.37136734> for 1 mass at <0,0>
127 /*
128 Vector<float> World::ForceAt(Vector<float> p1, float m1) const {
129         Vector<float> force(0, 0);
130
131         for (int i = 0; i < count; ++i) {
132                 const Vector<float> p2(i % size.y, i / size.y);
133                 if (p1 == p2) continue;
134
135                 const Vector<float> diff(p2 - p1);
136                 const Vector<float> dir(Norm(diff));
137
138                 const float m2 = masses[i];
139                 const float r2 = Dot(diff, diff);
140
141                 const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame
142
143                 force += dir * mag;
144         }
145
146         return force;
147 }
148 */
149
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);
154
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;
160
161                         const Vector<float> diff(Vector<float>(p2) - p1);
162                         const Vector<float> dir(Norm(diff));
163
164                         const float m2 = masses[i];
165                         const float r2 = Dot(diff, diff);
166
167                         const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame
168
169                         rowForce += dir * mag;
170                 }
171                 force += rowForce;
172         }
173
174         return force;
175 }
176
177 }