@@ -33,25 +33,49 @@ inline sf::Vector2f gridToWorld(const Node* node, int tileSize) {
3333 node->y * tileSize + tileSize / 2 );
3434}
3535
36+ // Function for pickup object collision
37+ template <typename PickupType, typename EffectFunc>
38+ void handlePickup (std::vector<PickupType>& pickups,
39+ Object& playerCollider,
40+ MapLoader& map,
41+ EffectFunc effect) {
42+ for (auto it = pickups.begin (); it != pickups.end ();) {
43+ Manifold m = { &playerCollider, it->collider () };
44+ if (AABBvsAABB (&m)) {
45+ // Apply pickup effect
46+ effect (*it);
47+
48+ // Remove from tilemap
49+ Vec2 pos = it->collider ()->pos ;
50+ int tileX = static_cast <int >(pos.x ) / TILE_SIZE;
51+ int tileY = static_cast <int >(pos.y ) / TILE_SIZE;
52+ map.setTile (tileX, tileY, ' .' );
53+
54+ // Remove from vector
55+ it = pickups.erase (it);
56+ } else {
57+ ++it;
58+ }
59+ }
60+ }
61+
3662int main ()
3763{
3864 sf::Clock clock;
3965 sf::Clock sprintClock;
4066
41- // Create colliders list
42- std::vector<Object*> colliders;
43-
44- // Create a player
67+ // ---- Create a player ----
4568 Object playerCollider = { Vec2 (275 , 200 ), { Vec2 (-50 , -50 ), Vec2 (50 , 50 ) } };
4669 Player player;
4770 player.sprite .setPosition (toSF (playerCollider.pos ));
4871
49- // Create tilemap
72+ // ---- Load tilemap ----
5073 MapLoader map;
5174 TileMapRenderer renderer;
5275 map.loadFromFile (" level.txt" );
5376
54- // Set up wall and health pickup colliders
77+ // ---- Set up colliders ----
78+ std::vector<Object*> colliders; // Create colliders list
5579 struct healthPickup {
5680 Object healthPickup;
5781 Object* collider () { return &healthPickup; }
@@ -62,11 +86,12 @@ int main()
6286 Object* collider () { return &goldPickup; }
6387 };
6488 std::vector<goldPickup> goldPickups;
65- // Set enemy list
6689 struct Enem {
6790 Enemy enemy;
6891 Object* collider () { return &enemy.collider ; }
6992 };
93+
94+ // ---- Set up objects ----
7095 std::vector<Enem> enemies;
7196 std::vector<Object> wallObjects;
7297 sf::Texture enemyTex;
@@ -122,17 +147,18 @@ int main()
122147 }
123148 }
124149
150+ // ---- Set up game window ----
125151 // Create game window
126152 sf::RenderWindow window (sf::VideoMode ({800 , 600 }), " 2D Game" , sf::Style::Titlebar | sf::Style::Close);
127153 window.setFramerateLimit (60 );
128-
129154 // Create game camera
130155 sf::View camera;
131156 sf::Vector2u winSize = window.getSize ();
132157 camera.setSize (sf::Vector2f (winSize.x , winSize.y ));
133158 camera.setCenter (player.getPosition ());
134159 window.setView (camera);
135160
161+ // ---- Events ----
136162 // Timers and keys used for detecting double taps
137163 sf::Time lastClickTime; // The last click of each key
138164 const sf::Time doubleClickTime = sf::milliseconds (500 ); // Expected time limit for second click to happen
@@ -145,7 +171,6 @@ int main()
145171 const auto onClose = [&window](const sf::Event::Closed&) {
146172 window.close ();
147173 };
148-
149174 // Check when key is pressed
150175 const auto onKeyPressed = [&window, &player, &sprintClock, &lastClickTime, &doubleClickTime, &lastDirection, &keyHeld, &sprint, &isDoubleTap](const sf::Event::KeyPressed& keyPressed) {
151176 // Ensure window is closed when Escape key is pressed
@@ -173,8 +198,6 @@ int main()
173198 lastDirection = keyPressed.scancode ; // Key that was last clicked
174199 lastClickTime = now; // Time user last clicked
175200 };
176-
177-
178201 // Check when key is released
179202 const auto onKeyReleased = [&window, &keyHeld](const sf::Event::KeyReleased& keyPressed) {
180203 // If double tap movement keys, tell player to sprint
@@ -196,51 +219,38 @@ int main()
196219 sf::Time delta = clock.restart (); // Time since last frame
197220 float deltaTime = delta.asSeconds (); // Convert to seconds
198221
222+ // Handle events and updates
199223 window.handleEvents (onClose, onKeyPressed, onKeyReleased);
200-
201- // Handle player controls and enemy updates
202224 player.handleInput ();
203225 player.update ();
204226
205- // Create new window with sprites drawn in
206- window.clear (sf::Color::White );
227+ // Create new window with black background
228+ window.clear (sf::Color::Black );
207229
208- // ---- Collision detection ----
209-
210- // Try movement
230+ // ---- Movement ----
211231 Vec2 originalPos = playerCollider.pos ;
212- // --- X axis ---
232+ // X axis
213233 float originalX = playerCollider.pos .x ;
214234 playerCollider.pos .x += player.movement .x ;
215235 // Stop if colliding with object
216- for (auto & enem : enemies) {
217- Manifold m = { &playerCollider, enem.collider ()};
218- if (AABBvsAABB ({&m})) {
219- if (enem.enemy .attacking ) {
220- player.takeDamage (1 );
221- }
222- playerCollider.pos .x = originalX;
223- break ;
224- }
236+ for (auto & enem : enemies) { Manifold m = { &playerCollider, enem.collider () };
237+ if (AABBvsAABB ({&m})) { playerCollider.pos .x = originalX; break ; }
225238 }
226- for (auto & obj : colliders) {
227- Manifold m = { &playerCollider, obj };
228- if (AABBvsAABB (&m)) {
229- playerCollider.pos .x = originalX;
230- break ;
231- }
239+ for (auto & obj : colliders) { Manifold m = { &playerCollider, obj };
240+ if (AABBvsAABB (&m)) { playerCollider.pos .x = originalX; break ; }
232241 }
233- // --- Y axis ---
242+ // Y axis
234243 float originalY = playerCollider.pos .y ;
235244 playerCollider.pos .y += player.movement .y ;
236245 // Stop if colliding with object
237- for (auto & enem : enemies) {
238- Manifold m = { &playerCollider, enem.collider ()};
239- if (AABBvsAABB ({&m})) {
240- playerCollider.pos .y = originalY;
241- break ;
242- }
246+ for (auto & enem : enemies) { Manifold m = { &playerCollider, enem.collider () };
247+ if (AABBvsAABB ({&m})) { playerCollider.pos .y = originalY; break ; }
248+ }
249+ for (auto & obj : colliders) { Manifold m = { &playerCollider, obj };
250+ if (AABBvsAABB (&m)) { playerCollider.pos .y = originalY; break ; }
243251 }
252+
253+ // ---- Damage ----
244254 // Check if enemy is attacking player, if close enough damage player
245255 for (auto & enem : enemies) {
246256 float dx = player.getPosition ().x - enem.enemy .getPosition ().x ;
@@ -250,54 +260,21 @@ int main()
250260 player.takeDamage (1 );
251261 }
252262 }
253- for (auto & obj : colliders) {
254- Manifold m = { &playerCollider, obj };
255- if (AABBvsAABB (&m)) {
256- playerCollider.pos .y = originalY;
257- break ;
258- }
259- }
260- // Delete healthPickup if collided with
261- for (auto it = healthPickups.begin (); it != healthPickups.end (); ) {
262- Manifold m = {&playerCollider, it->collider ()};
263- if (AABBvsAABB (&m)) {
264- if (player.getHealth () < player.getMaxHealth ()) {
265- // Heal player
263+
264+ // ---- Pickups ----
265+ // Heal player when colliding with health pickups if not at max health
266+ if (player.getHealth () < player.getMaxHealth ()) {
267+ handlePickup (healthPickups, playerCollider, map, [&](auto & pickup) {
266268 player.heal (1 );
267- // Remove healthPickup from tilemap
268- Vec2 pos = (it)->healthPickup .pos ;
269- int tileX = static_cast <int >(pos.x ) / TILE_SIZE;
270- int tileY = static_cast <int >(pos.y ) / TILE_SIZE;
271- map.setTile (tileX, tileY, ' .' );
272- // Remove healthPickup from objects and colliders
273- it = healthPickups.erase (it);
274- }
275- break ;
276- } else {
277- ++it;
278- }
279- }
280- // Delete goldPickup if collided with
281- for (auto it = goldPickups.begin (); it != goldPickups.end (); ) {
282- Manifold m = {&playerCollider, it->collider ()};
283- if (AABBvsAABB (&m)) {
284- // Add gold
285- player.addGold (25 );
286- // Remove healthPickup from tilemap
287- Vec2 pos = (it)->goldPickup .pos ;
288- int tileX = static_cast <int >(pos.x ) / TILE_SIZE;
289- int tileY = static_cast <int >(pos.y ) / TILE_SIZE;
290- map.setTile (tileX, tileY, ' .' );
291- // Remove healthPickup from objects and colliders
292- it = goldPickups.erase (it);
293- break ;
294- } else {
295- ++it;
296- }
269+
270+ });
297271 }
272+ // Give gold when colliding with gold pickups
273+ handlePickup (goldPickups, playerCollider, map, [&](auto & pickup) {
274+ player.addGold (25 );
275+ });
298276
299277 // ---- Draw items ----
300-
301278 // Draw tilemap with walls and healthPickups
302279 renderer.draw (window, map);
303280 // Draw shadows first and update enemies
0 commit comments