add fixture def creation logic
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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="1" source="tileset.tsx"/>
|
||||||
<tileset firstgid="99" source="objects.tsx"/>
|
<tileset firstgid="99" source="objects.tsx"/>
|
||||||
<layer id="1" name="ground" width="18" height="16">
|
<layer id="1" name="ground" width="18" height="16">
|
||||||
@@ -24,5 +24,6 @@
|
|||||||
</layer>
|
</layer>
|
||||||
<objectgroup id="5" name="objects">
|
<objectgroup id="5" name="objects">
|
||||||
<object id="1" gid="99" x="50.0586" y="458.934" width="32" height="32"/>
|
<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>
|
</objectgroup>
|
||||||
</map>
|
</map>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.badlogic.gdx.physics.box2d.World;
|
|||||||
import com.badlogic.gdx.utils.Disposable;
|
import com.badlogic.gdx.utils.Disposable;
|
||||||
import io.github.com.quillraven.GdxGame;
|
import io.github.com.quillraven.GdxGame;
|
||||||
import io.github.com.quillraven.asset.MapAsset;
|
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.RenderSystem;
|
||||||
import io.github.com.quillraven.system.TiledServiceTestSystem;
|
import io.github.com.quillraven.system.TiledServiceTestSystem;
|
||||||
import io.github.com.quillraven.tiled.TiledAshleySpawner;
|
import io.github.com.quillraven.tiled.TiledAshleySpawner;
|
||||||
@@ -32,6 +33,7 @@ public class GameScreen extends ScreenAdapter {
|
|||||||
// add ECS systems
|
// add ECS systems
|
||||||
this.engine.addSystem(new RenderSystem(game.getBatch(), game.getViewport(), game.getCamera()));
|
this.engine.addSystem(new RenderSystem(game.getBatch(), game.getViewport(), game.getCamera()));
|
||||||
this.engine.addSystem(new TiledServiceTestSystem(this.tiledService));
|
this.engine.addSystem(new TiledServiceTestSystem(this.tiledService));
|
||||||
|
this.engine.addSystem(new PhysicDebugRenderSystem(this.physicWorld, game.getCamera()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.ashley.core.EntitySystem;
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.Input;
|
import com.badlogic.gdx.Input;
|
||||||
|
import com.badlogic.gdx.maps.tiled.TiledMap;
|
||||||
import io.github.com.quillraven.asset.MapAsset;
|
import io.github.com.quillraven.asset.MapAsset;
|
||||||
import io.github.com.quillraven.tiled.TiledService;
|
import io.github.com.quillraven.tiled.TiledService;
|
||||||
|
|
||||||
@@ -18,11 +19,11 @@ public class TiledServiceTestSystem extends EntitySystem {
|
|||||||
public void update(float deltaTime) {
|
public void update(float deltaTime) {
|
||||||
if (Gdx.input.isKeyJustPressed(Input.Keys.X)) {
|
if (Gdx.input.isKeyJustPressed(Input.Keys.X)) {
|
||||||
Gdx.app.debug("TiledServiceTestSystem", "Setting map to MAIN");
|
Gdx.app.debug("TiledServiceTestSystem", "Setting map to MAIN");
|
||||||
var tiledMap = tiledService.loadMap(MapAsset.MAIN);
|
TiledMap tiledMap = tiledService.loadMap(MapAsset.MAIN);
|
||||||
tiledService.setMap(tiledMap);
|
tiledService.setMap(tiledMap);
|
||||||
} else if (Gdx.input.isKeyJustPressed(Input.Keys.C)) {
|
} else if (Gdx.input.isKeyJustPressed(Input.Keys.C)) {
|
||||||
Gdx.app.debug("TiledServiceTestSystem", "Setting map to SECOND");
|
Gdx.app.debug("TiledServiceTestSystem", "Setting map to SECOND");
|
||||||
var tiledMap = tiledService.loadMap(MapAsset.SECOND);
|
TiledMap tiledMap = tiledService.loadMap(MapAsset.SECOND);
|
||||||
tiledService.setMap(tiledMap);
|
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.math.Vector2;
|
||||||
import com.badlogic.gdx.physics.box2d.Body;
|
import com.badlogic.gdx.physics.box2d.Body;
|
||||||
import com.badlogic.gdx.physics.box2d.BodyDef;
|
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.physics.box2d.World;
|
||||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||||
import io.github.com.quillraven.GdxGame;
|
import io.github.com.quillraven.GdxGame;
|
||||||
@@ -71,8 +72,11 @@ public class TiledAshleySpawner {
|
|||||||
bodyDef.fixedRotation = true;
|
bodyDef.fixedRotation = true;
|
||||||
|
|
||||||
Body body = this.physicWorld.createBody(bodyDef);
|
Body body = this.physicWorld.createBody(bodyDef);
|
||||||
|
body.setUserData(entity);
|
||||||
for (MapObject object : objects) {
|
for (MapObject object : objects) {
|
||||||
|
FixtureDef fixtureDef = TiledPhysics.toFixtureDef(object);
|
||||||
|
body.createFixture(fixtureDef);
|
||||||
|
fixtureDef.shape.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.add(new Physic(body, new Vector2(body.getPosition())));
|
entity.add(new Physic(body, new Vector2(body.getPosition())));
|
||||||
|
|||||||
@@ -1,6 +1,163 @@
|
|||||||
package io.github.com.quillraven.tiled;
|
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 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