Skip to content

Commit f67e714

Browse files
committed
Added improved physics for collisions
1 parent cb96c65 commit f67e714

File tree

6 files changed

+264
-153
lines changed

6 files changed

+264
-153
lines changed

Physics.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#include <iostream>
2+
#include <cmath>
3+
4+
#include <SFML/Graphics.hpp>
5+
#include <SFML/System.hpp>
6+
#include <SFML/Window.hpp>
7+
#include <SFML/Audio.hpp>
8+
#include <SFML/Network.hpp>
9+
10+
struct Vec2 {
11+
float x, y;
12+
Vec2(float x_=0, float y_=0) : x(x_), y(y_) {}
13+
Vec2 operator-(const Vec2& other) const { return Vec2(x - other.x, y - other.y); }
14+
float abs() const { return std::sqrt(x*x + y*y); }
15+
};
16+
17+
struct AABB {
18+
Vec2 min;
19+
Vec2 max;
20+
};
21+
22+
struct Object {
23+
Vec2 pos;
24+
AABB aabb;
25+
};
26+
27+
struct Manifold {
28+
Object *A, *B;
29+
Vec2 normal;
30+
float penetration;
31+
};
32+
33+
// Compare objects
34+
bool AABBvsAABB( Manifold *m )
35+
{
36+
// Setup a couple pointers to each object
37+
Object *A = m->A;
38+
Object *B = m->B;
39+
40+
// Vector from A to B
41+
Vec2 n = B->pos - A->pos;
42+
43+
AABB abox = A->aabb;
44+
AABB bbox = B->aabb;
45+
46+
// Calculate half extents along x axis for each object
47+
float a_extent = (abox.max.x - abox.min.x) / 2;
48+
float b_extent = (bbox.max.x - bbox.min.x) / 2;
49+
50+
// Calculate overlap on x axis
51+
float x_overlap = a_extent + b_extent - abs( n.x );
52+
53+
// SAT test on x axis
54+
if(x_overlap > 0)
55+
{
56+
// Calculate half extents along x axis for each object
57+
float a_extent = (abox.max.y - abox.min.y) / 2;
58+
float b_extent = (bbox.max.y - bbox.min.y) / 2;
59+
60+
// Calculate overlap on y axis
61+
float y_overlap = a_extent + b_extent - abs( n.y );
62+
63+
// SAT test on y axis
64+
if(y_overlap > 0)
65+
{
66+
// Find out which axis is axis of least penetration
67+
if(x_overlap > y_overlap)
68+
{
69+
// Point towards B knowing that n points from A to B
70+
if(n.x < 0)
71+
m->normal = Vec2( -1, 0 );
72+
else
73+
m->normal = Vec2( 0, 0 );
74+
m->penetration = x_overlap;
75+
return true;
76+
}
77+
else
78+
{
79+
// Point toward B knowing that n points from A to B
80+
if(n.y < 0)
81+
m->normal = Vec2( 0, -1 );
82+
else
83+
m->normal = Vec2( 0, 1 );
84+
m->penetration = y_overlap;
85+
return true;
86+
}
87+
return false;
88+
}
89+
return false;
90+
}
91+
return false;
92+
};
93+
94+
// Function to convert vector
95+
sf::Vector2f toSF(const Vec2& v) {
96+
return sf::Vector2f(v.x, v.y);
97+
}
98+
99+
// Function to get dot product
100+
float Dot(const Vec2& a, const Vec2& b) {
101+
return a.x * b.x + a.y * b.y;
102+
}

Player.cpp

Lines changed: 83 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@ Player::Player()
1616
{
1717
sprite.setTexture(texture);
1818
sprite.setTextureRect({{485,1}, {240,240}});
19-
sprite.setOrigin({sprite.getTextureRect().size.x / 2.0f, sprite.getTextureRect().size.y / 2.0f});
20-
sf::Vector2<float> position(275.f, 200.f); // Set coordinates
21-
sprite.setPosition(position); // Place sprite at coordinates
2219
sprite.setScale({1.0f,1.0f});
2320
//sprite.setColor(sf::Color::White);
2421

2522
// Default movement speed
2623
verticalSpeed = 3.0f;
2724
horizontalSpeed = 3.0f;
25+
movement = {horizontalSpeed, 0};
2826
moving = false;
2927

3028
// Coordinates for current texture in spritesheet
@@ -81,138 +79,129 @@ Player::Player()
8179
sprintingWestXStart = 240; sprintingWestYStart = 3120; sprintingWestXEnd = 1440; sprintingWestYEnd = 3120;
8280
}
8381

