-
Notifications
You must be signed in to change notification settings - Fork 0
/
CollisionHandlers.cpp
88 lines (68 loc) · 3.17 KB
/
CollisionHandlers.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
#include <iostream>
#include <algorithm>
#include <utility>
#include "CollisionHandlers.h"
#include "Player.h"
#include "Block.h"
#include "Door.h"
#include "Beam.h"
#include "Projectile.h"
using namespace sf;
void CollisionHandlers::PlayerBlockHandler(std::shared_ptr<ICollidable> p, std::shared_ptr<ICollidable> b, Level& level) {
//Objects may no longer be colliding, so double check
if (!p->isCollidingWith(*b))
return;
Player& player = dynamic_cast<Player&>(*p);
Block& block = dynamic_cast<Block&>(*b);
FloatRect playerBox = player.getCollisionBox();
FloatRect blockBox = block.getCollisionBox();
//Calculate the best (shortest) distance and direction to move the player so that it is out of the block
Vector2f left(-1, 0);
Vector2f right(1, 0);
Vector2f up(0, -1);
Vector2f down(0, 1);
std::pair<float, Vector2f> dirs[4];
dirs[0] = std::make_pair((playerBox.left + playerBox.width) - blockBox.left, left);
dirs[1] = std::make_pair((blockBox.left + blockBox.width) - playerBox.left, right);
dirs[2] = std::make_pair((playerBox.top + playerBox.height) - blockBox.top, up);
dirs[3] = std::make_pair((blockBox.top + blockBox.height) - playerBox.top, down);
auto bestDir = *std::min_element(begin(dirs), end(dirs),
[](const std::pair<float, Vector2f>& a, const std::pair<float, Vector2f>& b){ return a.first < b.first; });
//If the player needs to be moved up, it collided with a block below it, so it is no longer airborne
if (bestDir.second == up)
player.setAirborne(false);
//Move player out of block
player.setPosition(player.getPosition() + (bestDir.first * bestDir.second));
}
void CollisionHandlers::PlayerDoorHandler(std::shared_ptr<ICollidable> p, std::shared_ptr<ICollidable> d, Level& level) {
//Objects may no longer be colliding, so double check
if (!p->isCollidingWith(*d))
return;
Door& door = dynamic_cast<Door&>(*d);
door.setActivated(true);
}
void CollisionHandlers::BeamBlockHandler(std::shared_ptr<ICollidable> be, std::shared_ptr<ICollidable> bl, Level& level) {
//Objects may no longer be colliding, so double check
if (!be->isCollidingWith(*bl))
return;
Beam& beam = dynamic_cast<Beam&>(*be);
Block& block = dynamic_cast<Block&>(*bl);
if (beam.getColor() == block.getColor()) {
level.removeEntity(std::static_pointer_cast<Block>(bl));
beam.addBlocks(1);
}
beam.move(beam.trace(block) - beam.getSize().x);
}
void CollisionHandlers::ProjectileBlockHandler(std::shared_ptr<ICollidable> p, std::shared_ptr<ICollidable> b, Level& level) {
//Objects may no longer be colliding, so double check
if (!p->isCollidingWith(*b))
return;
std::shared_ptr<Projectile> proj = std::static_pointer_cast<Projectile>(p);
if (!proj->wasPhasing()) {
Vector2f oldPos = proj->getOldPosition();
Vector2f blockPos((int)(oldPos.x / Level::BLOCK_SIZE) * Level::BLOCK_SIZE, (int)(oldPos.y / Level::BLOCK_SIZE) * Level::BLOCK_SIZE);
level.addEntity(std::shared_ptr<Block>{new Block(blockPos, proj->getColor())});
}
level.removeLevelObject(proj);
level.removeCollidable(proj);
}