Office progress

Added vents button and hallway interactable
Corrected buttons hitboxes
This commit is contained in:
2026-03-22 16:26:53 -03:00
parent b8713898e5
commit d1d117caaf
13 changed files with 421 additions and 108 deletions

View File

@@ -14,6 +14,7 @@ public class App extends Game {
public static final GameAssetManager assets = new GameAssetManager();
public static final int SCREEN_WIDTH = 1024;
public static final int SCREEN_HEIGHT = 768;
public static final boolean DEBUG = false;
private GameScene gameScene;
public static OrthographicCamera camera;
@@ -21,6 +22,10 @@ public class App extends Game {
@Override
public void create() {
if (DEBUG) {
System.out.println("Game running on DEBUG");
}
camera = new OrthographicCamera();
viewport = new StretchViewport(SCREEN_WIDTH, SCREEN_HEIGHT, camera);
camera.position.set((float) SCREEN_WIDTH /2, (float) SCREEN_HEIGHT /2, 0);
@@ -36,6 +41,7 @@ public class App extends Game {
@Override
public void render() {
super.render();
}
@Override

View File

@@ -12,18 +12,18 @@ public class GameAssetManager {
// =========================================================
// camera_sprites[0..10] → "sprites/monitor/1.png" .. "sprites/monitor/11.png"
// monitor_button → "sprites/monitor/button.png"
private static final String MONITOR_PATH = "sprites/monitor/";
public static final String MONITOR_PATH = "sprites/monitor/";
public static final String MONITOR_BUTTON = MONITOR_PATH + "button.png";
// =========================================================
// PATHS — Office
// =========================================================
private static final String OFFICE_PATH = "sprites/office/";
private static final String OFFICE_INSIDE_PATH = OFFICE_PATH + "inside/";
private static final String OFFICE_HALLWAY_PATH = OFFICE_PATH + "hallway/";
private static final String OFFICE_RVENTS_PATH = OFFICE_PATH + "right_vents/";
private static final String OFFICE_LVENTS_PATH = OFFICE_PATH + "left_vents/";
private static final String OFFICE_UTILS_PATH = OFFICE_PATH + "utils/";
public static final String OFFICE_PATH = "sprites/office/";
public static final String OFFICE_INSIDE_PATH = OFFICE_PATH + "inside/";
public static final String OFFICE_HALLWAY_PATH = OFFICE_PATH + "hallway/";
public static final String OFFICE_RVENTS_PATH = OFFICE_PATH + "right_vents/";
public static final String OFFICE_LVENTS_PATH = OFFICE_PATH + "left_vents/";
public static final String OFFICE_UTILS_PATH = OFFICE_PATH + "utils/";
public static final String OFFICE_BG = OFFICE_PATH + "office.png";
// animatronic_offices[0..3] → inside/0.png .. inside/4.png
@@ -52,7 +52,7 @@ public class GameAssetManager {
// =========================================================
// PATHS — Mask
// =========================================================
private static final String MASK_PATH = "sprites/mask/";
public static final String MASK_PATH = "sprites/mask/";
// mask_sprites[0..9] → mask/1.png .. mask/10.png
public static final String MASK_BUTTON = MASK_PATH + "button.png";

View File

@@ -0,0 +1,11 @@
package io.github.eldek0.game;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class Camera {
public Camera(){}
public void render(SpriteBatch batch){}
public void update(float delta){}
}

View File

@@ -0,0 +1,28 @@
package io.github.eldek0.game;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import io.github.eldek0.App;
import io.github.eldek0.asset.GameAssetManager;
import io.github.eldek0.screen.GameScene;
import io.github.eldek0.ui.HUD;
import java.util.Arrays;
public class Mask {
public boolean inside;
private HUD hud;
public Mask(HUD hud){
this.hud = hud;
}
public void render(SpriteBatch batch){
inside = hud.isInsideMask();
if (inside){
batch.draw(Arrays.stream(App.assets.getFrames(GameAssetManager.MASK_PATH, 10, 10)).findFirst().get(),
0, 0);
}
}
public void update(float delta){}
}

View File

@@ -0,0 +1,178 @@
package io.github.eldek0.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.graphics.Texture;
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 io.github.eldek0.App;
import io.github.eldek0.ui.HUD;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static io.github.eldek0.App.assets;
import static io.github.eldek0.asset.GameAssetManager.*;
public class Office {
private static final float SPEED = 600;
public static final float MAX_POS_X = assets.getTexture(OFFICE_BG).getWidth() - App.SCREEN_WIDTH;
private final HUD hud;
private ShapeRenderer shapeRenderer;
private int movement = 0;
private float positionX = 0;
private boolean rightLight = false;
private boolean leftLight = false;
private boolean hallwayLight = false;
private List<Texture> rightVentFrames;
private List<Texture> leftVentFrames;
private List<Texture> hallwayFrames;
public Office(HUD hud) {
this.hud = hud;
this.shapeRenderer = new ShapeRenderer();
this.inputInitialization();
rightVentFrames = Arrays.stream(assets.getFrames(OFFICE_RVENTS_PATH, 0, 1))
.collect(Collectors.toList());
leftVentFrames = Arrays.stream(assets.getFrames(OFFICE_LVENTS_PATH, 0, 1))
.collect(Collectors.toList());
hallwayFrames = Arrays.stream(assets.getFrames(OFFICE_HALLWAY_PATH, 0, 1))
.collect(Collectors.toList());
}
private void handleMovement(int screenX, int screenY) {
if (hud.isInsideMask() || hud.isInsideCamera()) return;
Vector2 worldPos = App.convertPosToWorldPos(new Vector2(screenX, screenY));
float threshold = (float) App.SCREEN_WIDTH / 2 * 0.5f;
if (worldPos.x < threshold) movement = 1;
else if (worldPos.x > App.SCREEN_WIDTH - threshold) movement = -1;
else movement = 0;
}
private void inputInitialization(){
Gdx.input.setInputProcessor(new InputAdapter() {
@Override
public boolean mouseMoved(int screenX, int screenY) {
handleMovement(screenX, screenY);
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
if (hud.isInsideMask() || hud.isInsideCamera()) return false;
handleMovement(screenX, screenY);
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;
return true;
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if (hud.isInsideMask() || hud.isInsideCamera()) return false;
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;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
rightLight = false;
leftLight = false;
hallwayLight = false;
return false;
}
});
}
private Rectangle getRightBounds() {
Texture t = assets.getTexture(RIGHT_VENT_BUTTON_OFF);
float lightHeight = App.SCREEN_HEIGHT - 340 - t.getHeight();
return new Rectangle(1440 + positionX, lightHeight, 80, 90);
}
private Rectangle getLeftBounds() {
Texture t = assets.getTexture(LEFT_VENT_BUTTON_OFF);
float lightHeight = App.SCREEN_HEIGHT - 340 - t.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) {
this.renderBackground(batch);
Texture lightTextureRight;
if (rightLight){lightTextureRight = assets.getTexture(RIGHT_VENT_BUTTON_ON);}
else {lightTextureRight = assets.getTexture(RIGHT_VENT_BUTTON_OFF);}
Texture lightTextureLeft;
if (leftLight){lightTextureLeft = assets.getTexture(LEFT_VENT_BUTTON_ON);}
else {lightTextureLeft = assets.getTexture(LEFT_VENT_BUTTON_OFF);}
float lightHeight = App.SCREEN_HEIGHT - 360 - lightTextureRight.getHeight();
batch.draw(lightTextureRight, 1440 + positionX, lightHeight);
batch.draw(lightTextureLeft, 100 + positionX, lightHeight);
}
public void renderHitboxes(ShapeRenderer shapeRenderer) {
if (hud.isInsideMask() || 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);
}
private void renderBackground(SpriteBatch batch) {
if (rightLight) {
batch.draw(rightVentFrames.get(0),
positionX, 0);
}
else if (leftLight) {
batch.draw(leftVentFrames.get(0),
positionX, 0);
}
else if (hallwayLight) {
batch.draw(hallwayFrames.get(0),
positionX, 0);
}
else {
batch.draw(assets.getTexture(OFFICE_BG), positionX, 0);
}
}
public void update(float dt) {
positionX += (int) (SPEED * movement * dt);
if (-positionX < 0) positionX = 0;
else if (-positionX > MAX_POS_X) positionX = -MAX_POS_X;
}
public void dispose() {
shapeRenderer.dispose();
}
}

View File

@@ -1,77 +0,0 @@
package io.github.eldek0.office;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Vector2;
import io.github.eldek0.App;
import io.github.eldek0.ui.HUD;
import static io.github.eldek0.App.assets;
import static io.github.eldek0.asset.GameAssetManager.*;
public class Office {
private static final float SPEED = 600;
public static final float MAX_POS_X = assets.getTexture(OFFICE_BG).getWidth() - App.SCREEN_WIDTH;
private final SpriteBatch batch;
private final HUD hud;
private ShapeRenderer shapeRenderer;
private int movement = 0; // 0, -1 (left), 1 (right)
private float positionX = 0;
public Office(HUD hud, SpriteBatch batch) {
this.hud = hud;
this.batch = batch;
this.shapeRenderer = new ShapeRenderer();
Gdx.input.setInputProcessor(new InputAdapter() {
@Override
public boolean mouseMoved(int screenX, int screenY) {
Vector2 worldPos = App.convertPosToWorldPos(new Vector2(screenX, screenY));
float threshold = (float) App.SCREEN_WIDTH / 2 * 0.5f;
if (worldPos.x < threshold) movement = 1;
else if (worldPos.x > App.SCREEN_WIDTH - threshold) movement = -1;
else movement = 0;
return true;
}
});
}
public void render(){
batch.begin();
batch.draw(assets.getTexture(OFFICE_BG),
positionX, 0);
Texture lightTextureRight = assets.getTexture(RIGHT_VENT_BUTTON_OFF);
Texture lightTextureLeft = assets.getTexture(LEFT_VENT_BUTTON_OFF);
float lightHeight = App.SCREEN_HEIGHT - 360 - lightTextureRight.getHeight();
batch.draw(lightTextureRight,
1440 + positionX, lightHeight);
batch.draw(lightTextureLeft,
100 + positionX, lightHeight);
batch.end();
}
public void update(float dt) {
positionX += (int) (SPEED * movement * dt);
if (-positionX < 0) {
positionX = 0;
} else if (-positionX > MAX_POS_X) {
positionX = -MAX_POS_X;
}
}
public void dispose() {
batch.dispose();
shapeRenderer.dispose();
}
}

View File

@@ -1,22 +1,45 @@
package io.github.eldek0.screen;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import io.github.eldek0.App;
import io.github.eldek0.office.Office;
import io.github.eldek0.game.Mask;
import io.github.eldek0.game.Office;
import io.github.eldek0.ui.HUD;
public class GameScene implements Screen {
private static final String VERTEX_PATH = "shaders/gameplay/vertex.glsl";
private static final String FRAGMENT_PATH = "shaders/gameplay/fragment.glsl";
private ShaderProgram shader;
private final SpriteBatch batch;
private final ShapeRenderer shapeRenderer;
private final Office office;
private final HUD hud;
public final HUD hud;
private final Mask mask;
FrameBuffer frameBuffer;
public GameScene(App app) {
this.hud = new HUD(app);
this.hud = new HUD(this);
this.batch = new SpriteBatch();
this.shapeRenderer = new ShapeRenderer();
this.office = new Office(this.hud, batch);
this.office = new Office(this.hud);
this.mask = new Mask(this.hud);
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, App.SCREEN_WIDTH, App.SCREEN_HEIGHT, false);
reloadShader();
}
@Override
@@ -27,12 +50,43 @@ public class GameScene implements Screen {
@Override
public void render(float v) {
batch.setProjectionMatrix(App.camera.combined);
shapeRenderer.setProjectionMatrix(App.camera.combined);
office.update(v);
hud.update(v);
mask.update(v);
office.render();
frameBuffer.begin();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
office.render(batch);
batch.end();
frameBuffer.end();
Texture frameBufferTexture = frameBuffer.getColorBufferTexture();
frameBufferTexture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
batch.begin();
batch.setShader(shader);
batch.draw(frameBufferTexture, 0, 0, App.SCREEN_WIDTH, App.SCREEN_HEIGHT, 0, 0, 1, 1); // UV manual para flip
batch.setShader(null);
mask.render(batch);
hud.render();
batch.end();
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(1, 0, 0, 1);
office.renderHitboxes(shapeRenderer);
hud.renderHitboxes(shapeRenderer);
shapeRenderer.end();
if (Gdx.input.isKeyJustPressed(Input.Keys.F5) && App.DEBUG) {
reloadShader();
}
}
@Override
@@ -59,4 +113,21 @@ public class GameScene implements Screen {
public void dispose() {
}
public void reloadShader() {
if (shader != null) shader.dispose();
String basePath = System.getProperty("user.dir") + "/assets/";
String vert = Gdx.files.internal(basePath + VERTEX_PATH).readString();
String frag = Gdx.files.internal(basePath + FRAGMENT_PATH).readString();
shader = new ShaderProgram(vert, frag);
if (!shader.isCompiled()) {
Gdx.app.error("Shader", shader.getLog());
} else {
Gdx.app.log("Shader", "Compilado OK: " + shader.getLog());
}
System.out.println("Shader reloaded: " + shader);
}
}

View File

@@ -2,35 +2,42 @@ package io.github.eldek0.ui;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
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 io.github.eldek0.App;
public class Button {
public static float FRAME_DURATION = 0.03f;
private boolean inside = false;
private boolean beingPressed = false;
private boolean quitting = false;
private boolean entering = false;
private Texture buttonTexture;
private Rectangle bounds;
private float x, y, width, height;
private final Texture buttonTexture;
private final Rectangle bounds;
private final float x, y;
public Button(Texture sprite, float x, float y, float width, float height) {
private final Animation<Texture> animation;
private float stateTime;
public Button(Texture sprite, float x, float y, Rectangle bounds, Texture[] transitionFrames) {
this.buttonTexture = sprite;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.bounds = new Rectangle(x, y, width, height);
this.bounds = bounds;
animation = new Animation<>(FRAME_DURATION, transitionFrames);
}
public void update() {
boolean touched = Gdx.input.isTouched() || Gdx.input.isButtonPressed(0);
float touchX = Gdx.input.getX();
float touchY = Gdx.graphics.getHeight() - Gdx.input.getY();
public void update(float delta) {
Vector2 position = App.convertPosToWorldPos(new Vector2(Gdx.input.getX(), Gdx.input.getY()));
if (touched && bounds.contains(touchX, touchY)) {
if (bounds.contains(position)) {
if (!beingPressed) {
beingPressed = true;
handleButton();
@@ -38,24 +45,51 @@ public class Button {
} else {
beingPressed = false;
}
if (isInTransition()){
stateTime += delta;
}
if (animation.isAnimationFinished(stateTime)) {
entering = false;
quitting = false;
}
}
public void render(SpriteBatch batch) {
batch.draw(buttonTexture, x, y, width, height);
batch.draw(buttonTexture, x, y, buttonTexture.getWidth(), buttonTexture.getHeight());
}
public void renderHitbox(ShapeRenderer shapeRenderer) {
shapeRenderer.rect(bounds.x, bounds.y, bounds.width, bounds.height);
}
public void renderAnimation(SpriteBatch batch) {
if (isInTransition()){
Texture currentFrame = animation.getKeyFrame(stateTime);
batch.draw(currentFrame, 0, 0, App.SCREEN_WIDTH, App.SCREEN_HEIGHT);
}
}
private void handleButton() {
if (isInTransition()) return;
if (!inside) {
entering = true;
quitting = false;
inside = true;
animation.setPlayMode(Animation.PlayMode.NORMAL);
} else {
quitting = true;
entering = false;
inside = false;
animation.setPlayMode(Animation.PlayMode.REVERSED);
}
stateTime = 0f;
}
public boolean isInTransition(){return entering || quitting;}
public boolean isInside() { return inside; }
public boolean isBeingPressed() { return beingPressed; }
public boolean isQuitting() { return quitting; }

View File

@@ -1,12 +1,14 @@
package io.github.eldek0.ui;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Rectangle;
import io.github.eldek0.App;
import io.github.eldek0.asset.GameAssetManager;
public class CameraButton extends Button {
public CameraButton(float x, float y) {
super(getButtonTexture(), x, y, getButtonTexture().getWidth(), getButtonTexture().getHeight());
super(getButtonTexture(), x, y, new Rectangle(x + 10, 0, 480, getButtonTexture().getHeight() + y),
App.assets.getFrames(GameAssetManager.MONITOR_PATH, 1, 10));
}
private static Texture getButtonTexture() {

View File

@@ -1,14 +1,15 @@
package io.github.eldek0.ui;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import io.github.eldek0.App;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import io.github.eldek0.screen.GameScene;
public class HUD {
private final SpriteBatch batch;
private final MaskButton maskButton;
private final CameraButton cameraButton;
public HUD(App app) {
public HUD(GameScene gameScene) {
this.batch = new SpriteBatch();
this.maskButton = new MaskButton(20, 20);
this.cameraButton = new CameraButton(510, 20);
@@ -16,10 +17,26 @@ public class HUD {
public void render() {
batch.begin();
maskButton.renderAnimation(batch);
cameraButton.renderAnimation(batch);
maskButton.render(batch);
cameraButton.render(batch);
batch.end();
}
public void update(float delta) {}
public void renderHitboxes(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(0, 1, 0, 1);
maskButton.renderHitbox(shapeRenderer);
cameraButton.renderHitbox(shapeRenderer);
}
public void update(float delta) {
this.maskButton.update(delta);
this.cameraButton.update(delta);
}
public boolean isInsideMask(){return this.maskButton.isInside() && !this.maskButton.isInTransition();}
public boolean isInsideCamera(){return this.cameraButton.isInside() && !this.cameraButton.isInTransition();}
}

View File

@@ -1,12 +1,14 @@
package io.github.eldek0.ui;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Rectangle;
import io.github.eldek0.App;
import io.github.eldek0.asset.GameAssetManager;
public class MaskButton extends Button {
public MaskButton(float x, float y) {
super(getButtonTexture(), x, y, getButtonTexture().getWidth(), getButtonTexture().getHeight());
super(getButtonTexture(), x, y, new Rectangle(x + 10, 0, 480, getButtonTexture().getHeight() + y),
App.assets.getFrames(GameAssetManager.MASK_PATH, 1, 9)); // 10th is not an animation
}
private static Texture getButtonTexture() {