From 3918f8c1f568a1229a779aa0636809450bceb359 Mon Sep 17 00:00:00 2001 From: Matt Low Date: Tue, 28 Jan 2020 17:58:12 +0400 Subject: [PATCH] Add Model interface to be used for ModelComponent instead of Polygon Allows shapes other than Polygons to be used a Model Add PolygonModel and LineModel implementations --- .../src/com/me/asteroids/AsteroidFactory.java | 5 +- core/src/com/me/asteroids/EntityFactory.java | 22 ++-- core/src/com/me/asteroids/Utils.java | 2 - .../asteroids/components/ModelComponent.java | 7 +- .../asteroids/components/model/LineModel.java | 110 ++++++++++++++++++ .../me/asteroids/components/model/Model.java | 32 +++++ .../components/model/PolygonModel.java | 91 +++++++++++++++ .../com/me/asteroids/screens/GameScreen.java | 6 +- .../systems/AsteroidSpawningSystem.java | 11 +- .../me/asteroids/systems/CollisionSystem.java | 5 +- .../asteroids/systems/ModelRenderSystem.java | 10 +- .../me/asteroids/systems/MovementSystem.java | 7 +- .../asteroids/systems/ScreenWrapSystem.java | 8 +- 13 files changed, 272 insertions(+), 44 deletions(-) create mode 100644 core/src/com/me/asteroids/components/model/LineModel.java create mode 100644 core/src/com/me/asteroids/components/model/Model.java create mode 100644 core/src/com/me/asteroids/components/model/PolygonModel.java diff --git a/core/src/com/me/asteroids/AsteroidFactory.java b/core/src/com/me/asteroids/AsteroidFactory.java index e6473d9..67f3dd3 100644 --- a/core/src/com/me/asteroids/AsteroidFactory.java +++ b/core/src/com/me/asteroids/AsteroidFactory.java @@ -1,7 +1,6 @@ package com.me.asteroids; import com.badlogic.gdx.math.MathUtils; -import com.badlogic.gdx.math.Polygon; import com.badlogic.gdx.math.Vector2; import static com.me.asteroids.Constants.rand; @@ -89,7 +88,7 @@ public final class AsteroidFactory { return size; } - public Polygon generate() { + public float[] generate() { validate(); float angleStep = MathUtils.PI2 / vertexCount; @@ -114,7 +113,7 @@ public final class AsteroidFactory { dir.rotateRad(angleStep); } - return new Polygon(vertices); + return vertices; } } diff --git a/core/src/com/me/asteroids/EntityFactory.java b/core/src/com/me/asteroids/EntityFactory.java index e57f65f..0370706 100644 --- a/core/src/com/me/asteroids/EntityFactory.java +++ b/core/src/com/me/asteroids/EntityFactory.java @@ -1,12 +1,13 @@ package com.me.asteroids; -import com.badlogic.gdx.math.Polygon; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; import com.me.asteroids.components.AccelerationComponent; import com.me.asteroids.components.AsteroidComponent; import com.me.asteroids.components.BulletComponent; import com.me.asteroids.components.ModelComponent; import com.me.asteroids.components.PlayerComponent; +import com.me.asteroids.components.model.PolygonModel; import com.me.asteroids.components.PositionComponent; import com.me.asteroids.components.VelocityComponent; import com.me.common.ecs.Engine; @@ -36,14 +37,15 @@ public class EntityFactory { velocity.maxVelocity = 400f; ModelComponent model = new ModelComponent(); - model.model = new Polygon(new float[] { + model.model = new PolygonModel(Color.WHITE); + model.model.setVertices(new float[] { 0f, 4f, // tip -2.5f, -4f, // bottom left -1f, -2.5f, // indent 1f, -2.5f, // indent 2.5f, -4f, // bottom right }); - model.model.scale(5); + model.model.setScale(5); AccelerationComponent accel = new AccelerationComponent(); accel.acceleration = new Vector2(0,1f); @@ -58,7 +60,7 @@ public class EntityFactory { } public static Entity createBullet(Engine engine, Entity player) { - float[] modelVertices = player.getComponent(ModelComponent.class).model.getTransformedVertices(); + float[] modelVertices = player.getComponent(ModelComponent.class).model.getVertices(); float rotation = player.getComponent(PositionComponent.class).rotation; Vector2 direction = Utils.setUnitVectorAngle(tmp, rotation); @@ -71,14 +73,15 @@ public class EntityFactory { position.rotation = rotation; ModelComponent model = new ModelComponent(); - model.model = new Polygon(new float[] { + model.model = new PolygonModel(Color.YELLOW); + model.model.setVertices(new float[] { 1f, 0f, -1f, 0f, -1f, -4f, 1f, -4f, }); model.model.setRotation(position.rotation); - model.model.setPosition(position.position.x, position.position.y); + model.model.setPosition(position.position); Entity bullet = createEntity(engine); @@ -96,13 +99,14 @@ public class EntityFactory { VelocityComponent velocity = new VelocityComponent(); ModelComponent model = new ModelComponent(); + model.model = new PolygonModel(Color.WHITE); int size = rand.nextInt(30, 60); - model.model = new AsteroidFactory() + model.model.setVertices(new AsteroidFactory() .setVertexCount(rand.nextInt(16, 24)) .setSize(size) .setSizeVariation(size * 0.7f) - .generate(); - model.aabb = model.model.getBoundingRectangle(); + .sizeRelativeToLast() + .generate()); Entity asteroid = createEntity(engine); asteroid.addComponent(position); diff --git a/core/src/com/me/asteroids/Utils.java b/core/src/com/me/asteroids/Utils.java index bbc6576..96b808c 100644 --- a/core/src/com/me/asteroids/Utils.java +++ b/core/src/com/me/asteroids/Utils.java @@ -3,8 +3,6 @@ package com.me.asteroids; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; -import java.lang.Math; - public final class Utils { private static final Vector2 tmp = new Vector2(); diff --git a/core/src/com/me/asteroids/components/ModelComponent.java b/core/src/com/me/asteroids/components/ModelComponent.java index c4cba0e..2284a64 100644 --- a/core/src/com/me/asteroids/components/ModelComponent.java +++ b/core/src/com/me/asteroids/components/ModelComponent.java @@ -1,11 +1,10 @@ package com.me.asteroids.components; -import com.badlogic.gdx.math.Polygon; -import com.badlogic.gdx.math.Rectangle; +import com.me.asteroids.components.model.Model; import com.me.common.ecs.Component; public class ModelComponent implements Component { - public Polygon model; - public Rectangle aabb; + public Model model; + } diff --git a/core/src/com/me/asteroids/components/model/LineModel.java b/core/src/com/me/asteroids/components/model/LineModel.java new file mode 100644 index 0000000..45ebc4d --- /dev/null +++ b/core/src/com/me/asteroids/components/model/LineModel.java @@ -0,0 +1,110 @@ +package com.me.asteroids.components.model; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Polyline; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; + +public class LineModel implements Model { + + private Vector2 tmp = new Vector2(); + + private Color color; + + private Polyline model; + private Rectangle aabb; + + private boolean dirty = true; + + public LineModel(Color color) { + this.color = color; + this.model = new Polyline(); + this.aabb = new Rectangle(); + } + + @Override + public Color getColor() { + return color; + } + + @Override + public void setVertices(float[] vertices) { + model.setVertices(vertices); + } + + @Override + public float[] getVertices() { + return model.getTransformedVertices(); + } + + @Override + public void setPosition(Vector2 position) { + model.setPosition(position.x, position.y); + dirty = true; + } + + @Override + public Vector2 getPosition() { + return tmp.set(model.getX(), model.getY()); + } + + @Override + public void setRotation(float degrees) { + model.setRotation(degrees); + dirty = true; + } + + @Override + public float getRotation() { + return model.getRotation(); + } + + @Override + public void setScale(float scale) { + model.setScale(scale, scale); + dirty = true; + } + + @Override + public float getScale() { + return model.getScaleX(); + } + + @Override + public Rectangle getBoundingBox() { + if (dirty) { + updateBoundingBox(); + dirty = false; + } + return aabb; + } + + @Override + public void render(ShapeRenderer renderer) { + renderer.polyline(getVertices()); + } + + private void updateBoundingBox() { + float[] vertices = getVertices(); + float minX = vertices[0]; + float minY = vertices[1]; + float maxX = vertices[0]; + float maxY = vertices[1]; + + for (int i = 0, n = vertices.length; i < n; i += 2) { + float x = vertices[i]; + float y = vertices[i+1]; + minX = x < minX ? x : minX; + maxX = x > maxX ? x : maxX; + minY = y < minY ? y : minY; + maxY = y > maxY ? y : maxY; + } + + aabb.x = minX; + aabb.y = minY; + aabb.width = maxX - minX; + aabb.height = maxY - minY; + } + +} diff --git a/core/src/com/me/asteroids/components/model/Model.java b/core/src/com/me/asteroids/components/model/Model.java new file mode 100644 index 0000000..79cc006 --- /dev/null +++ b/core/src/com/me/asteroids/components/model/Model.java @@ -0,0 +1,32 @@ +package com.me.asteroids.components.model; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; + +public interface Model { + + Color getColor(); + + void setVertices(float[] vertices); + + float[] getVertices(); + + void setPosition(Vector2 position); + + Vector2 getPosition(); + + void setRotation(float degrees); + + float getRotation(); + + void setScale(float scale); + + float getScale(); + + Rectangle getBoundingBox(); + + void render(ShapeRenderer render); + +} diff --git a/core/src/com/me/asteroids/components/model/PolygonModel.java b/core/src/com/me/asteroids/components/model/PolygonModel.java new file mode 100644 index 0000000..4478228 --- /dev/null +++ b/core/src/com/me/asteroids/components/model/PolygonModel.java @@ -0,0 +1,91 @@ +package com.me.asteroids.components.model; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Polygon; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; + +public class PolygonModel implements Model { + + private Vector2 tmp = new Vector2(); + + private Color color; + + private Polygon model; + private Rectangle aabb; + + private boolean dirty = true; + + public PolygonModel(Color color) { + this.color = color; + this.model = new Polygon(); + } + + @Override + public Color getColor() { + return color; + } + + @Override + public void setVertices(float[] vertices) { + model.setVertices(vertices); + } + + @Override + public float[] getVertices() { + return model.getTransformedVertices(); + } + + @Override + public void setPosition(Vector2 position) { + model.setPosition(position.x, position.y); + dirty = true; + } + + @Override + public Vector2 getPosition() { + return tmp.set(model.getX(), model.getY()); + } + + @Override + public void setRotation(float degrees) { + model.setRotation(degrees); + dirty = true; + } + + @Override + public float getRotation() { + return model.getRotation(); + } + + @Override + public void setScale(float scale) { + model.setScale(scale, scale); + dirty = true; + } + + @Override + public float getScale() { + return model.getScaleX(); + } + + @Override + public Rectangle getBoundingBox() { + if (dirty) { + aabb = model.getBoundingRectangle(); + dirty = false; + } + return aabb; + } + + @Override + public void render(ShapeRenderer renderer) { + renderer.polygon(getVertices()); + } + + public boolean contains(Vector2 point) { + return model.contains(point); + } + +} diff --git a/core/src/com/me/asteroids/screens/GameScreen.java b/core/src/com/me/asteroids/screens/GameScreen.java index 260edcd..0fdeeef 100644 --- a/core/src/com/me/asteroids/screens/GameScreen.java +++ b/core/src/com/me/asteroids/screens/GameScreen.java @@ -4,7 +4,6 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.math.Polygon; import com.badlogic.gdx.math.Vector2; import com.me.asteroids.Constants; import com.me.asteroids.EntityFactory; @@ -14,6 +13,7 @@ import com.me.asteroids.components.AsteroidComponent; import com.me.asteroids.components.BulletComponent; import com.me.asteroids.components.ModelComponent; import com.me.asteroids.components.PlayerComponent; +import com.me.asteroids.components.model.PolygonModel; import com.me.asteroids.components.PositionComponent; import com.me.asteroids.components.VelocityComponent; import com.me.asteroids.events.BulletAsteroidCollisionEvent; @@ -116,9 +116,9 @@ public class GameScreen extends Screen implements Listener { @EventHandler public void onBulletAsteroidCollision(BulletAsteroidCollisionEvent event) { Vector2 bulletPosition = positionMapper.get(event.getBullet()).position; - Polygon asteroidModel = modelMapper.get(event.getAsteroid()).model; - if (asteroidModel.contains(bulletPosition)) { + PolygonModel model = (PolygonModel) modelMapper.get(event.getAsteroid()).model; + if (model.contains(bulletPosition)) { // AABBs intersect but let's only consider it a hit if the bullet's position // is actually inside the asteroid event.getBullet().remove(); diff --git a/core/src/com/me/asteroids/systems/AsteroidSpawningSystem.java b/core/src/com/me/asteroids/systems/AsteroidSpawningSystem.java index 3be963c..98f0ba1 100644 --- a/core/src/com/me/asteroids/systems/AsteroidSpawningSystem.java +++ b/core/src/com/me/asteroids/systems/AsteroidSpawningSystem.java @@ -1,11 +1,13 @@ package com.me.asteroids.systems; +import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; import com.me.asteroids.Constants; import com.me.asteroids.EntityFactory; import com.me.asteroids.Utils; import com.me.asteroids.components.AsteroidComponent; +import com.me.asteroids.components.model.Model; import com.me.asteroids.components.ModelComponent; import com.me.asteroids.components.PositionComponent; import com.me.asteroids.components.VelocityComponent; @@ -53,12 +55,13 @@ public class AsteroidSpawningSystem extends BaseSystem { private void spawnAsteroid() { Entity asteroid = EntityFactory.createAsteroid(engine); - ModelComponent model = modelMapper.get(asteroid); + Model model = modelMapper.get(asteroid).model; + Rectangle aabb = model.getBoundingBox(); + Vector2 position = positionMapper.get(asteroid).position - = getRandomSpawnLocation(model.aabb.getWidth(), model.aabb.getHeight()); - model.model.setPosition(position.x, position.y); - model.aabb = model.model.getBoundingRectangle(); + = getRandomSpawnLocation(aabb.getWidth(), aabb.getHeight()); + model.setPosition(position); VelocityComponent velocityComponent = velocityMapper.get(asteroid); velocityComponent.velocity = new Vector2().setToRandomDirection().scl(rand.nextFloat(125, 175)); diff --git a/core/src/com/me/asteroids/systems/CollisionSystem.java b/core/src/com/me/asteroids/systems/CollisionSystem.java index d181c22..dc37c04 100644 --- a/core/src/com/me/asteroids/systems/CollisionSystem.java +++ b/core/src/com/me/asteroids/systems/CollisionSystem.java @@ -3,7 +3,6 @@ package com.me.asteroids.systems; import com.badlogic.gdx.math.Rectangle; import com.me.asteroids.EventFactory; import com.me.asteroids.components.ModelComponent; -import com.me.asteroids.events.CollisionEvent; import com.me.common.ecs.ComponentMapper; import com.me.common.ecs.Engine; import com.me.common.ecs.Entity; @@ -23,12 +22,12 @@ public class CollisionSystem extends EntitySystem { Entity[] entities = getEntities().items; for (int i = 0, n = getEntities().size; i < n-1; i++) { Entity entityA = entities[i]; - Rectangle aabbA = modelMapper.get(entityA).aabb; + Rectangle aabbA = modelMapper.get(entityA).model.getBoundingBox(); for (int j = i + 1; j < n; j++) { Entity entityB = entities[j]; - Rectangle aabbB = modelMapper.get(entityB).aabb; + Rectangle aabbB = modelMapper.get(entityB).model.getBoundingBox(); if (aabbA.overlaps(aabbB)) { engine.callEvent(EventFactory.getNewCollisionEvent(entityA, entityB)); } diff --git a/core/src/com/me/asteroids/systems/ModelRenderSystem.java b/core/src/com/me/asteroids/systems/ModelRenderSystem.java index 587c875..fb28fc3 100644 --- a/core/src/com/me/asteroids/systems/ModelRenderSystem.java +++ b/core/src/com/me/asteroids/systems/ModelRenderSystem.java @@ -1,9 +1,8 @@ package com.me.asteroids.systems; -import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; -import com.badlogic.gdx.math.Polygon; import com.me.asteroids.Graphics; +import com.me.asteroids.components.model.Model; import com.me.asteroids.components.ModelComponent; import com.me.common.ecs.ComponentMapper; import com.me.common.ecs.Engine; @@ -24,16 +23,15 @@ public class ModelRenderSystem extends EntitySystem { @Override public void preProcess() { - renderer.setColor(Color.WHITE); renderer.begin(ShapeRenderer.ShapeType.Line); } @Override public void processEntity(Entity entity, float dt) { - ModelComponent modelComponent = modelMapper.get(entity); + Model model = modelMapper.get(entity).model; - Polygon model = modelComponent.model; - renderer.polygon(model.getTransformedVertices()); + renderer.setColor(model.getColor()); + model.render(renderer); } @Override diff --git a/core/src/com/me/asteroids/systems/MovementSystem.java b/core/src/com/me/asteroids/systems/MovementSystem.java index 40d7a26..ea64986 100644 --- a/core/src/com/me/asteroids/systems/MovementSystem.java +++ b/core/src/com/me/asteroids/systems/MovementSystem.java @@ -1,8 +1,8 @@ package com.me.asteroids.systems; -import com.badlogic.gdx.math.Polygon; import com.badlogic.gdx.math.Vector2; import com.me.asteroids.components.AccelerationComponent; +import com.me.asteroids.components.model.Model; import com.me.asteroids.components.ModelComponent; import com.me.asteroids.components.PositionComponent; import com.me.asteroids.components.VelocityComponent; @@ -50,10 +50,9 @@ public class MovementSystem extends EntitySystem { ModelComponent modelComponent = modelMapper.get(entity); if (modelComponent != null) { - Polygon model = modelComponent.model; - model.setPosition(position.x, position.y); + Model model = modelComponent.model; + model.setPosition(position); model.setRotation(positionComponent.rotation - 90); - modelComponent.aabb = model.getBoundingRectangle(); } } diff --git a/core/src/com/me/asteroids/systems/ScreenWrapSystem.java b/core/src/com/me/asteroids/systems/ScreenWrapSystem.java index bf5b079..eeebb99 100644 --- a/core/src/com/me/asteroids/systems/ScreenWrapSystem.java +++ b/core/src/com/me/asteroids/systems/ScreenWrapSystem.java @@ -33,11 +33,8 @@ public class ScreenWrapSystem extends EntitySystem { @Override public void processEntity(Entity entity, float dt) { - PositionComponent positionComponent = positionMapper.get(entity); - ModelComponent modelComponent = modelMapper.get(entity); - - Vector2 position = positionComponent.position; - Rectangle aabb = modelComponent.aabb; + Vector2 position = positionMapper.get(entity).position; + Rectangle aabb = modelMapper.get(entity).model.getBoundingBox(); // Check top/bottom edges float minY = aabb.y; @@ -57,7 +54,6 @@ public class ScreenWrapSystem extends EntitySystem { updatePosition(entity, position, Constants.WIDTH + (position.x - minX) + maxX, position.y); } else if (minX > Constants.WIDTH) { updatePosition(entity, position, (position.x - maxX) + (minX - Constants.WIDTH), position.y); - } }