|
1 |
|
2 #include "Physics.hh" |
|
3 #include "Engine.hh" |
|
4 |
|
5 #include <algorithm> |
|
6 #include <functional> |
|
7 |
|
8 PhysicsWorld::PhysicsWorld (Vector gravity, Vector dimensions) |
|
9 : tick_timer(PHYSICS_TICK_MS), gravity(gravity), dimensions(dimensions) { |
|
10 |
|
11 slots.connect(tick_timer.sig_timer(), this, &PhysicsWorld::tick); |
|
12 tick_timer.enable(); |
|
13 } |
|
14 |
|
15 void PhysicsWorld::addObject (PhysicsObject *object) { |
|
16 objects.push_back(object); |
|
17 } |
|
18 |
|
19 void PhysicsWorld::tick () { |
|
20 // Engine::log(DEBUG, "physics.apply_force") << "*tick*"; |
|
21 |
|
22 for (std::vector<PhysicsObject*>::iterator i = objects.begin(); i != objects.end(); i++) { |
|
23 (*i)->tick(); |
|
24 } |
|
25 } |
|
26 |
|
27 PhysicsObject::PhysicsObject (PhysicsWorld &world, float mass, Vector position, Vector velocity) |
|
28 : world(world), mass(mass), position(position), velocity(velocity) { |
|
29 |
|
30 world.addObject(this); |
|
31 } |
|
32 |
|
33 void PhysicsObject::updatePosition () { |
|
34 |
|
35 // Check if the player is moving on the ground |
|
36 /*if (this->velocity.y == 0 && (position.y >= world.dimensions.y - 3)) { |
|
37 position.x += 50 * velocity.x * (PHYSICS_TICK_MS / 1000.0); |
|
38 velocity.x = 0; |
|
39 return; |
|
40 }*/ |
|
41 |
|
42 // If not moving on the ground, apply normal physics |
|
43 |
|
44 // Calculate gravity's influence on the velocity vector |
|
45 this->velocity += world.gravity * (PHYSICS_TICK_MS / 1000.0); |
|
46 |
|
47 Vector newPosition = position + velocity * (PHYSICS_TICK_MS / 1000.0); |
|
48 |
|
49 //TODO Handle the object as a square or a polygon |
|
50 |
|
51 // Engine::log(DEBUG, "physics.update_position") << "position=" << newPosition << ", velocity=" << velocity; |
|
52 |
|
53 bool collided = false; |
|
54 |
|
55 if (newPosition.x < 0 || (newPosition.x > world.dimensions.x)) { |
|
56 // CRASH! |
|
57 this->velocity.x *= -0.5; |
|
58 |
|
59 // If the velocity drops under some fixed constant we decide it is zero. |
|
60 // This is to prevent the object from bouncing eternally. |
|
61 if (abs(this->velocity.x) < 0.1) |
|
62 this->velocity.x = 0; |
|
63 |
|
64 collided = true; |
|
65 } else { |
|
66 this->position.x = newPosition.x; |
|
67 } |
|
68 |
|
69 if (newPosition.y <= 0 || (newPosition.y >= world.dimensions.y)) { |
|
70 this->velocity.y *= -0.3; |
|
71 |
|
72 |
|
73 |
|
74 if (abs(this->velocity.y) < 0.1) { |
|
75 this->velocity.y = 0; |
|
76 // Friction |
|
77 this->velocity.x *= 0.95; |
|
78 } else { |
|
79 // Bigger friction |
|
80 this->velocity.x *= 0.75; |
|
81 } |
|
82 |
|
83 collided = true; |
|
84 } else { |
|
85 this->position.y = newPosition.y; |
|
86 } |
|
87 |
|
88 if(!collided) { |
|
89 this->position = newPosition; |
|
90 } |
|
91 } |
|
92 |
|
93 void PhysicsObject::applyForce (Vector force, uint16_t dt) { |
|
94 Vector oldVelocity = velocity; |
|
95 |
|
96 this->velocity += force * dt / 1000 / mass; // The last factor denotes the time. |
|
97 // It should be scaled somehow. |
|
98 |
|
99 // Engine::log(DEBUG, "physics.apply_force") << "force=" << force << ", velocity " << oldVelocity << " -> " << velocity; |
|
100 } |
|
101 |
|
102 void PhysicsObject::updatePhysics (Vector position, Vector velocity) { |
|
103 this->position = position; |
|
104 this->velocity = velocity; |
|
105 } |
|
106 |
|
107 Vector PhysicsObject::getPosition () { |
|
108 return this->position; |
|
109 } |
|
110 |
|
111 void PhysicsObject::tick () { |
|
112 this->updatePosition(); |
|
113 } |
|
114 |