feat: Rendering room
We have a room!
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -36,4 +36,6 @@ build/
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
|
||||
logs
|
||||
|
||||
11
src/main/java/cz/jzitnik/config/RoomSizeConfig.java
Normal file
11
src/main/java/cz/jzitnik/config/RoomSizeConfig.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package cz.jzitnik.config;
|
||||
|
||||
import cz.jzitnik.annotations.Config;
|
||||
import lombok.Getter;
|
||||
|
||||
@Config
|
||||
@Getter
|
||||
public class RoomSizeConfig {
|
||||
private final int roomHeight = 450;
|
||||
private final int roomWidth = 450;
|
||||
}
|
||||
6
src/main/java/cz/jzitnik/events/FullRoomDraw.java
Normal file
6
src/main/java/cz/jzitnik/events/FullRoomDraw.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package cz.jzitnik.events;
|
||||
|
||||
import cz.jzitnik.utils.events.Event;
|
||||
|
||||
public class FullRoomDraw implements Event {
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
package cz.jzitnik.events.handlers;
|
||||
|
||||
import com.googlecode.lanterna.TextCharacter;
|
||||
import com.googlecode.lanterna.TextColor;
|
||||
import com.googlecode.lanterna.graphics.TextGraphics;
|
||||
import com.googlecode.lanterna.screen.Screen;
|
||||
import cz.jzitnik.annotations.EventHandler;
|
||||
import cz.jzitnik.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.events.RerenderScreen;
|
||||
@@ -13,10 +11,12 @@ import cz.jzitnik.ui.pixels.Empty;
|
||||
import cz.jzitnik.ui.pixels.Pixel;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.events.AbstractEventHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
@EventHandler(RerenderScreen.class)
|
||||
public class CliHandler extends AbstractEventHandler<RerenderScreen> {
|
||||
@InjectState
|
||||
@@ -43,7 +43,7 @@ public class CliHandler extends AbstractEventHandler<RerenderScreen> {
|
||||
for (int y = start.getRow(); y <= end.getRow(); y++) {
|
||||
for (int x = start.getColumn(); x <= end.getColumn(); x++) {
|
||||
Pixel pixel = buffer[y][x];
|
||||
TextColor color = pixel.getClass().equals(Empty.class) ? TextColor.ANSI.BLACK : pixel.getColor();
|
||||
TextColor color = pixel.getClass().equals(Empty.class) ? new TextColor.RGB(4, 4, 16) : pixel.getColor();
|
||||
|
||||
drawPixel(tg, x, y, color);
|
||||
}
|
||||
@@ -57,8 +57,8 @@ public class CliHandler extends AbstractEventHandler<RerenderScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawPixel(TextGraphics tg, int x, int y, TextColor color) {
|
||||
private void drawPixel(TextGraphics tg, int x, int y, TextColor color) {
|
||||
tg.setForegroundColor(color);
|
||||
tg.setCharacter(x, y, '█'); // full block character
|
||||
tg.setCharacter(x, y, '█');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package cz.jzitnik.events.handlers;
|
||||
|
||||
import com.googlecode.lanterna.TerminalPosition;
|
||||
import com.googlecode.lanterna.TerminalSize;
|
||||
import com.googlecode.lanterna.TextColor;
|
||||
import com.googlecode.lanterna.screen.TerminalScreen;
|
||||
import cz.jzitnik.annotations.EventHandler;
|
||||
import cz.jzitnik.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.events.FullRoomDraw;
|
||||
import cz.jzitnik.events.RerenderScreen;
|
||||
import cz.jzitnik.game.GameState;
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.states.RenderState;
|
||||
import cz.jzitnik.states.ScreenBuffer;
|
||||
import cz.jzitnik.states.TerminalState;
|
||||
import cz.jzitnik.ui.pixels.ColoredPixel;
|
||||
import cz.jzitnik.ui.pixels.Pixel;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.events.AbstractEventHandler;
|
||||
import cz.jzitnik.utils.events.EventManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@EventHandler(FullRoomDraw.class)
|
||||
public class FullRoomDrawHandler extends AbstractEventHandler<FullRoomDraw> {
|
||||
public FullRoomDrawHandler(DependencyManager dm) {
|
||||
super(dm);
|
||||
}
|
||||
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectState
|
||||
private ScreenBuffer screenBuffer;
|
||||
|
||||
@InjectDependency
|
||||
private ResourceManager resourceManager;
|
||||
|
||||
@InjectState
|
||||
private TerminalState terminalState;
|
||||
|
||||
@InjectDependency
|
||||
private EventManager eventManager;
|
||||
|
||||
@InjectState
|
||||
private RenderState renderState;
|
||||
|
||||
@Override
|
||||
public void handle(FullRoomDraw event) {
|
||||
log.debug("Rendering full room");
|
||||
TerminalScreen terminalScreen = terminalState.getTerminalScreen();
|
||||
List<RerenderScreen.ScreenPart> partsToRerender = new ArrayList<>();
|
||||
|
||||
var buffer = screenBuffer.getBuffer();
|
||||
|
||||
BufferedImage room = resourceManager.getResource(ResourceManager.Resource.ROOM1);
|
||||
TerminalSize terminalSize = terminalScreen.getTerminalSize();
|
||||
|
||||
int terminalHeight = terminalSize.getRows();
|
||||
int terminalWidth = terminalSize.getColumns();
|
||||
|
||||
int width = room.getWidth();
|
||||
int height = room.getHeight();
|
||||
|
||||
int startX = (terminalWidth - (width * 2)) / 2;
|
||||
int startY = (terminalHeight - height) / 2;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int pixel = room.getRGB(x, y);
|
||||
int red = (pixel >> 16) & 0xff;
|
||||
int green = (pixel >> 8) & 0xff;
|
||||
int blue = pixel & 0xff;
|
||||
|
||||
Pixel pixel1 = new ColoredPixel(new TextColor.RGB(red, green, blue));
|
||||
|
||||
buffer[y + startY][x * 2 + startX] = pixel1;
|
||||
buffer[y + startY][x * 2 + 1 + startX] = pixel1;
|
||||
}
|
||||
}
|
||||
partsToRerender.add(new RerenderScreen.ScreenPart(
|
||||
new TerminalPosition(startX, startY),
|
||||
new TerminalPosition(startY + height - 1, (startX + height - 1) * 2)
|
||||
));
|
||||
|
||||
if (renderState.isFirstRender()) {
|
||||
eventManager.emitEvent(RerenderScreen.full(terminalSize));
|
||||
renderState.setFirstRender(false);
|
||||
} else {
|
||||
|
||||
eventManager.emitEvent(new RerenderScreen(partsToRerender.toArray(RerenderScreen.ScreenPart[]::new)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.googlecode.lanterna.TerminalSize;
|
||||
import cz.jzitnik.annotations.EventHandler;
|
||||
import cz.jzitnik.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.events.FullRoomDraw;
|
||||
import cz.jzitnik.events.RerenderScreen;
|
||||
import cz.jzitnik.events.TerminalResizeEvent;
|
||||
import cz.jzitnik.states.ScreenBuffer;
|
||||
@@ -12,7 +13,9 @@ import cz.jzitnik.ui.pixels.Pixel;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.events.AbstractEventHandler;
|
||||
import cz.jzitnik.utils.events.EventManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@EventHandler(TerminalResizeEvent.class)
|
||||
public class TerminalResizeEventHandler extends AbstractEventHandler<TerminalResizeEvent> {
|
||||
public TerminalResizeEventHandler(DependencyManager dm) {
|
||||
@@ -39,6 +42,6 @@ public class TerminalResizeEventHandler extends AbstractEventHandler<TerminalRes
|
||||
}
|
||||
screenBuffer.setBuffer(buffer);
|
||||
|
||||
eventManager.emitEvent(RerenderScreen.full(size));
|
||||
eventManager.emitEvent(new FullRoomDraw());
|
||||
}
|
||||
}
|
||||
|
||||
19
src/main/java/cz/jzitnik/game/GameRoom.java
Normal file
19
src/main/java/cz/jzitnik/game/GameRoom.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package cz.jzitnik.game;
|
||||
|
||||
import cz.jzitnik.game.objects.GameObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GameRoom {
|
||||
private GameRoom left;
|
||||
private GameRoom right;
|
||||
private GameRoom up;
|
||||
private GameRoom down;
|
||||
|
||||
private List<GameObject> objects;
|
||||
|
||||
public GameRoom() {
|
||||
objects = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
11
src/main/java/cz/jzitnik/game/GameState.java
Normal file
11
src/main/java/cz/jzitnik/game/GameState.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package cz.jzitnik.game;
|
||||
|
||||
import cz.jzitnik.annotations.State;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
|
||||
@State
|
||||
public class GameState {
|
||||
private GameRoom currentRoom;
|
||||
|
||||
private RoomCords playerCords;
|
||||
}
|
||||
41
src/main/java/cz/jzitnik/game/ResourceManager.java
Normal file
41
src/main/java/cz/jzitnik/game/ResourceManager.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package cz.jzitnik.game;
|
||||
|
||||
import cz.jzitnik.annotations.Dependency;
|
||||
import cz.jzitnik.annotations.injectors.InjectDependency;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Dependency
|
||||
public class ResourceManager {
|
||||
@InjectDependency
|
||||
private ClassLoader classLoader;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum Resource {
|
||||
ROOM1("rooms/1.png");
|
||||
|
||||
private final String path; // Field must be final for enum
|
||||
}
|
||||
|
||||
private HashMap<Resource, BufferedImage> resourceCache = new HashMap<>();
|
||||
|
||||
public BufferedImage getResource(Resource resource) {
|
||||
InputStream is = classLoader.getResourceAsStream("textures/" + resource.getPath());
|
||||
if (is == null) {
|
||||
throw new RuntimeException("Image not found in resources!");
|
||||
}
|
||||
|
||||
try {
|
||||
return ImageIO.read(is);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cz.jzitnik.game.exceptions;
|
||||
|
||||
public class InvalidCoordinatesException extends RuntimeException {
|
||||
public InvalidCoordinatesException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidCoordinatesException() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
4
src/main/java/cz/jzitnik/game/items/Item.java
Normal file
4
src/main/java/cz/jzitnik/game/items/Item.java
Normal file
@@ -0,0 +1,4 @@
|
||||
package cz.jzitnik.game.items;
|
||||
|
||||
public abstract class Item {
|
||||
}
|
||||
10
src/main/java/cz/jzitnik/game/objects/Chest.java
Normal file
10
src/main/java/cz/jzitnik/game/objects/Chest.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package cz.jzitnik.game.objects;
|
||||
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.ui.pixels.Pixel;
|
||||
|
||||
public final class Chest extends GameObject {
|
||||
public Chest(Pixel[][] texture, RoomCords cords) {
|
||||
super(texture, cords);
|
||||
}
|
||||
}
|
||||
14
src/main/java/cz/jzitnik/game/objects/GameObject.java
Normal file
14
src/main/java/cz/jzitnik/game/objects/GameObject.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package cz.jzitnik.game.objects;
|
||||
|
||||
import cz.jzitnik.game.utils.Renderable;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.ui.pixels.Pixel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public sealed abstract class GameObject implements Renderable permits Chest {
|
||||
private Pixel[][] texture;
|
||||
private RoomCords cords;
|
||||
}
|
||||
7
src/main/java/cz/jzitnik/game/utils/Renderable.java
Normal file
7
src/main/java/cz/jzitnik/game/utils/Renderable.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package cz.jzitnik.game.utils;
|
||||
|
||||
import cz.jzitnik.ui.pixels.Pixel;
|
||||
|
||||
public interface Renderable {
|
||||
Pixel[][] getTexture();
|
||||
}
|
||||
27
src/main/java/cz/jzitnik/game/utils/RoomCords.java
Normal file
27
src/main/java/cz/jzitnik/game/utils/RoomCords.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package cz.jzitnik.game.utils;
|
||||
|
||||
import cz.jzitnik.config.RoomSizeConfig;
|
||||
import cz.jzitnik.game.exceptions.InvalidCoordinatesException;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class RoomCords {
|
||||
private final RoomSizeConfig roomSizeConfig;
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public RoomCords(int x, int y, RoomSizeConfig roomSizeConfig) {
|
||||
this.roomSizeConfig = roomSizeConfig;
|
||||
|
||||
updateCords(x, y);
|
||||
}
|
||||
|
||||
public void updateCords(int x, int y) {
|
||||
if (x >= roomSizeConfig.getRoomWidth() || y >= roomSizeConfig.getRoomHeight()) {
|
||||
throw new InvalidCoordinatesException();
|
||||
}
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
12
src/main/java/cz/jzitnik/states/RenderState.java
Normal file
12
src/main/java/cz/jzitnik/states/RenderState.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package cz.jzitnik.states;
|
||||
|
||||
import cz.jzitnik.annotations.State;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@State
|
||||
@Getter
|
||||
@Setter
|
||||
public class RenderState {
|
||||
private boolean isFirstRender = true;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ public class EventManager extends Thread {
|
||||
try {
|
||||
handler.handle(typedEvent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
log.debug(e.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
40
src/main/resources/logback.xml
Normal file
40
src/main/resources/logback.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<configuration>
|
||||
<appender name="GENERAL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>logs/general.log</file>
|
||||
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!-- File name pattern for rolled logs -->
|
||||
<fileNamePattern>logs/general.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
|
||||
<!-- Max size before rotation -->
|
||||
<maxFileSize>3MB</maxFileSize>
|
||||
<!-- Max history (how many days to keep) -->
|
||||
<maxHistory>30</maxHistory>
|
||||
<!-- Total size cap -->
|
||||
<totalSizeCap>30MB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>ERROR</level>
|
||||
<onMatch>DENY</onMatch>
|
||||
<onMismatch>ACCEPT</onMismatch>
|
||||
</filter>
|
||||
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="ERROR_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>ERROR</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="TRACE">
|
||||
<appender-ref ref="GENERAL_FILE" />
|
||||
<appender-ref ref="ERROR_CONSOLE" />
|
||||
</root>
|
||||
</configuration>
|
||||
BIN
src/main/resources/textures/rooms/1.png
Normal file
BIN
src/main/resources/textures/rooms/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
Reference in New Issue
Block a user