From 4b5a1fbfe5d6e3f2960e36cd0f4110377c7789f5 Mon Sep 17 00:00:00 2001 From: Anton Dolgopolov <131554010+beverly-hills-money-gangster@users.noreply.github.com> Date: Tue, 7 Jan 2025 23:50:50 +0200 Subject: [PATCH] Doors (#76) --- .../managers/registry/SoundRegistry.java | 9 +- .../hills/money/gang/entities/door/Door.java | 198 ++++++++++++++++++ .../money/gang/entities/player/Player.java | 3 +- .../entities/projectile/EnemyRocketBoom.java | 2 +- .../projectile/EnemyRocketProjectile.java | 9 +- .../entities/projectile/RocketProjectile.java | 2 +- .../gang/filters/OverlapFilterManager.java | 6 +- .../hills/money/gang/maps/MapBuilder.java | 22 ++ .../hills/money/gang/models/ModelMaker.java | 10 - .../hills/money/gang/rect/RectManager.java | 4 +- .../rect/filters/RectanglePlusFilter.java | 2 +- manual-testing-cases.html | 12 ++ 12 files changed, 253 insertions(+), 26 deletions(-) create mode 100644 core/src/com/beverly/hills/money/gang/entities/door/Door.java diff --git a/core/src/com/beverly/hills/money/gang/assets/managers/registry/SoundRegistry.java b/core/src/com/beverly/hills/money/gang/assets/managers/registry/SoundRegistry.java index a79a5ed..5c60bdb 100644 --- a/core/src/com/beverly/hills/money/gang/assets/managers/registry/SoundRegistry.java +++ b/core/src/com/beverly/hills/money/gang/assets/managers/registry/SoundRegistry.java @@ -62,7 +62,7 @@ public enum SoundRegistry { TAUNT_PREPARE_TO_DIE("voice/taunt/player/prepare_to_die.mp3"), TAUNT_YOU_ARE_NOTHING("voice/taunt/player/you_are_nothing.mp3"), TAUNT_YOU_WEAK_PATHETIC_FOOL("voice/taunt/player/you_are_weak_pathetic_fool.mp3"), - + ENEMY_TAUNT_DO_NOT_MAKE_ME_LAUGH("voice/taunt/enemy/do_not_make_me_laugh.mp3"), ENEMY_TAUNT_I_WIN("voice/taunt/enemy/i_win.mp3"), ENEMY_TAUNT_OFFICIAL_SUCK("voice/taunt/enemy/official_suck.mp3"), @@ -74,7 +74,7 @@ public enum SoundRegistry { ENEMY_TAUNT_PREPARE_TO_DIE("voice/taunt/enemy/prepare_to_die.mp3"), ENEMY_TAUNT_YOU_ARE_NOTHING("voice/taunt/enemy/you_are_nothing.mp3"), ENEMY_TAUNT_YOU_WEAK_PATHETIC_FOOL("voice/taunt/enemy/you_are_weak_pathetic_fool.mp3"), - + ENEMY_SHOTGUN("sfx/enemy_shotgun.mp3"), ENEMY_ROCKET_LAUNCHER("sfx/enemy_player_rocket_launcher.mp3"), QUAD_DAMAGE_ATTACK("sfx/quad_damage_attack.mp3"), @@ -96,7 +96,10 @@ public enum SoundRegistry { HIT_SOUND("sfx/shoot_hit_sound.mp3"), SPAWN1("sfx/spawn/spawn1.mp3"), SPAWN2("sfx/spawn/spawn2.mp3"), - SPAWN3("sfx/spawn/spawn3.mp3"); + SPAWN3("sfx/spawn/spawn3.mp3"), + + DOOR_OPEN("sfx/door_open.mp3"), + DOOR_CLOSE("sfx/door_close.mp3"); @Getter private final String fileName; diff --git a/core/src/com/beverly/hills/money/gang/entities/door/Door.java b/core/src/com/beverly/hills/money/gang/entities/door/Door.java new file mode 100644 index 0000000..43ef11a --- /dev/null +++ b/core/src/com/beverly/hills/money/gang/entities/door/Door.java @@ -0,0 +1,198 @@ +package com.beverly.hills.money.gang.entities.door; + + +import com.badlogic.gdx.graphics.g3d.Environment; +import com.badlogic.gdx.graphics.g3d.ModelBatch; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; +import com.beverly.hills.money.gang.Constants; +import com.beverly.hills.money.gang.assets.managers.registry.SoundRegistry; +import com.beverly.hills.money.gang.assets.managers.sound.UserSettingSound; +import com.beverly.hills.money.gang.entities.SoundMakingEntity; +import com.beverly.hills.money.gang.entities.player.Player; +import com.beverly.hills.money.gang.models.ModelInstanceBB; +import com.beverly.hills.money.gang.rect.RectanglePlus; +import com.beverly.hills.money.gang.rect.filters.RectanglePlusFilter; +import com.beverly.hills.money.gang.screens.GameScreen; + +public class Door extends SoundMakingEntity { + + public final Vector3 position = new Vector3(); + + private final ModelInstanceBB mdlInstDoor; + + private final DoorDirection direction; + + + private DoorState state = DoorState.CLOSE; + private final Vector3 openPos = new Vector3(); + private final Vector3 closedPos = new Vector3(); + + private static final float START_OPEN_DISTANCE = 1.75f; + + private static final float DOOR_OPEN_SPEED = 8.5f; + + private final UserSettingSound soundClose; + + private final UserSettingSound soundOpen; + + private RectanglePlus rect; + + private final Vector3 currentTranslation = new Vector3(); + + + public Door(final Vector3 position, final DoorDirection direction, + final GameScreen screen) { + super(screen); + this.soundOpen = screen.getGame().getAssMan().getUserSettingSound(SoundRegistry.DOOR_OPEN); + this.soundClose = screen.getGame().getAssMan().getUserSettingSound(SoundRegistry.DOOR_CLOSE); + this.position.set(position.cpy().add(Constants.HALF_UNIT, Constants.HALF_UNIT, 0)); + this.direction = direction; + mdlInstDoor = new ModelInstanceBB(screen.getGame().getCellBuilder().getMdlDoor()); + switch (direction) { + case NORTH -> + closedPos.set(this.position.cpy().add(new Vector3(0, -0.25f, 1 - Constants.PPU * 2))); + case EAST -> closedPos.set(this.position.cpy() + .add( + new Vector3(Constants.HALF_UNIT - Constants.PPU * 2, -0.25f, Constants.HALF_UNIT))); + case WEST -> closedPos.set(this.position.cpy() + .add(new Vector3(-Constants.HALF_UNIT + Constants.PPU * 2, -0.25f, + Constants.HALF_UNIT))); + case SOUTH -> + closedPos.set(this.position.cpy().add(new Vector3(0, -0.25f, 0 + Constants.PPU * 2))); + } + + openPos.set(closedPos.cpy().add(0, -1.5f, 0)); + + mdlInstDoor.transform.setToTranslation(closedPos.cpy()); + + if (direction == DoorDirection.WEST || direction == DoorDirection.EAST) { + mdlInstDoor.transform.rotate(Vector3.Y, -90); + } + mdlInstDoor.transform.scale(1, 1.5f, 1); + + setupRect(); + + screen.getGame().getRectMan().addRect(rect); + } + + @Override + public void destroy() { + if (rect != null) { + getScreen().getGame().getRectMan().removeRect(rect); + } + super.destroy(); // should be last. + } + + + @Override + public void render3D(final ModelBatch mdlBatch, final Environment env, final float delta) { + mdlInstDoor.setInFrustum(getScreen().frustumCull(getScreen().getCurrentCam(), mdlInstDoor)); + if (mdlInstDoor.isInFrustum()) { + mdlBatch.render(mdlInstDoor, env); + } + } + + private void setupRect() { + if (direction == DoorDirection.NORTH || direction == DoorDirection.SOUTH) { + rect = new RectanglePlus( + mdlInstDoor.transform.getTranslation(new Vector3()).x + - mdlInstDoor.getRenderBox().getWidth() / 2, + mdlInstDoor.transform.getTranslation(new Vector3()).z + - mdlInstDoor.getRenderBox().getDepth() / 2, + mdlInstDoor.getRenderBox().getWidth(), mdlInstDoor.getRenderBox().getDepth(), + getEntityId(), + RectanglePlusFilter.DOOR); + } else { + rect = new RectanglePlus( + mdlInstDoor.transform.getTranslation(new Vector3()).x + - mdlInstDoor.getRenderBox().getDepth() / 2, + mdlInstDoor.transform.getTranslation(new Vector3()).z + - mdlInstDoor.getRenderBox().getWidth() / 2, + mdlInstDoor.getRenderBox().getDepth(), mdlInstDoor.getRenderBox().getWidth(), + getEntityId(), + RectanglePlusFilter.DOOR); + } + } + + @Override + public void tick(final float delta) { + var targetState = getTargetState(); + if (targetState == state) { + return; + } + if (targetState == DoorState.CLOSE) { + if (state == DoorState.TO_BE_CLOSED) { + soundClose.play(getSFXVolume(), getSFXPan()); + state = DoorState.BEING_CLOSED; + } else if (state != DoorState.BEING_CLOSED) { + state = DoorState.TO_BE_CLOSED; + } + } else if (targetState == DoorState.OPEN) { + if (state == DoorState.TO_BE_OPEN) { + soundOpen.play(getSFXVolume(), getSFXPan()); + state = DoorState.BEING_OPEN; + } else if (state != DoorState.BEING_OPEN) { + state = DoorState.TO_BE_OPEN; + } + } + if (state == DoorState.BEING_OPEN) { + mdlInstDoor.transform.getTranslation(currentTranslation); + currentTranslation.y -= DOOR_OPEN_SPEED * delta; + mdlInstDoor.transform.setTranslation(currentTranslation.cpy()); + + if (currentTranslation.y <= openPos.y) { + mdlInstDoor.transform.setTranslation(openPos.cpy()); + state = DoorState.OPEN; + } + } else if (state == DoorState.BEING_CLOSED) { + mdlInstDoor.transform.getTranslation(currentTranslation); + currentTranslation.y += DOOR_OPEN_SPEED * delta; + mdlInstDoor.transform.setTranslation(currentTranslation.cpy()); + + if (currentTranslation.y >= closedPos.y) { + mdlInstDoor.transform.setTranslation(closedPos.cpy()); + state = DoorState.CLOSE; + } + } + + rect.setPosition(mdlInstDoor.transform.getTranslation(new Vector3()).x + - mdlInstDoor.getRenderBox().getWidth() / 2, + mdlInstDoor.transform.getTranslation(new Vector3()).z + - mdlInstDoor.getRenderBox().getDepth() / 2); + } + + private DoorState getTargetState() { + for (final RectanglePlus otherRect : getScreen().getGame().getRectMan().getRects()) { + if (otherRect != rect + && (otherRect.getFilter() == RectanglePlusFilter.PLAYER + || otherRect.getFilter() == RectanglePlusFilter.ENEMY + || otherRect.getFilter() == RectanglePlusFilter.PROJECTILE) && + new Vector2(position.x, position.z).dst(otherRect.getPosition(new Vector2())) + < START_OPEN_DISTANCE) { + return DoorState.OPEN; + } + } + return DoorState.CLOSE; + } + + @Override + protected Player getPlayer() { + return getScreen().getPlayer(); + } + + @Override + protected RectanglePlus getRect() { + return rect; + } + + + private enum DoorState { + OPEN, CLOSE, TO_BE_OPEN, TO_BE_CLOSED, BEING_CLOSED, BEING_OPEN + } + + public enum DoorDirection { + NORTH, SOUTH, EAST, WEST + } + +} \ No newline at end of file diff --git a/core/src/com/beverly/hills/money/gang/entities/player/Player.java b/core/src/com/beverly/hills/money/gang/entities/player/Player.java index 91797c2..faa5d1f 100644 --- a/core/src/com/beverly/hills/money/gang/entities/player/Player.java +++ b/core/src/com/beverly/hills/money/gang/entities/player/Player.java @@ -202,7 +202,8 @@ public final Optional getEnemyRectInRangeFromCam( final float weaponDistance) { return Streams.of(getScreen().getGame().getRectMan().getRects()) .filter(rect -> (rect.getFilter() == RectanglePlusFilter.ENEMY - || rect.getFilter() == RectanglePlusFilter.WALL)) + || rect.getFilter() == RectanglePlusFilter.WALL + || rect.getFilter() == RectanglePlusFilter.DOOR)) .filter(rect -> Intersector.intersectSegmentRectangle(playerCam.position.x, playerCam.position.z, playerCam.position.x + playerCam.direction.x * weaponDistance, diff --git a/core/src/com/beverly/hills/money/gang/entities/projectile/EnemyRocketBoom.java b/core/src/com/beverly/hills/money/gang/entities/projectile/EnemyRocketBoom.java index e3be64e..a7bc9e7 100644 --- a/core/src/com/beverly/hills/money/gang/entities/projectile/EnemyRocketBoom.java +++ b/core/src/com/beverly/hills/money/gang/entities/projectile/EnemyRocketBoom.java @@ -64,7 +64,7 @@ public EnemyRocketBoom(final Player player, final float rectWidth = Constants.HALF_UNIT; final float rectHeight = Constants.HALF_UNIT; rect = new RectanglePlus(this.position.x, this.position.z, rectWidth, rectHeight, getEntityId(), - RectanglePlusFilter.ITEM); + RectanglePlusFilter.PROJECTILE); rect.setPosition(this.position.x - rect.getWidth() / 2, this.position.z - rect.getHeight() / 2); player.getScreen().getGame().getRectMan().addRect(rect); diff --git a/core/src/com/beverly/hills/money/gang/entities/projectile/EnemyRocketProjectile.java b/core/src/com/beverly/hills/money/gang/entities/projectile/EnemyRocketProjectile.java index 9f71a45..22004a0 100644 --- a/core/src/com/beverly/hills/money/gang/entities/projectile/EnemyRocketProjectile.java +++ b/core/src/com/beverly/hills/money/gang/entities/projectile/EnemyRocketProjectile.java @@ -41,7 +41,7 @@ public class EnemyRocketProjectile extends Projectile { private final Player player; - private static final int LIVES_FOR_MLS = 350; + private static final int LIVES_FOR_MLS = 550; private final long destroyAtMls = System.currentTimeMillis() + LIVES_FOR_MLS; @@ -64,10 +64,9 @@ public EnemyRocketProjectile(final Vector3 startPosition, .set(new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)); mdlInst.materials.get(0).set(new FloatAttribute(FloatAttribute.AlphaTest)); - final float rectWidth = Constants.HALF_UNIT; - final float rectHeight = Constants.HALF_UNIT; - rect = new RectanglePlus(this.position.x, this.position.z, rectWidth, rectHeight, getEntityId(), - RectanglePlusFilter.ITEM); + rect = new RectanglePlus(this.position.x, this.position.z, Constants.HALF_UNIT, + Constants.HALF_UNIT, getEntityId(), + RectanglePlusFilter.PROJECTILE); rect.setPosition(this.position.x - rect.getWidth() / 2, this.position.z - rect.getHeight() / 2); player.getScreen().getGame().getRectMan().addRect(rect); diff --git a/core/src/com/beverly/hills/money/gang/entities/projectile/RocketProjectile.java b/core/src/com/beverly/hills/money/gang/entities/projectile/RocketProjectile.java index 90da8c7..ca56142 100644 --- a/core/src/com/beverly/hills/money/gang/entities/projectile/RocketProjectile.java +++ b/core/src/com/beverly/hills/money/gang/entities/projectile/RocketProjectile.java @@ -78,7 +78,7 @@ public RocketProjectile(final Player player, final Vector3 startPosition, final float rectWidth = Constants.HALF_UNIT; final float rectHeight = Constants.HALF_UNIT; rect = new RectanglePlus(this.position.x, this.position.z, rectWidth, rectHeight, getEntityId(), - RectanglePlusFilter.ITEM); + RectanglePlusFilter.PROJECTILE); rect.setPosition(this.position.x - rect.getWidth() / 2, this.position.z - rect.getHeight() / 2); screen.getGame().getRectMan().addRect(rect); diff --git a/core/src/com/beverly/hills/money/gang/filters/OverlapFilterManager.java b/core/src/com/beverly/hills/money/gang/filters/OverlapFilterManager.java index bc38510..db48b54 100644 --- a/core/src/com/beverly/hills/money/gang/filters/OverlapFilterManager.java +++ b/core/src/com/beverly/hills/money/gang/filters/OverlapFilterManager.java @@ -35,20 +35,20 @@ private void setupFilters() { overlapFilters[2][0] = RectanglePlusFilter.DOOR.getValue(); overlapFilters[3][0] = RectanglePlusFilter.PLAYER.getValue(); overlapFilters[4][0] = RectanglePlusFilter.ENEMY.getValue(); - overlapFilters[5][0] = RectanglePlusFilter.ENEMY_PROJECTILE.getValue(); + overlapFilters[5][0] = RectanglePlusFilter.PROJECTILE.getValue(); overlapFilters[6][0] = RectanglePlusFilter.ITEM.getValue(); // Door overlapFilters[2][1] = RectanglePlusFilter.PLAYER.getValue(); overlapFilters[2][2] = RectanglePlusFilter.ENEMY.getValue(); - overlapFilters[2][3] = RectanglePlusFilter.ENEMY_PROJECTILE.getValue(); + overlapFilters[2][3] = RectanglePlusFilter.PROJECTILE.getValue(); // Player overlapFilters[3][1] = RectanglePlusFilter.WALL.getValue(); overlapFilters[3][2] = RectanglePlusFilter.DOOR.getValue(); // overlapFilters[3][3] = RectanglePlusFilter.PLAYER.getValue(); overlapFilters[3][4] = RectanglePlusFilter.ENEMY.getValue(); - overlapFilters[3][5] = RectanglePlusFilter.ENEMY_PROJECTILE.getValue(); + overlapFilters[3][5] = RectanglePlusFilter.PROJECTILE.getValue(); overlapFilters[3][6] = RectanglePlusFilter.ITEM.getValue(); // Enemy diff --git a/core/src/com/beverly/hills/money/gang/maps/MapBuilder.java b/core/src/com/beverly/hills/money/gang/maps/MapBuilder.java index 05d9dde..be2487e 100644 --- a/core/src/com/beverly/hills/money/gang/maps/MapBuilder.java +++ b/core/src/com/beverly/hills/money/gang/maps/MapBuilder.java @@ -17,6 +17,8 @@ import com.beverly.hills.money.gang.DaiKombatGame; import com.beverly.hills.money.gang.assets.managers.registry.TexturesRegistry; import com.beverly.hills.money.gang.cell.Cell3D; +import com.beverly.hills.money.gang.entities.door.Door; +import com.beverly.hills.money.gang.entities.door.Door.DoorDirection; import com.beverly.hills.money.gang.rect.RectanglePlus; import com.beverly.hills.money.gang.rect.filters.RectanglePlusFilter; import org.apache.commons.math3.util.Precision; @@ -47,6 +49,7 @@ public void buildMap(final TiledMap map) { final TiledMapTileLayer floorLayer = (TiledMapTileLayer) mapLayers.get("floor"); final TiledMapTileLayer ceilingLayer = (TiledMapTileLayer) mapLayers.get("ceiling"); final MapObjects rects = mapLayers.get("rects").getObjects(); + final MapObjects doors = mapLayers.get("doors").getObjects(); final MapObjects teleports = mapLayers.get("teleports").getObjects(); final Array cell3DsForWorld = new Array<>(); @@ -186,6 +189,25 @@ public void buildMap(final TiledMap map) { cell3DsForWorld.clear(); + for (final MapObject doorObj : doors) { + final String direction = (String) doorObj.getProperties().get("direction"); + DoorDirection doorDir = switch (direction) { + case "north" -> DoorDirection.NORTH; + case "south" -> DoorDirection.SOUTH; + case "west" -> DoorDirection.WEST; + case "east" -> DoorDirection.EAST; + default -> throw new IllegalArgumentException("Not supported direction " + direction); + }; + + final Door door = new Door( + new Vector3((float) doorObj.getProperties().get("x") / TILE_SIZE - currentMapWidth / 2f, + 0, + (float) doorObj.getProperties().get("y") / TILE_SIZE - currentMapHeight / 2f), + doorDir, game.getEntMan().getScreen()); + + game.getEntMan().addEntity(door); + } + for (final MapObject teleportObj : teleports) { final boolean spawnOnMapLoad = teleportObj.getProperties().get("MapSpawn", Boolean.class); diff --git a/core/src/com/beverly/hills/money/gang/models/ModelMaker.java b/core/src/com/beverly/hills/money/gang/models/ModelMaker.java index 3dd6d36..39ac07c 100644 --- a/core/src/com/beverly/hills/money/gang/models/ModelMaker.java +++ b/core/src/com/beverly/hills/money/gang/models/ModelMaker.java @@ -227,16 +227,6 @@ private void buildModels() { node1.rotation.set(Vector3.Y, 180f); node1.translation.set(0, 0, Constants.PPU * -2); - final Node node2 = mdlBuilder.node(); - meshBuilder = mdlBuilder.part("middleSide", GL20.GL_TRIANGLES, - Usage.Position | Usage.Normal | Usage.TextureCoordinates, matDoorMiddle); - meshBuilder.rect(new Vector3(Constants.PPU * 2, Constants.HALF_UNIT, 0), - new Vector3(-Constants.PPU * 2, Constants.HALF_UNIT, 0), - new Vector3(-Constants.PPU * 2, -Constants.HALF_UNIT, 0), - new Vector3(Constants.PPU * 2, -Constants.HALF_UNIT, 0), new Vector3(0, 0, -1)); - - node2.rotation.set(Vector3.Y, -90f); - node2.translation.set(-0.5f, 0, 0); mdlDoor = mdlBuilder.end(); } } diff --git a/core/src/com/beverly/hills/money/gang/rect/RectManager.java b/core/src/com/beverly/hills/money/gang/rect/RectManager.java index b09676e..6332c06 100644 --- a/core/src/com/beverly/hills/money/gang/rect/RectManager.java +++ b/core/src/com/beverly/hills/money/gang/rect/RectManager.java @@ -27,6 +27,7 @@ public boolean checkCollision(final RectanglePlus rect) { && otherRect != rect && RectanglePlusFilter.ENEMY != otherRect.getFilter() && RectanglePlusFilter.ITEM != otherRect.getFilter() + && RectanglePlusFilter.DOOR != otherRect.getFilter() && rect.overlaps(otherRect)) { return true; } @@ -39,7 +40,8 @@ public void onCollisionWithPlayer(final RectanglePlus playerRect) { if (game.getOverlapFilterMan() .doesFiltersOverlap(playerRect.getFilter(), otherRect.getFilter()) && otherRect != playerRect - && RectanglePlusFilter.ITEM == otherRect.getFilter() + && (RectanglePlusFilter.ITEM == otherRect.getFilter() + || RectanglePlusFilter.DOOR == otherRect.getFilter()) && playerRect.overlaps(otherRect)) { Entity item = game.getEntMan() .getEntityFromId(otherRect.getConnectedEntityId()); diff --git a/core/src/com/beverly/hills/money/gang/rect/filters/RectanglePlusFilter.java b/core/src/com/beverly/hills/money/gang/rect/filters/RectanglePlusFilter.java index c86acdd..d08c27a 100644 --- a/core/src/com/beverly/hills/money/gang/rect/filters/RectanglePlusFilter.java +++ b/core/src/com/beverly/hills/money/gang/rect/filters/RectanglePlusFilter.java @@ -3,7 +3,7 @@ import lombok.Getter; public enum RectanglePlusFilter { - NONE(-1), WALL(1), DOOR(2), PLAYER(3), ENEMY(4), ENEMY_PROJECTILE(5), ITEM(6); + NONE(-1), WALL(1), DOOR(2), PLAYER(3), ENEMY(4), PROJECTILE(5), ITEM(6); @Getter private final int value; diff --git a/manual-testing-cases.html b/manual-testing-cases.html index 8a8fa41..c917d61 100644 --- a/manual-testing-cases.html +++ b/manual-testing-cases.html @@ -486,6 +486,18 @@

All tests must be performed against a remote game server

+ + Play screen + Two players join a game. Player 1 stands close to a door. Player 2 sees the door open. + + + + + Play screen + Players can't shoot each other through doors(except for rocket launcher). + + + Any screen Player presses alt+tab and the screen switches to Windows desktop