add fixture def creation logic
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.11.1-99-gec89c545" orientation="orthogonal" renderorder="right-down" width="18" height="16" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="2">
|
||||
<map version="1.10" tiledversion="1.11.1-99-gec89c545" orientation="orthogonal" renderorder="right-down" width="18" height="16" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="3">
|
||||
<tileset firstgid="1" source="tileset.tsx"/>
|
||||
<tileset firstgid="99" source="objects.tsx"/>
|
||||
<layer id="1" name="ground" width="18" height="16">
|
||||
@@ -24,5 +24,6 @@
|
||||
</layer>
|
||||
<objectgroup id="5" name="objects">
|
||||
<object id="1" gid="99" x="50.0586" y="458.934" width="32" height="32"/>
|
||||
<object id="2" gid="99" x="112.269" y="470.818" width="64" height="64"/>
|
||||
</objectgroup>
|
||||
</map>
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.badlogic.gdx.physics.box2d.World;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import io.github.com.quillraven.GdxGame;
|
||||
import io.github.com.quillraven.asset.MapAsset;
|
||||
import io.github.com.quillraven.system.PhysicDebugRenderSystem;
|
||||
import io.github.com.quillraven.system.RenderSystem;
|
||||
import io.github.com.quillraven.system.TiledServiceTestSystem;
|
||||
import io.github.com.quillraven.tiled.TiledAshleySpawner;
|
||||
@@ -32,6 +33,7 @@ public class GameScreen extends ScreenAdapter {
|
||||
// add ECS systems
|
||||
this.engine.addSystem(new RenderSystem(game.getBatch(), game.getViewport(), game.getCamera()));
|
||||
this.engine.addSystem(new TiledServiceTestSystem(this.tiledService));
|
||||
this.engine.addSystem(new PhysicDebugRenderSystem(this.physicWorld, game.getCamera()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package io.github.com.quillraven.system;
|
||||
|
||||
import com.badlogic.ashley.core.EntitySystem;
|
||||
import com.badlogic.gdx.graphics.Camera;
|
||||
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
|
||||
import com.badlogic.gdx.physics.box2d.World;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
public class PhysicDebugRenderSystem extends EntitySystem implements Disposable {
|
||||
private final World physicWorld;
|
||||
private final Box2DDebugRenderer box2DDebugRenderer;
|
||||
private final Camera camera;
|
||||
|
||||
public PhysicDebugRenderSystem(World physicWorld, Camera camera) {
|
||||
this.box2DDebugRenderer = new Box2DDebugRenderer();
|
||||
this.physicWorld = physicWorld;
|
||||
this.camera = camera;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float deltaTime) {
|
||||
this.box2DDebugRenderer.render(physicWorld, camera.combined);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
this.box2DDebugRenderer.dispose();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package io.github.com.quillraven.system;
|
||||
import com.badlogic.ashley.core.EntitySystem;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.maps.tiled.TiledMap;
|
||||
import io.github.com.quillraven.asset.MapAsset;
|
||||
import io.github.com.quillraven.tiled.TiledService;
|
||||
|
||||
@@ -18,11 +19,11 @@ public class TiledServiceTestSystem extends EntitySystem {
|
||||
public void update(float deltaTime) {
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.X)) {
|
||||
Gdx.app.debug("TiledServiceTestSystem", "Setting map to MAIN");
|
||||
var tiledMap = tiledService.loadMap(MapAsset.MAIN);
|
||||
TiledMap tiledMap = tiledService.loadMap(MapAsset.MAIN);
|
||||
tiledService.setMap(tiledMap);
|
||||
} else if (Gdx.input.isKeyJustPressed(Input.Keys.C)) {
|
||||
Gdx.app.debug("TiledServiceTestSystem", "Setting map to SECOND");
|
||||
var tiledMap = tiledService.loadMap(MapAsset.SECOND);
|
||||
TiledMap tiledMap = tiledService.loadMap(MapAsset.SECOND);
|
||||
tiledService.setMap(tiledMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.physics.box2d.Body;
|
||||
import com.badlogic.gdx.physics.box2d.BodyDef;
|
||||
import com.badlogic.gdx.physics.box2d.FixtureDef;
|
||||
import com.badlogic.gdx.physics.box2d.World;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
import io.github.com.quillraven.GdxGame;
|
||||
@@ -71,8 +72,11 @@ public class TiledAshleySpawner {
|
||||
bodyDef.fixedRotation = true;
|
||||
|
||||
Body body = this.physicWorld.createBody(bodyDef);
|
||||
body.setUserData(entity);
|
||||
for (MapObject object : objects) {
|
||||
|
||||
FixtureDef fixtureDef = TiledPhysics.toFixtureDef(object);
|
||||
body.createFixture(fixtureDef);
|
||||
fixtureDef.shape.dispose();
|
||||
}
|
||||
|
||||
entity.add(new Physic(body, new Vector2(body.getPosition())));
|
||||
|
||||
@@ -1,6 +1,163 @@
|
||||
package io.github.com.quillraven.tiled;
|
||||
|
||||
import com.badlogic.gdx.physics.box2d.World;
|
||||
import com.badlogic.gdx.maps.MapObject;
|
||||
import com.badlogic.gdx.maps.objects.EllipseMapObject;
|
||||
import com.badlogic.gdx.maps.objects.PolygonMapObject;
|
||||
import com.badlogic.gdx.maps.objects.PolylineMapObject;
|
||||
import com.badlogic.gdx.maps.objects.RectangleMapObject;
|
||||
import com.badlogic.gdx.maps.tiled.TiledMapTile;
|
||||
import com.badlogic.gdx.math.Ellipse;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.physics.box2d.ChainShape;
|
||||
import com.badlogic.gdx.physics.box2d.CircleShape;
|
||||
import com.badlogic.gdx.physics.box2d.FixtureDef;
|
||||
import com.badlogic.gdx.physics.box2d.PolygonShape;
|
||||
import com.badlogic.gdx.physics.box2d.Shape;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
import io.github.com.quillraven.GdxGame;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class TiledPhysics {
|
||||
|
||||
public static List<FixtureDef> toFixtureDefs(TiledMapTile tiledMapTile) {
|
||||
List<FixtureDef> result = new ArrayList<>();
|
||||
for (MapObject mapObject : tiledMapTile.getObjects()) {
|
||||
result.add(toFixtureDef(mapObject));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// relativeTo is necessary for map objects that are directly placed on a layer because
|
||||
// their x/y is equal to the position of the object, but we need it relative to 0,0 like it
|
||||
// is in the collision editor of a tile.
|
||||
public static FixtureDef toFixtureDef(MapObject mapObject, Vector2 relativeTo) {
|
||||
if (mapObject instanceof RectangleMapObject rectMapObj) {
|
||||
return rectangleFixtureDef(rectMapObj, relativeTo);
|
||||
} else if (mapObject instanceof EllipseMapObject ellipseMapObj) {
|
||||
return ellipseFixtureDef(ellipseMapObj, relativeTo);
|
||||
} else if (mapObject instanceof PolygonMapObject polygonMapObj) {
|
||||
return polygonFixtureDef(polygonMapObj, polygonMapObj.getPolygon().getVertices(), relativeTo);
|
||||
} else if (mapObject instanceof PolylineMapObject polylineMapObj) {
|
||||
return polygonFixtureDef(polylineMapObj, polylineMapObj.getPolyline().getVertices(), relativeTo);
|
||||
} else {
|
||||
throw new GdxRuntimeException("Unsupported MapObject: " + mapObject);
|
||||
}
|
||||
}
|
||||
|
||||
public static FixtureDef toFixtureDef(MapObject mapObject) {
|
||||
return toFixtureDef(mapObject, Vector2.Zero);
|
||||
}
|
||||
|
||||
// Box is centered around body position in Box2D, but we want to have it aligned in a way
|
||||
// that the body position is the bottom left corner of the box.
|
||||
// That's why we use a 'boxOffset' below.
|
||||
private static FixtureDef rectangleFixtureDef(RectangleMapObject mapObject, Vector2 relativeTo) {
|
||||
Rectangle rectangle = mapObject.getRectangle();
|
||||
float rectX = rectangle.x;
|
||||
float rectY = rectangle.y;
|
||||
float rectW = rectangle.width;
|
||||
float rectH = rectangle.height;
|
||||
|
||||
float boxX = rectX * GdxGame.UNIT_SCALE - relativeTo.x;
|
||||
float boxY = rectY * GdxGame.UNIT_SCALE - relativeTo.y;
|
||||
float boxW = rectW * GdxGame.UNIT_SCALE * 0.5f;
|
||||
float boxH = rectH * GdxGame.UNIT_SCALE * 0.5f;
|
||||
|
||||
FixtureDef fixtureDef = new FixtureDef();
|
||||
PolygonShape shape = new PolygonShape();
|
||||
shape.setAsBox(boxW, boxH, new Vector2(boxX + boxW, boxY + boxH), 0f);
|
||||
initFixtureDef(mapObject, fixtureDef, shape);
|
||||
|
||||
return fixtureDef;
|
||||
}
|
||||
|
||||
private static FixtureDef ellipseFixtureDef(EllipseMapObject mapObject, Vector2 relativeTo) {
|
||||
Ellipse ellipse = mapObject.getEllipse();
|
||||
float x = ellipse.x;
|
||||
float y = ellipse.y;
|
||||
float w = ellipse.width;
|
||||
float h = ellipse.height;
|
||||
|
||||
float ellipseX = x * GdxGame.UNIT_SCALE - relativeTo.x;
|
||||
float ellipseY = y * GdxGame.UNIT_SCALE - relativeTo.y;
|
||||
float ellipseW = w * GdxGame.UNIT_SCALE / 2f;
|
||||
float ellipseH = h * GdxGame.UNIT_SCALE / 2f;
|
||||
|
||||
FixtureDef fixtureDef = new FixtureDef();
|
||||
if (MathUtils.isEqual(ellipseW, ellipseH, 0.1f)) {
|
||||
// width and height are equal -> return a circle shape
|
||||
CircleShape shape = new CircleShape();
|
||||
shape.setPosition(new Vector2(ellipseX + ellipseW, ellipseY + ellipseH));
|
||||
shape.setRadius(ellipseW);
|
||||
initFixtureDef(mapObject, fixtureDef, shape);
|
||||
} else {
|
||||
// width and height are not equal -> return an ellipse shape (=polygon with 'numVertices' vertices)
|
||||
// PolygonShape only supports 8 vertices
|
||||
// ChainShape supports more but does not properly collide in some scenarios
|
||||
final int numVertices = 8;
|
||||
float angleStep = MathUtils.PI2 / numVertices;
|
||||
Vector2[] vertices = new Vector2[numVertices];
|
||||
|
||||
for (int vertexIdx = 0; vertexIdx < numVertices; vertexIdx++) {
|
||||
float angle = vertexIdx * angleStep;
|
||||
float offsetX = ellipseW * MathUtils.cos(angle);
|
||||
float offsetY = ellipseH * MathUtils.sin(angle);
|
||||
vertices[vertexIdx] = new Vector2(ellipseX + ellipseW + offsetX, ellipseY + ellipseH + offsetY);
|
||||
}
|
||||
|
||||
PolygonShape shape = new PolygonShape();
|
||||
shape.set(vertices);
|
||||
initFixtureDef(mapObject, fixtureDef, shape);
|
||||
}
|
||||
|
||||
return fixtureDef;
|
||||
}
|
||||
|
||||
private static FixtureDef polygonFixtureDef(
|
||||
MapObject mapObject, // Could be PolygonMapObject or PolylineMapObject
|
||||
float[] polyVertices,
|
||||
Vector2 relativeTo
|
||||
) {
|
||||
final float offsetX;
|
||||
final float offsetY;
|
||||
if (mapObject instanceof PolygonMapObject polygonMapObject) {
|
||||
offsetX = polygonMapObject.getPolygon().getX() * GdxGame.UNIT_SCALE - relativeTo.x;
|
||||
offsetY = polygonMapObject.getPolygon().getY() * GdxGame.UNIT_SCALE - relativeTo.y;
|
||||
} else {
|
||||
PolylineMapObject polylineMapObject = (PolylineMapObject) mapObject;
|
||||
offsetX = polylineMapObject.getPolyline().getX() * GdxGame.UNIT_SCALE - relativeTo.x;
|
||||
offsetY = polylineMapObject.getPolyline().getY() * GdxGame.UNIT_SCALE - relativeTo.y;
|
||||
}
|
||||
float[] vertices = new float[polyVertices.length];
|
||||
for (int vertexIdx = 0; vertexIdx < polyVertices.length; vertexIdx += 2) {
|
||||
// x-coordinate
|
||||
vertices[vertexIdx] = offsetX + polyVertices[vertexIdx] * GdxGame.UNIT_SCALE;
|
||||
// y-coordinate
|
||||
vertices[vertexIdx + 1] = offsetY + polyVertices[vertexIdx + 1] * GdxGame.UNIT_SCALE;
|
||||
}
|
||||
|
||||
FixtureDef fixtureDef = new FixtureDef();
|
||||
ChainShape shape = new ChainShape();
|
||||
|
||||
if (mapObject instanceof PolygonMapObject) {
|
||||
shape.createLoop(vertices);
|
||||
} else { // PolylineMapObject
|
||||
shape.createChain(vertices);
|
||||
}
|
||||
initFixtureDef(mapObject, fixtureDef, shape);
|
||||
|
||||
return fixtureDef;
|
||||
}
|
||||
|
||||
private static void initFixtureDef(MapObject mapObject, FixtureDef fixtureDef, Shape shape) {
|
||||
fixtureDef.shape = shape;
|
||||
fixtureDef.friction = mapObject.getProperties().get("friction", 0f, Float.class);
|
||||
fixtureDef.restitution = mapObject.getProperties().get("restitution", 0f, Float.class);
|
||||
fixtureDef.density = mapObject.getProperties().get("density", 0f, Float.class);
|
||||
fixtureDef.isSensor = mapObject.getProperties().get("sensor", false, Boolean.class);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user