add animated water ripple tile and a trap trigger

This commit is contained in:
Quillraven
2025-06-01 21:46:14 +02:00
parent d5cd88a245
commit 7cf6dbe9e4
28 changed files with 445 additions and 167 deletions

View File

@@ -3,6 +3,7 @@ package io.github.com.quillraven.asset;
public enum SoundAsset {
SWORD_HIT("sword_hit.wav"),
LIFE_REG("life_reg.wav"),
TRAP("trap.wav"),
;
private final String path;

View File

@@ -68,10 +68,6 @@ public class Animation2D implements Component {
return playMode;
}
public float getSpeed() {
return speed;
}
public void setSpeed(float speed) {
this.speed = speed;
}

View File

@@ -0,0 +1,25 @@
package io.github.com.quillraven.component;
import com.badlogic.ashley.core.Component;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.gdx.maps.MapObject;
public class Tiled implements Component {
public static final ComponentMapper<Tiled> MAPPER = ComponentMapper.getFor(Tiled.class);
private final int id;
private final MapObject mapObjectRef;
public Tiled(MapObject mapObjectRef) {
this.id = mapObjectRef.getProperties().get("id", -1, Integer.class);
this.mapObjectRef = mapObjectRef;
}
public int getId() {
return id;
}
public MapObject getMapObjectRef() {
return mapObjectRef;
}
}

View File

@@ -0,0 +1,29 @@
package io.github.com.quillraven.component;
import com.badlogic.ashley.core.Component;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.ashley.core.Entity;
public class Trigger implements Component {
public static final ComponentMapper<Trigger> MAPPER = ComponentMapper.getFor(Trigger.class);
private final String name;
private Entity triggeringEntity;
public Trigger(String name) {
this.name = name;
this.triggeringEntity = null;
}
public String getName() {
return name;
}
public void setTriggeringEntity(Entity triggeringEntity) {
this.triggeringEntity = triggeringEntity;
}
public Entity getTriggeringEntity() {
return triggeringEntity;
}
}

View File

@@ -4,8 +4,4 @@ public class IdleControllerState implements ControllerState {
@Override
public void keyDown(Command command) {
}
@Override
public void keyUp(Command command) {
}
}

View File

@@ -28,7 +28,8 @@ import io.github.com.quillraven.system.PhysicDebugRenderSystem;
import io.github.com.quillraven.system.PhysicMoveSystem;
import io.github.com.quillraven.system.PhysicSystem;
import io.github.com.quillraven.system.RenderSystem;
import io.github.com.quillraven.tiled.TiledAshleySpawner;
import io.github.com.quillraven.system.TriggerSystem;
import io.github.com.quillraven.tiled.TiledAshleyConfigurator;
import io.github.com.quillraven.tiled.TiledService;
import io.github.com.quillraven.ui.model.GameViewModel;
import io.github.com.quillraven.ui.view.GameView;
@@ -43,7 +44,7 @@ public class GameScreen extends ScreenAdapter {
private final Viewport uiViewport;
private final TiledService tiledService;
private final Engine engine;
private final TiledAshleySpawner tiledAshleySpawner;
private final TiledAshleyConfigurator tiledAshleyConfigurator;
private final World physicWorld;
private final KeyboardController keyboardController;
private final AudioService audioService;
@@ -55,11 +56,11 @@ public class GameScreen extends ScreenAdapter {
this.skin = game.getAssetService().get(SkinAsset.DEFAULT);
this.viewModel = new GameViewModel(game);
this.audioService = game.getAudioService();
this.tiledService = new TiledService(game.getAssetService());
this.physicWorld = new World(Vector2.Zero, true);
this.physicWorld.setAutoClearForces(false);
this.tiledService = new TiledService(game.getAssetService(), this.physicWorld);
this.engine = new Engine();
this.tiledAshleySpawner = new TiledAshleySpawner(this.engine, this.physicWorld, this.game.getAssetService());
this.tiledAshleyConfigurator = new TiledAshleyConfigurator(this.engine, this.physicWorld, this.game.getAssetService());
this.keyboardController = new KeyboardController(GameControllerState.class, engine, null);
// add ECS systems
@@ -67,6 +68,7 @@ public class GameScreen extends ScreenAdapter {
this.engine.addSystem(new PhysicSystem(physicWorld, 1 / 60f));
this.engine.addSystem(new FacingSystem());
this.engine.addSystem(new FsmSystem());
this.engine.addSystem(new TriggerSystem(audioService));
this.engine.addSystem(new LifeSystem(this.viewModel));
this.engine.addSystem(new AnimationSystem(game.getAssetService()));
this.engine.addSystem(new CameraSystem(game.getCamera()));
@@ -83,12 +85,12 @@ public class GameScreen extends ScreenAdapter {
this.stage.addActor(new GameView(stage, skin, this.viewModel));
Consumer<TiledMap> renderConsumer = this.engine.getSystem(RenderSystem.class)::setMap;
Consumer<TiledMap> ashleySpawnerConsumer = this.tiledAshleySpawner::loadMapObjects;
Consumer<TiledMap> cameraConsumer = this.engine.getSystem(CameraSystem.class)::setMap;
Consumer<TiledMap> audioConsumer = this.audioService::setMap;
this.tiledService.setMapChangeConsumer(
renderConsumer.andThen(ashleySpawnerConsumer).andThen(cameraConsumer).andThen(audioConsumer)
);
this.tiledService.setMapChangeConsumer(renderConsumer.andThen(cameraConsumer).andThen(audioConsumer));
this.tiledService.setLoadTriggerConsumer(tiledAshleyConfigurator::onLoadTrigger);
this.tiledService.setLoadObjectConsumer(tiledAshleyConfigurator::onLoadObject);
this.tiledService.setLoadTileConsumer(tiledAshleyConfigurator::onLoadTile);
TiledMap startMap = this.tiledService.loadMap(MapAsset.MAIN);
this.tiledService.setMap(startMap);

View File

@@ -7,11 +7,17 @@ import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.systems.IteratingSystem;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.badlogic.gdx.physics.box2d.World;
import io.github.com.quillraven.component.Physic;
import io.github.com.quillraven.component.Player;
import io.github.com.quillraven.component.Transform;
import io.github.com.quillraven.component.Trigger;
public class PhysicSystem extends IteratingSystem implements EntityListener {
public class PhysicSystem extends IteratingSystem implements EntityListener, ContactListener {
private final World world;
private final float interval;
@@ -22,6 +28,7 @@ public class PhysicSystem extends IteratingSystem implements EntityListener {
this.world = world;
this.interval = interval;
this.accumulator = 0f;
world.setContactListener(this);
}
@Override
@@ -86,4 +93,42 @@ public class PhysicSystem extends IteratingSystem implements EntityListener {
}
}
@Override
public void beginContact(Contact contact) {
Object userDataA = contact.getFixtureA().getBody().getUserData();
Object userDataB = contact.getFixtureB().getBody().getUserData();
if (!(userDataA instanceof Entity entityA) || !(userDataB instanceof Entity entityB)) {
return;
}
playerTriggerContact(entityA, entityB);
}
private static void playerTriggerContact(Entity entityA, Entity entityB) {
Trigger trigger = Trigger.MAPPER.get(entityA);
boolean isPlayer = Player.MAPPER.get(entityB) != null;
if (trigger != null && isPlayer) {
trigger.setTriggeringEntity(entityB);
return;
}
trigger = Trigger.MAPPER.get(entityB);
isPlayer = Player.MAPPER.get(entityA) != null;
if (trigger != null && isPlayer) {
trigger.setTriggeringEntity(entityA);
}
}
@Override
public void endContact(Contact contact) {
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
}

View File

@@ -0,0 +1,75 @@
package io.github.com.quillraven.system;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.systems.IteratingSystem;
import com.badlogic.ashley.utils.ImmutableArray;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.Timer;
import io.github.com.quillraven.asset.SoundAsset;
import io.github.com.quillraven.audio.AudioService;
import io.github.com.quillraven.component.Animation2D;
import io.github.com.quillraven.component.Life;
import io.github.com.quillraven.component.Tiled;
import io.github.com.quillraven.component.Trigger;
public class TriggerSystem extends IteratingSystem {
private final AudioService audioService;
public TriggerSystem(AudioService audioService) {
super(Family.all(Trigger.class).get());
this.audioService = audioService;
}
@Override
protected void processEntity(Entity entity, float deltaTime) {
Trigger trigger = Trigger.MAPPER.get(entity);
if (trigger.getTriggeringEntity() == null) return;
fireTrigger(trigger.getName(), trigger.getTriggeringEntity());
trigger.setTriggeringEntity(null);
}
private Entity getByTiledId(int tiledId) {
ImmutableArray<Entity> entities = getEngine().getEntitiesFor(Family.all(Tiled.class).get());
for (Entity entity : entities) {
if (Tiled.MAPPER.get(entity).getId() == tiledId) {
return entity;
}
}
return null;
}
private void fireTrigger(String triggerName, Entity triggeringEntity) {
switch (triggerName) {
case "trap_trigger" -> trapTrigger(triggeringEntity);
default -> throw new GdxRuntimeException("Unsupported trigger: " + triggerName);
}
}
private void trapTrigger(Entity triggeringEntity) {
Entity trapEntity = getByTiledId(15);
if (trapEntity != null) {
// play trap animation
Animation2D animation2D = Animation2D.MAPPER.get(trapEntity);
animation2D.setSpeed(1f);
animation2D.setPlayMode(Animation.PlayMode.NORMAL);
audioService.playSound(SoundAsset.TRAP);
// reset animation
Timer.schedule(new Timer.Task() {
@Override
public void run() {
animation2D.setSpeed(0f);
animation2D.setType(Animation2D.AnimationType.IDLE);
}
}, 2.5f);
// damage player
Life life = Life.MAPPER.get(triggeringEntity);
if (life.getLife() > 2) {
life.addLife(-2f);
}
}
}
}

View File

@@ -7,13 +7,10 @@ import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FileTextureData;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.MapObjects;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
@@ -21,7 +18,6 @@ import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.GdxRuntimeException;
import io.github.com.quillraven.GdxGame;
@@ -39,10 +35,12 @@ import io.github.com.quillraven.component.Life;
import io.github.com.quillraven.component.Move;
import io.github.com.quillraven.component.Physic;
import io.github.com.quillraven.component.Player;
import io.github.com.quillraven.component.Tiled;
import io.github.com.quillraven.component.Transform;
import io.github.com.quillraven.component.Trigger;
public class TiledAshleySpawner {
private static final Vector2 DEFAULT_SCALING = new Vector2(1f, 1f);
public class TiledAshleyConfigurator {
private static final Vector2 DEFAULT_PHYSIC_SCALING = new Vector2(1f, 1f);
private final Engine engine;
private final World physicWorld;
@@ -50,7 +48,7 @@ public class TiledAshleySpawner {
private final Vector2 tmpVec2;
private final AssetService assetService;
public TiledAshleySpawner(Engine engine, World physicWorld, AssetService assetService) {
public TiledAshleyConfigurator(Engine engine, World physicWorld, AssetService assetService) {
this.engine = engine;
this.physicWorld = physicWorld;
this.tmpMapObjects = new MapObjects();
@@ -58,120 +56,49 @@ public class TiledAshleySpawner {
this.assetService = assetService;
}
public void loadMapObjects(TiledMap tiledMap) {
for (MapLayer layer : tiledMap.getLayers()) {
if (layer instanceof TiledMapTileLayer tileLayer) {
loadTileLayer(tileLayer);
} else if ("objects".equals(layer.getName())) {
loadObjectLayer(layer);
} else if ("trigger".equals(layer.getName())) {
loadTriggerLayer(layer);
}
}
spawnMapBoundary(tiledMap);
public void onLoadTile(TiledMapTile tile, float x, float y) {
createBody(tile.getObjects(),
new Vector2(x, y),
DEFAULT_PHYSIC_SCALING,
BodyDef.BodyType.StaticBody,
Vector2.Zero,
"environment");
}
private void spawnMapBoundary(TiledMap tiledMap) {
// create four boxes for the map boundary (left, right, bottom and top edge)
int width = tiledMap.getProperties().get("width", 0, Integer.class);
int tileW = tiledMap.getProperties().get("tilewidth", 0, Integer.class);
int height = tiledMap.getProperties().get("height", 0, Integer.class);
int tileH = tiledMap.getProperties().get("tileheight", 0, Integer.class);
float mapW = width * tileW * GdxGame.UNIT_SCALE;
float mapH = height * tileH * GdxGame.UNIT_SCALE;
float halfW = mapW * 0.5f;
float halfH = mapH * 0.5f;
float boxThickness = 0.5f;
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.StaticBody;
bodyDef.position.setZero();
bodyDef.fixedRotation = true;
Body body = physicWorld.createBody(bodyDef);
// left edge
PolygonShape shape = new PolygonShape();
shape.setAsBox(boxThickness, halfH, new Vector2(-boxThickness, halfH), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// right edge
shape = new PolygonShape();
shape.setAsBox(boxThickness, halfH, new Vector2(mapW + boxThickness, halfH), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// bottom edge
shape = new PolygonShape();
shape.setAsBox(halfW, boxThickness, new Vector2(halfW, -boxThickness), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// top edge
shape = new PolygonShape();
shape.setAsBox(halfW, boxThickness, new Vector2(halfW, mapH + boxThickness), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
}
private void loadTileLayer(TiledMapTileLayer tileLayer) {
for (int y = 0; y < tileLayer.getHeight(); y++) {
for (int x = 0; x < tileLayer.getWidth(); x++) {
TiledMapTileLayer.Cell cell = tileLayer.getCell(x, y);
if (cell == null) continue;
TiledMapTile tile = cell.getTile();
createBody(tile.getObjects(),
new Vector2(x, y),
DEFAULT_SCALING,
BodyType.StaticBody,
Vector2.Zero,
"environment");
}
public void onLoadTrigger(String triggerName, MapObject mapObject) {
if (mapObject instanceof RectangleMapObject rectMapObj) {
Entity entity = this.engine.createEntity();
Rectangle rect = rectMapObj.getRectangle();
addEntityTransform(
rect.getX(), rect.getY(), 0,
rect.getWidth(), rect.getHeight(),
1f, 1f,
0,
entity);
addEntityPhysic(
rectMapObj,
BodyDef.BodyType.StaticBody,
tmpVec2.set(rect.getX(), rect.getY()).scl(GdxGame.UNIT_SCALE),
entity);
entity.add(new Trigger(triggerName));
entity.add(new Tiled(rectMapObj));
this.engine.addEntity(entity);
} else {
throw new GdxRuntimeException("Unsupported map object type for trigger: " + mapObject.getClass().getSimpleName());
}
}
private void loadTriggerLayer(MapLayer triggerLayer) {
for (MapObject mapObject : triggerLayer.getObjects()) {
if (mapObject instanceof RectangleMapObject rectMapObj) {
Entity entity = this.engine.createEntity();
Rectangle rect = rectMapObj.getRectangle();
addEntityTransform(
rect.getX(), rect.getY(),
rect.getWidth(), rect.getHeight(),
1f, 1f,
0,
entity);
addEntityPhysic(
rectMapObj,
BodyType.StaticBody,
tmpVec2.set(rect.getX(), rect.getY()).scl(GdxGame.UNIT_SCALE),
entity);
this.engine.addEntity(entity);
} else {
throw new GdxRuntimeException("Unsupported trigger: " + mapObject.getClass().getSimpleName());
}
}
}
private void loadObjectLayer(MapLayer objectLayer) {
for (MapObject mapObject : objectLayer.getObjects()) {
if (mapObject instanceof TiledMapTileMapObject tileMapObject) {
spawnEntityOf(tileMapObject);
} else {
throw new GdxRuntimeException("Unsupported object: " + mapObject.getClass().getSimpleName());
}
}
}
private void spawnEntityOf(TiledMapTileMapObject tileMapObject) {
public void onLoadObject(TiledMapTileMapObject tileMapObject) {
Entity entity = this.engine.createEntity();
TiledMapTile tile = tileMapObject.getTile();
TextureRegion textureRegion = getTextureRegion(tile);
String classType = tile.getProperties().get("type", "", String.class);
float sortOffsetY = tile.getProperties().get("sortOffsetY", 0, Integer.class);
sortOffsetY *= GdxGame.UNIT_SCALE;
int z = tile.getProperties().get("z", 1, Integer.class);
addEntityTransform(
tileMapObject.getX(), tileMapObject.getY(),
tileMapObject.getX(), tileMapObject.getY(), z,
textureRegion.getRegionWidth(), textureRegion.getRegionHeight(),
tileMapObject.getScaleX(), tileMapObject.getScaleY(),
sortOffsetY,
@@ -190,6 +117,7 @@ public class TiledAshleySpawner {
entity.add(new Facing(FacingDirection.DOWN));
entity.add(new Fsm(entity));
entity.add(new Graphic(textureRegion, Color.WHITE.cpy()));
entity.add(new Tiled(tileMapObject));
this.engine.addEntity(entity);
}
@@ -258,8 +186,9 @@ public class TiledAshleySpawner {
AtlasAsset atlasAsset = AtlasAsset.valueOf(atlasAssetStr);
FileTextureData textureData = (FileTextureData) tile.getTextureRegion().getTexture().getTextureData();
String atlasKey = textureData.getFileHandle().nameWithoutExtension();
float speed = tile.getProperties().get("animationSpeed", 0f, Float.class);
entity.add(new Animation2D(atlasAsset, atlasKey, animationType, Animation.PlayMode.LOOP, 1f));
entity.add(new Animation2D(atlasAsset, atlasKey, animationType, Animation.PlayMode.LOOP, speed));
}
private void addEntityPhysic(MapObject mapObject, @SuppressWarnings("SameParameterValue") BodyType bodyType, Vector2 relativeTo, Entity entity) {
@@ -305,7 +234,7 @@ public class TiledAshleySpawner {
}
private static void addEntityTransform(
float x, float y,
float x, float y, int z,
float w, float h,
float scaleX, float scaleY,
float sortOffsetY,
@@ -318,7 +247,7 @@ public class TiledAshleySpawner {
position.scl(GdxGame.UNIT_SCALE);
size.scl(GdxGame.UNIT_SCALE);
entity.add(new Transform(position, 0, size, scaling, 0f, sortOffsetY));
entity.add(new Transform(position, z, size, scaling, 0f, sortOffsetY));
}
}

View File

@@ -1,19 +1,43 @@
package io.github.com.quillraven.tiled;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
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.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.GdxRuntimeException;
import io.github.com.quillraven.GdxGame;
import io.github.com.quillraven.asset.AssetService;
import io.github.com.quillraven.asset.MapAsset;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class TiledService {
private final AssetService assetService;
private Consumer<TiledMap> mapChangeConsumer;
private final World physicWorld;
private TiledMap currentMap;
public TiledService(AssetService assetService) {
private Consumer<TiledMap> mapChangeConsumer;
private BiConsumer<String, MapObject> loadTriggerConsumer;
private Consumer<TiledMapTileMapObject> loadObjectConsumer;
private LoadTileConsumer loadTileConsumer;
public TiledService(AssetService assetService, World physicWorld) {
this.assetService = assetService;
this.physicWorld = physicWorld;
this.mapChangeConsumer = null;
this.loadTriggerConsumer = null;
this.loadObjectConsumer = null;
this.loadTileConsumer = null;
this.currentMap = null;
}
@@ -29,6 +53,7 @@ public class TiledService {
}
this.currentMap = tiledMap;
loadMapObjects(tiledMap);
if (this.mapChangeConsumer != null) {
this.mapChangeConsumer.accept(tiledMap);
}
@@ -37,4 +62,116 @@ public class TiledService {
public void setMapChangeConsumer(Consumer<TiledMap> mapChangeConsumer) {
this.mapChangeConsumer = mapChangeConsumer;
}
public void setLoadObjectConsumer(Consumer<TiledMapTileMapObject> loadObjectConsumer) {
this.loadObjectConsumer = loadObjectConsumer;
}
public void setLoadTriggerConsumer(BiConsumer<String, MapObject> loadTriggerConsumer) {
this.loadTriggerConsumer = loadTriggerConsumer;
}
public void setLoadTileConsumer(LoadTileConsumer loadTileConsumer) {
this.loadTileConsumer = loadTileConsumer;
}
public void loadMapObjects(TiledMap tiledMap) {
for (MapLayer layer : tiledMap.getLayers()) {
if (layer instanceof TiledMapTileLayer tileLayer) {
loadTileLayer(tileLayer);
} else if ("objects".equals(layer.getName())) {
loadObjectLayer(layer);
} else if ("trigger".equals(layer.getName())) {
loadTriggerLayer(layer);
}
}
spawnMapBoundary(tiledMap);
}
private void spawnMapBoundary(TiledMap tiledMap) {
// create four boxes for the map boundary (left, right, bottom and top edge)
int width = tiledMap.getProperties().get("width", 0, Integer.class);
int tileW = tiledMap.getProperties().get("tilewidth", 0, Integer.class);
int height = tiledMap.getProperties().get("height", 0, Integer.class);
int tileH = tiledMap.getProperties().get("tileheight", 0, Integer.class);
float mapW = width * tileW * GdxGame.UNIT_SCALE;
float mapH = height * tileH * GdxGame.UNIT_SCALE;
float halfW = mapW * 0.5f;
float halfH = mapH * 0.5f;
float boxThickness = 0.5f;
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.StaticBody;
bodyDef.position.setZero();
bodyDef.fixedRotation = true;
Body body = physicWorld.createBody(bodyDef);
// left edge
PolygonShape shape = new PolygonShape();
shape.setAsBox(boxThickness, halfH, new Vector2(-boxThickness, halfH), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// right edge
shape = new PolygonShape();
shape.setAsBox(boxThickness, halfH, new Vector2(mapW + boxThickness, halfH), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// bottom edge
shape = new PolygonShape();
shape.setAsBox(halfW, boxThickness, new Vector2(halfW, -boxThickness), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// top edge
shape = new PolygonShape();
shape.setAsBox(halfW, boxThickness, new Vector2(halfW, mapH + boxThickness), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
}
private void loadTileLayer(TiledMapTileLayer tileLayer) {
if (loadTileConsumer == null) return;
for (int y = 0; y < tileLayer.getHeight(); y++) {
for (int x = 0; x < tileLayer.getWidth(); x++) {
TiledMapTileLayer.Cell cell = tileLayer.getCell(x, y);
if (cell == null) continue;
loadTileConsumer.accept(cell.getTile(), x, y);
}
}
}
private void loadTriggerLayer(MapLayer triggerLayer) {
if (loadTriggerConsumer == null) return;
for (MapObject mapObject : triggerLayer.getObjects()) {
if (mapObject.getName() == null || mapObject.getName().isBlank()) {
throw new GdxRuntimeException("Trigger must have a name: " + mapObject);
}
if (mapObject instanceof RectangleMapObject rectMapObj) {
loadTriggerConsumer.accept(mapObject.getName(), rectMapObj);
} else {
throw new GdxRuntimeException("Unsupported trigger: " + mapObject.getClass().getSimpleName());
}
}
}
private void loadObjectLayer(MapLayer objectLayer) {
if (loadObjectConsumer == null) return;
for (MapObject mapObject : objectLayer.getObjects()) {
if (mapObject instanceof TiledMapTileMapObject tileMapObject) {
loadObjectConsumer.accept(tileMapObject);
} else {
throw new GdxRuntimeException("Unsupported object: " + mapObject.getClass().getSimpleName());
}
}
}
@FunctionalInterface
public interface LoadTileConsumer {
void accept(TiledMapTile tile, float x, float y);
}
}

View File

@@ -33,7 +33,7 @@ public class GameViewModel extends ViewModel {
public void setLifePoints(int lifePoints) {
if (this.lifePoints != lifePoints) {
this.propertyChangeSupport.firePropertyChange(LIFE_POINTS, this.lifePoints, lifePoints);
if (this.lifePoints < lifePoints) {
if (this.lifePoints != 0 && this.lifePoints < lifePoints) {
audioService.playSound(SoundAsset.LIFE_REG);
}
}