Implement event system scaffolding

This commit is contained in:
2021-04-06 11:57:11 +02:00
parent a11773e60c
commit 898bcc809c
12 changed files with 125 additions and 72 deletions

View File

@@ -1,6 +1,7 @@
package com.bartlomiejpluta.base.api.entity; package com.bartlomiejpluta.base.api.entity;
import com.bartlomiejpluta.base.api.animation.Animated; import com.bartlomiejpluta.base.api.animation.Animated;
import com.bartlomiejpluta.base.api.event.Reactive;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.Movable; import com.bartlomiejpluta.base.api.move.Movable;
@@ -9,7 +10,7 @@ import com.bartlomiejpluta.base.internal.render.Renderable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public interface Entity extends Movable, Animated, Renderable, Updatable { public interface Entity extends Reactive, Movable, Animated, Renderable, Updatable {
Direction getFaceDirection(); Direction getFaceDirection();

View File

@@ -1,7 +0,0 @@
package com.bartlomiejpluta.base.api.entity;
import com.bartlomiejpluta.base.api.move.Movement;
public interface EntityStepInListener extends Entity {
void onEntityStepIn(Movement movement, Entity entity);
}

View File

@@ -1,7 +0,0 @@
package com.bartlomiejpluta.base.api.entity;
import com.bartlomiejpluta.base.api.move.Movement;
public interface EntityStepOutListener extends Entity {
void onEntityStepOut(Movement movement, Entity entity);
}

View File

@@ -0,0 +1,5 @@
package com.bartlomiejpluta.base.api.event;
public interface Event {
EventType<? extends Event> getType();
}

View File

@@ -0,0 +1,10 @@
package com.bartlomiejpluta.base.api.event;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
@EqualsAndHashCode
@RequiredArgsConstructor
public final class EventType<E extends Event> {
private final String type;
}

View File

@@ -0,0 +1,11 @@
package com.bartlomiejpluta.base.api.event;
import java.util.function.Consumer;
public interface Reactive {
<E extends Event> void handleEvent(E event);
<E extends Event> void addEventListener(EventType<E> type, Consumer<E> listener);
<E extends Event> void removeEventListener(EventType<E> type, Consumer<E> listener);
}

View File

@@ -1,6 +1,7 @@
package com.bartlomiejpluta.base.api.map.layer.object; package com.bartlomiejpluta.base.api.map.layer.object;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.map.layer.base.Layer; import com.bartlomiejpluta.base.api.map.layer.base.Layer;
import com.bartlomiejpluta.base.api.move.Movement; import com.bartlomiejpluta.base.api.move.Movement;
import org.joml.Vector2ic; import org.joml.Vector2ic;
@@ -24,8 +25,5 @@ public interface ObjectLayer extends Layer {
void pushMovement(Movement movement); void pushMovement(Movement movement);
// Notifiers void fireEvent(Event event);
void notifyEntityStepIn(Movement movement, Entity entity);
void notifyEntityStepOut(Movement movement, Entity entity);
} }

View File

@@ -27,7 +27,7 @@ public final class EntityMovement implements Movement {
public boolean perform() { public boolean perform() {
var result = object.move(this); var result = object.move(this);
if (result) { if (result) {
object.getLayer().notifyEntityStepOut(this, object); object.getLayer().fireEvent(new MoveEvent(MoveEvent.Action.BEGIN, object, this));
} }
return result; return result;
@@ -40,6 +40,6 @@ public final class EntityMovement implements Movement {
@Override @Override
public void onFinish() { public void onFinish() {
object.getLayer().notifyEntityStepIn(this, object); object.getLayer().fireEvent(new MoveEvent(MoveEvent.Action.END, object, this));
} }
} }

View File

@@ -0,0 +1,23 @@
package com.bartlomiejpluta.base.api.move;
import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public final class MoveEvent implements Event {
public enum Action {BEGIN, END}
private final Action action;
private final Movable movable;
private final Movement movement;
@Override
public EventType<? extends Event> getType() {
return TYPE;
}
public static EventType<MoveEvent> TYPE = new EventType<>("MOVE_EVENT");
}

View File

@@ -2,6 +2,8 @@ package com.bartlomiejpluta.base.lib.entity;
import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.EntityMovement; import com.bartlomiejpluta.base.api.move.EntityMovement;
@@ -14,6 +16,7 @@ import org.joml.Vector2fc;
import org.joml.Vector2ic; import org.joml.Vector2ic;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public abstract class EntityDelegate implements Entity { public abstract class EntityDelegate implements Entity {
protected final Entity entity; protected final Entity entity;
@@ -267,6 +270,21 @@ public abstract class EntityDelegate implements Entity {
entity.setZIndex(zIndex); entity.setZIndex(zIndex);
} }
@Override
public <E extends Event> void handleEvent(E event) {
entity.handleEvent(event);
}
@Override
public <E extends Event> void addEventListener(EventType<E> type, Consumer<E> listener) {
entity.addEventListener(type, listener);
}
@Override
public <E extends Event> void removeEventListener(EventType<E> type, Consumer<E> listener) {
entity.removeEventListener(type, listener);
}
@Override @Override
public CompletableFuture<Void> performInstantAnimation() { public CompletableFuture<Void> performInstantAnimation() {
return entity.performInstantAnimation(); return entity.performInstantAnimation();

View File

@@ -1,6 +1,8 @@
package com.bartlomiejpluta.base.engine.world.entity.model; package com.bartlomiejpluta.base.engine.world.entity.model;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.EntityMovement; import com.bartlomiejpluta.base.api.move.EntityMovement;
@@ -17,10 +19,9 @@ import org.joml.Vector2f;
import org.joml.Vector2fc; import org.joml.Vector2fc;
import org.joml.Vector2i; import org.joml.Vector2i;
import java.util.LinkedList; import java.util.*;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@@ -33,6 +34,8 @@ public class DefaultEntity extends MovableSprite implements Entity {
private final Vector2f entityScale = new Vector2f(1, 1); private final Vector2f entityScale = new Vector2f(1, 1);
private Vector2fc entitySetSize; private Vector2fc entitySetSize;
private final Map<EventType<?>, List<Consumer<? extends Event>>> listeners = new HashMap<>();
@Getter @Getter
@Setter @Setter
private int zIndex = 0; private int zIndex = 0;
@@ -233,6 +236,42 @@ public class DefaultEntity extends MovableSprite implements Entity {
return entityScale.y; return entityScale.y;
} }
@SuppressWarnings("unchecked")
@Override
public <E extends Event> void handleEvent(E event) {
var list = listeners.get(event.getType());
if (list != null) {
for (var listener : list) {
((Consumer<E>) listener).accept(event);
}
}
}
@Override
public <E extends Event> void addEventListener(EventType<E> type, Consumer<E> listener) {
var list = this.listeners.get(type);
if (list != null) {
list.add(listener);
} else {
list = new ArrayList<>();
list.add(listener);
listeners.put(type, list);
}
}
@Override
public <E extends Event> void removeEventListener(EventType<E> type, Consumer<E> listener) {
var list = this.listeners.get(type);
if (list != null) {
list.remove(listener);
if (list.isEmpty()) {
this.listeners.remove(type);
}
}
}
@Override @Override
public void update(float dt) { public void update(float dt) {
super.update(dt); super.update(dt);

View File

@@ -3,8 +3,7 @@ package com.bartlomiejpluta.base.engine.world.map.layer.object;
import com.bartlomiejpluta.base.api.ai.NPC; import com.bartlomiejpluta.base.api.ai.NPC;
import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.entity.EntityStepInListener; import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.entity.EntityStepOutListener;
import com.bartlomiejpluta.base.api.input.KeyEvent; import com.bartlomiejpluta.base.api.input.KeyEvent;
import com.bartlomiejpluta.base.api.input.KeyEventHandler; import com.bartlomiejpluta.base.api.input.KeyEventHandler;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
@@ -20,7 +19,6 @@ import org.joml.Vector2ic;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Queue; import java.util.Queue;
import static java.lang.Float.compare; import static java.lang.Float.compare;
@@ -31,10 +29,6 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve
@Getter @Getter
private final ArrayList<Entity> entities = new ArrayList<>(); private final ArrayList<Entity> entities = new ArrayList<>();
private final List<EntityStepInListener> stepInListeners = new ArrayList<>();
private final List<EntityStepOutListener> stepOutListeners = new ArrayList<>();
private final List<KeyEventHandler> keyEventHandlers = new ArrayList<>();
@Getter @Getter
private final PassageAbility[][] passageMap; private final PassageAbility[][] passageMap;
@@ -58,18 +52,6 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve
layer.entities.remove(entity); layer.entities.remove(entity);
} }
if (entity instanceof EntityStepInListener) {
stepInListeners.add((EntityStepInListener) entity);
}
if (entity instanceof EntityStepOutListener) {
stepOutListeners.add((EntityStepOutListener) entity);
}
if (entity instanceof KeyEventHandler) {
keyEventHandlers.add((KeyEventHandler) entity);
}
entity.setStepSize(stepSize.x(), stepSize.y()); entity.setStepSize(stepSize.x(), stepSize.y());
entities.add(entity); entities.add(entity);
@@ -80,18 +62,6 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve
public void removeEntity(Entity entity) { public void removeEntity(Entity entity) {
entities.remove(entity); entities.remove(entity);
if (entity instanceof EntityStepInListener) {
stepInListeners.remove(entity);
}
if (entity instanceof EntityStepOutListener) {
stepOutListeners.remove(entity);
}
if (entity instanceof KeyEventHandler) {
keyEventHandlers.remove(entity);
}
entity.onRemove(this); entity.onRemove(this);
} }
@@ -149,7 +119,6 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve
while (!movements.isEmpty()) { while (!movements.isEmpty()) {
var movement = movements.poll(); var movement = movements.poll();
var from = movement.getFrom();
var to = movement.getTo(); var to = movement.getTo();
if (isTileReachable(to)) { if (isTileReachable(to)) {
movement.perform(); movement.perform();
@@ -189,26 +158,19 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer, KeyEve
@Override @Override
public void handleKeyEvent(KeyEvent event) { public void handleKeyEvent(KeyEvent event) {
for (var handler : keyEventHandlers) {
if (event.isConsumed()) {
return;
}
handler.handleKeyEvent(event);
}
} }
@SuppressWarnings("ForLoopReplaceableByForEach")
@Override @Override
public void notifyEntityStepIn(Movement movement, Entity entity) { public void fireEvent(Event event) {
for (var listener : stepInListeners) { // Disclaimer
listener.onEntityStepIn(movement, entity); // For the sake of an easy adding and removing
} // entities from the entity.update() method inside
} // the loop, the loop itself has been implemented
// as plain old C-style for loop.
@Override for (int i = 0; i < entities.size(); ++i) {
public void notifyEntityStepOut(Movement movement, Entity entity) { entities.get(i).handleEvent(event);
for (var listener : stepOutListeners) {
listener.onEntityStepOut(movement, entity);
} }
} }
} }