Implement asteroids breaking apart

Rename createPlayerDebris -> createDebris to make it clear it's not only
for the player entity.

Add Constants.ASTEROID_SPAWN_COUNT

Slow down asteroids, tweak sizing
This commit is contained in:
Matt Low 2020-01-30 13:37:52 +04:00
parent d140959fdc
commit 3b1c075102
5 changed files with 89 additions and 17 deletions

View File

@ -15,5 +15,6 @@ public class Constants {
public static final int HALF_HEIGHT = HEIGHT / 2; public static final int HALF_HEIGHT = HEIGHT / 2;
public static final float ASTEROID_SPAWN_DELAY = 1f; public static final float ASTEROID_SPAWN_DELAY = 1f;
public static final int ASTEROID_SPAWN_COUNT = 4;
} }

View File

@ -1,6 +1,7 @@
package com.me.asteroids; package com.me.asteroids;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.me.asteroids.components.AccelerationComponent; import com.me.asteroids.components.AccelerationComponent;
import com.me.asteroids.components.AsteroidComponent; import com.me.asteroids.components.AsteroidComponent;
@ -16,6 +17,8 @@ import com.me.asteroids.components.model.PolygonModel;
import com.me.common.ecs.Engine; import com.me.common.ecs.Engine;
import com.me.common.ecs.Entity; import com.me.common.ecs.Entity;
import java.util.Arrays;
import static com.me.asteroids.Constants.rand; import static com.me.asteroids.Constants.rand;
public class EntityFactory { public class EntityFactory {
@ -94,10 +97,10 @@ public class EntityFactory {
return models; return models;
} }
public static Entity[] createPlayerDebris(Engine engine, Entity player) { public static Entity[] createDebris(Engine engine, Entity entity) {
Vector2 playerVelocity = player.getComponent(VelocityComponent.class).velocity; Vector2 playerVelocity = entity.getComponent(VelocityComponent.class).velocity;
PositionComponent playerPosition = player.getComponent(PositionComponent.class); PositionComponent playerPosition = entity.getComponent(PositionComponent.class);
LineModel[] models = getLineModels(player.getComponent(ModelComponent.class).model); LineModel[] models = getLineModels(entity.getComponent(ModelComponent.class).model);
Vector2 explosionCenter = tmp.set(playerPosition.position).sub(Utils.setUnitVectorAngle(tmp2, playerPosition.rotation).scl(5)); Vector2 explosionCenter = tmp.set(playerPosition.position).sub(Utils.setUnitVectorAngle(tmp2, playerPosition.rotation).scl(5));
Entity[] entities = new Entity[models.length]; Entity[] entities = new Entity[models.length];
@ -118,12 +121,12 @@ public class EntityFactory {
.add(tmp2.set(playerVelocity).scl(0.75f)); // Maintain 75% of the player's velocity at impact .add(tmp2.set(playerVelocity).scl(0.75f)); // Maintain 75% of the player's velocity at impact
velocity.angularVelocity = rand.nextFloat(-60, 60); // Make each piece spin at a different rate velocity.angularVelocity = rand.nextFloat(-60, 60); // Make each piece spin at a different rate
Entity entity = createEntity(engine); Entity debris = createEntity(engine);
entity.addComponent(position); debris.addComponent(position);
entity.addComponent(velocity); debris.addComponent(velocity);
entity.addComponent(model); debris.addComponent(model);
entity.addComponent(new DebrisComponent()); debris.addComponent(new DebrisComponent());
entities[i] = entity; entities[i] = debris;
} }
return entities; return entities;
} }
@ -170,11 +173,11 @@ public class EntityFactory {
ModelComponent model = new ModelComponent(); ModelComponent model = new ModelComponent();
model.model = new PolygonModel(Color.WHITE); model.model = new PolygonModel(Color.WHITE);
int size = rand.nextInt(30, 60); int size = rand.nextInt(45, 75);
model.model.setVertices(new AsteroidFactory() model.model.setVertices(new AsteroidFactory()
.setVertexCount(rand.nextInt(16, 24)) .setVertexCount(32)
.setSize(size) .setSize(size)
.setSizeVariation(size * 0.7f) .setSizeVariation(size * 0.5f)
.sizeRelativeToLast() .sizeRelativeToLast()
.generate()); .generate());
@ -186,4 +189,57 @@ public class EntityFactory {
return asteroid; return asteroid;
} }
private static float[] scaleAndRelativizeVertices(Vector2 position, float[] vertices, float scale) {
float[] ret = new float[vertices.length];
for (int j = 0, n = vertices.length; j < n; j += 2) {
ret[j] = (vertices[j] - position.x) * scale;
ret[j + 1] = (vertices[j + 1] - position.y) * scale;
}
return ret;
}
public static Entity[] splitAsteroidIntoChunks(Engine engine, Entity asteroid, int chunkCount, float chunkScale) {
Vector2 asteroidVelocity = asteroid.getComponent(VelocityComponent.class).velocity;
Model asteroidModel = asteroid.getComponent(ModelComponent.class).model;
Vector2 asteroidPosition = asteroidModel.getPosition();
float[] scaledVertices = scaleAndRelativizeVertices(asteroidPosition, asteroidModel.getVertices(), chunkScale);
float angle = rand.nextFloat() * MathUtils.PI2;
float angleStep = MathUtils.PI2 / chunkCount;
Utils.setUnitVectorAngleRad(tmp, angle);
Entity[] entities = new Entity[chunkCount];
for (int i = 0; i < chunkCount; i++) {
Vector2 chunkPosition = tmp2.set(asteroidPosition).add(tmp.scl(25));
ModelComponent model = new ModelComponent();
model.model = new PolygonModel(asteroidModel.getColor());
model.model.setVertices(Arrays.copyOf(scaledVertices, scaledVertices.length));
model.model.setPosition(chunkPosition);
PositionComponent position = new PositionComponent();
position.position = new Vector2(chunkPosition);
position.rotation = 90;
VelocityComponent velocity = new VelocityComponent();
velocity.velocity = new Vector2(tmp).nor().rotate(rand.nextFloat(-45, 45)).scl(asteroidVelocity.len() * 1.10f);
velocity.angularVelocity = rand.nextFloat(-30, 30);
AsteroidComponent asteroidComponent = new AsteroidComponent();
asteroidComponent.generation = asteroid.getComponent(AsteroidComponent.class).generation + 1;
angle += angleStep;
Utils.setUnitVectorAngleRad(tmp, angle);
Entity split = createEntity(engine);
split.addComponent(model);
split.addComponent(position);
split.addComponent(velocity);
split.addComponent(asteroidComponent);
entities[i] = split;
}
return entities;
}
} }

