Handling the collisions

Location
  1. Tutorials

    /

  2. Introduction to coding

    /

  3. Handling the collisions

Currently, collisions are not tested. The player can walk over the trees and stones. Let us resolve that.

Testing the collision between two sprites

The class sf::FloatRect is almost the same as sf::IntRect. The only difference is that its members (Representing its position and size) are of type 'float' rather than 'int'.

The method 'getGlobalBounds' of the class sf::Sprite returns an object of type sf::FloatRect representing its boundaries.

The class sf::FloatRect has a method called 'intersects' that returns 'true' if it is in collision with the sf::FloatRect object it received in argument and 'false' otherwise.

Let us define two sprites:

sf::Sprite s1, s2;

The following code tests if the two sprites are in collision:

if(s1.getGlobalBounds().intersects(s2.getGlobalBounds())) { // The instructions here are executed if the two sprites are in collision. }

The strategy

There are many ways to handle collisions. Here, we will employ a simple technique. It comes as follow: After each translation of the character, we test if it is in collision with any of the objects inside the game (Trees, stones...). If it is, we cancel the previous movement (We subtract the translation vector that we added to the position of the character). Otherwise, we do nothing. Basically, if a translation causes the player 'merge' with an object, we cancel it. Because the movement of the player is updated very frequently (Many very small movements), the character will stop right before he comes to collision with an object.

The code

Here is the code handling the collisions between the player and the trees:

1
2
3
4
5
6
7
8
9
10
// For each tree. for(int c=0; c < 8; c++) { // If the player is in collision with the tree. if(player.getGlobalBounds().intersects(trees[c].getGlobalBounds())) { // We cancel the movement. player.setPosition(player.getPosition().x-trans.x, player.getPosition().y-trans.y); } }

The same, but for the stones:

for(int c=0; c < 3; c++) { if(player.getGlobalBounds().intersects(stones[c].getGlobalBounds())) player.setPosition(player.getPosition().x-trans.x, player.getPosition().y-trans.y); }

The 2 sections of code from above must be placed after the player has been translated.

The code of the game so far

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <SFML/Graphics.hpp> int main() { sf::RenderWindow win(sf::VideoMode(800, 600), "Introduction to coding", sf::Style::Close); // Grass sf::Texture grassTex; grassTex.loadFromFile("resources/grass.png"); grassTex.setRepeated(true); sf::Sprite grass; grass.setTexture(grassTex); grass.setScale(5, 5); grass.setTextureRect(sf::IntRect(0,0,160,120)); // Dirt tiles sf::Texture dirtTex; dirtTex.loadFromFile("resources/dirt.png"); sf::Sprite dirtTiles[10]; dirtTiles[0].setPosition(300, 60); dirtTiles[1].setPosition(660, 300); dirtTiles[2].setPosition(390, 480); dirtTiles[3].setPosition(660, 60); dirtTiles[4].setPosition(720, 420); dirtTiles[5].setPosition(180, 300); dirtTiles[6].setPosition(60, 180); dirtTiles[7].setPosition(60, 420); dirtTiles[8].setPosition(240, 420); dirtTiles[9].setPosition(480, 120); for(int c = 0; c < 10; c++) { dirtTiles[c].setTexture(dirtTex); dirtTiles[c].setScale(5, 5); } // Trees sf::Texture treeTex; treeTex.loadFromFile("resources/tree.png"); sf::Sprite trees[8]; trees[0].setPosition(50, 60); trees[1].setPosition(600, 150); trees[2].setPosition(630, 456); trees[3].setPosition(300, 600); trees[4].setPosition(720, 40); trees[5].setPosition(460, 500); trees[6].setPosition(20, 370); trees[7].setPosition(340, 240); for(int c = 0; c < 8; c++) { trees[c].setTexture(treeTex); trees[c].setScale(3, 3); } // Stones sf::Texture stoneTex; stoneTex.loadFromFile("resources/stone.png"); sf::Sprite stones[3]; stones[0].setPosition(304, 64); stones[1].setPosition(664, 304); stones[2].setPosition(180, 300); for(int c = 0; c < 3; c++) { stones[c].setTexture(stoneTex); stones[c].setScale(3, 3); } // Player sf::Texture playerTex; playerTex.loadFromFile("resources/player.png"); sf::Sprite player; player.setTexture(playerTex); player.setPosition(400, 300); player.setScale(3, 3); float playerMovementSpeed = 200.0; sf::Clock playerMovementClock; // Game loop sf::Event event; while(win.isOpen()) { while(win.pollEvent(event)) { if(event.type == sf::Event::Closed) win.close(); } // Player movements sf::Vector2f trans; float mouv = playerMovementClock.getElapsedTime().asSeconds() * playerMovementSpeed; if(sf::Keyboard::isKeyPressed(sf::Keyboard::W)) trans.y -= mouv; if(sf::Keyboard::isKeyPressed(sf::Keyboard::S)) trans.y += mouv; if(sf::Keyboard::isKeyPressed(sf::Keyboard::A)) trans.x -= mouv; if(sf::Keyboard::isKeyPressed(sf::Keyboard::D)) trans.x += mouv; player.setPosition(player.getPosition().x+trans.x, player.getPosition().y+trans.y); playerMovementClock.restart(); // Collision testing for(int c=0; c < 8; c++) { if(player.getGlobalBounds().intersects(trees[c].getGlobalBounds())) player.setPosition(player.getPosition().x-trans.x, player.getPosition().y-trans.y); } for(int c=0; c < 3; c++) { if(player.getGlobalBounds().intersects(stones[c].getGlobalBounds())) player.setPosition(player.getPosition().x-trans.x, player.getPosition().y-trans.y); } // Rendering win.clear(); win.draw(grass); for(int c = 0; c < 10; c++) win.draw(dirtTiles[c]); for(int c = 0; c < 8; c++) win.draw(trees[c]); for(int c = 0; c < 3; c++) win.draw(stones[c]); win.draw(player); win.display(); } return 0; }