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
|
#pragma once
#include "StarPoly.hpp"
#include "StarList.hpp"
#include "StarBiMap.hpp"
namespace Star {
enum class CollisionKind : uint8_t {
// Special collision block that is used for unloaded / un-generated tiles.
// Collides the same as "Block", but does not tile with it.
Null,
None,
Platform,
Dynamic,
Slippery,
Block
};
enum class TileCollisionOverride : uint8_t {
None,
Empty,
Platform,
Block
};
inline CollisionKind collisionKindFromOverride(TileCollisionOverride const& over) {
switch (over) {
case TileCollisionOverride::Empty:
return CollisionKind::None;
case TileCollisionOverride::Platform:
return CollisionKind::Platform;
case TileCollisionOverride::Block:
return CollisionKind::Block;
default:
return CollisionKind::Null;
}
}
class CollisionSet {
public:
CollisionSet();
CollisionSet(initializer_list<CollisionKind> kinds);
void insert(CollisionKind kind);
void remove(CollisionKind kind);
bool contains(CollisionKind kind) const;
private:
static uint8_t kindBit(CollisionKind kind);
uint8_t m_kinds;
};
// The default CollisionSet consists of Null, Slippery, Dynamic and Block
extern CollisionSet const DefaultCollisionSet;
// Defines what can be "blocks" e.g. for tile rendering: Block and Slippery
extern CollisionSet const BlockCollisionSet;
extern EnumMap<TileCollisionOverride> const TileCollisionOverrideNames;
extern EnumMap<CollisionKind> const CollisionKindNames;
bool isColliding(CollisionKind kind, CollisionSet const& collisionSet);
bool isSolidColliding(CollisionKind kind);
// Returns the highest priority collision kind, where Block > Slippery >
// Dynamic > Platform > None > Null
CollisionKind maxCollision(CollisionKind first, CollisionKind second);
struct CollisionBlock {
// Make a null collision block for the given space.
static CollisionBlock nullBlock(Vec2I const& space);
CollisionKind kind;
Vec2I space;
PolyF poly;
RectF polyBounds;
};
inline CollisionSet::CollisionSet()
: m_kinds(0) {}
inline CollisionSet::CollisionSet(initializer_list<CollisionKind> kinds)
: CollisionSet() {
for (auto kind : kinds) {
insert(kind);
}
}
inline void CollisionSet::insert(CollisionKind kind) {
m_kinds = m_kinds | kindBit(kind);
}
inline void CollisionSet::remove(CollisionKind kind) {
m_kinds = m_kinds & ~kindBit(kind);
}
inline bool CollisionSet::contains(CollisionKind kind) const {
return m_kinds & kindBit(kind);
}
inline uint8_t CollisionSet::kindBit(CollisionKind kind) {
return 1 << ((uint8_t)kind + 1);
}
inline bool isColliding(CollisionKind kind, CollisionSet const& collisionSet) {
return collisionSet.contains(kind);
}
inline bool isSolidColliding(CollisionKind kind) {
return isColliding(kind, DefaultCollisionSet);
}
inline CollisionKind maxCollision(CollisionKind first, CollisionKind second) {
return max(first, second);
}
inline CollisionBlock CollisionBlock::nullBlock(Vec2I const& space) {
CollisionBlock block;
block.kind = CollisionKind::Null;
block.space = space;
block.poly = {
Vec2F(space) + Vec2F(0, 0),
Vec2F(space) + Vec2F(1, 0),
Vec2F(space) + Vec2F(1, 1),
Vec2F(space) + Vec2F(0, 1)
};
block.polyBounds = RectF::withSize(Vec2F(space), Vec2F(1, 1));
return block;
}
}
|