84-
void Player::handleInput(std::vector<sf::FloatRect> wallBounds) {
85-
// Predict future collision
86-
sf::FloatRect nextBounds = sprite.getGlobalBounds();
8782

83+
void Player::handleInput() {
8884
// If both right and up key pressed then move character right and up at same time
8985
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Right) && sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Up) || sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::D) && sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::W)) {
9086
moving = true; northEast = true;
9187
north = false; east = false; southEast = false; south = false; southWest = false; west = false; northWest = false;
92-
sf::Vector2f movement{horizontalSpeed / 1.5f, -verticalSpeed / 1.5f};
93-
if (!handleCollision(movement, nextBounds, wallBounds)) {
94-
// Waits for set amount of time then plays Jog north east animation
95-
timer += 0.08f;
96-
// Sprinting animation
97-
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, movement.y * 3}); textureX += 240; animate(sprintingNorthEastXStart, sprintingNorthEastXEnd,
98-
sprintingNorthEastYStart, sprintingNorthEastYEnd); timer = 0.0f;}
99-
// Jog animation
100-
else if (timer >= timerMax) {textureX += 240; animate(JogNorthEastXStart, JogNorthEastXEnd,
101-
JogNorthEastYStart, JogNorthEastYEnd); timer = 0.0f;}
102-
}
88+
movement = {horizontalSpeed / 1.5f, -verticalSpeed / 1.5f};
89+
sprite.move(movement);
90+
// Waits for set amount of time then plays Jog north east animation
91+
timer += 0.08f;
92+
// Sprinting animation
93+
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, movement.y * 3}); textureX += 240; animate(sprintingNorthEastXStart, sprintingNorthEastXEnd,
94+
sprintingNorthEastYStart, sprintingNorthEastYEnd); timer = 0.0f;}
95+
// Jog animation
96+
else if (timer >= timerMax) {textureX += 240; animate(JogNorthEastXStart, JogNorthEastXEnd,
97+
JogNorthEastYStart, JogNorthEastYEnd); timer = 0.0f;}
10398
}
10499
// If both right and down key pressed then move character right and down at same time
105100
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Right) && sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::D) && sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::S)) {
106101
moving = true; southEast = true;
107102
north = false; northEast = false; east = false; south = false; southWest = false; west = false; northWest = false;
108-
sf::Vector2f movement{horizontalSpeed / 1.5f, verticalSpeed / 1.5f};
109-
if (!handleCollision(movement, nextBounds, wallBounds)) {
110-
// Waits for set amount of time then plays Jog south east animation
111-
timer += 0.08f;
112-
// Sprinting animation
113-
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, movement.y * 3}); textureX += 240; animate(sprintingSouthEastXStart, sprintingSouthEastXEnd,
114-
sprintingSouthEastYStart, sprintingSouthEastYEnd); timer = 0.0f;}
115-
// Jog animation
116-
else if (timer >= timerMax) {textureX += 240; animate(JogSouthEastXStart, JogSouthEastXEnd,
117-
JogSouthEastYStart, JogSouthEastYEnd); timer = 0.0f;}
118-
}
103+
movement = {horizontalSpeed / 1.5f, verticalSpeed / 1.5f};
104+
sprite.move(movement);
105+
// Waits for set amount of time then plays Jog south east animation
106+
timer += 0.08f;
107+
// Sprinting animation
108+
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, movement.y * 3}); textureX += 240; animate(sprintingSouthEastXStart, sprintingSouthEastXEnd,
109+
sprintingSouthEastYStart, sprintingSouthEastYEnd); timer = 0.0f;}
110+
// Jog animation
111+
else if (timer >= timerMax) {textureX += 240; animate(JogSouthEastXStart, JogSouthEastXEnd,
112+
JogSouthEastYStart, JogSouthEastYEnd); timer = 0.0f;}
119113
}
120114
// If both left and up key pressed then move character left and up at same time
121115
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Left) && sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Up) || sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::A) && sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::W)) {
122116
moving = true; northWest = true;
123117
north = false; northEast = false; east = false; southEast = false; south = false; southWest = false; west = false;
124-
sf::Vector2f movement{-horizontalSpeed / 1.5f, -verticalSpeed / 1.5f};
125-
if (!handleCollision(movement, nextBounds, wallBounds)) {
126-
// Waits for set amount of time then plays Jog north west animation
127-
timer += 0.08f;
128-
// Sprinting animation
129-
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, movement.y * 3}); textureX += 240; animate(sprintingNorthWestXStart, sprintingNorthWestXEnd,
130-
sprintingNorthWestYStart, sprintingNorthWestYEnd); timer = 0.0f;}
131-
// Jog animation
132-
else if (timer >= timerMax) {textureX += 240; animate(JogNorthWestXStart, JogNorthWestXEnd,
133-
JogNorthWestYStart, JogNorthWestYEnd); timer = 0.0f;}
134-
}
118+
movement = {-horizontalSpeed / 1.5f, -verticalSpeed / 1.5f};
119+
sprite.move(movement);
120+
// Waits for set amount of time then plays Jog north west animation
121+
timer += 0.08f;
122+
// Sprinting animation
123+
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, movement.y * 3}); textureX += 240; animate(sprintingNorthWestXStart, sprintingNorthWestXEnd,
124+
sprintingNorthWestYStart, sprintingNorthWestYEnd); timer = 0.0f;}
125+
// Jog animation
126+
else if (timer >= timerMax) {textureX += 240; animate(JogNorthWestXStart, JogNorthWestXEnd,
127+
JogNorthWestYStart, JogNorthWestYEnd); timer = 0.0f;}
135128
}
136129
// If both left and down key pressed then move character left and down at same time
137130
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Left) && sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::A) && sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::S)) {
138131
moving = true; southWest = true;
139132
north = false; northEast = false; east = false; southEast = false; south = false; west = false; northWest = false;
140-
sf::Vector2f movement{-horizontalSpeed / 1.5f, verticalSpeed / 1.5f};
141-
if (!handleCollision(movement, nextBounds, wallBounds)) {
142-
// Waits for set amount of time then plays Jog south west animation
143-
timer += 0.08f;
144-
// Sprinting animation
145-
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, movement.y * 3}); textureX += 240; animate(sprintingSouthWestXStart, sprintingSouthWestXEnd,
146-
sprintingSouthWestYStart, sprintingSouthWestYEnd); timer = 0.0f;}
147-
// Jog animation
148-
else if (timer >= timerMax) {textureX += 240; animate(JogSouthWestXStart, JogSouthWestXEnd,
149-
JogSouthWestYStart, JogSouthWestYEnd); timer = 0.0f;}
150-
}
133+
movement = {-horizontalSpeed / 1.5f, verticalSpeed / 1.5f};
134+
sprite.move(movement);
135+
// Waits for set amount of time then plays Jog south west animation
136+
timer += 0.08f;
137+
// Sprinting animation
138+
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, movement.y * 3}); textureX += 240; animate(sprintingSouthWestXStart, sprintingSouthWestXEnd,
139+
sprintingSouthWestYStart, sprintingSouthWestYEnd); timer = 0.0f;}
140+
// Jog animation
141+
else if (timer >= timerMax) {textureX += 240; animate(JogSouthWestXStart, JogSouthWestXEnd,
142+
JogSouthWestYStart, JogSouthWestYEnd); timer = 0.0f;}
151143
}
152144
// If right key pressed then move character right
153145
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Right) || sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::D)) {
154146
moving = true; east = true;
155147
north = false; northEast = false; southEast = false; south = false ;southWest = false; west = false; northWest = false;
156-
sf::Vector2f movement{horizontalSpeed, 0.0f};
157-
if (!handleCollision(movement, nextBounds, wallBounds)) {
158-
// Waits for set amount of time then plays Jog east animation
159-
timer += 0.08f;
160-
// Sprinting animation
161-
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, 0.0f}); textureX += 240; animate(sprintingEastXStart, sprintingEastXEnd,
162-
sprintingEastYStart, sprintingEastYEnd); timer = 0.0f;}
163-
// Jog animation
164-
else if (timer >= timerMax) {textureX += 240; animate(JogEastXStart, JogEastXEnd,
165-
JogEastYStart, JogEastYEnd); timer = 0.0f;}
166-
}
148+
movement = {horizontalSpeed, 0.0f};
149+
sprite.move(movement);
150+
// Waits for set amount of time then plays Jog east animation
151+
timer += 0.08f;
152+
// Sprinting animation
153+
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, 0.0f}); textureX += 240; animate(sprintingEastXStart, sprintingEastXEnd,
154+
sprintingEastYStart, sprintingEastYEnd); timer = 0.0f;}
155+
// Jog animation
156+
else if (timer >= timerMax) {textureX += 240; animate(JogEastXStart, JogEastXEnd,
157+
JogEastYStart, JogEastYEnd); timer = 0.0f;}
167158
}
168159
// If up key pressed then move character up
169160
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Up) || sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::W)) {
170161
moving = true; north = true;
171162
northEast = false; east = false; southEast = false; south = false; southWest = false; west = false; northWest = false;
172-
sf::Vector2f movement{0.0f, -verticalSpeed};
173-
if (!handleCollision(movement, nextBounds, wallBounds)) {
174-
// Waits for set amount of time then plays Jog north animation
175-
timer += 0.08f;
176-
// Sprinting animation
177-
if (timer >= timerMax && sprinting) {sprite.move({0.0f, movement.y * 3}); textureX += 240; animate(sprintingNorthXStart, sprintingNorthXEnd,
178-
sprintingNorthYStart, sprintingNorthYEnd); timer = 0.0f;}
179-
// Jog animation
180-
else if (timer >= timerMax) {textureX += 240; animate(JogNorthXStart, JogNorthXEnd,
181-
JogNorthYStart, JogNorthYEnd); timer = 0.0f;}
182-
}
163+
movement = {0.0f, -verticalSpeed};
164+
sprite.move(movement);
165+
// Waits for set amount of time then plays Jog north animation
166+
timer += 0.08f;
167+
// Sprinting animation
168+
if (timer >= timerMax && sprinting) {sprite.move({0.0f, -movement.y * 3}); textureX += 240; animate(sprintingNorthXStart, sprintingNorthXEnd,
169+
sprintingNorthYStart, sprintingNorthYEnd); timer = 0.0f;}
170+
// Jog animation
171+
else if (timer >= timerMax) {textureX += 240; animate(JogNorthXStart, JogNorthXEnd,
172+
JogNorthYStart, JogNorthYEnd); timer = 0.0f;}
183173
}
184174
// If down key pressed then move character down
185175
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Down) || sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::S)) {
186176
moving = true; south = true;
187177
north = false; northEast = false; east = false; southEast = false; southWest = false; west = false; northWest = false;
188-
sf::Vector2f movement{0.0f, verticalSpeed};
189-
if (!handleCollision(movement, nextBounds, wallBounds)) {
190-
// Waits for set amount of time then plays Jog south animation
191-
timer += 0.08f;
192-
// Sprinting animation
193-
if (timer >= timerMax && sprinting) {sprite.move({0.0f, movement.y * 3}); textureX += 240; animate(sprintingSouthXStart, sprintingSouthXEnd,
194-
sprintingSouthYStart, sprintingSouthYEnd); timer = 0.0f;}
195-
// Jog animation
196-
else if (timer >= timerMax) {textureX += 240; animate(JogSouthXStart, JogSouthXEnd,
197-
JogSouthYStart, JogSouthYEnd); timer = 0.0f;}
198-
}
178+
movement = {0.0f, verticalSpeed};
179+
sprite.move(movement);
180+
// Waits for set amount of time then plays Jog south animation
181+
timer += 0.08f;
182+
// Sprinting animation
183+
if (timer >= timerMax && sprinting) {sprite.move({0.0f, movement.y * 3}); textureX += 240; animate(sprintingSouthXStart, sprintingSouthXEnd,
184+
sprintingSouthYStart, sprintingSouthYEnd); timer = 0.0f;}
185+
// Jog animation
186+
else if (timer >= timerMax) {textureX += 240; animate(JogSouthXStart, JogSouthXEnd,
187+
JogSouthYStart, JogSouthYEnd); timer = 0.0f;}
199188
}
200189
// If left key pressed then move character left
201190
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::Scan::A)) {
202191
moving = true; west = true;
203192
north = false; northEast = false; east = false; southEast = false; south = false; southWest = false; northWest = false;
204-
sf::Vector2f movement{-horizontalSpeed, 0.0f};
205-
if (!handleCollision(movement, nextBounds, wallBounds)) {
206-
// Waits for set amount of time then plays Jog west animation
207-
timer += 0.08f;
208-
// Sprinting animation
209-
if (timer >= timerMax && sprinting) {sprite.move({movement.x * 3, 0.0f}); textureX += 240; animate(sprintingWestXStart, sprintingWestXEnd,
210-
sprintingWestYStart, sprintingWestYEnd); timer = 0.0f;}
211-
// Jog animation
212-
else if (timer >= timerMax) {textureX += 240; animate(JogWestXStart, JogWestXEnd,
213-
JogWestYStart, JogWestYEnd); timer = 0.0f;}
214-
}
193+
movement = {-horizontalSpeed, 0.0f};
194+
sprite.move(movement);
195+
// Waits for set amount of time then plays Jog west animation
196+
timer += 0.08f;
197+
// Sprinting animation
198+
if (timer >= timerMax && sprinting) {sprite.move({-movement.x * 3, 0.0f}); textureX += 240; animate(sprintingWestXStart, sprintingWestXEnd,
199+
sprintingWestYStart, sprintingWestYEnd); timer = 0.0f;}
200+
// Jog animation
201+
else if (timer >= timerMax) {textureX += 240; animate(JogWestXStart, JogWestXEnd,
202+
JogWestYStart, JogWestYEnd); timer = 0.0f;}
215203
} else {
204+
movement = {0.0f, 0.0f};
216205
moving = false;
217206
}
218207
// If space pressed then attack and change to attack animation
@@ -258,38 +247,6 @@ void Player::handleInput(std::vector<sf::FloatRect> wallBounds) {
258247
}
259248
}
260249

261-
bool Player::handleCollision(sf::Vector2f movement, sf::FloatRect nextBounds, std::vector<sf::FloatRect> wallBounds) {
262-
// Full movement prediction
263-
nextBounds.position += movement;
264-
265-
for (const auto& wall : wallBounds) {
266-
if (nextBounds.findIntersection(wall).has_value()) {
267-
// Try horizontal-only movement
268-
sf::Rect<float> horizontalBounds = nextBounds;
269-
horizontalBounds.position.x -= movement.x; // Undo x movement
270-
271-
if (!horizontalBounds.findIntersection(wall).has_value()) {
272-
sprite.move({0.f, movement.y}); // Slide vertically
273-
return true;
274-
}
275-
276-
// Try vertical-only movement
277-
sf::Rect<float> verticalBounds = nextBounds;
278-
verticalBounds.position.y -= movement.y; // Undo y movement
279-
280-
if (!verticalBounds.findIntersection(wall).has_value()) {
281-
sprite.move({movement.x, 0.f}); // Slide horizontally
282-
return true;
283-
}
284-
285-
std::cout << "Blocked from all sides\n";
286-
return true; // Fully blocked
287-
}
288-
}
289-
// No collision — move freely
290-
sprite.move(movement);
291-
return false;
292-
}
293250

294251
// Reusable function for animating player
295252
void Player::animate(int xStart, int xEnd, int yStart, int yEnd) {

0 commit comments

Comments
 (0)