forked from jzitnik/twodcraft
feat: Implemented mouse events and block breaking
This commit is contained in:
parent
b4641c5c86
commit
a359bedd3a
@ -1,8 +1,10 @@
|
||||
package cz.jzitnik;
|
||||
|
||||
import cz.jzitnik.game.Game;
|
||||
import cz.jzitnik.game.MouseHandler;
|
||||
import cz.jzitnik.game.SpriteLoader;
|
||||
import cz.jzitnik.tui.ScreenRenderer;
|
||||
import org.jline.terminal.MouseEvent;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
|
||||
@ -11,18 +13,22 @@ import java.io.IOException;
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
// Set up terminal with JLine
|
||||
Terminal terminal = TerminalBuilder.terminal();
|
||||
terminal.enterRawMode();
|
||||
terminal.trackMouse(Terminal.MouseTracking.Any);
|
||||
|
||||
if (!terminal.hasMouseSupport()) {
|
||||
System.out.println("Error: This terminal does not support mouse.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
var spriteList = SpriteLoader.load();
|
||||
var screenRenderer = new ScreenRenderer(spriteList, terminal);
|
||||
var game = new Game();
|
||||
|
||||
final boolean[] isRunning = {true};
|
||||
MouseHandler mouseHandler = new MouseHandler(game, terminal, screenRenderer);
|
||||
|
||||
// Enable mouse tracking
|
||||
terminal.writer().print("\033[?1003h\n"); // Enable mouse move events
|
||||
terminal.writer().flush();
|
||||
final boolean[] isRunning = {true};
|
||||
|
||||
Thread inputThread = new Thread(() -> {
|
||||
try {
|
||||
@ -35,14 +41,8 @@ public class Main {
|
||||
if (key == '[') {
|
||||
key = terminal.reader().read();
|
||||
if (key == 'M') {
|
||||
int buttonCode = terminal.reader().read() - 32;
|
||||
int x = terminal.reader().read() - 32;
|
||||
int y = terminal.reader().read() - 32;
|
||||
|
||||
if (buttonCode == 0) {
|
||||
game.handleMouseClick(x, y);
|
||||
//screenRenderer.render(game.getWorld());
|
||||
}
|
||||
MouseEvent mouseEvent = terminal.readMouseEvent();
|
||||
mouseHandler.handle(mouseEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,9 +60,6 @@ public class Main {
|
||||
game.movePlayerUp(screenRenderer);
|
||||
screenRenderer.render(game.getWorld());
|
||||
break;
|
||||
case 'm':
|
||||
game.mine(screenRenderer);
|
||||
break;
|
||||
case 'q':
|
||||
System.out.println("Exiting game...");
|
||||
isRunning[0] = false;
|
||||
@ -89,8 +86,7 @@ public class Main {
|
||||
}
|
||||
|
||||
// Disable mouse tracking on exit
|
||||
terminal.writer().print("\033[?1003l\n");
|
||||
terminal.writer().flush();
|
||||
terminal.trackMouse(Terminal.MouseTracking.Off);
|
||||
|
||||
terminal.close();
|
||||
} catch (IOException e) {
|
||||
|
@ -2,6 +2,7 @@ package cz.jzitnik.game;
|
||||
|
||||
import cz.jzitnik.tui.ScreenRenderer;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -19,6 +20,7 @@ public class Game {
|
||||
}
|
||||
|
||||
Block steveBlock = new Block("steve", SpriteLoader.SPRITES.STEVE);
|
||||
world[9][0].add(new Block("grass", SpriteLoader.SPRITES.GRASS));
|
||||
player = steveBlock;
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
@ -45,7 +47,7 @@ public class Game {
|
||||
world[10][0].add(steveBlock);
|
||||
}
|
||||
|
||||
private int[] getPlayerCords() {
|
||||
public int[] getPlayerCords() {
|
||||
for (int i = 0; i < world.length; i++) {
|
||||
for (int j = 0; j < world[i].length; j++) {
|
||||
for (Block block : world[i][j]) {
|
||||
@ -148,15 +150,25 @@ public class Game {
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void mine(ScreenRenderer screenRenderer) {
|
||||
public void mine(ScreenRenderer screenRenderer, int x, int y) {
|
||||
int[] cords = getPlayerCords();
|
||||
|
||||
if (world[cords[1] + 1][cords[0]].stream().allMatch(Block::isGhost)) {
|
||||
int playerX = cords[0];
|
||||
int playerY = cords[1];
|
||||
|
||||
int distanceX = Math.abs(playerX - x);
|
||||
int distanceY = Math.abs(playerY - y);
|
||||
|
||||
if (distanceX > 5 || distanceY > 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
world[cords[1] + 1][cords[0]].clear();
|
||||
world[cords[1] + 1][cords[0]].add(new Block("air", SpriteLoader.SPRITES.AIR, true));
|
||||
if (world[y][x].stream().allMatch(Block::isGhost)) {
|
||||
return;
|
||||
}
|
||||
|
||||
world[y][x].clear();
|
||||
world[y][x].add(new Block("air", SpriteLoader.SPRITES.AIR, true));
|
||||
screenRenderer.render(world);
|
||||
|
||||
new Thread(() -> {
|
||||
@ -175,33 +187,4 @@ public class Game {
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void handleMouseClick(int mouseX, int mouseY) {
|
||||
/*int[] cords = getPlayerCords();
|
||||
if (cords == null) return;
|
||||
|
||||
int playerX = cords[0];
|
||||
int playerY = cords[1];
|
||||
int viewXRadius = 5;
|
||||
int viewUpRadius = 4;
|
||||
int viewDownRadius = 3;
|
||||
|
||||
// Convert mouse coordinates to world coordinates
|
||||
int blockX = startX + (mouseX / 50); // 50 chars wide per sprite
|
||||
int blockY = startY + (mouseY / 25); // 25 lines high per sprite
|
||||
|
||||
// Check if within bounds
|
||||
if (blockY >= startY && blockY < endY && blockX >= startX && blockX < endX) {
|
||||
List<Block> blocks = world[blockY][blockX];
|
||||
if (!blocks.isEmpty()) {
|
||||
Block topBlock = blocks.get(blocks.size() - 1); // Get topmost block
|
||||
System.out.println("Mouse clicked on block: " + topBlock.getBlockId() +
|
||||
" at World Coordinates: [" + blockX + ", " + blockY + "]");
|
||||
} else {
|
||||
System.out.println("No block at the clicked position.");
|
||||
}
|
||||
} else {
|
||||
System.out.println("Clicked outside the visible area.");
|
||||
}*/
|
||||
}
|
||||
}
|
101
src/main/java/cz/jzitnik/game/MouseHandler.java
Normal file
101
src/main/java/cz/jzitnik/game/MouseHandler.java
Normal file
@ -0,0 +1,101 @@
|
||||
package cz.jzitnik.game;
|
||||
|
||||
import cz.jzitnik.tui.ScreenMovingCalculationProvider;
|
||||
import cz.jzitnik.tui.ScreenRenderer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.jline.terminal.MouseEvent;
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class MouseHandler {
|
||||
private Game game;
|
||||
private Terminal terminal;
|
||||
private ScreenRenderer screenRenderer;
|
||||
|
||||
public void handle(MouseEvent mouseEvent) {
|
||||
if (mouseEvent.getButton() == MouseEvent.Button.Button1 && mouseEvent.getType() == MouseEvent.Type.Pressed) {
|
||||
leftClick(mouseEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouseEvent.getType() == MouseEvent.Type.Moved) {
|
||||
move(mouseEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void leftClick(MouseEvent mouseEvent) {
|
||||
int mouseX = mouseEvent.getX();
|
||||
int mouseY = mouseEvent.getY();
|
||||
|
||||
int[] cords = game.getPlayerCords();
|
||||
if (cords == null) return;
|
||||
|
||||
int playerX = cords[0];
|
||||
int playerY = cords[1];
|
||||
|
||||
int[] data = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(), terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);
|
||||
|
||||
int startX = data[0];
|
||||
int endX = data[1];
|
||||
int startY = data[2];
|
||||
int endY = data[3];
|
||||
|
||||
int blockX = startX + (mouseX / 50); // 50 chars wide per sprite
|
||||
int blockY = startY + (mouseY / 25); // 25 lines high per sprite
|
||||
|
||||
if (blockY == playerX && blockY == playerY) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (blockY >= startY && blockY < endY && blockX >= startX && blockX < endX) {
|
||||
List<Block> blocks = game.getWorld()[blockY][blockX];
|
||||
System.out.println(blockX);
|
||||
System.out.println(blockY);
|
||||
if (!blocks.isEmpty()) {
|
||||
game.mine(screenRenderer, blockX, blockY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void move(MouseEvent mouseEvent) {
|
||||
int mouseX = mouseEvent.getX();
|
||||
int mouseY = mouseEvent.getY();
|
||||
|
||||
int[] cords = game.getPlayerCords();
|
||||
if (cords == null) return;
|
||||
|
||||
int playerX = cords[0];
|
||||
int playerY = cords[1];
|
||||
|
||||
int[] data = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(), terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);
|
||||
|
||||
int startX = data[0];
|
||||
int endX = data[1];
|
||||
int startY = data[2];
|
||||
int endY = data[3];
|
||||
|
||||
int blockX = startX + (mouseX / 50); // 50 chars wide per sprite
|
||||
int blockY = startY + (mouseY / 25); // 25 lines high per sprite
|
||||
|
||||
if (blockY == playerX && blockY == playerY) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Block> blocks = game.getWorld()[blockY][blockX];
|
||||
|
||||
if (blockY >= startY && blockY < endY && blockX >= startX && blockX < endX && !blocks.stream().allMatch(block -> block.getBlockId().equals("air"))) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
list.add(blockX);
|
||||
list.add(blockY);
|
||||
screenRenderer.setSelectedBlock(Optional.of(list));
|
||||
} else {
|
||||
screenRenderer.setSelectedBlock(Optional.empty());
|
||||
}
|
||||
|
||||
screenRenderer.render(game.getWorld());
|
||||
}
|
||||
}
|
@ -1,16 +1,29 @@
|
||||
package cz.jzitnik.tui;
|
||||
|
||||
import cz.jzitnik.game.Block;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
public class ScreenRenderer {
|
||||
private SpriteList spriteList;
|
||||
private Terminal terminal;
|
||||
|
||||
public ScreenRenderer(SpriteList spriteList, Terminal terminal) {
|
||||
this.spriteList = spriteList;
|
||||
this.terminal = terminal;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private Optional<List<Integer>> selectedBlock = Optional.empty();
|
||||
|
||||
private int[] getPlayerCords(List<Block>[][] world) {
|
||||
for (int i = 0; i < world.length; i++) {
|
||||
for (int j = 0; j < world[i].length; j++) {
|
||||
@ -50,9 +63,9 @@ public class ScreenRenderer {
|
||||
if (visibleWidth % 2 != 0) {
|
||||
endX = Math.max(startX, endX - 1);
|
||||
}
|
||||
/*if (visibleHeight % 2 != 0) {
|
||||
if (visibleHeight % 2 != 0) {
|
||||
endY = Math.max(startY, endY - 1);
|
||||
}*/
|
||||
}
|
||||
|
||||
StringBuilder[] lines = new StringBuilder[(endY - startY) * 26];
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
@ -63,9 +76,36 @@ public class ScreenRenderer {
|
||||
for (int y = startY; y < endY; y++) {
|
||||
for (int x = startX; x < endX; x++) {
|
||||
List<Block> blocks = world[y][x];
|
||||
String sprite = SpriteCombiner.combineSprites(blocks.stream()
|
||||
.map(block -> spriteList.getSprite(block.getSprite()).getSprite())
|
||||
.toArray(String[]::new));
|
||||
List<String> sprites = new ArrayList<>(blocks.stream()
|
||||
.map(block -> spriteList.getSprite(block.getSprite()).getSprite()).toList());
|
||||
|
||||
if (selectedBlock.isPresent() && selectedBlock.get().get(0) == x && selectedBlock.get().get(1) == y) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
stringBuilder.append("\033[38;5;231;48;5;231m▓");
|
||||
}
|
||||
stringBuilder.append("\n");
|
||||
|
||||
for (int i = 0; i < 23; i++) {
|
||||
stringBuilder.append("\033[38;5;231;48;5;231m▓");
|
||||
for (int j = 0; j < 48; j++) {
|
||||
stringBuilder.append("\033[0m ");
|
||||
}
|
||||
stringBuilder.append("\033[38;5;231;48;5;231m▓");
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
stringBuilder.append("\033[38;5;231;48;5;231m▓");
|
||||
}
|
||||
stringBuilder.append("\n");
|
||||
|
||||
sprites.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
String sprite = SpriteCombiner.combineSprites(sprites.toArray(String[]::new));
|
||||
|
||||
|
||||
String[] spriteLines = sprite.split("\n");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user