Introduce Character

This commit is huge breaking change.
The Entity class has been downgraded to some generic object which can be pushed onto the ObjectLayer, whereas the former "entity" concept has been replaced with Character class.
This commit is contained in:
2022-08-22 22:49:06 +02:00
parent 439ec984a3
commit b8b51bf35d
33 changed files with 339 additions and 315 deletions

View File

@@ -1,7 +1,7 @@
package com.bartlomiejpluta.base.api.ai; package com.bartlomiejpluta.base.api.ai;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.character.Character;
public interface NPC extends Entity { public interface NPC extends Character {
AI getStrategy(); AI getStrategy();
} }

View File

@@ -0,0 +1,26 @@
package com.bartlomiejpluta.base.api.character;
import com.bartlomiejpluta.base.api.animation.Animated;
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.move.Direction;
import com.bartlomiejpluta.base.api.move.Movable;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public interface Character extends Movable, Animated, Entity {
Direction getFaceDirection();
void setFaceDirection(Direction direction);
void changeCharacterSet(String characterSetUid);
CompletableFuture<Void> performInstantAnimation();
<E extends Event> void addEventListener(EventType<E> type, Consumer<E> listener);
<E extends Event> void removeEventListener(EventType<E> type, Consumer<E> listener);
}

View File

@@ -3,7 +3,7 @@ package com.bartlomiejpluta.base.api.context;
import com.bartlomiejpluta.base.api.animation.Animation; import com.bartlomiejpluta.base.api.animation.Animation;
import com.bartlomiejpluta.base.api.audio.Sound; import com.bartlomiejpluta.base.api.audio.Sound;
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.character.Character;
import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.api.gui.GUI; import com.bartlomiejpluta.base.api.gui.GUI;
@@ -39,7 +39,7 @@ public interface Context extends Updatable, Renderable, Disposable {
void closeMap(); void closeMap();
Entity createEntity(String entitySetUid); Character createCharacter(String characterSetUid);
Animation createAnimation(String animationUid); Animation createAnimation(String animationUid);

View File

@@ -1,49 +1,23 @@
package com.bartlomiejpluta.base.api.entity; package com.bartlomiejpluta.base.api.entity;
import com.bartlomiejpluta.base.api.animation.Animated;
import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.api.event.Reactive; import com.bartlomiejpluta.base.api.event.Reactive;
import com.bartlomiejpluta.base.api.location.Locationable;
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.Movable;
import com.bartlomiejpluta.base.internal.logic.Updatable; import com.bartlomiejpluta.base.internal.logic.Updatable;
import com.bartlomiejpluta.base.internal.render.Renderable; import com.bartlomiejpluta.base.internal.render.Renderable;
import java.util.concurrent.CompletableFuture; public interface Entity extends Locationable, Renderable, Updatable, Reactive {
import java.util.function.Consumer; boolean isBlocking();
public interface Entity extends Reactive, Movable, Animated, Renderable, Updatable { void setBlocking(boolean blocking);
Direction getFaceDirection(); int getZIndex();
void setFaceDirection(Direction direction); void setZIndex(int zIndex);
int chebyshevDistance(Entity other);
int manhattanDistance(Entity other);
Direction getDirectionTowards(Entity target);
ObjectLayer getLayer(); ObjectLayer getLayer();
void onAdd(ObjectLayer layer); void onAdd(ObjectLayer layer);
void onRemove(ObjectLayer layer); void onRemove(ObjectLayer layer);
boolean isBlocking();
void setBlocking(boolean blocking);
void changeEntitySet(String entitySetUid);
int getZIndex();
void setZIndex(int zIndex);
CompletableFuture<Void> performInstantAnimation();
<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,5 +1,6 @@
package com.bartlomiejpluta.base.api.location; package com.bartlomiejpluta.base.api.location;
import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.internal.object.Placeable; import com.bartlomiejpluta.base.internal.object.Placeable;
import org.joml.Vector2fc; import org.joml.Vector2fc;
import org.joml.Vector2ic; import org.joml.Vector2ic;
@@ -19,7 +20,13 @@ public interface Locationable extends Placeable {
void setPositionOffset(float offsetX, float offsetY); void setPositionOffset(float offsetX, float offsetY);
Direction getDirectionTowards(Locationable target);
int chebyshevDistance(Vector2ic coordinates); int chebyshevDistance(Vector2ic coordinates);
int manhattanDistance(Vector2ic coordinates); int manhattanDistance(Vector2ic coordinates);
int chebyshevDistance(Locationable other);
int manhattanDistance(Locationable other);
} }

View File

@@ -1,6 +1,6 @@
package com.bartlomiejpluta.base.api.move; package com.bartlomiejpluta.base.api.move;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.character.Character;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@@ -9,13 +9,13 @@ import org.joml.Vector2ic;
@Getter @Getter
@EqualsAndHashCode @EqualsAndHashCode
public final class EntityMovement implements Movement { public final class CharacterMovement implements Movement {
private final Entity object; private final Character object;
private final Direction direction; private final Direction direction;
private final Vector2ic from; private final Vector2ic from;
private final Vector2ic to; private final Vector2ic to;
public EntityMovement(@NonNull Entity object, @NonNull Direction direction) { public CharacterMovement(@NonNull Character object, @NonNull Direction direction) {
this.object = object; this.object = object;
this.direction = direction; this.direction = direction;

View File

@@ -2,7 +2,7 @@ package com.bartlomiejpluta.base.lib.ai;
import com.bartlomiejpluta.base.api.ai.AI; import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.ai.NPC; import com.bartlomiejpluta.base.api.ai.NPC;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.location.Locationable;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.MoveEvent; import com.bartlomiejpluta.base.api.move.MoveEvent;
import com.bartlomiejpluta.base.util.path.MovementPath; import com.bartlomiejpluta.base.util.path.MovementPath;
@@ -11,7 +11,7 @@ import com.bartlomiejpluta.base.util.pathfinder.PathFinder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Setter; import lombok.Setter;
public abstract class FollowEntityAI<N extends NPC, T extends Entity> implements AI { public abstract class FollowObjectAI<N extends NPC, T extends Locationable> implements AI {
private final PathFinder finder; private final PathFinder finder;
private final PathExecutor<N> executor; private final PathExecutor<N> executor;
@@ -22,7 +22,7 @@ public abstract class FollowEntityAI<N extends NPC, T extends Entity> implements
private MovementPath<N> path = null; private MovementPath<N> path = null;
protected FollowEntityAI(@NonNull PathFinder finder, @NonNull N npc, @NonNull T target) { protected FollowObjectAI(@NonNull PathFinder finder, @NonNull N npc, @NonNull T target) {
this.finder = finder; this.finder = finder;
this.npc = npc; this.npc = npc;
this.target = target; this.target = target;
@@ -37,7 +37,7 @@ public abstract class FollowEntityAI<N extends NPC, T extends Entity> implements
var movable = event.getMovable(); var movable = event.getMovable();
// Refresh only when target has been displaced // Refresh only when target has been displaced
// or another entity is blocking current path // or another object is blocking current path
if (movable == target || (path != null && path.contains(movable))) { if (movable == target || (path != null && path.contains(movable))) {
path = null; path = null;
} }

View File

@@ -2,7 +2,7 @@ package com.bartlomiejpluta.base.lib.ai;
import com.bartlomiejpluta.base.api.ai.AI; import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.ai.NPC; import com.bartlomiejpluta.base.api.ai.NPC;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.location.Locationable;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.MoveEvent; import com.bartlomiejpluta.base.api.move.MoveEvent;
import com.bartlomiejpluta.base.util.path.MovementPath; import com.bartlomiejpluta.base.util.path.MovementPath;
@@ -15,7 +15,7 @@ import org.joml.Vector2ic;
import java.util.ArrayList; import java.util.ArrayList;
public abstract class KeepStraightDistanceAI<N extends NPC, T extends Entity> implements AI { public abstract class KeepStraightDistanceAI<N extends NPC, T extends Locationable> implements AI {
private final N npc; private final N npc;
@Setter(onParam = @__(@NonNull)) @Setter(onParam = @__(@NonNull))
private T target; private T target;
@@ -44,7 +44,7 @@ public abstract class KeepStraightDistanceAI<N extends NPC, T extends Entity> im
var movable = event.getMovable(); var movable = event.getMovable();
// Refresh only when target has been displaced // Refresh only when target has been displaced
// or another entity is blocking current path // or another object is blocking current path
if (movable == target || (path != null && path.contains(movable))) { if (movable == target || (path != null && path.contains(movable))) {
path = null; path = null;
} }

View File

@@ -2,7 +2,7 @@ package com.bartlomiejpluta.base.lib.ai;
import com.bartlomiejpluta.base.api.ai.AI; import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.ai.NPC; import com.bartlomiejpluta.base.api.ai.NPC;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.location.Locationable;
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 lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -12,7 +12,7 @@ import lombok.Setter;
import java.util.Random; import java.util.Random;
@AllArgsConstructor @AllArgsConstructor
public class RunawayAI<N extends NPC, T extends Entity> implements AI { public class RunawayAI<N extends NPC, T extends Locationable> implements AI {
@NonNull @NonNull
private final N npc; private final N npc;

View File

@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.lib.animation;
import com.bartlomiejpluta.base.api.animation.Animation; import com.bartlomiejpluta.base.api.animation.Animation;
import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.location.Locationable;
import com.bartlomiejpluta.base.api.map.layer.base.Layer; import com.bartlomiejpluta.base.api.map.layer.base.Layer;
import com.bartlomiejpluta.base.api.move.AnimationMovement; import com.bartlomiejpluta.base.api.move.AnimationMovement;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
@@ -196,6 +197,11 @@ public abstract class AnimationDelegate implements Animation {
return animation.isMoving(); return animation.isMoving();
} }
@Override
public Direction getDirectionTowards(Locationable target) {
return animation.getDirectionTowards(target);
}
@Override @Override
public int chebyshevDistance(Vector2ic coordinates) { public int chebyshevDistance(Vector2ic coordinates) {
return animation.chebyshevDistance(coordinates); return animation.chebyshevDistance(coordinates);
@@ -206,6 +212,16 @@ public abstract class AnimationDelegate implements Animation {
return animation.manhattanDistance(coordinates); return animation.manhattanDistance(coordinates);
} }
@Override
public int chebyshevDistance(Locationable other) {
return animation.chebyshevDistance(other);
}
@Override
public int manhattanDistance(Locationable other) {
return animation.manhattanDistance(other);
}
@Override @Override
public Vector2fc getPositionOffset() { public Vector2fc getPositionOffset() {
return animation.getPositionOffset(); return animation.getPositionOffset();

View File

@@ -179,7 +179,7 @@ public class BulletAnimationRunner implements AnimationRunner {
var target = getCoordinates().add(direction.vector, new Vector2i()); var target = getCoordinates().add(direction.vector, new Vector2i());
if (layer instanceof ObjectLayer) { if (layer instanceof ObjectLayer) {
for (var entity : ((ObjectLayer) layer).getEntities()) { for (var entity : ((ObjectLayer) layer).getEntities()) {
var movement = entity.getMovement(); var movement = (entity instanceof Movable) ? ((Movable) entity).getMovement() : null;
if ((entity.getCoordinates().equals(target) || movement != null && movement.getTo().equals(target)) && entity.isBlocking()) { if ((entity.getCoordinates().equals(target) || movement != null && movement.getTo().equals(target)) && entity.isBlocking()) {
onHit.accept(movable, entity); onHit.accept(movable, entity);
return; return;

View File

@@ -1,12 +1,13 @@
package com.bartlomiejpluta.base.lib.entity; package com.bartlomiejpluta.base.lib.character;
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.character.Character;
import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.api.location.Locationable;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.CharacterMovement;
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.Movement; import com.bartlomiejpluta.base.api.move.Movement;
import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.internal.object.Placeable; import com.bartlomiejpluta.base.internal.object.Placeable;
@@ -18,300 +19,300 @@ import org.joml.Vector2ic;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
public abstract class EntityDelegate implements Entity { public abstract class CharacterDelegate implements Character {
protected final Entity entity; protected final Character character;
protected EntityDelegate(Entity entity) { protected CharacterDelegate(Character character) {
this.entity = entity; this.character = character;
} }
@Override @Override
public void setStepSize(float x, float y) { public void setStepSize(float x, float y) {
entity.setStepSize(x, y); character.setStepSize(x, y);
} }
@Override @Override
public Vector2ic getCoordinates() { public Vector2ic getCoordinates() {
return entity.getCoordinates(); return character.getCoordinates();
} }
@Override @Override
public void setCoordinates(Vector2ic coordinates) { public void setCoordinates(Vector2ic coordinates) {
entity.setCoordinates(coordinates); character.setCoordinates(coordinates);
} }
@Override @Override
public void setCoordinates(int x, int y) { public void setCoordinates(int x, int y) {
entity.setCoordinates(x, y); character.setCoordinates(x, y);
} }
@Override @Override
public Movement prepareMovement(Direction direction) { public Movement prepareMovement(Direction direction) {
return new EntityMovement(this, direction); return new CharacterMovement(this, direction);
} }
@Override @Override
public Movement getMovement() { public Movement getMovement() {
return entity.getMovement(); return character.getMovement();
} }
@Override @Override
public Direction getFaceDirection() { public Direction getFaceDirection() {
return entity.getFaceDirection(); return character.getFaceDirection();
} }
@Override @Override
public void setFaceDirection(Direction direction) { public void setFaceDirection(Direction direction) {
entity.setFaceDirection(direction); character.setFaceDirection(direction);
} }
@Override @Override
public void setSpeed(float speed) { public void setSpeed(float speed) {
entity.setSpeed(speed); character.setSpeed(speed);
} }
@Override @Override
public boolean isAnimationEnabled() { public boolean isAnimationEnabled() {
return entity.isAnimationEnabled(); return character.isAnimationEnabled();
} }
@Override @Override
public void setAnimationEnabled(boolean enabled) { public void setAnimationEnabled(boolean enabled) {
entity.setAnimationEnabled(enabled); character.setAnimationEnabled(enabled);
} }
@Override @Override
public void enableAnimation() { public void enableAnimation() {
entity.enableAnimation(); character.enableAnimation();
} }
@Override @Override
public void disableAnimation() { public void disableAnimation() {
entity.disableAnimation(); character.disableAnimation();
} }
@Override @Override
public void toggleAnimationEnabled() { public void toggleAnimationEnabled() {
entity.toggleAnimationEnabled(); character.toggleAnimationEnabled();
} }
@Override @Override
public void setAnimationFrame(int frame) { public void setAnimationFrame(int frame) {
entity.setAnimationFrame(frame); character.setAnimationFrame(frame);
} }
@Override @Override
public float getAnimationSpeed() { public float getAnimationSpeed() {
return entity.getAnimationSpeed(); return character.getAnimationSpeed();
} }
@Override @Override
public void setAnimationSpeed(float speed) { public void setAnimationSpeed(float speed) {
entity.setAnimationSpeed(speed); character.setAnimationSpeed(speed);
} }
@Override @Override
public boolean isMoving() { public boolean isMoving() {
return entity.isMoving(); return character.isMoving();
} }
@Override @Override
public Vector2fc getPositionOffset() { public Vector2fc getPositionOffset() {
return entity.getPositionOffset(); return character.getPositionOffset();
} }
@Override @Override
public void setPositionOffset(Vector2fc offset) { public void setPositionOffset(Vector2fc offset) {
entity.setPositionOffset(offset); character.setPositionOffset(offset);
} }
@Override @Override
public void setPositionOffset(float offsetX, float offsetY) { public void setPositionOffset(float offsetX, float offsetY) {
entity.setPositionOffset(offsetX, offsetY); character.setPositionOffset(offsetX, offsetY);
} }
@Override @Override
public int chebyshevDistance(Entity other) { public int chebyshevDistance(Locationable other) {
return entity.chebyshevDistance(other); return character.chebyshevDistance(other);
} }
@Override @Override
public int manhattanDistance(Entity other) { public int manhattanDistance(Locationable other) {
return entity.manhattanDistance(other); return character.manhattanDistance(other);
} }
@Override @Override
public Direction getDirectionTowards(Entity target) { public Direction getDirectionTowards(Locationable target) {
return entity.getDirectionTowards(target); return character.getDirectionTowards(target);
} }
@Override @Override
public Vector2fc getPosition() { public Vector2fc getPosition() {
return entity.getPosition(); return character.getPosition();
}
@Override
public void setPosition(float x, float y) {
entity.setPosition(x, y);
} }
@Override @Override
public void setPosition(Vector2fc position) { public void setPosition(Vector2fc position) {
entity.setPosition(position); character.setPosition(position);
}
@Override
public void setPosition(float x, float y) {
character.setPosition(x, y);
} }
@Override @Override
public void movePosition(float x, float y) { public void movePosition(float x, float y) {
entity.movePosition(x, y); character.movePosition(x, y);
} }
@Override @Override
public void movePosition(Vector2fc position) { public void movePosition(Vector2fc position) {
entity.movePosition(position); character.movePosition(position);
} }
@Override @Override
public float getRotation() { public float getRotation() {
return entity.getRotation(); return character.getRotation();
} }
@Override @Override
public void setRotation(float rotation) { public void setRotation(float rotation) {
entity.setRotation(rotation); character.setRotation(rotation);
} }
@Override @Override
public void moveRotation(float rotation) { public void moveRotation(float rotation) {
entity.moveRotation(rotation); character.moveRotation(rotation);
} }
@Override @Override
public float getScaleX() { public float getScaleX() {
return entity.getScaleX(); return character.getScaleX();
} }
@Override @Override
public void setScaleX(float scale) { public void setScaleX(float scale) {
entity.setScaleX(scale); character.setScaleX(scale);
} }
@Override @Override
public float getScaleY() { public float getScaleY() {
return entity.getScaleY(); return character.getScaleY();
} }
@Override @Override
public void setScaleY(float scale) { public void setScaleY(float scale) {
entity.setScaleY(scale); character.setScaleY(scale);
} }
@Override @Override
public void setScale(float scale) { public void setScale(float scale) {
entity.setScale(scale); character.setScale(scale);
} }
@Override @Override
public void setScale(float scaleX, float scaleY) { public void setScale(float scaleX, float scaleY) {
entity.setScale(scaleX, scaleY); character.setScale(scaleX, scaleY);
} }
@Override @Override
public float euclideanDistance(Placeable other) { public float euclideanDistance(Placeable other) {
return entity.euclideanDistance(other); return character.euclideanDistance(other);
} }
@Override @Override
public int chebyshevDistance(Vector2ic coordinates) { public int chebyshevDistance(Vector2ic coordinates) {
return entity.chebyshevDistance(coordinates); return character.chebyshevDistance(coordinates);
} }
@Override @Override
public int manhattanDistance(Vector2ic coordinates) { public int manhattanDistance(Vector2ic coordinates) {
return entity.manhattanDistance(coordinates); return character.manhattanDistance(coordinates);
} }
@Override @Override
public Matrix4fc getModelMatrix() { public Matrix4fc getModelMatrix() {
return entity.getModelMatrix(); return character.getModelMatrix();
} }
@Override @Override
public ObjectLayer getLayer() { public ObjectLayer getLayer() {
return entity.getLayer(); return character.getLayer();
} }
@Override @Override
public void onAdd(ObjectLayer layer) { public void onAdd(ObjectLayer layer) {
entity.onAdd(layer); character.onAdd(layer);
} }
@Override @Override
public void onRemove(ObjectLayer layer) { public void onRemove(ObjectLayer layer) {
entity.onRemove(layer); character.onRemove(layer);
} }
@Override @Override
public boolean isBlocking() { public boolean isBlocking() {
return entity.isBlocking(); return character.isBlocking();
} }
@Override @Override
public void setBlocking(boolean blocking) { public void setBlocking(boolean blocking) {
entity.setBlocking(blocking); character.setBlocking(blocking);
} }
@Override @Override
public void changeEntitySet(String entitySetUid) { public void changeCharacterSet(String characterSetUid) {
entity.changeEntitySet(entitySetUid); character.changeCharacterSet(characterSetUid);
} }
@Override @Override
public int getZIndex() { public int getZIndex() {
return entity.getZIndex(); return character.getZIndex();
} }
@Override @Override
public void setZIndex(int zIndex) { public void setZIndex(int zIndex) {
entity.setZIndex(zIndex); character.setZIndex(zIndex);
} }
@Override @Override
public <E extends Event> void handleEvent(E event) { public <E extends Event> void handleEvent(E event) {
entity.handleEvent(event); character.handleEvent(event);
} }
@Override @Override
public <E extends Event> void addEventListener(EventType<E> type, Consumer<E> listener) { public <E extends Event> void addEventListener(EventType<E> type, Consumer<E> listener) {
entity.addEventListener(type, listener); character.addEventListener(type, listener);
} }
@Override @Override
public <E extends Event> void removeEventListener(EventType<E> type, Consumer<E> listener) { public <E extends Event> void removeEventListener(EventType<E> type, Consumer<E> listener) {
entity.removeEventListener(type, listener); character.removeEventListener(type, listener);
} }
@Override @Override
public CompletableFuture<Void> performInstantAnimation() { public CompletableFuture<Void> performInstantAnimation() {
return entity.performInstantAnimation(); return character.performInstantAnimation();
} }
@Override @Override
public boolean move(Movement movement) { public boolean move(Movement movement) {
return entity.move(movement); return character.move(movement);
} }
@Override @Override
public void abortMove() { public void abortMove() {
entity.abortMove(); character.abortMove();
} }
@Override @Override
public void update(float dt) { public void update(float dt) {
entity.update(dt); character.update(dt);
} }
@Override @Override
public void render(Screen screen, Camera camera, ShaderManager shaderManager) { public void render(Screen screen, Camera camera, ShaderManager shaderManager) {
entity.render(screen, camera, shaderManager); character.render(screen, camera, shaderManager);
} }
} }

View File

@@ -1,53 +1,53 @@
package com.bartlomiejpluta.base.util.path; package com.bartlomiejpluta.base.util.path;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import lombok.Getter; import lombok.Getter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class EntityPath<T extends Entity> implements Path<T> { public class CharacterPath<T extends Character> implements Path<T> {
@Getter @Getter
private final List<PathSegment<T>> path = new ArrayList<>(); private final List<PathSegment<T>> path = new ArrayList<>();
public EntityPath<T> add(PathSegment<T> segment) { public CharacterPath<T> add(PathSegment<T> segment) {
path.add(segment); path.add(segment);
return this; return this;
} }
public EntityPath<T> addFirst(PathSegment<T> segment) { public CharacterPath<T> addFirst(PathSegment<T> segment) {
path.add(0, segment); path.add(0, segment);
return this; return this;
} }
public EntityPath<T> move(Direction direction) { public CharacterPath<T> move(Direction direction) {
path.add(new MoveSegment<>(direction)); path.add(new MoveSegment<>(direction));
return this; return this;
} }
public EntityPath<T> move(Direction direction, boolean ignore) { public CharacterPath<T> move(Direction direction, boolean ignore) {
path.add(new MoveSegment<>(direction, ignore)); path.add(new MoveSegment<>(direction, ignore));
return this; return this;
} }
public EntityPath<T> turn(Direction direction) { public CharacterPath<T> turn(Direction direction) {
path.add(new TurnSegment<>(direction)); path.add(new TurnSegment<>(direction));
return this; return this;
} }
public EntityPath<T> turn(Direction direction, int newAnimationFrame) { public CharacterPath<T> turn(Direction direction, int newAnimationFrame) {
path.add(new TurnSegment<>(direction, newAnimationFrame)); path.add(new TurnSegment<>(direction, newAnimationFrame));
return this; return this;
} }
public EntityPath<T> wait(float seconds) { public CharacterPath<T> wait(float seconds) {
path.add(new WaitSegment<>(seconds)); path.add(new WaitSegment<>(seconds));
return this; return this;
} }
public EntityPath<T> run(Runnable runnable) { public CharacterPath<T> run(Runnable runnable) {
path.add(new RunSegment<>(runnable)); path.add(new RunSegment<>(runnable));
return this; return this;
} }

View File

@@ -1,13 +1,11 @@
package com.bartlomiejpluta.base.util.path; package com.bartlomiejpluta.base.util.path;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.character.Character;
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 lombok.NonNull; import lombok.NonNull;
import static java.util.Objects.requireNonNull; public class TurnSegment<T extends Character> implements PathSegment<T> {
public class TurnSegment<T extends Entity> implements PathSegment<T> {
private final Direction direction; private final Direction direction;
private final Integer newAnimationFrame; private final Integer newAnimationFrame;
@@ -22,10 +20,10 @@ public class TurnSegment<T extends Entity> implements PathSegment<T> {
} }
@Override @Override
public PathProgress perform(T entity, ObjectLayer layer, float dt) { public PathProgress perform(T character, ObjectLayer layer, float dt) {
entity.setFaceDirection(direction); character.setFaceDirection(direction);
if (newAnimationFrame != null) { if (newAnimationFrame != null) {
entity.setAnimationFrame(newAnimationFrame); character.setAnimationFrame(newAnimationFrame);
} }
return PathProgress.SEGMENT_DONE; return PathProgress.SEGMENT_DONE;
} }

View File

@@ -1,8 +1,8 @@
package com.bartlomiejpluta.base.util.world; package com.bartlomiejpluta.base.util.world;
import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.context.Context; import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType; 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;
@@ -22,11 +22,11 @@ import java.util.Random;
import java.util.function.Supplier; import java.util.function.Supplier;
public class EntitySpawner implements Updatable { public class CharacterSpawner implements Updatable {
private static final int MAX_REPOSITION_ATTEMPTS = 10; private static final int MAX_REPOSITION_ATTEMPTS = 10;
private final Random random = new Random(); private final Random random = new Random();
private final List<Entity> spawnedEntities = new LinkedList<>(); private final List<Character> spawnedEntities = new LinkedList<>();
private final List<Supplier<Entity>> spawners = new ArrayList<>(); private final List<Supplier<Character>> spawners = new ArrayList<>();
private final Vector2ic origin; private final Vector2ic origin;
private final Context context; private final Context context;
private final Camera camera; private final Camera camera;
@@ -36,12 +36,12 @@ public class EntitySpawner implements Updatable {
private int range = 4; private int range = 4;
private float spawnChance = 50; private float spawnChance = 50;
private DiceRoller countRoller = DiceRoller.of("1d4"); private DiceRoller countRoller = DiceRoller.of("1d4");
private EventType<? extends Event> entityRemoveEvent; private EventType<? extends Event> characterRemoveEvent;
private float accumulator = 10000f; private float accumulator = 10000f;
private boolean spawnOutsideViewport = false; private boolean spawnOutsideViewport = false;
private float threshold; private float threshold;
public EntitySpawner(int x, int y, @NonNull Context context, @NonNull GameMap map, @NonNull ObjectLayer layer) { public CharacterSpawner(int x, int y, @NonNull Context context, @NonNull GameMap map, @NonNull ObjectLayer layer) {
this.origin = new Vector2i(x, y); this.origin = new Vector2i(x, y);
this.context = context; this.context = context;
this.camera = context.getCamera(); this.camera = context.getCamera();
@@ -50,43 +50,43 @@ public class EntitySpawner implements Updatable {
drawThreshold(); drawThreshold();
} }
public EntitySpawner interval(@NonNull String interval) { public CharacterSpawner interval(@NonNull String interval) {
this.interval = DiceRoller.of(interval); this.interval = DiceRoller.of(interval);
drawThreshold(); drawThreshold();
return this; return this;
} }
public EntitySpawner range(int range) { public CharacterSpawner range(int range) {
this.range = range; this.range = range;
return this; return this;
} }
public EntitySpawner spawnChance(float change) { public CharacterSpawner spawnChance(float change) {
this.spawnChance = change; this.spawnChance = change;
return this; return this;
} }
public EntitySpawner count(String dices) { public CharacterSpawner count(String dices) {
this.countRoller = DiceRoller.of(dices); this.countRoller = DiceRoller.of(dices);
return this; return this;
} }
public EntitySpawner trackEntities(@NonNull EventType<? extends Event> entityRemoveEvent) { public CharacterSpawner trackEntities(@NonNull EventType<? extends Event> characterRemoveEvent) {
this.entityRemoveEvent = entityRemoveEvent; this.characterRemoveEvent = characterRemoveEvent;
return this; return this;
} }
public EntitySpawner spawnOutsideViewport() { public CharacterSpawner spawnOutsideViewport() {
this.spawnOutsideViewport = true; this.spawnOutsideViewport = true;
return this; return this;
} }
public EntitySpawner spawnOnCreate() { public CharacterSpawner spawnOnCreate() {
this.threshold = 0; this.threshold = 0;
return this; return this;
} }
public EntitySpawner spawn(@NonNull Supplier<Entity> spawner) { public CharacterSpawner spawn(@NonNull Supplier<Character> spawner) {
this.spawners.add(spawner); this.spawners.add(spawner);
return this; return this;
} }
@@ -151,19 +151,19 @@ public class EntitySpawner implements Updatable {
break; break;
} }
// Draw the entity spawner // Draw the character spawner
var spawner = spawners.get(random.nextInt(spawners.size())); var spawner = spawners.get(random.nextInt(spawners.size()));
// Create the entity and push it onto the map layer // Create the character and push it onto the map layer
var entity = spawner.get(); var character = spawner.get();
entity.setCoordinates(coordinates); character.setCoordinates(coordinates);
layer.addEntity(entity); layer.addEntity(character);
// If we want to keep the number of spawned entities per spawner almost constant // If we want to keep the number of spawned entities per spawner almost constant
// we need to know when the entity should be removed (i.e. it has been killed by player). // we need to know when the character should be removed (i.e. it has been killed by player).
if (entityRemoveEvent != null) { if (characterRemoveEvent != null) {
spawnedEntities.add(entity); spawnedEntities.add(character);
entity.addEventListener(entityRemoveEvent, e -> spawnedEntities.remove(entity)); character.addEventListener(characterRemoveEvent, e -> spawnedEntities.remove(character));
} }
} }
} }

View File

@@ -14,8 +14,8 @@ import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
import com.bartlomiejpluta.base.engine.project.serial.ProjectDeserializer; import com.bartlomiejpluta.base.engine.project.serial.ProjectDeserializer;
import com.bartlomiejpluta.base.engine.util.reflection.ClassLoader; import com.bartlomiejpluta.base.engine.util.reflection.ClassLoader;
import com.bartlomiejpluta.base.engine.world.animation.manager.AnimationManager; import com.bartlomiejpluta.base.engine.world.animation.manager.AnimationManager;
import com.bartlomiejpluta.base.engine.world.entity.manager.EntityManager; import com.bartlomiejpluta.base.engine.world.character.manager.CharacterManager;
import com.bartlomiejpluta.base.engine.world.entity.manager.EntitySetManager; import com.bartlomiejpluta.base.engine.world.character.manager.CharacterSetManager;
import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager; import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager;
import com.bartlomiejpluta.base.engine.world.map.manager.MapManager; import com.bartlomiejpluta.base.engine.world.map.manager.MapManager;
import com.bartlomiejpluta.base.engine.world.tileset.manager.TileSetManager; import com.bartlomiejpluta.base.engine.world.tileset.manager.TileSetManager;
@@ -35,9 +35,9 @@ public class DefaultContextManager implements ContextManager {
private final TileSetManager tileSetManager; private final TileSetManager tileSetManager;
private final MapManager mapManager; private final MapManager mapManager;
private final ImageManager imageManager; private final ImageManager imageManager;
private final EntitySetManager entitySetManager; private final CharacterSetManager characterSetManager;
private final FontManager fontManager; private final FontManager fontManager;
private final EntityManager entityManager; private final CharacterManager characterManager;
private final AnimationManager animationManager; private final AnimationManager animationManager;
private final ClassLoader classLoader; private final ClassLoader classLoader;
private final Inflater inflater; private final Inflater inflater;
@@ -56,7 +56,7 @@ public class DefaultContextManager implements ContextManager {
project.getTileSetAssets().forEach(tileSetManager::registerAsset); project.getTileSetAssets().forEach(tileSetManager::registerAsset);
project.getMapAssets().forEach(mapManager::registerAsset); project.getMapAssets().forEach(mapManager::registerAsset);
project.getImageAssets().forEach(imageManager::registerAsset); project.getImageAssets().forEach(imageManager::registerAsset);
project.getEntitySetAssets().forEach(entitySetManager::registerAsset); project.getCharacterSetAssets().forEach(characterSetManager::registerAsset);
project.getAnimationAssets().forEach(animationManager::registerAsset); project.getAnimationAssets().forEach(animationManager::registerAsset);
project.getFontAssets().forEach(fontManager::registerAsset); project.getFontAssets().forEach(fontManager::registerAsset);
project.getWidgetDefinitionAssets().forEach(widgetDefinitionManager::registerAsset); project.getWidgetDefinitionAssets().forEach(widgetDefinitionManager::registerAsset);
@@ -69,7 +69,7 @@ public class DefaultContextManager implements ContextManager {
log.info("Building context up"); log.info("Building context up");
var context = DefaultContext.builder() var context = DefaultContext.builder()
.engine(engine) .engine(engine)
.entityManager(entityManager) .characterManager(characterManager)
.animationManager(animationManager) .animationManager(animationManager)
.imageManager(imageManager) .imageManager(imageManager)
.mapManager(mapManager) .mapManager(mapManager)

View File

@@ -3,9 +3,9 @@ package com.bartlomiejpluta.base.engine.context.model;
import com.bartlomiejpluta.base.api.animation.Animation; import com.bartlomiejpluta.base.api.animation.Animation;
import com.bartlomiejpluta.base.api.audio.Sound; import com.bartlomiejpluta.base.api.audio.Sound;
import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.context.Context; import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.context.GamePauseEvent; import com.bartlomiejpluta.base.api.context.GamePauseEvent;
import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.api.gui.GUI; import com.bartlomiejpluta.base.api.gui.GUI;
@@ -22,7 +22,7 @@ import com.bartlomiejpluta.base.engine.gui.manager.WidgetDefinitionManager;
import com.bartlomiejpluta.base.engine.gui.render.NanoVGGUI; import com.bartlomiejpluta.base.engine.gui.render.NanoVGGUI;
import com.bartlomiejpluta.base.engine.gui.xml.inflater.Inflater; import com.bartlomiejpluta.base.engine.gui.xml.inflater.Inflater;
import com.bartlomiejpluta.base.engine.world.animation.manager.AnimationManager; import com.bartlomiejpluta.base.engine.world.animation.manager.AnimationManager;
import com.bartlomiejpluta.base.engine.world.entity.manager.EntityManager; import com.bartlomiejpluta.base.engine.world.character.manager.CharacterManager;
import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager; import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager;
import com.bartlomiejpluta.base.engine.world.map.manager.MapManager; import com.bartlomiejpluta.base.engine.world.map.manager.MapManager;
import com.bartlomiejpluta.base.engine.world.map.model.DefaultGameMap; import com.bartlomiejpluta.base.engine.world.map.model.DefaultGameMap;
@@ -50,7 +50,7 @@ public class DefaultContext implements Context {
private final GameEngine engine; private final GameEngine engine;
@NonNull @NonNull
private final EntityManager entityManager; private final CharacterManager characterManager;
@NonNull @NonNull
private final AnimationManager animationManager; private final AnimationManager animationManager;
@@ -146,9 +146,9 @@ public class DefaultContext implements Context {
} }
@Override @Override
public Entity createEntity(String entitySetUid) { public Character createCharacter(String characterSetUid) {
log.info("Creating new entity with UID: [{}]", entitySetUid); log.info("Creating new character with UID: [{}]", characterSetUid);
return entityManager.createEntity(entitySetUid); return characterManager.createCharacter(characterSetUid);
} }
@Override @Override

View File

@@ -4,7 +4,7 @@ import com.bartlomiejpluta.base.engine.audio.asset.SoundAsset;
import com.bartlomiejpluta.base.engine.gui.asset.FontAsset; import com.bartlomiejpluta.base.engine.gui.asset.FontAsset;
import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset; import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset;
import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset; import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset;
import com.bartlomiejpluta.base.engine.world.entity.asset.EntitySetAsset; import com.bartlomiejpluta.base.engine.world.character.asset.CharacterSetAsset;
import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset; import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset;
import com.bartlomiejpluta.base.engine.world.map.asset.GameMapAsset; import com.bartlomiejpluta.base.engine.world.map.asset.GameMapAsset;
import com.bartlomiejpluta.base.engine.world.tileset.asset.TileSetAsset; import com.bartlomiejpluta.base.engine.world.tileset.asset.TileSetAsset;
@@ -34,7 +34,7 @@ public class Project {
private final List<ImageAsset> imageAssets; private final List<ImageAsset> imageAssets;
@NonNull @NonNull
private final List<EntitySetAsset> entitySetAssets; private final List<CharacterSetAsset> characterSetAssets;
@NonNull @NonNull
private final List<AnimationAsset> animationAssets; private final List<AnimationAsset> animationAssets;

View File

@@ -5,7 +5,7 @@ import com.bartlomiejpluta.base.engine.gui.asset.FontAsset;
import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset; import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset;
import com.bartlomiejpluta.base.engine.project.model.Project; import com.bartlomiejpluta.base.engine.project.model.Project;
import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset; import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset;
import com.bartlomiejpluta.base.engine.world.entity.asset.EntitySetAsset; import com.bartlomiejpluta.base.engine.world.character.asset.CharacterSetAsset;
import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset; import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset;
import com.bartlomiejpluta.base.engine.world.map.asset.GameMapAsset; import com.bartlomiejpluta.base.engine.world.map.asset.GameMapAsset;
import com.bartlomiejpluta.base.engine.world.tileset.asset.TileSetAsset; import com.bartlomiejpluta.base.engine.world.tileset.asset.TileSetAsset;
@@ -29,7 +29,7 @@ public class ProtobufProjectDeserializer extends ProjectDeserializer {
.tileSetAssets(proto.getTileSetsList().stream().map(this::parseTileSetAsset).collect(toList())) .tileSetAssets(proto.getTileSetsList().stream().map(this::parseTileSetAsset).collect(toList()))
.mapAssets(proto.getMapsList().stream().map(this::parseGameMapAsset).collect(toList())) .mapAssets(proto.getMapsList().stream().map(this::parseGameMapAsset).collect(toList()))
.imageAssets(proto.getImagesList().stream().map(this::parseImageAsset).collect(toList())) .imageAssets(proto.getImagesList().stream().map(this::parseImageAsset).collect(toList()))
.entitySetAssets(proto.getEntitySetsList().stream().map(this::parseEntitySetAsset).collect(toList())) .characterSetAssets(proto.getEntitySetsList().stream().map(this::parseEntitySetAsset).collect(toList()))
.animationAssets(proto.getAnimationsList().stream().map(this::parseAnimationAsset).collect(toList())) .animationAssets(proto.getAnimationsList().stream().map(this::parseAnimationAsset).collect(toList()))
.fontAssets(proto.getFontsList().stream().map(this::parseFontAsset).collect(toList())) .fontAssets(proto.getFontsList().stream().map(this::parseFontAsset).collect(toList()))
.widgetDefinitionAssets(proto.getWidgetsList().stream().map(this::parseWidgetAsset).collect(toList())) .widgetDefinitionAssets(proto.getWidgetsList().stream().map(this::parseWidgetAsset).collect(toList()))
@@ -49,8 +49,8 @@ public class ProtobufProjectDeserializer extends ProjectDeserializer {
return new ImageAsset(proto.getUid(), proto.getSource()); return new ImageAsset(proto.getUid(), proto.getSource());
} }
private EntitySetAsset parseEntitySetAsset(ProjectProto.EntitySetAsset proto) { private CharacterSetAsset parseEntitySetAsset(ProjectProto.EntitySetAsset proto) {
return new EntitySetAsset(proto.getUid(), proto.getSource(), proto.getRows(), proto.getColumns()); return new CharacterSetAsset(proto.getUid(), proto.getSource(), proto.getRows(), proto.getColumns());
} }
private FontAsset parseFontAsset(ProjectProto.FontAsset proto) { private FontAsset parseFontAsset(ProjectProto.FontAsset proto) {

View File

@@ -46,7 +46,7 @@ public class DefaultAnimationManager implements AnimationManager {
var asset = assets.get(uid); var asset = assets.get(uid);
if (asset == null) { if (asset == null) {
throw new AppException("The entity set asset with UID: [%s] does not exist", uid); throw new AppException("The animation asset with UID: [%s] does not exist", uid);
} }
var animationFrames = frames.computeIfAbsent(asset.framesSignature(), var animationFrames = frames.computeIfAbsent(asset.framesSignature(),

View File

@@ -1,15 +1,15 @@
package com.bartlomiejpluta.base.engine.world.entity.asset; package com.bartlomiejpluta.base.engine.world.character.asset;
import com.bartlomiejpluta.base.engine.common.asset.Asset; import com.bartlomiejpluta.base.engine.common.asset.Asset;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@Getter @Getter
public class EntitySetAsset extends Asset { public class CharacterSetAsset extends Asset {
private final int rows; private final int rows;
private final int columns; private final int columns;
public EntitySetAsset(@NonNull String uid, @NonNull String source, int rows, int columns) { public CharacterSetAsset(@NonNull String uid, @NonNull String source, int rows, int columns) {
super(uid, source); super(uid, source);
this.rows = rows; this.rows = rows;
this.columns = columns; this.columns = columns;

View File

@@ -1,4 +1,4 @@
package com.bartlomiejpluta.base.engine.world.entity.config; package com.bartlomiejpluta.base.engine.world.character.config;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import lombok.Data; import lombok.Data;
@@ -9,8 +9,8 @@ import java.util.Map;
@Data @Data
@Configuration @Configuration
@ConfigurationProperties(prefix = "app.sprite.entity") @ConfigurationProperties(prefix = "app.sprite.character")
public class EntitySpriteConfiguration { public class CharacterSpriteConfiguration {
private int defaultSpriteColumn; private int defaultSpriteColumn;
private Map<Direction, Integer> spriteDirectionRows; private Map<Direction, Integer> spriteDirectionRows;
} }

View File

@@ -0,0 +1,9 @@
package com.bartlomiejpluta.base.engine.world.character.manager;
import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.engine.common.init.Initializable;
import com.bartlomiejpluta.base.internal.gc.Cleanable;
public interface CharacterManager extends Initializable, Cleanable {
Character createCharacter(String characterSetUid);
}

View File

@@ -0,0 +1,8 @@
package com.bartlomiejpluta.base.engine.world.character.manager;
import com.bartlomiejpluta.base.engine.common.manager.AssetManager;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.world.character.asset.CharacterSetAsset;
public interface CharacterSetManager extends AssetManager<CharacterSetAsset, Material> {
}

View File

@@ -1,11 +1,11 @@
package com.bartlomiejpluta.base.engine.world.entity.manager; package com.bartlomiejpluta.base.engine.world.character.manager;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh; import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.util.mesh.MeshManager; import com.bartlomiejpluta.base.engine.util.mesh.MeshManager;
import com.bartlomiejpluta.base.engine.world.entity.config.EntitySpriteConfiguration; import com.bartlomiejpluta.base.engine.world.character.config.CharacterSpriteConfiguration;
import com.bartlomiejpluta.base.engine.world.entity.model.DefaultEntity; import com.bartlomiejpluta.base.engine.world.character.model.DefaultCharacter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.joml.Vector2f; import org.joml.Vector2f;
import org.joml.Vector2fc; import org.joml.Vector2fc;
@@ -19,9 +19,9 @@ import static java.util.stream.Collectors.toUnmodifiableMap;
@Slf4j @Slf4j
@Component @Component
public class DefaultEntityManager implements EntityManager { public class DefaultCharacterManager implements CharacterManager {
private final MeshManager meshManager; private final MeshManager meshManager;
private final EntitySetManager entitySetManager; private final CharacterSetManager characterSetManager;
private final int defaultSpriteColumn; private final int defaultSpriteColumn;
private final Map<Direction, Integer> spriteDirectionRows; private final Map<Direction, Integer> spriteDirectionRows;
@@ -30,9 +30,9 @@ public class DefaultEntityManager implements EntityManager {
private Mesh mesh; private Mesh mesh;
@Autowired @Autowired
public DefaultEntityManager(MeshManager meshManager, EntitySetManager entitySetManager, EntitySpriteConfiguration configuration) { public DefaultCharacterManager(MeshManager meshManager, CharacterSetManager characterSetManager, CharacterSpriteConfiguration configuration) {
this.meshManager = meshManager; this.meshManager = meshManager;
this.entitySetManager = entitySetManager; this.characterSetManager = characterSetManager;
this.spriteDirectionRows = configuration.getSpriteDirectionRows(); this.spriteDirectionRows = configuration.getSpriteDirectionRows();
@@ -49,8 +49,8 @@ public class DefaultEntityManager implements EntityManager {
} }
@Override @Override
public Entity createEntity(String entitySetUid) { public Character createCharacter(String characterSetUid) {
return new DefaultEntity(mesh, entitySetManager, defaultSpriteColumn, spriteDirectionRows, spriteDefaultRows, entitySetUid); return new DefaultCharacter(mesh, characterSetManager, defaultSpriteColumn, spriteDirectionRows, spriteDefaultRows, characterSetUid);
} }
@Override @Override

View File

@@ -1,10 +1,10 @@
package com.bartlomiejpluta.base.engine.world.entity.manager; package com.bartlomiejpluta.base.engine.world.character.manager;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager; import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration; import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
import com.bartlomiejpluta.base.engine.world.entity.asset.EntitySetAsset; import com.bartlomiejpluta.base.engine.world.character.asset.CharacterSetAsset;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -16,14 +16,14 @@ import java.util.Map;
@Slf4j @Slf4j
@Component @Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) @RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DefaultEntitySetManager implements EntitySetManager { public class DefaultCharacterSetManager implements CharacterSetManager {
private final TextureManager textureManager; private final TextureManager textureManager;
private final Map<String, EntitySetAsset> assets = new HashMap<>(); private final Map<String, CharacterSetAsset> assets = new HashMap<>();
private final ProjectConfiguration configuration; private final ProjectConfiguration configuration;
@Override @Override
public void registerAsset(EntitySetAsset asset) { public void registerAsset(CharacterSetAsset asset) {
log.info("Registering [{}] entity set asset under UID: [{}]", asset.getSource(), asset.getUid()); log.info("Registering [{}] character set asset under UID: [{}]", asset.getSource(), asset.getUid());
assets.put(asset.getUid(), asset); assets.put(asset.getUid(), asset);
} }
@@ -32,7 +32,7 @@ public class DefaultEntitySetManager implements EntitySetManager {
var asset = assets.get(uid); var asset = assets.get(uid);
if (asset == null) { if (asset == null) {
throw new AppException("The entity set asset with UID: [%s] does not exist", uid); throw new AppException("The character set asset with UID: [%s] does not exist", uid);
} }
var source = configuration.projectFile("entsets", asset.getSource()); var source = configuration.projectFile("entsets", asset.getSource());

View File

@@ -1,13 +1,13 @@
package com.bartlomiejpluta.base.engine.world.entity.model; package com.bartlomiejpluta.base.engine.world.character.model;
import lombok.Getter; import lombok.Getter;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class EntityInstantAnimation { public class CharacterInstantAnimation {
public enum State {RUNNING, COMPLETED} public enum State {RUNNING, COMPLETED}
private final DefaultEntity entity; private final DefaultCharacter character;
private final int firstFrame; private final int firstFrame;
private final int lastFrame; private final int lastFrame;
@@ -16,19 +16,19 @@ public class EntityInstantAnimation {
@Getter @Getter
private final CompletableFuture<Void> future = new CompletableFuture<>(); private final CompletableFuture<Void> future = new CompletableFuture<>();
EntityInstantAnimation(DefaultEntity entity, int firstFrame) { CharacterInstantAnimation(DefaultCharacter character, int firstFrame) {
this.entity = entity; this.character = character;
this.firstFrame = firstFrame; this.firstFrame = firstFrame;
this.lastFrame = entity.getMaterial().getTexture().getColumns() - 1; this.lastFrame = character.getMaterial().getTexture().getColumns() - 1;
} }
public State update() { public State update() {
if (!finished && entity.currentFrame() == lastFrame) { if (!finished && character.currentFrame() == lastFrame) {
finished = true; finished = true;
return State.RUNNING; return State.RUNNING;
} }
if (finished && entity.currentFrame() == firstFrame) { if (finished && character.currentFrame() == firstFrame) {
future.complete(null); future.complete(null);
return State.COMPLETED; return State.COMPLETED;

View File

@@ -1,16 +1,16 @@
package com.bartlomiejpluta.base.engine.world.entity.model; package com.bartlomiejpluta.base.engine.world.character.model;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType; 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.CharacterMovement;
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.Movement; import com.bartlomiejpluta.base.api.move.Movement;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh; import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.world.entity.manager.EntitySetManager; import com.bartlomiejpluta.base.engine.world.character.manager.CharacterSetManager;
import com.bartlomiejpluta.base.engine.world.movement.MovableSprite; import com.bartlomiejpluta.base.engine.world.movement.MovableSprite;
import com.bartlomiejpluta.base.lib.event.EventHandler; import com.bartlomiejpluta.base.lib.event.EventHandler;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@@ -18,7 +18,6 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.joml.Vector2f; import org.joml.Vector2f;
import org.joml.Vector2fc; import org.joml.Vector2fc;
import org.joml.Vector2i;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map; import java.util.Map;
@@ -29,9 +28,9 @@ import java.util.function.Consumer;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class DefaultEntity extends MovableSprite implements Entity { public class DefaultCharacter extends MovableSprite implements Character {
private final int defaultSpriteColumn; private final int defaultSpriteColumn;
private final EntitySetManager entitySetManager; private final CharacterSetManager characterSetManager;
private final Map<Direction, Integer> spriteDirectionRows; private final Map<Direction, Integer> spriteDirectionRows;
private final Map<Direction, Vector2fc> spriteDefaultRows; private final Map<Direction, Vector2fc> spriteDefaultRows;
private final Vector2f entityScale = new Vector2f(1, 1); private final Vector2f entityScale = new Vector2f(1, 1);
@@ -55,12 +54,12 @@ public class DefaultEntity extends MovableSprite implements Entity {
private boolean animationEnabled = true; private boolean animationEnabled = true;
private final Queue<EntityInstantAnimation> instantAnimations = new LinkedList<>(); private final Queue<CharacterInstantAnimation> instantAnimations = new LinkedList<>();
public DefaultEntity(Mesh mesh, EntitySetManager entitySetManager, int defaultSpriteColumn, Map<Direction, Integer> spriteDirectionRows, Map<Direction, Vector2fc> spriteDefaultRows, String entitySetUid) { public DefaultCharacter(Mesh mesh, CharacterSetManager characterSetManager, int defaultSpriteColumn, Map<Direction, Integer> spriteDirectionRows, Map<Direction, Vector2fc> spriteDefaultRows, String entitySetUid) {
super(mesh, createMaterial(entitySetManager, entitySetUid)); super(mesh, createMaterial(characterSetManager, entitySetUid));
this.defaultSpriteColumn = defaultSpriteColumn; this.defaultSpriteColumn = defaultSpriteColumn;
this.entitySetManager = entitySetManager; this.characterSetManager = characterSetManager;
this.spriteDirectionRows = spriteDirectionRows; this.spriteDirectionRows = spriteDirectionRows;
this.faceDirection = Direction.DOWN; this.faceDirection = Direction.DOWN;
this.spriteDefaultRows = spriteDefaultRows; this.spriteDefaultRows = spriteDefaultRows;
@@ -72,17 +71,8 @@ public class DefaultEntity extends MovableSprite implements Entity {
} }
} }
@Override private static Material createMaterial(CharacterSetManager characterSetManager, String entitySetUid) {
public void changeEntitySet(String entitySetUid) { return entitySetUid != null ? characterSetManager.loadObject(requireNonNull(entitySetUid)) : Material.colored(0, 0, 0, 0);
this.material = createMaterial(entitySetManager, entitySetUid);
var texture = this.material.getTexture();
if (texture != null) {
this.entitySetSize = texture.getSpriteSize();
super.setScale(entitySetSize.x() * entityScale.x, entitySetSize.y() * entityScale.y);
} else {
this.entitySetSize = null;
}
} }
@Override @Override
@@ -134,16 +124,24 @@ public class DefaultEntity extends MovableSprite implements Entity {
} }
@Override @Override
public CompletableFuture<Void> performInstantAnimation() { public void changeCharacterSet(String entitySetUid) {
var animation = new EntityInstantAnimation(this, defaultSpriteColumn); this.material = createMaterial(characterSetManager, entitySetUid);
instantAnimations.add(animation); var texture = this.material.getTexture();
return animation.getFuture(); if (texture != null) {
this.entitySetSize = texture.getSpriteSize();
super.setScale(entitySetSize.x() * entityScale.x, entitySetSize.y() * entityScale.y);
} else {
this.entitySetSize = null;
}
} }
@Override @Override
public Movement prepareMovement(Direction direction) { public CompletableFuture<Void> performInstantAnimation() {
return new EntityMovement(this, direction); var animation = new CharacterInstantAnimation(this, defaultSpriteColumn);
instantAnimations.add(animation);
return animation.getFuture();
} }
@Override @Override
@@ -162,21 +160,6 @@ public class DefaultEntity extends MovableSprite implements Entity {
setDefaultAnimationFrame(); setDefaultAnimationFrame();
} }
@Override
public int chebyshevDistance(Entity other) {
return chebyshevDistance(other.getCoordinates());
}
@Override
public int manhattanDistance(Entity other) {
return manhattanDistance(other.getCoordinates());
}
@Override
public Direction getDirectionTowards(Entity target) {
return Direction.ofVector(target.getCoordinates().sub(getCoordinates(), new Vector2i()));
}
@Override @Override
public void onAdd(ObjectLayer layer) { public void onAdd(ObjectLayer layer) {
this.layer = layer; this.layer = layer;
@@ -187,10 +170,15 @@ public class DefaultEntity extends MovableSprite implements Entity {
this.layer = null; this.layer = null;
} }
@Override
public Movement prepareMovement(Direction direction) {
return new CharacterMovement(this, direction);
}
@Override @Override
public void setScaleX(float scaleX) { public void setScaleX(float scaleX) {
if (entitySetSize == null) { if (entitySetSize == null) {
throw new AppException("Cannot change Entity scale if no Entity Set is provided"); throw new AppException("Cannot change Character scale if no Character Set is provided");
} }
this.entityScale.x = scaleX; this.entityScale.x = scaleX;
@@ -200,7 +188,7 @@ public class DefaultEntity extends MovableSprite implements Entity {
@Override @Override
public void setScaleY(float scaleY) { public void setScaleY(float scaleY) {
if (entitySetSize == null) { if (entitySetSize == null) {
throw new AppException("Cannot change Entity scale if no Entity Set is provided"); throw new AppException("Cannot change Character scale if no Character Set is provided");
} }
this.entityScale.y = scaleY; this.entityScale.y = scaleY;
@@ -210,7 +198,7 @@ public class DefaultEntity extends MovableSprite implements Entity {
@Override @Override
public void setScale(float scale) { public void setScale(float scale) {
if (entitySetSize == null) { if (entitySetSize == null) {
throw new AppException("Cannot change Entity scale if no Entity Set is provided"); throw new AppException("Cannot change Character scale if no Character Set is provided");
} }
this.entityScale.x = scale; this.entityScale.x = scale;
@@ -218,17 +206,6 @@ public class DefaultEntity extends MovableSprite implements Entity {
super.setScale(entitySetSize.x() * scale, entitySetSize.y() * scale); super.setScale(entitySetSize.x() * scale, entitySetSize.y() * scale);
} }
@Override
public void setScale(float scaleX, float scaleY) {
if (entitySetSize == null) {
throw new AppException("Cannot change Entity scale if no Entity Set is provided");
}
this.entityScale.x = scaleX;
this.entityScale.y = scaleY;
super.setScale(entitySetSize.x() * scaleX, entitySetSize.y() * scaleY);
}
@Override @Override
public float getScaleX() { public float getScaleX() {
return entityScale.x; return entityScale.x;
@@ -255,20 +232,27 @@ public class DefaultEntity extends MovableSprite implements Entity {
} }
@Override @Override
public void update(float dt) { public void setScale(float scaleX, float scaleY) {
super.update(dt); if (entitySetSize == null) {
throw new AppException("Cannot change Character scale if no Character Set is provided");
var instantAnimation = instantAnimations.peek();
if (instantAnimation != null && instantAnimation.update() == EntityInstantAnimation.State.COMPLETED) {
instantAnimations.poll();
} }
this.entityScale.x = scaleX;
this.entityScale.y = scaleY;
super.setScale(entitySetSize.x() * scaleX, entitySetSize.y() * scaleY);
} }
int currentFrame() { int currentFrame() {
return currentAnimationFrame; return currentAnimationFrame;
} }
private static Material createMaterial(EntitySetManager entitySetManager, String entitySetUid) { @Override
return entitySetUid != null ? entitySetManager.loadObject(requireNonNull(entitySetUid)) : Material.colored(0, 0, 0, 0); public void update(float dt) {
super.update(dt);
var instantAnimation = instantAnimations.peek();
if (instantAnimation != null && instantAnimation.update() == CharacterInstantAnimation.State.COMPLETED) {
instantAnimations.poll();
}
} }
} }

View File

@@ -1,9 +0,0 @@
package com.bartlomiejpluta.base.engine.world.entity.manager;
import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.engine.common.init.Initializable;
import com.bartlomiejpluta.base.internal.gc.Cleanable;
public interface EntityManager extends Initializable, Cleanable {
Entity createEntity(String entitySetUid);
}

View File

@@ -1,8 +0,0 @@
package com.bartlomiejpluta.base.engine.world.entity.manager;
import com.bartlomiejpluta.base.engine.common.manager.AssetManager;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.world.entity.asset.EntitySetAsset;
public interface EntitySetManager extends AssetManager<EntitySetAsset, Material> {
}

View File

@@ -1,9 +1,9 @@
package com.bartlomiejpluta.base.engine.world.location; package com.bartlomiejpluta.base.engine.world.location;
import com.bartlomiejpluta.base.api.location.Locationable; import com.bartlomiejpluta.base.api.location.Locationable;
import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh; import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.world.movement.MovableSprite;
import com.bartlomiejpluta.base.engine.world.object.Sprite; import com.bartlomiejpluta.base.engine.world.object.Sprite;
import com.bartlomiejpluta.base.util.math.Distance; import com.bartlomiejpluta.base.util.math.Distance;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@@ -88,6 +88,11 @@ public abstract class LocationableSprite extends Sprite implements Locationable
adjustPosition(); adjustPosition();
} }
@Override
public Direction getDirectionTowards(Locationable target) {
return Direction.ofVector(target.getCoordinates().sub(getCoordinates(), new Vector2i()));
}
@Override @Override
public int chebyshevDistance(Vector2ic coordinates) { public int chebyshevDistance(Vector2ic coordinates) {
return Distance.chebyshev(this.coordinates, coordinates); return Distance.chebyshev(this.coordinates, coordinates);
@@ -97,4 +102,14 @@ public abstract class LocationableSprite extends Sprite implements Locationable
public int manhattanDistance(Vector2ic coordinates) { public int manhattanDistance(Vector2ic coordinates) {
return Distance.manhattan(this.coordinates, coordinates); return Distance.manhattan(this.coordinates, coordinates);
} }
@Override
public int chebyshevDistance(Locationable other) {
return Distance.chebyshev(this.coordinates, other.getCoordinates());
}
@Override
public int manhattanDistance(Locationable other) {
return Distance.manhattan(this.coordinates, other.getCoordinates());
}
} }

View File

@@ -7,6 +7,7 @@ import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.map.layer.object.PassageAbility; import com.bartlomiejpluta.base.api.map.layer.object.PassageAbility;
import com.bartlomiejpluta.base.api.map.model.GameMap; import com.bartlomiejpluta.base.api.map.model.GameMap;
import com.bartlomiejpluta.base.api.move.Movable;
import com.bartlomiejpluta.base.api.move.Movement; import com.bartlomiejpluta.base.api.move.Movement;
import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.engine.world.map.layer.base.BaseLayer; import com.bartlomiejpluta.base.engine.world.map.layer.base.BaseLayer;
@@ -93,13 +94,15 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer {
return false; return false;
} }
if (entity instanceof Movable) {
// The tile is empty, however another entity is moving on it // The tile is empty, however another entity is moving on it
var otherMovement = entity.getMovement(); var otherMovement = ((Movable) entity).getMovement();
if (otherMovement != null && otherMovement.getTo().equals(tileCoordinates)) { if (otherMovement != null && otherMovement.getTo().equals(tileCoordinates)) {
return false; return false;
} }
} }
} }
}
return true; return true;
} }
@@ -140,16 +143,16 @@ public class DefaultObjectLayer extends BaseLayer implements ObjectLayer {
@Override @Override
public void render(Screen screen, Camera camera, ShaderManager shaderManager) { public void render(Screen screen, Camera camera, ShaderManager shaderManager) {
entities.sort(this::compareObjects); entities.sort(this::compareEntities);
for (var object : entities) { for (var entity : entities) {
object.render(screen, camera, shaderManager); entity.render(screen, camera, shaderManager);
} }
super.render(screen, camera, shaderManager); super.render(screen, camera, shaderManager);
} }
private int compareObjects(Entity a, Entity b) { private int compareEntities(Entity a, Entity b) {
var z = compare(a.getZIndex(), b.getZIndex()); var z = compare(a.getZIndex(), b.getZIndex());
return z == 0 ? compare(a.getPosition().y(), b.getPosition().y()) : z; return z == 0 ? compare(a.getPosition().y(), b.getPosition().y()) : z;
} }

View File

@@ -5,7 +5,7 @@ app:
database-script-file: /database/data.sql database-script-file: /database/data.sql
sprite: sprite:
entity: character:
default-sprite-column: 0 default-sprite-column: 0
sprite-direction-rows: sprite-direction-rows: