Air-Trap 1.0.0
A multiplayer R-Type clone game engine built with C++23 and ECS architecture
Loading...
Searching...
No Matches
RenderSystem.cpp
Go to the documentation of this file.
1
11
12namespace rtp::client {
13
15{
16 _textureCache.clear();
17 log::info("RenderSystem: Texture cache cleared");
18}
19
21{
22 (void)dt;
23
24 struct RenderItem {
25 int zIndex;
26 sf::Sprite sprite;
27 };
28 std::vector<RenderItem> itemsToDraw;
29
31
32 for (auto&& [trans, spriteComp] : view) {
33 const std::string &path = spriteComp.texturePath;
34
35 if (_textureCache.find(path) == _textureCache.end()) {
36 sf::Texture tex;
37 if (!tex.loadFromFile(path)) {
38 log::error("TEXTURE ERROR: Impossible de charger '{}'", path);
39 _textureCache[path] = sf::Texture();
40 } else {
41 _textureCache[path] = std::move(tex);
42 }
43 }
44
45 sf::Sprite s(_textureCache[path]);
46 const bool valid = (_textureCache[path].getSize().x > 0);
47
48 if (!valid) {
49 s.setTextureRect(sf::IntRect({0, 0}, {32, 32}));
50 s.setColor(sf::Color::Magenta);
51 } else {
52 if (spriteComp.rectWidth > 0 && spriteComp.rectHeight > 0) {
53 s.setTextureRect(sf::IntRect(
54 {spriteComp.rectLeft, spriteComp.rectTop},
55 {spriteComp.rectWidth, spriteComp.rectHeight}
56 ));
57 }
58 s.setColor(sf::Color(spriteComp.red, spriteComp.green, spriteComp.blue, spriteComp.opacity));
59 }
60
61 s.setPosition({trans.position.x, trans.position.y});
62 s.setRotation(sf::degrees(trans.rotation));
63 s.setScale({trans.scale.x, trans.scale.y});
64 s.setOrigin(valid && spriteComp.rectWidth > 0
65 ? sf::Vector2f(spriteComp.rectWidth / 2.0f, spriteComp.rectHeight / 2.0f)
66 : sf::Vector2f(16.f, 16.f));
67
68 itemsToDraw.push_back({spriteComp.zIndex, s});
69 }
70
71 std::sort(itemsToDraw.begin(), itemsToDraw.end(),
72 [](const RenderItem& a, const RenderItem& b) { return a.zIndex < b.zIndex; });
73
74 for (const auto &item : itemsToDraw) {
75 _window.draw(item.sprite);
77 sf::FloatRect bounds = item.sprite.getGlobalBounds();
78 sf::RectangleShape box({bounds.size.x, bounds.size.y});
79 box.setPosition({bounds.position.x, bounds.position.y});
80 box.setFillColor(sf::Color::Transparent);
81 box.setOutlineColor(sf::Color(255, 80, 80, 200));
82 box.setOutlineThickness(1.0f);
83 _window.draw(box);
84 }
85 }
86
87 auto obstacleView = _r.zipView<
91 >();
92
93 for (auto&& [trans, box, type] : obstacleView) {
94 if (type.type != net::EntityType::Obstacle &&
95 type.type != net::EntityType::ObstacleSolid &&
96 type.type != net::EntityType::Boss &&
97 type.type != net::EntityType::Boss2 &&
98 type.type != net::EntityType::BossShield &&
99 type.type != net::EntityType::Scout &&
100 type.type != net::EntityType::Tank) {
101 continue;
102 }
103
104 // Pour les ennemis, centrer la hitbox
105 float posX = trans.position.x;
106 float posY = trans.position.y;
107
108 if (type.type == net::EntityType::Boss ||
109 type.type == net::EntityType::Boss2 ||
110 type.type == net::EntityType::BossShield ||
111 type.type == net::EntityType::Scout ||
112 type.type == net::EntityType::Tank) {
113 // Centrer la hitbox autour de la position du sprite
114 posX = trans.position.x - box.width / 2.0f;
115 posY = trans.position.y - box.height / 2.0f;
116 }
117
118 sf::RectangleShape rect({box.width, box.height});
119 rect.setPosition({posX, posY});
120 if (type.type == net::EntityType::ObstacleSolid) {
121 rect.setFillColor(sf::Color(40, 40, 40, 220));
122 rect.setOutlineColor(sf::Color(90, 90, 90, 240));
123 } else if (type.type == net::EntityType::Boss) {
124 rect.setFillColor(sf::Color::Transparent);
125 rect.setOutlineColor(sf::Color(255, 0, 0, 240)); // Rouge pour le boss
126 } else if (type.type == net::EntityType::Boss2) {
127 rect.setFillColor(sf::Color::Transparent);
128 rect.setOutlineColor(sf::Color(200, 50, 200, 240)); // Magenta pour le Kraken
129 } else if (type.type == net::EntityType::BossShield) {
130 rect.setFillColor(sf::Color::Transparent);
131 rect.setOutlineColor(sf::Color(255, 165, 0, 240)); // Orange pour le shield
132 } else {
133 rect.setFillColor(sf::Color(60, 60, 60, 180));
134 rect.setOutlineColor(sf::Color(120, 120, 120, 220));
135 }
136 rect.setOutlineThickness(1.0f);
137 _window.draw(rect);
138 }
139
140 auto shieldView = _r.zipView<
144 >();
145
146 for (auto&& [trans, box, shield] : shieldView) {
147 const float radius = std::max(box.width, box.height) / 2.0f + 8.0f;
148
149 sf::CircleShape circle(radius);
150 circle.setPosition(sf::Vector2f(trans.position.x - radius, trans.position.y - radius));
151 circle.setFillColor(sf::Color::Transparent);
152 circle.setOutlineColor(sf::Color(0, 255, 0, static_cast<uint8_t>(shield.alpha)));
153 circle.setOutlineThickness(2.5f);
154
155 _window.draw(circle);
156
157 sf::CircleShape innerCircle(radius - 4.0f);
158 innerCircle.setPosition(sf::Vector2f(trans.position.x - (radius - 4.0f), trans.position.y - (radius - 4.0f)));
159 innerCircle.setFillColor(sf::Color::Transparent);
160 innerCircle.setOutlineColor(sf::Color(100, 255, 100, static_cast<uint8_t>(shield.alpha * 0.5f)));
161 innerCircle.setOutlineThickness(1.0f);
162
163 _window.draw(innerCircle);
164 }
165}
166
167} // namespace rtp::client
void update(float dt) override
Update system logic for one frame.
sf::RenderWindow & _window
std::unordered_map< std::string, sf::Texture > _textureCache
auto zipView(this Self &self)
R-Type client namespace.
bool g_drawDebugBounds
void error(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an error message.
void info(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an informational message.
Component for visual shield effect displayed around the player.
Component representing a sprite.
Definition Sprite.hpp:21
std::string texturePath
Identifier for the texture resource.
Definition Sprite.hpp:22
Component representing position, rotation, and scale of an entity.
Definition Transform.hpp:23