Skip to content

Commit fab2d71

Browse files
committed
Added Asteroid size and breaking functionality
1 parent cdba5ce commit fab2d71

4 files changed

Lines changed: 251 additions & 22 deletions

File tree

exemples/Asteroid/application.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ StandardSystemImpl* createAsteroidSpawnTimerSystem()
4141
float timer = sys->getData("spawnTimer").get<float>();
4242
timer += deltaTime;
4343

44-
if (timer > 2.0f)
44+
if (timer > 10.0f)
4545
{
46-
timer -= 2.0f;
46+
timer -= 10.0f;
4747
// for (int i = 0; i < 10; i++)
4848
sys->sendEvent("SpawnAsteroid");
4949
}
@@ -140,6 +140,8 @@ GameApp::GameApp(const std::string &appName) : engine(appName)
140140

141141
engine.setSetupFunction([this](EntitySystem& ecs, Window& window)
142142
{
143+
ecs.setVMOptimizationLevel(VmOptimizationLevel::O0);
144+
143145
ecs.createSystem<CollisionSystem>();
144146

145147
ecs.createSystem<CollisionHandlerSystem>();

res/asteroid/README_ASTEROID.md

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,54 @@ All bullet data stored in `sysData`:
125125
- `bullet[N]_lifetime` - Remaining lifetime
126126
- `bullet[N]_spawn` - Flag to trigger spawning (1 = spawn, 0 = spawned)
127127

128+
## Asteroid Health and Splitting System
129+
130+
### Three-Tier Asteroid System:
131+
132+
The game features a three-tier asteroid system where larger asteroids break apart into smaller ones:
133+
134+
1. **Big Asteroids** (60px)
135+
- Health: 3 hits required
136+
- Splits into: 2 medium asteroids
137+
- Speed: 50-150 px/s
138+
139+
2. **Medium Asteroids** (40px)
140+
- Health: 2 hits required
141+
- Splits into: 2 small asteroids
142+
- Speed: 60-120 px/s (spawned from big asteroids)
143+
144+
3. **Small Asteroids** (20px)
145+
- Health: 1 hit required
146+
- Splits into: Nothing (completely destroyed)
147+
- Speed: 80-150 px/s (spawned from medium asteroids)
148+
149+
### How It Works:
150+
151+
1. When a bullet hits an asteroid, the asteroid's health decreases by 1
152+
2. If health reaches 0:
153+
- Big asteroids spawn 2 medium asteroids at the destruction location
154+
- Medium asteroids spawn 2 small asteroids at the destruction location
155+
- Small asteroids are completely destroyed with no fragments
156+
3. Fragment asteroids inherit the parent's position but get random velocities in opposite directions
157+
4. Each fragment has its own rotation speed for visual variety
158+
159+
### Asteroid Component Data:
160+
161+
Each asteroid stores the following in its `Asteroid` component:
162+
- `size` - Visual size in pixels (60/40/20)
163+
- `vx`, `vy` - Velocity components
164+
- `rotSpeed` - Rotation speed
165+
- `health` - Current health (decreases when hit)
166+
- `maxHealth` - Maximum health for this asteroid type
167+
- `type` - Asteroid type: "big", "medium", or "small"
168+
169+
### Spawning Custom Asteroids:
170+
171+
To spawn a specific asteroid type, set these values in `sysData` before calling the spawn script:
172+
- `spawnAsteroidType` - "big", "medium", or "small" (defaults to "big")
173+
- `spawnAsteroidX`, `spawnAsteroidY` - Optional spawn position
174+
- `spawnAsteroidVX`, `spawnAsteroidVY` - Optional velocity
175+
128176
## Next Steps for Full Game
129177

130178
### TODO:
@@ -135,13 +183,14 @@ All bullet data stored in `sysData`:
135183
5. ✅ Player ship thrust (up arrow)
136184
6. ✅ Player velocity/momentum
137185
7. ✅ Shooting bullets (spacebar with fire rate limiting)
138-
8. ⬜ Collision detection (bullets vs asteroids, player vs asteroids)
139-
9. ⬜ Asteroid splitting (large → 2 medium → 2 small)
140-
10. ⬜ Score tracking
141-
11. ⬜ Lives system
142-
12. ⬜ Game over/win conditions
143-
13. ⬜ Different textures for different sized asteroids
144-
14. ⬜ Sound effects
186+
8. ✅ Collision detection (bullets vs asteroids)
187+
9. ✅ Asteroid health system and splitting (big(3hp) → 2 medium(2hp) → 2 small(1hp))
188+
10. ⬜ Collision detection (player vs asteroids)
189+
11. ⬜ Score tracking
190+
12. ⬜ Lives system
191+
13. ⬜ Game over/win conditions
192+
14. ⬜ Different textures for different sized asteroids
193+
15. ⬜ Sound effects
145194

146195
## Module Usage
147196

@@ -151,6 +200,7 @@ The spawn script uses these modules:
151200
- `ecs` - For entity management
152201
- `math` - For trigonometry (sin, cos, sqrt)
153202
- `random` - For random number generation
203+
- `algorithm` - For utility functions like `contain()` to check if keys exist in tables
154204

155205
## How Asteroid Data is Stored
156206

Lines changed: 123 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,130 @@
11
import "ecs"
22
import "string"
3+
import "math"
4+
import "random"
5+
import "texture"
6+
import "algorithm"
37

48
// This script is called when a Bullet and an Asteroid collide
5-
// ent1 and ent2 are automatically provided by the collision system
9+
// Need to detect which entity is which since order can vary
610

7-
// Log the collision
8-
logInfo("Collision! Bullet " + toString(ent1.__entityId) + " hit asteroid " + toString(ent2.__entityId))
11+
// Detect which entity is the bullet and which is the asteroid
12+
var bullet = 0
13+
var asteroid = 0
914

10-
// Remove both entities
11-
removeEntity(ent1.__entityId)
12-
removeEntity(ent2.__entityId)
15+
if (contain(ent1, "Bullet"))
16+
{
17+
bullet = ent1
18+
asteroid = ent2
19+
}
20+
else
21+
{
22+
bullet = ent2
23+
asteroid = ent1
24+
}
1325

14-
logInfo("Both entities destroyed")
26+
logInfo("Collision! Bullet " + toString(bullet.__entityId) + " hit asteroid " + toString(asteroid.__entityId))
27+
28+
// Always remove the bullet
29+
removeEntity(bullet.__entityId)
30+
31+
// Get asteroid data
32+
var asteroidData = asteroid["Asteroid"]
33+
var currentHealth = asteroidData.health
34+
var asteroidType = asteroidData.type
35+
36+
logInfo("Asteroid type: " + asteroidType + ", Health before hit: " + toString(currentHealth))
37+
38+
// Reduce health by 1
39+
currentHealth = currentHealth - 1
40+
41+
if (currentHealth <= 0)
42+
{
43+
logInfo("Asteroid health depleted")
44+
45+
debugTable(asteroid)
46+
47+
var pos = asteroid["PositionComponent"]
48+
var asteroidX = pos.x
49+
var asteroidY = pos.y
50+
var parentVX = asteroidData.vx
51+
var parentVY = asteroidData.vy
52+
53+
// Remove the destroyed asteroid
54+
removeEntity(asteroid.__entityId)
55+
56+
// Asteroid is destroyed - spawn smaller asteroids if applicable
57+
logInfo("Asteroid destroyed!")
58+
59+
// Spawn 2 smaller asteroids if this was big or medium
60+
if (asteroidType == "big")
61+
{
62+
logInfo("Big asteroid destroyed - spawning 2 medium asteroids")
63+
64+
// Spawn first medium asteroid
65+
var angle1 = randomRange(0, 6.28)
66+
var speed1 = randomRange(60, 120)
67+
var vx1 = cos(angle1) * speed1
68+
var vy1 = sin(angle1) * speed1
69+
var rotSpeed1 = randomRange(-2, 2)
70+
71+
var medium1 = createTexture("Ghost", 40, 40)
72+
medium1["PositionComponent"].setX(asteroidX)
73+
medium1["PositionComponent"].setY(asteroidY)
74+
medium1.attachComp("Asteroid", "size", 40, "vx", vx1, "vy", vy1, "rotSpeed", rotSpeed1, "health", 2, "maxHealth", 2, "type", "medium")
75+
medium1.attachComp("Collision")
76+
77+
// Spawn second medium asteroid (opposite direction)
78+
var angle2 = angle1 + 3.14 + randomRange(-0.5, 0.5)
79+
var speed2 = randomRange(60, 120)
80+
var vx2 = cos(angle2) * speed2
81+
var vy2 = sin(angle2) * speed2
82+
var rotSpeed2 = randomRange(-2, 2)
83+
84+
var medium2 = createTexture("Ghost", 40, 40)
85+
medium2["PositionComponent"].setX(asteroidX)
86+
medium2["PositionComponent"].setY(asteroidY)
87+
medium2.attachComp("Asteroid", "size", 40, "vx", vx2, "vy", vy2, "rotSpeed", rotSpeed2, "health", 2, "maxHealth", 2, "type", "medium")
88+
medium2.attachComp("Collision")
89+
}
90+
else if (asteroidType == "medium")
91+
{
92+
logInfo("Medium asteroid destroyed - spawning 2 small asteroids")
93+
94+
// Spawn first small asteroid
95+
var angle1 = randomRange(0, 6.28)
96+
var speed1 = randomRange(80, 150)
97+
var vx1 = cos(angle1) * speed1
98+
var vy1 = sin(angle1) * speed1
99+
var rotSpeed1 = randomRange(-2, 2)
100+
101+
var small1 = createTexture("Ghost", 20, 20)
102+
small1["PositionComponent"].setX(asteroidX)
103+
small1["PositionComponent"].setY(asteroidY)
104+
small1.attachComp("Asteroid", "size", 20, "vx", vx1, "vy", vy1, "rotSpeed", rotSpeed1, "health", 1, "maxHealth", 1, "type", "small")
105+
small1.attachComp("Collision")
106+
107+
// Spawn second small asteroid (opposite direction)
108+
var angle2 = angle1 + 3.14 + randomRange(-0.5, 0.5)
109+
var speed2 = randomRange(80, 150)
110+
var vx2 = cos(angle2) * speed2
111+
var vy2 = sin(angle2) * speed2
112+
var rotSpeed2 = randomRange(-2, 2)
113+
114+
var small2 = createTexture("Ghost", 20, 20)
115+
small2["PositionComponent"].setX(asteroidX)
116+
small2["PositionComponent"].setY(asteroidY)
117+
small2.attachComp("Asteroid", "size", 20, "vx", vx2, "vy", vy2, "rotSpeed", rotSpeed2, "health", 1, "maxHealth", 1, "type", "small")
118+
small2.attachComp("Collision")
119+
}
120+
else
121+
{
122+
logInfo("Small asteroid destroyed - no fragments")
123+
}
124+
}
125+
else
126+
{
127+
// Asteroid still has health - just update the health value
128+
logInfo("Asteroid damaged! Remaining health: " + toString(currentHealth))
129+
asteroidData.setHealth(currentHealth)
130+
}

res/asteroid/spawn_single_asteroid.pg

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,46 @@ import "string"
33
import "ecs"
44
import "math"
55
import "random"
6+
import "algorithm"
67

78
// Screen dimensions (these should match your window size)
89
var screenWidth = 800
910
var screenHeight = 600
1011

1112
logInfo("Spawning new asteroid")
1213

13-
// Create asteroid with random size
14-
var size = randomInt(30, 60)
14+
// Determine asteroid type: "big", "medium", or "small"
15+
// Default to "big" if no type specified in sysData
16+
var asteroidType = "big"
17+
if (contain(sysData, "spawnAsteroidType"))
18+
{
19+
asteroidType = sysData["spawnAsteroidType"]
20+
}
21+
22+
// Set size and health based on type
23+
var size = 60
24+
var health = 3
25+
var maxHealth = 3
26+
27+
if (asteroidType == "big")
28+
{
29+
size = 60
30+
health = 3
31+
maxHealth = 3
32+
}
33+
else if (asteroidType == "medium")
34+
{
35+
size = 40
36+
health = 2
37+
maxHealth = 2
38+
}
39+
else if (asteroidType == "small")
40+
{
41+
size = 20
42+
health = 1
43+
maxHealth = 1
44+
}
45+
1546
var asteroid = createTexture("Ghost", size, size)
1647

1748
// Random spawn position on screen edges
@@ -76,12 +107,42 @@ var vy = finalDirY * speed
76107
// Random rotation speed (in degrees per second for visual rotation)
77108
var rotSpeed = randomRange(-2, 2)
78109

110+
// Allow spawning at a specific position (for when asteroids split)
111+
if (contain(sysData, "spawnAsteroidX") and contain(sysData, "spawnAsteroidY"))
112+
{
113+
spawnX = sysData["spawnAsteroidX"]
114+
spawnY = sysData["spawnAsteroidY"]
115+
asteroid["PositionComponent"].setX(spawnX)
116+
asteroid["PositionComponent"].setY(spawnY)
117+
118+
// Clear the position override
119+
sysData.remove("spawnAsteroidX")
120+
sysData.remove("spawnAsteroidY")
121+
}
122+
123+
// Allow custom velocity (for when asteroids split)
124+
if (contain(sysData, "spawnAsteroidVX") and contain(sysData, "spawnAsteroidVY"))
125+
{
126+
vx = sysData["spawnAsteroidVX"]
127+
vy = sysData["spawnAsteroidVY"]
128+
129+
// Clear the velocity override
130+
sysData.remove("spawnAsteroidVX")
131+
sysData.remove("spawnAsteroidVY")
132+
}
133+
79134
debugTable(asteroid)
80135

81-
// Attach Asteroid component with all necessary data
82-
asteroid.attachComp("Asteroid", "size", size, "vx", vx, "vy", vy, "rotSpeed", rotSpeed)
136+
// Attach Asteroid component with all necessary data including health and type
137+
asteroid.attachComp("Asteroid", "size", size, "vx", vx, "vy", vy, "rotSpeed", rotSpeed, "health", health, "maxHealth", maxHealth, "type", asteroidType)
83138

84139
asteroid.attachComp("Collision")
85140

86-
logInfo("Asteroid spawned at (" + toString(spawnX) + ", " + toString(spawnY) + ")")
87-
logInfo("Velocity: (" + toString(vx) + ", " + toString(vy) + ")")
141+
// Clear the type override for next spawn
142+
if (contain(sysData, "spawnAsteroidType"))
143+
{
144+
sysData.remove("spawnAsteroidType")
145+
}
146+
147+
logInfo("Asteroid (" + asteroidType + ") spawned at (" + toString(spawnX) + ", " + toString(spawnY) + ")")
148+
logInfo("Velocity: (" + toString(vx) + ", " + toString(vy) + "), Health: " + toString(health) + "/" + toString(maxHealth))

0 commit comments

Comments
 (0)