R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
PrefabFactory.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created by hugo on 06/12/2025
4** File description:
5** PrefabFactory.cpp
6*/
7
13
14namespace ecs {
15
16 Address PrefabFactory::createPlayer(Registry &registry, uint32_t playerId) {
17 try {
18 Address player = registry.newEntity();
19
20 registry.setComponent(player, Player(0, 3, playerId));
21 registry.setComponent(player, Transform(100.0F, 300.0F));
22 registry.setComponent(player, Velocity(0.0F, 0.0F, 200.0F));
23 registry.setComponent(player, Health(100, 100));
24 registry.setComponent(player, Collider(50.0F, 50.0F, 0.0F, 0.0F, 1, 0xFFFFFFFF, false));
25 registry.setComponent(player,
26 Weapon(7.0F, 0.0F, 0, 25)); // fire rate: 7 shots/sec, type 0, 25 damage
27 LOG_INFO("✓ Player created with ID: ", playerId);
28
29 return player;
30 } catch (const std::exception &e) {
31 LOG_ERROR("Failed to create player: ", e.what());
32 return 0;
33 }
34 }
35
36 Address PrefabFactory::createEnemy(Registry &registry, int enemyType, float posX, float posY) {
37 try {
38 EnemySpawnData spawnData = _getEnemySpawnData(enemyType);
39 Address enemy = registry.newEntity();
40 registry.setComponent(enemy, Enemy(enemyType, spawnData.scoreValue));
41 registry.setComponent(enemy, Transform(posX, posY));
42 registry.setComponent(enemy, Velocity(-spawnData.speed, 0.0f, 0.0f));
43 registry.setComponent(enemy, Health(spawnData.health, spawnData.health));
44 registry.setComponent(enemy, Collider(spawnData.colliderWidth, spawnData.colliderHeight, 0.0f,
45 0.0f, 2, 0xFFFFFFFF, false));
46 registry.setComponent(enemy, Weapon(0.33f, 2.0f, 1, 15)); // ~1 shot per 1.5s
47 LOG_INFO("✓ Enemy created (ID:", enemy, ") type:", enemyType, " HP:", spawnData.health, " at (",
48 posX, ",", posY, ")");
49 return enemy;
50 } catch (const std::exception &e) {
51 LOG_ERROR("Failed to create enemy: ", e.what());
52 return 0;
53 }
54 }
55
56 Address PrefabFactory::createProjectile(Registry &registry, uint32_t ownerId, float posX, float posY,
57 float dirX, float dirY, float speed, int damage, bool friendly) {
58 try {
59 Address projectile = registry.newEntity();
60
61 registry.setComponent(projectile, Projectile(damage, 10.0f, ownerId, friendly));
62 registry.setComponent(projectile, Transform(posX, posY));
63 registry.setComponent(projectile, Velocity(dirX, dirY, speed));
64 // Layer 4 = projectiles, mask 0xFFFFFFFF = collides with all, isTrigger = false for solid collision
65 registry.setComponent(projectile, Collider(10.0f, 10.0f, 0.0f, 0.0f, 4, 0xFFFFFFFF, false));
66
67 // Add animation components for projectile rendering
69 registry.setComponent(projectile, Animation("projectile_fly", true, true));
70 registry.setComponent(projectile,
71 Sprite("Projectiles", {267, 84, 17, 13}, 2.0f, 0.0f, false, false, 0));
72
73 return projectile;
74 } catch (const std::exception &e) {
75 LOG_ERROR("Failed to create projectile: ", e.what());
76 return 0;
77 }
78 }
79
80 Address PrefabFactory::createEnemy(Registry &registry, const std::string &enemyType, float posX,
81 float posY, float health, int scoreValue,
82 const std::string &scriptPath) {
83 try {
84 int typeInt = _enemyTypeFromString(enemyType);
85 EnemySpawnData spawnData = _getEnemySpawnData(typeInt);
86
87 Address enemy = registry.newEntity();
88 registry.setComponent(enemy, Enemy(typeInt, scoreValue));
89 registry.setComponent(enemy, Transform(posX, posY));
90 registry.setComponent(enemy, Velocity(-1.0f, 0.0f, spawnData.speed));
91 registry.setComponent(enemy, Health(static_cast<int>(health), static_cast<int>(health)));
92 registry.setComponent(enemy, Collider(spawnData.colliderWidth, spawnData.colliderHeight, 0.0f,
93 0.0f, 2, 0xFFFFFFFF, false));
94 registry.setComponent(enemy, Weapon(0.33f, 2.0f, 1, 15)); // ~1 shot per 1.5s
95
96 // Add Lua script if provided
97 if (!scriptPath.empty()) {
98 registry.setComponent(enemy, LuaScript(scriptPath));
99 }
100
101 LOG_INFO("✓ Enemy '", enemyType, "' created at (", posX, ", ", posY, ")");
102 return enemy;
103 } catch (const std::exception &e) {
104 LOG_ERROR("Failed to create enemy: ", e.what());
105 return 0;
106 }
107 }
108
109 Address PrefabFactory::createEnemyFromRegistry(Registry &registry, const std::string &enemyType,
110 float posX, float posY, float health, int scoreValue,
111 const std::string &scriptPath) {
112 try {
113 int typeInt = _enemyTypeFromString(enemyType);
114 EnemySpawnData spawnData = _getEnemySpawnData(typeInt);
115
116 Address enemy = registry.newEntity();
117 registry.setComponent(enemy, Enemy(typeInt, scoreValue));
118 registry.setComponent(enemy, Transform(posX, posY));
119 registry.setComponent(enemy, Velocity(-1.0f, 0.0f, spawnData.speed));
120 registry.setComponent(enemy, Health(static_cast<int>(health), static_cast<int>(health)));
121 registry.setComponent(enemy, Collider(spawnData.colliderWidth, spawnData.colliderHeight, 0.0f,
122 0.0f, 2, 0xFFFFFFFF, false));
123 registry.setComponent(enemy, Weapon(0.33f, 2.0f, 1, 15)); // ~1 shot per 1.5s
124
125 // Add Lua script if provided
126 if (!scriptPath.empty()) {
127 registry.setComponent(enemy, LuaScript(scriptPath));
128 }
129
130 LOG_INFO("✓ Enemy '", enemyType, "' created at (", posX, ", ", posY, ")");
131 return enemy;
132 } catch (const std::exception &e) {
133 LOG_ERROR("Failed to create enemy: ", e.what());
134 return 0;
135 }
136 }
137
138 Address PrefabFactory::createPowerUp(Registry &registry, BuffType buffType, float duration, float value,
139 float posX, float posY) {
140 try {
141 Address powerUp = registry.newEntity();
142 registry.setComponent(powerUp, Collectible(buffType, duration, value));
143 registry.setComponent(powerUp, Transform(posX, posY));
144 registry.setComponent(powerUp, Velocity(0.0f, 0.0f, 0.0f));
145 registry.setComponent(powerUp, Collider(20.0f, 20.0f, 0.0f, 0.0f, 8, 0xFFFFFFFF, false));
146
147 LOG_INFO("✓ Power-up created at (", posX, ", ", posY, ")");
148 return powerUp;
149 } catch (const std::exception &e) {
150 LOG_ERROR("Failed to create power-up: ", e.what());
151 return 0;
152 }
153 }
154
155 Address PrefabFactory::createHealthPack(Registry &registry, int healthRestore, float posX, float posY) {
156 try {
157 Address healthPack = registry.newEntity();
158 registry.setComponent(healthPack, Collectible(healthRestore));
159 registry.setComponent(healthPack, Transform(posX, posY));
160 registry.setComponent(healthPack, Velocity(0.0f, 0.0f, 0.0f));
161 registry.setComponent(healthPack, Collider(20.0f, 20.0f, 0.0f, 0.0f, 8, 0xFFFFFFFF, false));
162
163 LOG_INFO("✓ Health pack created at (", posX, ", ", posY, ")");
164 return healthPack;
165 } catch (const std::exception &e) {
166 LOG_ERROR("Failed to create health pack: ", e.what());
167 return 0;
168 }
169 }
170
172 switch (enemyType) {
173 case 0: // Basic enemy
174 return {150.0f, 50, 100, 40.0f, 40.0f};
175 case 1: // Heavy enemy
176 return {100.0f, 100, 200, 60.0f, 60.0f};
177 case 2: // Fast enemy
178 return {200.0f, 30, 150, 30.0f, 30.0f};
179 case 3: // Boss-like enemy
180 return {120.0f, 200, 500, 80.0f, 80.0f};
181 default: // Default to basic
182 return {150.0f, 50, 100, 40.0f, 40.0f};
183 }
184 }
185
186 int PrefabFactory::_enemyTypeFromString(const std::string &enemyType) {
187 if (enemyType == "basic")
188 return 0;
189 if (enemyType == "advanced" || enemyType == "heavy")
190 return 1;
191 if (enemyType == "fast")
192 return 2;
193 if (enemyType == "boss")
194 return 3;
195 LOG_WARNING("Unknown enemy type '", enemyType, "', defaulting to basic");
196 return 0;
197 }
198
199 ecs::Address PrefabFactory::createWall(ecs::Registry &registry, float posX, float posY, float width,
200 float height, bool destructible, int health) {
201 try {
202 ecs::Address wall = registry.newEntity();
203 registry.setComponent(wall, ecs::Transform(posX, posY));
204 registry.setComponent(wall, ecs::Wall(destructible));
205 registry.setComponent(wall, ecs::Collider(width, height, 0.0f, 0.0f, 16, 0xFFFFFFFF,
206 false)); // Layer 16 for walls
207 registry.setComponent(
208 wall, ecs::Sprite("Wall.png", {0, 0, static_cast<int>(width), static_cast<int>(height)}, 1.0f,
209 0.0f, false, false, 0));
210
211 // Add health if destructible
212 if (destructible && health > 0) {
213 registry.setComponent(wall, ecs::Health(health, health));
214 }
215
216 LOG_INFO("✓ Wall spawned at (", posX, ", ", posY, ") - Size: ", width, "x", height,
217 destructible ? " [Destructible]" : " [Solid]");
218 return wall;
219 } catch (const std::exception &e) {
220 LOG_ERROR("Failed to create wall: ", e.what());
221 return 0;
222 }
223 }
224
226 float orbitRadius, float orbitSpeed, float startAngle,
227 int damage, int moduleHealth) {
228 try {
229 // Get parent position to initialize module near it
230 float initialX = 0.0f;
231 float initialY = 0.0f;
232 if (registry.hasComponent<Transform>(parentEntityId)) {
233 const Transform &parentTransform = registry.getComponent<Transform>(parentEntityId);
234 auto parentPos = parentTransform.getPosition();
235 initialX = parentPos.x + orbitRadius;
236 initialY = parentPos.y;
237 }
238
239 ecs::Address module = registry.newEntity();
240
241 // Orbital behavior component
242 registry.setComponent(
243 module, ecs::OrbitalModule(parentEntityId, orbitRadius, orbitSpeed, startAngle, damage));
244
245 // Position and movement
246 registry.setComponent(module, ecs::Transform(initialX, initialY));
247
248 // Collision - using PLAYER_MODULE layer
249 registry.setComponent(module,
250 ecs::Collider(16.0f, 16.0f, 0.0f, 0.0f, CollisionLayers::PLAYER_MODULE,
252
253 // Health for the module
254 registry.setComponent(module, ecs::Health(moduleHealth, moduleHealth));
255
256 // Animation components for orbital module
258 registry.setComponent(module, ecs::Animation("orbital_spin", true, true));
259
260 // Visual sprite (initial frame from animation)
261 registry.setComponent(module,
262 ecs::Sprite("OrbitalModule", {0, 0, 17, 18}, 2.0f, 0.0f, false, false, 0));
263
264 LOG_INFO("✓ Orbital module created for entity ", parentEntityId, " - Radius: ", orbitRadius,
265 ", Speed: ", orbitSpeed, " rad/s");
266 return module;
267 } catch (const std::exception &e) {
268 LOG_ERROR("Failed to create orbital module: ", e.what());
269 return 0;
270 }
271 }
272
273} // namespace ecs
#define LOG_INFO(...)
Definition Logger.hpp:181
#define LOG_ERROR(...)
Definition Logger.hpp:183
#define LOG_WARNING(...)
Definition Logger.hpp:182
Component managing current animation playback state.
Definition Animation.hpp:21
Component for items that can be picked up by players.
Component for collision detection and physics interactions.
Definition Collider.hpp:21
Component identifying an entity as an enemy with AI behavior.
Definition Enemy.hpp:20
Component representing entity health and invincibility.
Definition Health.hpp:20
Component that holds the path to a Lua script for entity behavior.
Definition LuaScript.hpp:21
Component for entities that orbit around a parent entity (like drones in Isaac).
Component identifying an entity as a player with game statistics.
Definition Player.hpp:20
static ecs::Address createEnemyFromRegistry(ecs::Registry &registry, const std::string &enemyType, float posX, float posY, float health, int scoreValue, const std::string &scriptPath="")
Create an enemy entity directly from Registry (for SpawnSystem)
static ecs::Address createHealthPack(ecs::Registry &registry, int healthRestore, float posX, float posY)
Create a health pack collectible.
static ecs::Address createPlayer(ecs::Registry &registry, uint32_t playerId)
Create a player entity.
static ecs::Address createEnemy(ecs::Registry &registry, int enemyType, float posX, float posY)
Create an enemy entity.
static ecs::Address createPowerUp(ecs::Registry &registry, ecs::BuffType buffType, float duration, float value, float posX, float posY)
Create a collectible power-up entity.
static int _enemyTypeFromString(const std::string &enemyType)
static ecs::Address createWall(ecs::Registry &registry, float posX, float posY, float width, float height, bool destructible=false, int health=0)
Create a wall/obstacle entity.
static ecs::Address createProjectile(ecs::Registry &registry, uint32_t ownerId, float posX, float posY, float dirX, float dirY, float speed, int damage, bool friendly)
Create a projectile entity.
static ecs::Address createOrbitalModule(ecs::Registry &registry, uint32_t parentEntityId, float orbitRadius=50.0f, float orbitSpeed=2.0f, float startAngle=0.0f, int damage=10, int moduleHealth=50)
Create an orbital module (drone) entity.
static EnemySpawnData _getEnemySpawnData(int enemyType)
Component for projectile entities (bullets, missiles, etc.).
Manages entities, their signatures and component type registrations.
Definition Registry.hpp:68
Address newEntity()
Create and register a new entity, returning its Address.
Definition Registry.cpp:47
T & getComponent(Address address)
Get a component from an entity.
bool hasComponent(Address address)
Check if an entity has a specific component.
void setComponent(Address address, const T &component)
Set/add a component to an entity with its data.
Component representing a visual sprite from a texture.
Definition Sprite.hpp:32
Component representing position, rotation and scale in 2D space.
Definition Transform.hpp:20
Vector2 getPosition() const
Get the position vector.
Definition Transform.hpp:61
Component representing movement direction and speed.
Definition Velocity.hpp:20
Component for static or destructible walls/obstacles.
Definition Wall.hpp:20
Component for entities capable of shooting projectiles.
Definition Weapon.hpp:28
ecs::AnimationSet createOrbitalModuleAnimations()
Create drone (orbital module) animations.
ecs::AnimationSet createPlayerBulletAnimations()
Create player bullet animations.
constexpr std::uint32_t PLAYER_MODULE
constexpr std::uint32_t MASK_PLAYER_MODULE
Maximum number of distinct component types supported by the Registry.
Definition GameLogic.hpp:26
BuffType
Types of buffs that can be applied to entities.
Definition Buff.hpp:20
std::uint32_t Address
Type used to represent an entity address/ID.