View File

@ -3,5 +3,7 @@ package com.me.asteroids.components;
import com.me.common.ecs.Component; import com.me.common.ecs.Component;
public class AsteroidComponent implements Component { public class AsteroidComponent implements Component {
// TODO: See PlayerComponent's TODO
public int generation;
} }

View File

@ -101,12 +101,14 @@ public class GameScreen extends Screen implements Listener {
ComponentMapper<ModelComponent> modelMapper; ComponentMapper<ModelComponent> modelMapper;
ComponentMapper<BulletComponent> bulletMapper; ComponentMapper<BulletComponent> bulletMapper;
ComponentMapper<DebrisComponent> debrisMapper; ComponentMapper<DebrisComponent> debrisMapper;
ComponentMapper<AsteroidComponent> asteroidMapper;
EventListener(Engine engine) { EventListener(Engine engine) {
this.positionMapper = engine.getComponentMapper(PositionComponent.class); this.positionMapper = engine.getComponentMapper(PositionComponent.class);
this.modelMapper = engine.getComponentMapper(ModelComponent.class); this.modelMapper = engine.getComponentMapper(ModelComponent.class);
this.bulletMapper = engine.getComponentMapper(BulletComponent.class); this.bulletMapper = engine.getComponentMapper(BulletComponent.class);
this.debrisMapper = engine.getComponentMapper(DebrisComponent.class); this.debrisMapper = engine.getComponentMapper(DebrisComponent.class);
this.asteroidMapper = engine.getComponentMapper(AsteroidComponent.class);
} }
@EventHandler @EventHandler
@ -127,7 +129,18 @@ public class GameScreen extends Screen implements Listener {
// AABBs intersect but let's only consider it a hit if the bullet's position // AABBs intersect but let's only consider it a hit if the bullet's position
// is actually inside the asteroid // is actually inside the asteroid
event.getBullet().remove(); event.getBullet().remove();
int generation = asteroidMapper.get(event.getAsteroid()).generation;
if (generation < 2) {
for (Entity shard : EntityFactory.splitAsteroidIntoChunks(engine, event.getAsteroid(), 2, 2/3f)) {
shard.activate();
}
} else {
for (Entity debris : EntityFactory.createDebris(engine, event.getAsteroid())) {
debris.activate();
}
}
event.getAsteroid().remove(); event.getAsteroid().remove();
} }
} }
@ -138,7 +151,7 @@ public class GameScreen extends Screen implements Listener {
if (asteroid.contains(player.getVertices()) || player.contains(asteroid.getVertices())) { if (asteroid.contains(player.getVertices()) || player.contains(asteroid.getVertices())) {
event.getPlayer().deactivate(); event.getPlayer().deactivate();
for (Entity debris : EntityFactory.createPlayerDebris(engine, event.getPlayer())) { for (Entity debris : EntityFactory.createDebris(engine, event.getPlayer())) {
debris.activate(); debris.activate();
} }
} }

View File

@ -64,7 +64,7 @@ public class AsteroidSpawningSystem extends BaseSystem {
model.setPosition(position); model.setPosition(position);
VelocityComponent velocityComponent = velocityMapper.get(asteroid); VelocityComponent velocityComponent = velocityMapper.get(asteroid);
velocityComponent.velocity = new Vector2().setToRandomDirection().scl(rand.nextFloat(125, 175)); velocityComponent.velocity = new Vector2().setToRandomDirection().scl(rand.nextFloat(75, 125));
velocityComponent.angularVelocity = rand.nextFloat(-30, 30); velocityComponent.angularVelocity = rand.nextFloat(-30, 30);
asteroid.activate(); asteroid.activate();
@ -83,7 +83,7 @@ public class AsteroidSpawningSystem extends BaseSystem {
} }
} }
if (asteroidCount++ < 6 && (asteroidSpawnDelay -= dt) <= 0) { if (asteroidCount++ < Constants.ASTEROID_SPAWN_COUNT && (asteroidSpawnDelay -= dt) <= 0) {
spawnAsteroid(); spawnAsteroid();
asteroidSpawnDelay = Constants.ASTEROID_SPAWN_DELAY; asteroidSpawnDelay = Constants.ASTEROID_SPAWN_DELAY;
} }