Create animation scaffolding in :engine
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
package com.bartlomiejpluta.base.api.game.animation;
|
||||
|
||||
import com.bartlomiejpluta.base.api.game.entity.Direction;
|
||||
import com.bartlomiejpluta.base.api.game.entity.Movement;
|
||||
import com.bartlomiejpluta.base.api.game.map.layer.object.ObjectLayer;
|
||||
import com.bartlomiejpluta.base.api.internal.logic.Updatable;
|
||||
import com.bartlomiejpluta.base.api.internal.object.Placeable;
|
||||
import com.bartlomiejpluta.base.api.internal.render.Renderable;
|
||||
import org.joml.Vector2ic;
|
||||
|
||||
public interface Animation extends Placeable, Renderable, Updatable {
|
||||
void setStepSize(float x, float y);
|
||||
|
||||
Vector2ic getCoordinates();
|
||||
|
||||
void setCoordinates(Vector2ic coordinates);
|
||||
|
||||
void setCoordinates(int x, int y);
|
||||
|
||||
Movement prepareMovement(Direction direction);
|
||||
|
||||
Movement getMovement();
|
||||
|
||||
void setSpeed(float speed);
|
||||
|
||||
void setAnimationSpeed(float speed);
|
||||
|
||||
boolean isMoving();
|
||||
|
||||
void onAdd(ObjectLayer layer);
|
||||
|
||||
void onRemove(ObjectLayer layer);
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.bartlomiejpluta.base.engine.gui.xml.inflater.Inflater;
|
||||
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
|
||||
import com.bartlomiejpluta.base.engine.project.serial.ProjectDeserializer;
|
||||
import com.bartlomiejpluta.base.engine.util.reflection.ClassLoader;
|
||||
import com.bartlomiejpluta.base.engine.world.animation.manager.AnimationManager;
|
||||
import com.bartlomiejpluta.base.engine.world.entity.manager.EntityManager;
|
||||
import com.bartlomiejpluta.base.engine.world.entity.manager.EntitySetManager;
|
||||
import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager;
|
||||
@@ -34,6 +35,7 @@ public class DefaultContextManager implements ContextManager {
|
||||
private final EntitySetManager entitySetManager;
|
||||
private final FontManager fontManager;
|
||||
private final EntityManager entityManager;
|
||||
private final AnimationManager animationManager;
|
||||
private final ClassLoader classLoader;
|
||||
private final Inflater inflater;
|
||||
private final WidgetDefinitionManager widgetDefinitionManager;
|
||||
@@ -50,6 +52,7 @@ public class DefaultContextManager implements ContextManager {
|
||||
project.getMapAssets().forEach(mapManager::registerAsset);
|
||||
project.getImageAssets().forEach(imageManager::registerAsset);
|
||||
project.getEntitySetAssets().forEach(entitySetManager::registerAsset);
|
||||
project.getAnimationAssets().forEach(animationManager::registerAsset);
|
||||
project.getFontAssets().forEach(fontManager::registerAsset);
|
||||
project.getWidgetDefinitionAssets().forEach(widgetDefinitionManager::registerAsset);
|
||||
|
||||
|
||||
@@ -2,18 +2,19 @@ package com.bartlomiejpluta.base.engine.project.model;
|
||||
|
||||
import com.bartlomiejpluta.base.engine.gui.asset.FontAsset;
|
||||
import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.entity.asset.EntitySetAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.map.asset.GameMapAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.tileset.asset.TileSetAsset;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@Builder
|
||||
public class Project {
|
||||
|
||||
@NonNull
|
||||
@@ -34,6 +35,9 @@ public class Project {
|
||||
@NonNull
|
||||
private final List<EntitySetAsset> entitySetAssets;
|
||||
|
||||
@NonNull
|
||||
private final List<AnimationAsset> animationAssets;
|
||||
|
||||
@NonNull
|
||||
private final List<FontAsset> fontAssets;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.engine.project.serial;
|
||||
import com.bartlomiejpluta.base.engine.gui.asset.FontAsset;
|
||||
import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset;
|
||||
import com.bartlomiejpluta.base.engine.project.model.Project;
|
||||
import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.entity.asset.EntitySetAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.map.asset.GameMapAsset;
|
||||
@@ -20,16 +21,18 @@ public class ProtobufProjectDeserializer extends ProjectDeserializer {
|
||||
@Override
|
||||
protected Project parse(InputStream input) throws Exception {
|
||||
var proto = ProjectProto.Project.parseFrom(input);
|
||||
var name = proto.getName();
|
||||
var runner = proto.getRunner();
|
||||
var tileSetAssets = proto.getTileSetsList().stream().map(this::parseTileSetAsset).collect(toList());
|
||||
var mapAssets = proto.getMapsList().stream().map(this::parseGameMapAsset).collect(toList());
|
||||
var imageAssets = proto.getImagesList().stream().map(this::parseImageAsset).collect(toList());
|
||||
var entitySetAssets = proto.getEntitySetsList().stream().map(this::parseEntitySetAsset).collect(toList());
|
||||
var fontAssets = proto.getFontsList().stream().map(this::parseFontAsset).collect(toList());
|
||||
var widgetAssets = proto.getWidgetsList().stream().map(this::parseWidgetAsset).collect(toList());
|
||||
|
||||
return new Project(name, runner, tileSetAssets, mapAssets, imageAssets, entitySetAssets, fontAssets, widgetAssets);
|
||||
return Project.builder()
|
||||
.name(proto.getName())
|
||||
.runner(proto.getRunner())
|
||||
.tileSetAssets(proto.getTileSetsList().stream().map(this::parseTileSetAsset).collect(toList()))
|
||||
.mapAssets(proto.getMapsList().stream().map(this::parseGameMapAsset).collect(toList()))
|
||||
.imageAssets(proto.getImagesList().stream().map(this::parseImageAsset).collect(toList()))
|
||||
.entitySetAssets(proto.getEntitySetsList().stream().map(this::parseEntitySetAsset).collect(toList()))
|
||||
.animationAssets(proto.getAnimationsList().stream().map(this::parseAnimationAsset).collect(toList()))
|
||||
.fontAssets(proto.getFontsList().stream().map(this::parseFontAsset).collect(toList()))
|
||||
.widgetDefinitionAssets(proto.getWidgetsList().stream().map(this::parseWidgetAsset).collect(toList()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private TileSetAsset parseTileSetAsset(ProjectProto.TileSetAsset proto) {
|
||||
@@ -55,4 +58,8 @@ public class ProtobufProjectDeserializer extends ProjectDeserializer {
|
||||
private WidgetDefinitionAsset parseWidgetAsset(ProjectProto.WidgetAsset proto) {
|
||||
return new WidgetDefinitionAsset(proto.getUid(), proto.getSource());
|
||||
}
|
||||
|
||||
private AnimationAsset parseAnimationAsset(ProjectProto.AnimationAsset proto) {
|
||||
return new AnimationAsset(proto.getUid(), proto.getSource(), proto.getRows(), proto.getColumns());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.bartlomiejpluta.base.engine.world.animation.asset;
|
||||
|
||||
import com.bartlomiejpluta.base.engine.common.asset.Asset;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Getter
|
||||
public class AnimationAsset extends Asset {
|
||||
private final int rows;
|
||||
private final int columns;
|
||||
private final String framesSignature;
|
||||
|
||||
public AnimationAsset(@NonNull String uid, @NonNull String source, int rows, int columns) {
|
||||
super(uid, source);
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
this.framesSignature = String.format("%dx%d", rows, columns);
|
||||
}
|
||||
|
||||
public String framesSignature() {
|
||||
return framesSignature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.bartlomiejpluta.base.engine.world.animation.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.api.game.animation.Animation;
|
||||
import com.bartlomiejpluta.base.engine.common.manager.AssetManager;
|
||||
import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset;
|
||||
|
||||
public interface AnimationManager extends AssetManager<AnimationAsset, Animation> {
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.bartlomiejpluta.base.engine.world.animation.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.api.game.animation.Animation;
|
||||
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.texture.TextureManager;
|
||||
import com.bartlomiejpluta.base.engine.error.AppException;
|
||||
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
|
||||
import com.bartlomiejpluta.base.engine.util.mesh.MeshManager;
|
||||
import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.animation.model.DefaultAnimation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2fc;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultAnimationManager implements AnimationManager {
|
||||
private final MeshManager meshManager;
|
||||
private final TextureManager textureManager;
|
||||
private final Map<String, AnimationAsset> assets = new HashMap<>();
|
||||
private final Map<String, Vector2fc[]> frames = new HashMap<>();
|
||||
private final ProjectConfiguration configuration;
|
||||
|
||||
|
||||
@Override
|
||||
public void registerAsset(AnimationAsset asset) {
|
||||
log.info("Registering [{}] animation asset under UID: [{}]", asset.getSource(), asset.getUid());
|
||||
assets.put(asset.getUid(), asset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animation loadObject(String uid) {
|
||||
var asset = assets.get(uid);
|
||||
|
||||
if (asset == null) {
|
||||
throw new AppException("The entity set asset with UID: [%s] does not exist", uid);
|
||||
}
|
||||
|
||||
var animationFrames = frames.computeIfAbsent(asset.framesSignature(),
|
||||
signature -> createFrames(asset.getRows(), asset.getColumns())
|
||||
);
|
||||
|
||||
var source = configuration.projectFile("animations", asset.getSource());
|
||||
var texture = textureManager.loadTexture(source, asset.getRows(), asset.getColumns());
|
||||
var material = Material.textured(texture);
|
||||
var mesh = buildMesh(material, asset.getRows(), asset.getColumns());
|
||||
|
||||
return new DefaultAnimation(mesh, material, animationFrames);
|
||||
}
|
||||
|
||||
private Vector2fc[] createFrames(int rows, int columns) {
|
||||
var frames = new Vector2fc[rows * columns];
|
||||
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
for (int column = 0; column < columns; ++column) {
|
||||
frames[row * columns + column] = new Vector2f(column, row);
|
||||
}
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
private Mesh buildMesh(Material material, int rows, int columns) {
|
||||
var texture = material.getTexture();
|
||||
var spriteWidth = texture.getWidth() / columns;
|
||||
var spriteHeight = texture.getHeight() / rows;
|
||||
return meshManager.createQuad(spriteWidth, spriteHeight, spriteWidth / 2f, spriteHeight * 0.9f);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.bartlomiejpluta.base.engine.world.animation;
|
||||
package com.bartlomiejpluta.base.engine.world.animation.model;
|
||||
|
||||
import com.bartlomiejpluta.base.api.game.camera.Camera;
|
||||
import com.bartlomiejpluta.base.api.game.screen.Screen;
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.bartlomiejpluta.base.engine.world.animation.model;
|
||||
|
||||
import com.bartlomiejpluta.base.api.game.animation.Animation;
|
||||
import com.bartlomiejpluta.base.api.game.map.layer.object.ObjectLayer;
|
||||
import com.bartlomiejpluta.base.api.util.math.MathUtil;
|
||||
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.world.movement.MovableSprite;
|
||||
import lombok.NonNull;
|
||||
import org.joml.Vector2fc;
|
||||
|
||||
public class DefaultAnimation extends MovableSprite implements Animation {
|
||||
private final Vector2fc[] frames;
|
||||
private int animationSpeed = 100;
|
||||
|
||||
public DefaultAnimation(Mesh mesh, Material material, @NonNull Vector2fc[] frames) {
|
||||
super(mesh, material);
|
||||
this.frames = frames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpeed(float speed) {
|
||||
framesToCrossOneTile = (int) (1 / MathUtil.clamp(speed, Float.MIN_VALUE, 1.0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnimationSpeed(float speed) {
|
||||
animationSpeed = (int) (1 / MathUtil.clamp(speed, Float.MIN_VALUE, 1.0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdd(ObjectLayer layer) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(ObjectLayer layer) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAnimationSpeed() {
|
||||
return animationSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldAnimate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector2fc[] getSpriteAnimationFramesPositions() {
|
||||
return frames;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDefaultAnimationFrame() {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,17 @@ public class DefaultEntity extends MovableSprite implements Entity {
|
||||
@Getter
|
||||
private Direction faceDirection;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean blocking;
|
||||
|
||||
public DefaultEntity(Mesh mesh, Material material, Map<Direction, Integer> spriteDirectionRows, Map<Direction, Vector2fc> spriteDefaultRows) {
|
||||
super(mesh, material);
|
||||
this.spriteDirectionRows = spriteDirectionRows;
|
||||
this.faceDirection = Direction.DOWN;
|
||||
this.spriteDefaultRows = spriteDefaultRows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAnimationSpeed() {
|
||||
return animationSpeed;
|
||||
@@ -37,10 +48,6 @@ public class DefaultEntity extends MovableSprite implements Entity {
|
||||
return isMoving();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean blocking;
|
||||
|
||||
@Override
|
||||
public Vector2fc[] getSpriteAnimationFramesPositions() {
|
||||
var row = spriteDirectionRows.get(faceDirection);
|
||||
@@ -109,11 +116,4 @@ public class DefaultEntity extends MovableSprite implements Entity {
|
||||
public void onRemove(ObjectLayer layer) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public DefaultEntity(Mesh mesh, Material material, Map<Direction, Integer> spriteDirectionRows, Map<Direction, Vector2fc> spriteDefaultRows) {
|
||||
super(mesh, material);
|
||||
this.spriteDirectionRows = spriteDirectionRows;
|
||||
this.faceDirection = Direction.DOWN;
|
||||
this.spriteDefaultRows = spriteDefaultRows;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.bartlomiejpluta.base.api.game.entity.Movement;
|
||||
import com.bartlomiejpluta.base.api.internal.logic.Updatable;
|
||||
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.world.animation.AnimatedSprite;
|
||||
import com.bartlomiejpluta.base.engine.world.animation.model.AnimatedSprite;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import org.joml.Vector2f;
|
||||
|
||||
Reference in New Issue
Block a user