feat: Swinging mechanic
This commit is contained in:
@@ -8,4 +8,5 @@ import lombok.Getter;
|
||||
public class PlayerConfig {
|
||||
private final double playerReach = 20;
|
||||
private final int playerMoveDistance = 3;
|
||||
private final int swingTimeMs = 500;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package cz.jzitnik.events.handlers;
|
||||
|
||||
import cz.jzitnik.annotations.EventHandler;
|
||||
import cz.jzitnik.annotations.injectors.InjectConfig;
|
||||
import cz.jzitnik.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.config.PlayerConfig;
|
||||
import cz.jzitnik.events.MouseAction;
|
||||
import cz.jzitnik.events.MouseMoveEvent;
|
||||
import cz.jzitnik.game.GameState;
|
||||
import cz.jzitnik.game.objects.GameObject;
|
||||
import cz.jzitnik.game.objects.Interactable;
|
||||
import cz.jzitnik.game.utils.Selectable;
|
||||
import cz.jzitnik.states.RenderState;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.UIClickHandlerRepository;
|
||||
@@ -15,6 +18,7 @@ import cz.jzitnik.utils.events.AbstractEventHandler;
|
||||
import cz.jzitnik.utils.events.EventManager;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@EventHandler(MouseAction.class)
|
||||
public class MouseActionEventHandler extends AbstractEventHandler<MouseAction> {
|
||||
@@ -34,6 +38,9 @@ public class MouseActionEventHandler extends AbstractEventHandler<MouseAction> {
|
||||
@InjectState
|
||||
private RenderState renderState;
|
||||
|
||||
@InjectConfig
|
||||
private PlayerConfig playerConfig;
|
||||
|
||||
@Override
|
||||
public void handle(MouseAction event) {
|
||||
if (gameState.getScreen() != null) {
|
||||
@@ -48,14 +55,22 @@ public class MouseActionEventHandler extends AbstractEventHandler<MouseAction> {
|
||||
switch (event.getActionType()) {
|
||||
case MOVE -> eventManager.emitEvent(new MouseMoveEvent(event));
|
||||
case CLICK_RELEASE -> {
|
||||
Optional<GameObject> object = gameState.getCurrentRoom().getObjects().stream().filter(GameObject::isSelected).findFirst();
|
||||
boolean clicked = uiClickHandlerRepository.handleClick(event);
|
||||
|
||||
if (object.isPresent()) {
|
||||
((Interactable) object.get()).interact(dm);
|
||||
if (clicked || gameState.getPlayer().isSwinging()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiClickHandlerRepository.handleClick(event);
|
||||
Stream<? extends Selectable> combined = Stream.concat(
|
||||
gameState.getCurrentRoom().getMobs().stream(),
|
||||
gameState.getCurrentRoom().getObjects().stream()
|
||||
);
|
||||
|
||||
Optional<? extends Selectable> object = combined.filter(Selectable::isSelected).findFirst();
|
||||
|
||||
gameState.getPlayer().swing(playerConfig.getSwingTimeMs());
|
||||
|
||||
object.ifPresent(selectable -> selectable.interact(dm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ import cz.jzitnik.game.GameState;
|
||||
import cz.jzitnik.game.Player;
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.objects.GameObject;
|
||||
import cz.jzitnik.game.utils.Renderable;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.game.utils.Selectable;
|
||||
import cz.jzitnik.states.ScreenBuffer;
|
||||
import cz.jzitnik.states.TerminalState;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
@@ -30,6 +32,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Slf4j
|
||||
@EventHandler(MouseMoveEvent.class)
|
||||
@@ -90,7 +93,10 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
|
||||
int startX = start.getX();
|
||||
int startY = start.getY();
|
||||
|
||||
Set<GameObject> selectedObjects = currentRoom.getObjects().stream().filter(gameObject -> {
|
||||
List<? extends Selectable> combinedObjects = Stream
|
||||
.concat(currentRoom.getObjects().stream(), currentRoom.getMobs().stream()).toList();
|
||||
|
||||
Set<Selectable> selectedObjects = combinedObjects.stream().filter(gameObject -> {
|
||||
if (!gameObject.isSelectable()) return false;
|
||||
BufferedImage texture = gameObject.getTexture();
|
||||
RoomCords cords = gameObject.getCords();
|
||||
@@ -122,9 +128,9 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
|
||||
relativeMouseY < cords.getY() + texture.getHeight();
|
||||
}).collect(Collectors.toSet());
|
||||
|
||||
Set<GameObject> changedObjects = new HashSet<>();
|
||||
Set<Selectable> changedObjects = new HashSet<>();
|
||||
|
||||
for (GameObject object : currentRoom.getObjects()) {
|
||||
for (Selectable object : combinedObjects) {
|
||||
boolean newValue = selectedObjects.contains(object);
|
||||
boolean changed = object.isSelected() != newValue;
|
||||
|
||||
@@ -136,7 +142,7 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
|
||||
|
||||
List<RerenderScreen.ScreenPart> parts = new ArrayList<>();
|
||||
|
||||
for (GameObject object : changedObjects) {
|
||||
for (Selectable object : changedObjects) {
|
||||
RoomCords cords = object.getCords();
|
||||
BufferedImage objectTexture = object.getTexture();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package cz.jzitnik.game;
|
||||
|
||||
import cz.jzitnik.game.objects.GameObject;
|
||||
import cz.jzitnik.game.objects.Mob;
|
||||
import cz.jzitnik.game.mobs.Mob;
|
||||
import cz.jzitnik.ui.pixels.Empty;
|
||||
import cz.jzitnik.ui.pixels.Pixel;
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -4,16 +4,38 @@ import cz.jzitnik.game.utils.RoomCords;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class Player {
|
||||
public enum PlayerRotation {
|
||||
FRONT, BACK, LEFT, RIGHT
|
||||
}
|
||||
|
||||
private final RoomCords playerCords;
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
private boolean swinging = false;
|
||||
|
||||
@Setter
|
||||
private PlayerRotation playerRotation = PlayerRotation.FRONT;
|
||||
|
||||
public void swing(int delayMs) {
|
||||
if (swinging) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Started swinging");
|
||||
swinging = true;
|
||||
|
||||
scheduler.schedule(() -> {
|
||||
swinging = false;
|
||||
log.debug("Swinging done");
|
||||
}, delayMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public enum PlayerRotation {
|
||||
FRONT, BACK, LEFT, RIGHT
|
||||
}
|
||||
}
|
||||
|
||||
33
src/main/java/cz/jzitnik/game/mobs/HittableMob.java
Normal file
33
src/main/java/cz/jzitnik/game/mobs/HittableMob.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package cz.jzitnik.game.mobs;
|
||||
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.roomtasks.RoomTask;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
@Slf4j
|
||||
public abstract class HittableMob extends Mob {
|
||||
protected int health;
|
||||
|
||||
public HittableMob(BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth) {
|
||||
super(texture, task, cords);
|
||||
health = initialHealth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interact(DependencyManager dm) {
|
||||
// TODO: Swords in hand will deal more damage, for now deal always one
|
||||
health--;
|
||||
|
||||
log.debug("Health: {}", health);
|
||||
|
||||
if (health <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// play animation
|
||||
|
||||
}
|
||||
}
|
||||
22
src/main/java/cz/jzitnik/game/mobs/Mob.java
Normal file
22
src/main/java/cz/jzitnik/game/mobs/Mob.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package cz.jzitnik.game.mobs;
|
||||
|
||||
import cz.jzitnik.game.utils.Renderable;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.game.utils.Selectable;
|
||||
import cz.jzitnik.utils.roomtasks.RoomTask;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public abstract class Mob implements Renderable, Selectable {
|
||||
private final BufferedImage texture;
|
||||
private final RoomTask task;
|
||||
private final RoomCords cords;
|
||||
|
||||
@Setter
|
||||
private boolean selected = false;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public final class Chest extends GameObject implements Interactable, UIClickHandler {
|
||||
public final class Chest extends GameObject implements UIClickHandler {
|
||||
private static final TextColor BORDER_COLOR = new TextColor.RGB(0, 0, 0);
|
||||
private static final TextColor TRANSPARENT_COLOR = new TextColor.RGB(255, 255, 255);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package cz.jzitnik.game.objects;
|
||||
|
||||
import cz.jzitnik.game.utils.Renderable;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.game.utils.Selectable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
@@ -10,7 +11,7 @@ import java.awt.image.BufferedImage;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public sealed abstract class GameObject implements Renderable permits Chest {
|
||||
public sealed abstract class GameObject implements Renderable, Selectable permits Chest {
|
||||
private final BufferedImage texture;
|
||||
private final RoomCords cords;
|
||||
private final boolean selectable;
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package cz.jzitnik.game.objects;
|
||||
|
||||
import cz.jzitnik.utils.roomtasks.RoomTask;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public abstract class Mob {
|
||||
private final RoomTask task;
|
||||
}
|
||||
12
src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java
Normal file
12
src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package cz.jzitnik.game.setup.mobs;
|
||||
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.mobs.HittableMob;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
|
||||
public class Zombie extends HittableMob {
|
||||
|
||||
public Zombie(ResourceManager resourceManager, RoomCords cords) {
|
||||
super(resourceManager.getResource(ResourceManager.Resource.CHEST), null, cords, 10);
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,11 @@ import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.items.GameItem;
|
||||
import cz.jzitnik.game.items.WoodenSword;
|
||||
import cz.jzitnik.game.objects.Chest;
|
||||
import cz.jzitnik.game.objects.Mob;
|
||||
import cz.jzitnik.game.setup.mobs.Zombie;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.states.SoundState;
|
||||
import cz.jzitnik.utils.DependencyManager;
|
||||
import cz.jzitnik.utils.StateManager;
|
||||
import cz.jzitnik.utils.roomtasks.RoomTask;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
public class MainRoom extends GameRoom {
|
||||
public MainRoom(DependencyManager dependencyManager, ResourceManager resourceManager) {
|
||||
@@ -32,13 +27,7 @@ public class MainRoom extends GameRoom {
|
||||
));
|
||||
addObject(chest);
|
||||
|
||||
SoundState soundState = dependencyManager.getDependencyOrThrow(StateManager.class).getOrThrow(SoundState.class);
|
||||
Mob testMob = new Mob(new RoomTask(
|
||||
() -> log.debug("Sound: {}", soundState.getSoundVolume()),
|
||||
1,
|
||||
TimeUnit.SECONDS
|
||||
)) {};
|
||||
|
||||
addMob(testMob);
|
||||
Zombie zombie = new Zombie(resourceManager, new RoomCords(100, 100));
|
||||
addMob(zombie);
|
||||
}
|
||||
}
|
||||
|
||||
16
src/main/java/cz/jzitnik/game/utils/Selectable.java
Normal file
16
src/main/java/cz/jzitnik/game/utils/Selectable.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package cz.jzitnik.game.utils;
|
||||
|
||||
import cz.jzitnik.game.objects.Interactable;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public interface Selectable extends Interactable {
|
||||
boolean isSelected();
|
||||
void setSelected(boolean selected);
|
||||
BufferedImage getTexture();
|
||||
RoomCords getCords();
|
||||
|
||||
default boolean isSelectable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,14 @@ import cz.jzitnik.events.handlers.FullRoomDrawHandler;
|
||||
import cz.jzitnik.game.GameRoom;
|
||||
import cz.jzitnik.game.Player;
|
||||
import cz.jzitnik.game.ResourceManager;
|
||||
import cz.jzitnik.game.mobs.Mob;
|
||||
import cz.jzitnik.game.objects.GameObject;
|
||||
import cz.jzitnik.game.utils.RoomCords;
|
||||
import cz.jzitnik.states.ScreenBuffer;
|
||||
import cz.jzitnik.ui.pixels.ColoredPixel;
|
||||
import cz.jzitnik.ui.pixels.Empty;
|
||||
import cz.jzitnik.ui.pixels.Pixel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashSet;
|
||||
@@ -80,11 +82,13 @@ public class RerenderUtils {
|
||||
}
|
||||
}
|
||||
|
||||
for (GameObject object : currentRoom.getObjects()) {
|
||||
// TODO: Remove duplicates
|
||||
for (Mob object: currentRoom.getMobs()) {
|
||||
RoomCords startObjectCords = object.getCords();
|
||||
BufferedImage texture = object.getTexture();
|
||||
RoomCords endObjectCords = new RoomCords(startObjectCords.getX() + texture.getWidth() - 1, startObjectCords.getY() + texture.getHeight() - 1);
|
||||
boolean isSelected = object.isSelected();
|
||||
|
||||
RoomCords endObjectCords = new RoomCords(startObjectCords.getX() + texture.getWidth() - 1, startObjectCords.getY() + texture.getHeight() - 1);
|
||||
if (x >= startObjectCords.getX() && x <= endObjectCords.getX() && y >= startObjectCords.getY() && y <= endObjectCords.getY()) {
|
||||
int pixel = texture.getRGB(x - startObjectCords.getX(), y - startObjectCords.getY());
|
||||
int alpha = (pixel >> 24) & 0xff;
|
||||
@@ -94,7 +98,34 @@ public class RerenderUtils {
|
||||
float factor = 1.5f; // brightness multiplier
|
||||
|
||||
if (alpha != 0) {
|
||||
if (object.isSelected()) {
|
||||
if (isSelected) {
|
||||
r = Math.min(255, (int)(r * factor));
|
||||
g = Math.min(255, (int)(g * factor));
|
||||
b = Math.min(255, (int)(b * factor));
|
||||
pixel = (alpha << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
return new PixelResult(pixel, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (GameObject object : currentRoom.getObjects()) {
|
||||
RoomCords startObjectCords = object.getCords();
|
||||
BufferedImage texture = object.getTexture();
|
||||
boolean isSelected = object.isSelected();
|
||||
|
||||
RoomCords endObjectCords = new RoomCords(startObjectCords.getX() + texture.getWidth() - 1, startObjectCords.getY() + texture.getHeight() - 1);
|
||||
if (x >= startObjectCords.getX() && x <= endObjectCords.getX() && y >= startObjectCords.getY() && y <= endObjectCords.getY()) {
|
||||
int pixel = texture.getRGB(x - startObjectCords.getX(), y - startObjectCords.getY());
|
||||
int alpha = (pixel >> 24) & 0xff;
|
||||
int r = (pixel >> 16) & 0xff;
|
||||
int g = (pixel >> 8) & 0xff;
|
||||
int b = pixel & 0xff;
|
||||
float factor = 1.5f; // brightness multiplier
|
||||
|
||||
if (alpha != 0) {
|
||||
if (isSelected) {
|
||||
r = Math.min(255, (int)(r * factor));
|
||||
g = Math.min(255, (int)(g * factor));
|
||||
b = Math.min(255, (int)(b * factor));
|
||||
|
||||
@@ -34,9 +34,9 @@ public class UIClickHandlerRepository {
|
||||
return screenPart.hashCode();
|
||||
}
|
||||
|
||||
public void handleClick(MouseAction mouseAction) {
|
||||
public boolean handleClick(MouseAction mouseAction) {
|
||||
if (!roomSpecificHandlers.containsKey(gameState.getCurrentRoom())) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<RerenderScreen.ScreenPart, UIClickHandler> handlers = roomSpecificHandlers.get(gameState.getCurrentRoom());
|
||||
@@ -48,9 +48,11 @@ public class UIClickHandlerRepository {
|
||||
|
||||
if (part.isWithin(position)) {
|
||||
uiClickHandler.handleClick(mouseAction);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removeHandlerForCurrentRoom(int screenPartHashCode, UIClickHandler uiClickHandler) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import cz.jzitnik.annotations.PostInit;
|
||||
import cz.jzitnik.annotations.injectors.InjectConfig;
|
||||
import cz.jzitnik.config.ThreadPoolConfig;
|
||||
import cz.jzitnik.game.GameRoom;
|
||||
import cz.jzitnik.game.objects.Mob;
|
||||
import cz.jzitnik.game.mobs.Mob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -54,7 +54,9 @@ public class RoomTaskScheduler {
|
||||
|
||||
for (Mob mob : currentRoom.getMobs()) {
|
||||
RoomTask task = mob.getTask();
|
||||
scheduler.scheduleAtFixedRate(task.task(), 0, task.rate(), task.rateUnit());
|
||||
if (task != null) {
|
||||
scheduler.scheduleAtFixedRate(task.task(), 0, task.rate(), task.rateUnit());
|
||||
}
|
||||
}
|
||||
|
||||
firstRun = false;
|
||||
|
||||
Reference in New Issue
Block a user