Partially implemented office.json and states in animatronics movements

This commit is contained in:
2026-04-02 15:42:08 -03:00
parent 8e85745222
commit 458d30f107
20 changed files with 487 additions and 262 deletions

View File

@@ -2,14 +2,17 @@
"id": "toy_freddy",
"displayName": "Freddy Fazbear (Toy)",
"inRoom": 9,
"restRoom": 9,
"inRoom": "cam9",
"restRoom": "cam9",
"color": "#FF5733",
"movement": {
"type": "SEQUENTIAL",
"path": [9, 10, -2, -3],
"path": [
{ "room": "hallway", "state": 0 },
{ "room": "hallway", "state": 1 }
],
"moveIntervalSeconds": 12,
"aiSpeedMultiplier": true
},

View File

@@ -1,5 +1,5 @@
{
"inCameraId": 1,
"inCameraId": "cam1",
"wideRandomMov": {
"min": 5000,
"max": 7000
@@ -19,171 +19,171 @@
],
"cameras": [
{
"id": 1,
"id": "cam1",
"name": "PartyRoom1",
"labelPathId": 0,
"buttonX": 595,
"buttonY": 496,
"wide": false,
"variants": [
{ "animatronics": ["toy_chica"], "indexOff": 0, "indexOn": 3 },
{ "animatronics": ["withered_bonnie"], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "toy_chica" }], "indexOff": 0, "indexOn": 3 },
{ "animatronics": [{ "id": "withered_bonnie" }], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
},
{
"id": 2,
"id": "cam2",
"name": "PartyRoom2",
"labelPathId": 1,
"buttonX": 710,
"buttonY": 496,
"wide": false,
"variants": [
{ "animatronics": ["toy_bonnie"], "indexOff": 0, "indexOn": 2 },
{ "animatronics": ["withered_chica"], "indexOff": 3, "indexOn": 4 },
{ "animatronics": [{ "id": "toy_bonnie" }], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "withered_chica" }], "indexOff": 3, "indexOn": 4 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
},
{
"id": 3,
"id": "cam3",
"name": "PartyRoom3",
"labelPathId": 2,
"buttonX": 595,
"buttonY": 431,
"wide": false,
"variants": [
{ "animatronics": ["toy_bonnie"], "indexOff": 0, "indexOn": 2 },
{ "animatronics": ["withered_freddy"], "indexOff": 3, "indexOn": 4 },
{ "animatronics": [{ "id": "toy_bonnie" }], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "withered_freddy" }], "indexOff": 3, "indexOn": 4 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
},
{
"id": 4,
"id": "cam4",
"name": "PartyRoom4",
"labelPathId": 3,
"buttonX": 710,
"buttonY": 431,
"wide": false,
"variants": [
{ "animatronics": ["toy_bonnie"], "indexOff": 2, "indexOn": 3 },
{ "animatronics": ["toy_chica"], "indexOff": 0, "indexOn": 4 },
{ "animatronics": ["withered_chica"], "indexOff": 0, "indexOn": 5 },
{ "animatronics": [{ "id": "toy_bonnie" }], "indexOff": 2, "indexOn": 3 },
{ "animatronics": [{ "id": "toy_chica" }], "indexOff": 0, "indexOn": 4 },
{ "animatronics": [{ "id": "withered_chica" }], "indexOff": 0, "indexOn": 5 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
},
{
"id": 5,
"id": "cam5",
"name": "LeftAirVent",
"labelPathId": 4,
"buttonX": 585,
"buttonY": 595,
"wide": false,
"variants": [
{ "animatronics": ["toy_chica"], "indexOff": 0, "indexOn": 4 },
{ "animatronics": ["baloon_boy"], "indexOff": 0, "indexOn": 3 },
{ "animatronics": ["withered_bonnie"], "indexOff": 0, "indexOn": 2 },
{ "animatronics": ["endo"], "indexOff": 0, "indexOn": 5 },
{ "animatronics": [{ "id": "toy_chica" }], "indexOff": 0, "indexOn": 4 },
{ "animatronics": [{ "id": "baloon_boy" }], "indexOff": 0, "indexOn": 3 },
{ "animatronics": [{ "id": "withered_bonnie" }], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "endo" }], "indexOff": 0, "indexOn": 5 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
},
{
"id": 6,
"id": "cam6",
"name": "RightAirVent",
"labelPathId": 5,
"buttonX": 695,
"buttonY": 595,
"wide": false,
"variants": [
{ "animatronics": ["toy_bonnie"], "indexOff": 0, "indexOn": 2 },
{ "animatronics": ["withered_chica"], "indexOff": 0, "indexOn": 3 },
{ "animatronics": ["mangle"], "indexOff": 0, "indexOn": 4 },
{ "animatronics": [{ "id": "toy_bonnie" }], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "withered_chica" }], "indexOff": 0, "indexOn": 3 },
{ "animatronics": [{ "id": "mangle" }], "indexOff": 0, "indexOn": 4 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
},
{
"id": 7,
"id": "cam7",
"name": "MainHall",
"labelPathId": 6,
"buttonX": 734,
"buttonY": 367,
"wide": true,
"variants": [
{ "animatronics": ["toy_chica"], "indexOff": 4, "indexOn": 5 },
{ "animatronics": ["withered_freddy"], "indexOff": 0, "indexOn": 3 },
{ "animatronics": ["withered_bonnie"], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "toy_chica" }], "indexOff": 4, "indexOn": 5 },
{ "animatronics": [{ "id": "withered_freddy" }], "indexOff": 0, "indexOn": 3 },
{ "animatronics": [{ "id": "withered_bonnie" }], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
},
{
"id": 8,
"id": "cam8",
"name": "PartsnService",
"labelPathId": 7,
"buttonX": 575,
"buttonY": 356,
"wide": true,
"variants": [
{ "animatronics": ["withered_freddy", "withered_bonnie", "withered_chica"], "indexOff": 0, "indexOn": 1 },
{ "animatronics": ["withered_freddy", "withered_chica"], "indexOff": 0, "indexOn": 2 },
{ "animatronics": ["withered_freddy"], "indexOff": 0, "indexOn": 3 },
{ "animatronics": ["foxy"], "indexOff": 0, "indexOn": 4 },
{ "animatronics": ["TODO"], "condition": "ENDO_1987", "indexOff": 0, "indexOn": 6 },
{ "animatronics": ["TODO"], "condition": "SHADOW_FREDDY", "indexOff": 0, "indexOn": 5 },
{ "animatronics": [{ "id": "withered_freddy" }, { "id": "withered_bonnie" }, { "id": "withered_chica" }], "indexOff": 0, "indexOn": 1 },
{ "animatronics": [{ "id": "withered_freddy" }, { "id": "withered_chica" }], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "withered_freddy" }], "indexOff": 0, "indexOn": 3 },
{ "animatronics": [{ "id": "foxy" }], "indexOff": 0, "indexOn": 4 },
{ "animatronics": [{ "id": "TODO" }], "condition": "ENDO_1987", "indexOff": 0, "indexOn": 6 },
{ "animatronics": [{ "id": "TODO" }], "condition": "SHADOW_FREDDY", "indexOff": 0, "indexOn": 5 },
{ "animatronics": [], "indexOff": 0, "indexOn": 5 }
]
},
{
"id": 9,
"id": "cam9",
"name": "ShowStage",
"labelPathId": 8,
"buttonX": 895,
"buttonY": 331,
"wide": true,
"variants": [
{ "animatronics": ["toy_bonnie", "toy_freddy", "toy_chica"], "indexOff": 0, "indexOn": 1 },
{ "animatronics": ["toy_freddy", "toy_chica"], "indexOff": 2, "indexOn": 3 },
{ "animatronics": ["toy_freddy"], "indexOff": 4, "indexOn": 5 },
{ "animatronics": [{ "id": "toy_bonnie" }, { "id": "toy_freddy" }, { "id": "toy_chica" }], "indexOff": 0, "indexOn": 1 },
{ "animatronics": [{ "id": "toy_freddy" }, { "id": "toy_chica" }], "indexOff": 2, "indexOn": 3 },
{ "animatronics": [{ "id": "toy_freddy" }], "indexOff": 4, "indexOn": 5 },
{ "animatronics": [], "indexOff": 6, "indexOn": -1 }
]
},
{
"id": 10,
"id": "cam10",
"name": "GameArea",
"labelPathId": 9,
"buttonX": 820,
"buttonY": 455,
"wide": true,
"variants": [
{ "animatronics": ["toy_freddy", "baloon_boy"], "indexOff": 0, "indexOn": 4 },
{ "animatronics": ["toy_freddy"], "indexOff": 2, "indexOn": 5 },
{ "animatronics": ["baloon_boy"], "indexOff": 0, "indexOn": 1 },
{ "animatronics": [{ "id": "toy_freddy" }, { "id": "baloon_boy" }], "indexOff": 0, "indexOn": 4 },
{ "animatronics": [{ "id": "toy_freddy" }], "indexOff": 2, "indexOn": 5 },
{ "animatronics": [{ "id": "baloon_boy" }], "indexOff": 0, "indexOn": 1 },
{ "animatronics": [], "indexOff": 2, "indexOn": 3 }
]
},
{
"id": 11,
"id": "cam11",
"name": "PrizeCorner",
"labelPathId": 10,
"buttonX": 929,
"buttonY": 405,
"wide": true,
"variants": [
{ "animatronics": ["puppet"], "indexOff": 0, "indexOn": 1 },
{ "animatronics": ["puppet", "TODO"], "condition": "PUPPET_POS_1_TIMEOUT", "indexOff": 0, "indexOn": 2 },
{ "animatronics": ["puppet", "TODO"], "condition": "PUPPET_POS_2_TIMEOUT", "indexOff": 0, "indexOn": 3 },
{ "animatronics": ["puppet", "TODO"], "condition": "PUPPET_POS_3_TIMEOUT", "indexOff": 0, "indexOn": 4 },
{ "animatronics": ["endo"], "indexOff": 0, "indexOn": 5 },
{ "animatronics": [{ "id": "puppet" }], "indexOff": 0, "indexOn": 1 },
{ "animatronics": [{ "id": "puppet" }, { "id": "TODO" }], "condition": "PUPPET_POS_1_TIMEOUT", "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "puppet" }, { "id": "TODO" }], "condition": "PUPPET_POS_2_TIMEOUT", "indexOff": 0, "indexOn": 3 },
{ "animatronics": [{ "id": "puppet" }, { "id": "TODO" }], "condition": "PUPPET_POS_3_TIMEOUT", "indexOff": 0, "indexOn": 4 },
{ "animatronics": [{ "id": "endo" }], "indexOff": 0, "indexOn": 5 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
},
{
"id": 12,
"id": "cam12",
"name": "KidsCove",
"labelPathId": 11,
"buttonX": 920,
"buttonY": 503,
"wide": true,
"variants": [
{ "animatronics": ["mangle"], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [{ "id": "mangle" }], "indexOff": 0, "indexOn": 2 },
{ "animatronics": [], "indexOff": 0, "indexOn": 1 }
]
}

View File

@@ -0,0 +1,60 @@
{
"config": [
{
"id": "hallway",
"officeSpriteKey": "hallway",
"hitbox": {
"x": 600,
"y": 200,
"width": 400,
"height": 300
},
"variants": [
{
"animatronics": [],
"indexOn": 0
},
{
"animatronics": [{"id": "toy_freddy", "state": 0}],
"indexOn": 2
},
{
"animatronics": [{"id": "toy_freddy", "state": 1}],
"indexOn": 4
}
]
},
{
"id": "rightVent",
"officeSpriteKey": "rightVents",
"hitbox": {
"x": 1440,
"y": 200,
"width": 80,
"height": 90
},
"variants": [
{
"animatronics": [],
"indexOn": 0
}
]
},
{
"id": "leftVent",
"officeSpriteKey": "leftVents",
"hitbox": {
"x": 100,
"y": 200,
"width": 80,
"height": 90
},
"variants": [
{
"animatronics": [],
"indexOn": 0
}
]
}
]
}

View File

@@ -1,9 +0,0 @@
package io.github.eldek0.config;
public class CameraConfigFile {
public int inCameraId;
public RangeLong wideRandomMov;
public Rect lightHitbox;
public SpritePositionData[] sprites;
public CameraConfig[] cameras;
}

View File

@@ -1,8 +0,0 @@
package io.github.eldek0.config;
public class CameraVariant {
public String[] animatronics;
public int indexOff;
public int indexOn = -1;
public String condition = null;
}

View File

@@ -0,0 +1,6 @@
package io.github.eldek0.config.animatronic;
public class AnimState {
public String id;
public int state = 0;
}

View File

@@ -3,8 +3,9 @@ package io.github.eldek0.config.animatronic;
public class AnimatronicConfig {
public String id;
public String displayName;
public int inRoom;
public int restRoom;
public String inRoom;
public int state = 0;
public String restRoom;
public String color;
public AnimatronicMovement movement;
public AttackType attackType;

View File

@@ -2,7 +2,7 @@ package io.github.eldek0.config.animatronic;
public class AnimatronicMovement {
public MovementType type;
public int[] path;
public Path[] path;
public int moveIntervalSeconds;
public boolean aiSpeedMultiplier;

View File

@@ -0,0 +1,6 @@
package io.github.eldek0.config.animatronic;
public class Path {
public String room;
public int state = 0;
}

View File

@@ -1,7 +1,7 @@
package io.github.eldek0.config;
package io.github.eldek0.config.camera;
public class CameraConfig {
public int id;
public String id;
public String name;
public int labelPathId;
public float buttonX;

View File

@@ -0,0 +1,13 @@
package io.github.eldek0.config.camera;
import io.github.eldek0.config.RangeLong;
import io.github.eldek0.config.Rect;
import io.github.eldek0.config.SpritePositionData;
public class CameraConfigFile {
public String inCameraId;
public RangeLong wideRandomMov;
public Rect lightHitbox;
public SpritePositionData[] sprites;
public CameraConfig[] cameras;
}

View File

@@ -1,4 +1,4 @@
package io.github.eldek0.config;
package io.github.eldek0.config.camera;
public enum CameraSpriteType {
BORDER,

View File

@@ -0,0 +1,10 @@
package io.github.eldek0.config.camera;
import io.github.eldek0.config.animatronic.AnimState;
public class CameraVariant {
public AnimState[] animatronics;
public int indexOff;
public int indexOn = -1;
public String condition = null;
}

View File

@@ -0,0 +1,20 @@
package io.github.eldek0.config.office;
import io.github.eldek0.config.Rect;
public class OfficeConfig {
public String id;
public Rect hitbox;
public String officeSpriteKey;
public OfficeVariant[] variants;
private boolean lightOn = true;
public boolean isLightOn() {
return lightOn;
}
public void setLightOn(boolean lightOn) {
this.lightOn = lightOn;
}
}

View File

@@ -0,0 +1,5 @@
package io.github.eldek0.config.office;
public class OfficeConfigFile {
public OfficeConfig[] config;
}

View File

@@ -0,0 +1,8 @@
package io.github.eldek0.config.office;
import io.github.eldek0.config.animatronic.AnimState;
public class OfficeVariant {
public AnimState[] animatronics;
public int indexOn;
}

View File

@@ -4,11 +4,9 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Json;
import io.github.eldek0.config.animatronic.AnimatronicConfig;
import io.github.eldek0.config.animatronic.AnimatronicManifest;
import io.github.eldek0.config.animatronic.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.*;
public class Animatronic {
private static final String MANIFEST = "data/config/animatronics.json";
@@ -66,17 +64,19 @@ public class Animatronic {
index = 0;
}
animatronic.movement.setPathIndex(index);
animatronic.inRoom = animatronic.movement.path[index];
Path path = animatronic.movement.path[index];
animatronic.inRoom = path.room;
animatronic.state = path.state;
movementsTimer[i] = 0;
}
}
}
public List<String> getAnimatronicsInLocation(int location){
List<String> list = new ArrayList<>();
public List<AnimatronicConfig> getAnimatronicsInLocation(String location){
List<AnimatronicConfig> list = new ArrayList<>();
for (AnimatronicConfig animatronic : data.values()){
if (animatronic.inRoom == location){
list.add(animatronic.id);
if (Objects.equals(animatronic.inRoom, location)){
list.add(animatronic);
}
}
return list;

View File

@@ -10,92 +10,106 @@ import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Json;
import io.github.eldek0.App;
import io.github.eldek0.config.*;
import io.github.eldek0.config.RangeLong;
import io.github.eldek0.config.SpriteConfig;
import io.github.eldek0.config.animatronic.AnimState;
import io.github.eldek0.config.animatronic.AnimatronicConfig;
import io.github.eldek0.config.camera.CameraConfig;
import io.github.eldek0.config.camera.CameraConfigFile;
import io.github.eldek0.config.camera.CameraSpriteType;
import io.github.eldek0.config.camera.CameraVariant;
import io.github.eldek0.screen.GameScene;
import io.github.eldek0.ui.SpriteLayout;
import java.util.*;
import java.util.stream.Collectors;
import static io.github.eldek0.App.assets;
public class Camera {
private static final float CAMERA_SPEED = 5f * 60f; // px/s
private static final float CAMERA_SPEED = 5f * 60f;
private static final String CONFIG = "data/config/cameras.json";
private CameraConfig[] cameraConfigs;
private final Map<String, CameraConfig> camerasById = new LinkedHashMap<>();
/** 1-based room index currently shown on the monitor. */
private int inCameraRoom;
private String inCameraRoom;
private Rectangle[] buttonScreenRects;
private final Map<String, Rectangle> buttonScreenRects = new HashMap<>();
private Rectangle lightHitbox;
// Wide-camera panning
private float[] camerasXPosition;
private int[] wideCameraMovDirection;
private long[] timerCheckpoints;
private long[] timerWaitTimeMs;
private final Map<String, Float> camerasXPosition = new HashMap<>();
private final Map<String, Integer> wideCameraMovDirection = new HashMap<>();
private final Map<String, Long> timerCheckpoints = new HashMap<>();
private final Map<String, Long> timerWaitTimeMs = new HashMap<>();
private RangeLong wideRandomMov;
private boolean[] occupiedCamera;
private final Map<String, Boolean> occupiedCamera = new HashMap<>();
private float recBlinkTimer = 0f;
private boolean recVisible = true;
SpriteLayout<CameraSpriteType> layout;
private GameScene gameScene;
private float recBlinkTimer = 0f;
private boolean recVisible = true;
private SpriteLayout<CameraSpriteType> layout;
private final GameScene gameScene;
private boolean lightOn;
public Camera(GameScene gameScene) {
this.gameScene = gameScene;
loadCameraConfig();
initializeArrays();
java.util.Random rng = new java.util.Random();
for (int i = 0; i < cameraConfigs.length; i++) {
timerWaitTimeMs[i] = wideRandomMov.min + (long) rng.nextInt((int) (wideRandomMov.max - wideRandomMov.min));
}
initializeMaps();
initButtonScreenRects();
randomizeWideTimers();
this.lightOn = false;
this.initButtonScreenRects();
}
private void initializeArrays() {
int camCount = cameraConfigs.length;
private void initializeMaps() {
camerasById.clear();
buttonScreenRects = new Rectangle[camCount];
camerasXPosition = new float[camCount];
wideCameraMovDirection = new int[camCount];
timerCheckpoints = new long[camCount];
timerWaitTimeMs = new long[camCount];
occupiedCamera = new boolean[camCount];
for (CameraConfig config : cameraConfigs) {
camerasById.put(config.id, config);
camerasXPosition.put(config.id, 0f);
wideCameraMovDirection.put(config.id, 0);
timerCheckpoints.put(config.id, 0L);
timerWaitTimeMs.put(config.id, 0L);
occupiedCamera.put(config.id, false);
}
}
private void initButtonScreenRects(){
private void randomizeWideTimers() {
Random rng = new Random();
for (CameraConfig config : cameraConfigs) {
long wait = wideRandomMov.min
+ (long) rng.nextInt((int) (wideRandomMov.max - wideRandomMov.min));
timerWaitTimeMs.put(config.id, wait);
}
}
private void initButtonScreenRects() {
Texture btnUnsel = assets.cameras.roomButtonUnselected;
for (int i = 0; i < cameraConfigs.length; i++) {
CameraConfig cameraConfig = cameraConfigs[i];
float worldY = App.SCREEN_HEIGHT - cameraConfig.buttonY - btnUnsel.getHeight();
buttonScreenRects[i] = new Rectangle(
cameraConfig.buttonX,
worldY,
btnUnsel.getWidth(),
btnUnsel.getHeight());
for (CameraConfig config : cameraConfigs) {
float worldY = App.SCREEN_HEIGHT - config.buttonY - btnUnsel.getHeight();
buttonScreenRects.put(
config.id,
new Rectangle(
config.buttonX,
worldY,
btnUnsel.getWidth(),
btnUnsel.getHeight()
)
);
}
}
public void update(float delta) {
debugUpdateCamConfig();
for (int i = 0; i < cameraConfigs.length; i++) {
if (cameraConfigs[i].wide) {
updateCameraTimer(i, delta);
for (CameraConfig config : cameraConfigs) {
if (config.wide) {
updateCameraTimer(config.id, delta);
}
}
@@ -105,11 +119,11 @@ public class Camera {
recVisible = !recVisible;
}
this.onTouchDown();
onTouchDown();
}
public void renderBackground(SpriteBatch batch) {
if (!gameScene.hud.isInsideCamera()){return;}
if (!gameScene.hud.isInsideCamera()) return;
renderCurrentRoom(batch);
}
@@ -122,9 +136,10 @@ public class Camera {
return;
}
for (int i = 0; i < cameraConfigs.length; i++) {
if (buttonScreenRects[i].contains(position)) {
inCameraRoom = cameraConfigs[i].id;
for (CameraConfig config : cameraConfigs) {
Rectangle rect = buttonScreenRects.get(config.id);
if (rect != null && rect.contains(position)) {
inCameraRoom = config.id;
lightOn = false;
return;
}
@@ -134,40 +149,65 @@ public class Camera {
}
private void renderCurrentRoom(SpriteBatch batch) {
int idx = inCameraRoom - 1;
float xOff = camerasXPosition[idx];
Texture frame;
CameraConfig currentCamera = camerasById.get(inCameraRoom);
if (currentCamera == null) return;
if (!occupiedCamera[idx]) {
List<String> animatronicsInCam = gameScene.animatronic.getAnimatronicsInLocation(idx + 1);
CameraVariant variant = null;
for (CameraVariant v : cameraConfigs[idx].variants){
System.out.println(animatronicsInCam + ", " + Arrays.toString(v.animatronics));
if (Arrays.equals(v.animatronics, animatronicsInCam.toArray())){
variant = v;
break;
}
}
if (variant == null){
return;
}
if (lightOn && variant.indexOn != -1){
frame = getFrame(inCameraRoom, variant.indexOn);
}
else {
frame = getFrame(inCameraRoom, variant.indexOff);
}
float xOff = camerasXPosition.getOrDefault(inCameraRoom, 0f);
if (frame != null) {
batch.draw(frame, xOff, 0);
}
if (occupiedCamera.getOrDefault(inCameraRoom, false)) {
return;
}
List<AnimatronicConfig> animatronicsInCam =
gameScene.animatronic.getAnimatronicsInLocation(currentCamera.id);
CameraVariant variant = findVariant(currentCamera, animatronicsInCam);
if (variant == null) return;
int frameIndex = (!lightOn || variant.indexOn == -1)
? variant.indexOff
: variant.indexOn;
Texture frame = getFrame(currentCamera.id, frameIndex);
if (frame != null) {
batch.draw(frame, xOff, 0);
}
}
private void loadCameraConfig(){
private CameraVariant findVariant(CameraConfig camera, List<AnimatronicConfig> animatronicsInCam) {
if (camera.variants == null) return null;
Set<String> inCamIds = animatronicsInCam.stream()
.filter(a -> a.inRoom.equals(camera.id))
.map(a -> a.id)
.collect(Collectors.toSet());
for (CameraVariant variant : camera.variants) {
AnimState[] expected = variant.animatronics;
if (expected.length == 0 && inCamIds.isEmpty()) {
return variant;
}
if (expected.length != inCamIds.size()) continue;
Set<String> expectedIds = Arrays.stream(expected)
.map(a -> a.id)
.collect(Collectors.toSet());
if (expectedIds.equals(inCamIds)) {
return variant;
}
}
return null;
}
private void loadCameraConfig() {
Json json = new Json();
String raw = Gdx.files.internal(CONFIG).readString();
CameraConfigFile configFile = json.fromJson(CameraConfigFile.class, raw);
this.inCameraRoom = configFile.inCameraId;
this.cameraConfigs = configFile.cameras;
this.wideRandomMov = configFile.wideRandomMov;
@@ -182,16 +222,17 @@ public class Camera {
configFile.sprites,
CameraSpriteType::valueOf
);
}
private void debugUpdateCamConfig(){
private void debugUpdateCamConfig() {
Json json = new Json();
String raw = Gdx.files.internal(CONFIG).readString();
CameraConfigFile configFile = json.fromJson(CameraConfigFile.class, raw);
for (int i = 0; i<this.cameraConfigs.length; i++){
for (int i = 0; i < this.cameraConfigs.length; i++) {
this.cameraConfigs[i].variants = configFile.cameras[i].variants;
}
this.lightHitbox = new Rectangle(
configFile.lightHitbox.x,
configFile.lightHitbox.y,
@@ -200,10 +241,11 @@ public class Camera {
);
}
private Texture getFrame(int room, int index) {
CameraConfig config = cameraConfigs[room - 1];
Texture[] textures = assets.cameras.getLocationFrames(config.name);
private Texture getFrame(String roomId, int index) {
CameraConfig config = camerasById.get(roomId);
if (config == null) return null;
Texture[] textures = assets.cameras.getLocationFrames(config.name);
if (textures == null || index < 0 || index >= textures.length) {
return null;
}
@@ -211,8 +253,10 @@ public class Camera {
return textures[index];
}
private Texture getRoomLabel(int room) {
CameraConfig config = cameraConfigs[room - 1];
private Texture getRoomLabel(String roomId) {
CameraConfig config = camerasById.get(roomId);
if (config == null) return null;
return assets.cameras.locationLabels.get(config.name);
}
@@ -228,9 +272,9 @@ public class Camera {
}
if (texture == null) continue;
if (config.type() == CameraSpriteType.REC && !recVisible) continue;
if (config.type() == CameraSpriteType.SIGNAL_INTERRUPTED && !occupiedCamera[inCameraRoom - 1]) continue;
if (config.type() == CameraSpriteType.SIGNAL_INTERRUPTED
&& !occupiedCamera.getOrDefault(inCameraRoom, false)) continue;
batch.draw(
texture,
@@ -243,37 +287,35 @@ public class Camera {
}
public void renderHitboxes(ShapeRenderer shapeRenderer) {
if (!gameScene.hud.isInsideCamera()) return;
shapeRenderer.setColor(1, 0, 0, 1);
CameraConfig config;
Rectangle rect;
for (int i = 0; i<this.buttonScreenRects.length; i++){
rect = this.buttonScreenRects[i];
config = this.cameraConfigs[i];
for (CameraConfig config : cameraConfigs) {
Rectangle rect = buttonScreenRects.get(config.id);
if (rect == null) continue;
shapeRenderer.rect(rect.x, rect.y, rect.width, rect.height);
shapeRenderer.end();
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
for (AnimatronicConfig animatronicConfig : gameScene.animatronic.getAnimatronicsData()) {
shapeRenderer.setColor(Color.valueOf(animatronicConfig.color));
if (animatronicConfig.inRoom == config.id) {
if (Objects.equals(animatronicConfig.inRoom, config.id)) {
shapeRenderer.rect(rect.x, rect.y, 10, 30);
}
else if (animatronicConfig.inRoom == -2){
} else if (Objects.equals(animatronicConfig.inRoom, "-2")) {
shapeRenderer.rect(670, 300, 10, 30);
}
else if (animatronicConfig.inRoom == -3){
} else if (Objects.equals(animatronicConfig.inRoom, "-3")) {
shapeRenderer.rect(670, 260, 10, 30);
}
}
shapeRenderer.end();
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(1, 0, 0, 1);
}
// Light hitbox
shapeRenderer.rect(lightHitbox.x, lightHitbox.y, lightHitbox.width, lightHitbox.height);
}
@@ -282,7 +324,7 @@ public class Camera {
Texture btnSel = assets.cameras.roomButtonSelected;
for (CameraConfig config : cameraConfigs) {
Texture btn = (config.id == inCameraRoom) ? btnSel : btnUnsel;
Texture btn = config.id.equals(inCameraRoom) ? btnSel : btnUnsel;
float worldY = App.SCREEN_HEIGHT - config.buttonY - btnUnsel.getHeight();
batch.draw(btn, config.buttonX, worldY);
@@ -292,41 +334,60 @@ public class Camera {
}
}
private void updateCameraTimer(int index, float delta) {
if (index < 6) return;
private void updateCameraTimer(String cameraId, float delta) {
CameraConfig config = camerasById.get(cameraId);
if (config == null || !config.wide) return;
Texture sample = getFrame(index + 1, 0);
Texture sample = getFrame(cameraId, 0);
if (sample == null) return;
float maxOffset = -(sample.getWidth() - App.SCREEN_WIDTH);
float maxOffset = -(sample.getWidth() - App.SCREEN_WIDTH);
long now = System.currentTimeMillis();
if (timerCheckpoints[index] != 0) {
if (now - timerCheckpoints[index] > timerWaitTimeMs[index]) {
timerCheckpoints[index] = 0;
long checkpoint = timerCheckpoints.getOrDefault(cameraId, 0L);
long waitTime = timerWaitTimeMs.getOrDefault(cameraId, 0L);
int direction = wideCameraMovDirection.getOrDefault(cameraId, 0);
float x = camerasXPosition.getOrDefault(cameraId, 0f);
if (checkpoint != 0L) {
if (now - checkpoint > waitTime) {
timerCheckpoints.put(cameraId, 0L);
}
return;
}
if (wideCameraMovDirection[index] == 0) {
camerasXPosition[index] -= CAMERA_SPEED * delta;
if (camerasXPosition[index] <= maxOffset) {
camerasXPosition[index] = maxOffset;
timerCheckpoints[index] = now;
wideCameraMovDirection[index] = 1;
if (direction == 0) {
x -= CAMERA_SPEED * delta;
if (x <= maxOffset) {
x = maxOffset;
timerCheckpoints.put(cameraId, now);
wideCameraMovDirection.put(cameraId, 1);
}
} else {
camerasXPosition[index] += CAMERA_SPEED * delta;
if (camerasXPosition[index] >= 0) {
camerasXPosition[index] = 0;
timerCheckpoints[index] = now;
wideCameraMovDirection[index] = 0;
x += CAMERA_SPEED * delta;
if (x >= 0) {
x = 0;
timerCheckpoints.put(cameraId, now);
wideCameraMovDirection.put(cameraId, 0);
}
}
camerasXPosition.put(cameraId, x);
}
public int getInCameraRoom() { return inCameraRoom; }
public void setInCameraRoom(int room) { this.inCameraRoom = room; }
public boolean isOccupied(int roomIndex) { return occupiedCamera[roomIndex]; }
public void setOccupied(int roomIndex, boolean v) { occupiedCamera[roomIndex] = v; }
public String getInCameraRoom() {
return inCameraRoom;
}
public void setInCameraRoom(String roomId) {
this.inCameraRoom = roomId;
}
public boolean isOccupied(String roomId) {
return occupiedCamera.getOrDefault(roomId, false);
}
public void setOccupied(String roomId, boolean value) {
occupiedCamera.put(roomId, value);
}
}

View File

@@ -7,32 +7,42 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Json;
import io.github.eldek0.App;
import io.github.eldek0.ui.HUD;
import io.github.eldek0.config.Rect;
import io.github.eldek0.config.animatronic.AnimState;
import io.github.eldek0.config.animatronic.AnimatronicConfig;
import io.github.eldek0.config.office.OfficeConfig;
import io.github.eldek0.config.office.OfficeConfigFile;
import io.github.eldek0.config.office.OfficeVariant;
import io.github.eldek0.screen.GameScene;
import java.util.List;
import static io.github.eldek0.App.assets;
public class Office {
private static final String CONFIG = "data/config/office.json";
private static final float SPEED = 600;
public static final float MAX_POS_X = assets.office.bg.getWidth() - App.SCREEN_WIDTH;
private final HUD hud;
private final GameScene gameScene;
private final ShapeRenderer shapeRenderer;
private int movement = 0;
private float positionX = 0;
private boolean rightLight = false;
private boolean leftLight = false;
private boolean hallwayLight = false;
private OfficeConfig[] officeConfig;
private Rectangle[] hitboxes;
public Office(HUD hud) {
this.hud = hud;
public Office(GameScene gameScene) {
this.gameScene = gameScene;
this.shapeRenderer = new ShapeRenderer();
this.loadOfficeConfig();
this.inputInitialization();
}
private void handleMovement(int screenX, int screenY) {
if (hud.isInsideMask() || hud.isInsideCamera()) return;
if (gameScene.hud.isInsideMask() || gameScene.hud.isInsideCamera()) return;
Vector2 worldPos = App.convertPosToWorldPos(new Vector2(screenX, screenY));
float threshold = (float) App.SCREEN_WIDTH / 2 * 0.5f;
@@ -42,6 +52,19 @@ public class Office {
else movement = 0;
}
private void loadOfficeConfig(){
Json json = new Json();
String raw = Gdx.files.internal(CONFIG).readString();
OfficeConfigFile configFile = json.fromJson(OfficeConfigFile.class, raw);
officeConfig = configFile.config;
hitboxes = new Rectangle[officeConfig.length];
for (int i = 0; i< officeConfig.length; i++){
Rect hitbox = officeConfig[i].hitbox;
hitboxes[i] = new Rectangle(hitbox.x + positionX, hitbox.y, hitbox.width, hitbox.height);
}
}
private void inputInitialization() {
Gdx.input.setInputProcessor(new InputAdapter() {
@Override
@@ -51,59 +74,48 @@ public class Office {
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
if (hud.isInsideMask() || hud.isInsideCamera()) return false;
handleMovement(screenX, screenY);
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if (gameScene.hud.isInsideMask() || gameScene.hud.isInsideCamera()) return false;
Vector2 pos = App.convertPosToWorldPos(new Vector2(screenX, screenY));
if (!getRightBounds().contains(pos)) rightLight = false;
if (!getLeftBounds().contains(pos)) leftLight = false;
if (!getHallwayBounds().contains(pos)) hallwayLight = false;
for (int i = 0; i < officeConfig.length; i++) {
Rectangle rect = hitboxes[i];
OfficeConfig config = officeConfig[i];
if (rect.contains(pos)) config.setLightOn(true);
}
return true;
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if (hud.isInsideMask() || hud.isInsideCamera()) return false;
public boolean touchDragged(int screenX, int screenY, int pointer) {
if (gameScene.hud.isInsideMask() || gameScene.hud.isInsideCamera()) return false;
handleMovement(screenX, screenY);
Vector2 pos = App.convertPosToWorldPos(new Vector2(screenX, screenY));
if (getRightBounds().contains(pos)) rightLight = true;
if (getLeftBounds().contains(pos)) leftLight = true;
if (getHallwayBounds().contains(pos)) hallwayLight = true;
return false;
for (int i = 0; i < officeConfig.length; i++) {
Rectangle rect = hitboxes[i];
OfficeConfig config = officeConfig[i];
if (!rect.contains(pos)) config.setLightOn(false);
}
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
rightLight = false;
leftLight = false;
hallwayLight = false;
for (OfficeConfig config : officeConfig) {
config.setLightOn(false);
}
return false;
}
});
}
private Rectangle getRightBounds() {
float lightHeight = App.SCREEN_HEIGHT - 340 - assets.office.rightVentButtonOff.getHeight();
return new Rectangle(1440 + positionX, lightHeight, 80, 90);
}
private Rectangle getLeftBounds() {
float lightHeight = App.SCREEN_HEIGHT - 340 - assets.office.leftVentButtonOff.getHeight();
return new Rectangle(100 + positionX, lightHeight, 80, 90);
}
private Rectangle getHallwayBounds() {
return new Rectangle(600 + positionX, 200, 400, 380);
}
public void render(SpriteBatch batch) {
renderBackground(batch);
Texture btnRight = rightLight ? assets.office.rightVentButtonOn : assets.office.rightVentButtonOff;
Texture btnLeft = leftLight ? assets.office.leftVentButtonOn : assets.office.leftVentButtonOff;
Texture btnRight = assets.office.rightVentButtonOn;
Texture btnLeft = assets.office.leftVentButtonOn;
float lightHeight = App.SCREEN_HEIGHT - 360 - btnRight.getHeight();
batch.draw(btnRight, 1440 + positionX, lightHeight);
@@ -111,29 +123,66 @@ public class Office {
}
private void renderBackground(SpriteBatch batch) {
if (rightLight) batch.draw(assets.office.rightVents[0], positionX, 0);
else if (leftLight) batch.draw(assets.office.leftVents[0], positionX, 0);
else if (hallwayLight) batch.draw(assets.office.hallway[0], positionX, 0);
else batch.draw(assets.office.bg, positionX, 0);
Texture bg = assets.office.bg;
for (OfficeConfig config : officeConfig) {
if (!config.isLightOn()) continue;
List<AnimatronicConfig> animInLocation = gameScene.animatronic
.getAnimatronicsInLocation(config.id);
if (animInLocation == null) animInLocation = List.of();
for (OfficeVariant variant : config.variants) {
AnimState[] variantList = variant.animatronics;
if (variantList.length == 0 && animInLocation.isEmpty()) {
bg = assets.resolve("office", config.officeSpriteKey, variant.indexOn);
break;
}
if (variantList.length != animInLocation.size()) continue;
boolean allMatch = true;
for (AnimState animVariant : variantList) {
boolean found = animInLocation.stream().anyMatch(a ->
a.id.equals(animVariant.id) && a.state == animVariant.state
);
if (!found) {
allMatch = false;
break;
}
}
if (allMatch) {
bg = assets.resolve("office", config.officeSpriteKey, variant.indexOn);
break;
}
}
}
batch.draw(bg, positionX, 0);
}
public void renderHitboxes(ShapeRenderer shapeRenderer) {
if (hud.isInsideMask() || hud.isInsideCamera()) return;
if (gameScene.hud.isInsideMask() || gameScene.hud.isInsideCamera()) return;
shapeRenderer.setColor(1, 0, 0, 1);
Rectangle right = getRightBounds();
Rectangle left = getLeftBounds();
Rectangle hallway = getHallwayBounds();
shapeRenderer.rect(right.x, right.y, right.width, right.height);
shapeRenderer.rect(left.x, left.y, left.width, left.height);
shapeRenderer.rect(hallway.x, hallway.y, hallway.width, hallway.height);
for (OfficeConfig config : officeConfig){
Rect hitbox = config.hitbox;
Rectangle rect = new Rectangle(hitbox.x + positionX, hitbox.y, hitbox.width, hitbox.height);
shapeRenderer.rect(rect.x, rect.y, rect.width, rect.height);
}
}
public void update(float dt) {
positionX += SPEED * movement * dt;
if (-positionX < 0) positionX = 0;
if (-positionX < 0) positionX = 0;
else if (-positionX > MAX_POS_X) positionX = -MAX_POS_X;
for (int i = 0; i < officeConfig.length; i++) {
Rect hitbox = officeConfig[i].hitbox;
hitboxes[i].setPosition(hitbox.x + positionX, hitbox.y);
}
}
public void dispose() {

View File

@@ -37,7 +37,7 @@ public class GameScene implements Screen {
this.batch = new SpriteBatch();
this.shapeRenderer = new ShapeRenderer();
this.office = new Office(this.hud);
this.office = new Office(this);
this.mask = new Mask(this.hud);
this.camera = new Camera(this);