Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
785e1ac524
|
|||
|
f581805efd
|
|||
|
620970fb10
|
|||
|
bbf0109080
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
build/
|
||||
data.trace.db
|
||||
|
||||
BIN
data.mv.db
BIN
data.mv.db
Binary file not shown.
BIN
entsets/9da2c95b-45b7-49e5-957b-c1c8803cdf28.png
Normal file
BIN
entsets/9da2c95b-45b7-49e5-957b-c1c8803cdf28.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
entsets/cb4c89a7-a421-49ea-8c58-571e9b215d37.png
Normal file
BIN
entsets/cb4c89a7-a421-49ea-8c58-571e9b215d37.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
@@ -2,7 +2,9 @@
|
||||
BASE Demo*com.bartlomiejpluta.demo.runner.DemoRunner`
|
||||
$f845355e-b9ad-4884-a217-dd3a4c18a3fa(f845355e-b9ad-4884-a217-dd3a4c18a3fa.datForrest Temple"d
|
||||
$d314b030-f865-432e-a356-3845f8aac7bc(d314b030-f865-432e-a356-3845f8aac7bc.pngForrest Temple ](2Z
|
||||
$815a5c5c-4979-42f5-a42a-ccbbff9a97e5(815a5c5c-4979-42f5-a42a-ccbbff9a97e5.pngLuna (:`
|
||||
$815a5c5c-4979-42f5-a42a-ccbbff9a97e5(815a5c5c-4979-42f5-a42a-ccbbff9a97e5.pngLuna (2Z
|
||||
$cb4c89a7-a421-49ea-8c58-571e9b215d37(cb4c89a7-a421-49ea-8c58-571e9b215d37.pngDeku (2\
|
||||
$9da2c95b-45b7-49e5-957b-c1c8803cdf28(9da2c95b-45b7-49e5-957b-c1c8803cdf28.pngCorpse (:`
|
||||
$2261c04f-b02e-4486-b388-8a0fa41622e9(2261c04f-b02e-4486-b388-8a0fa41622e9.ttfRoboto RegularB\
|
||||
$ab9d40b4-eb28-45d7-bff2-9432a05eb41a(ab9d40b4-eb28-45d7-bff2-9432a05eb41a.xml
|
||||
Start MenuB[
|
||||
|
||||
43
src/main/java/com/bartlomiejpluta/demo/ai/SimpleEnemyAI.java
Normal file
43
src/main/java/com/bartlomiejpluta/demo/ai/SimpleEnemyAI.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package com.bartlomiejpluta.demo.ai;
|
||||
|
||||
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
|
||||
|
||||
import com.bartlomiejpluta.base.util.pathfinder.*;
|
||||
import com.bartlomiejpluta.base.api.ai.*;
|
||||
import com.bartlomiejpluta.base.lib.ai.*;
|
||||
|
||||
import com.bartlomiejpluta.demo.entity.Enemy;
|
||||
import com.bartlomiejpluta.demo.entity.Character;
|
||||
|
||||
public class SimpleEnemyAI extends FollowEntityAI<Enemy, Character> {
|
||||
private static final int ASTAR_MAX_NODES = 100;
|
||||
private static final int IDLE_MOVEMENT_INTERVAL = 4;
|
||||
private final AI idle;
|
||||
private final int range;
|
||||
|
||||
public SimpleEnemyAI(Enemy enemy, Character target, int range) {
|
||||
super(new AstarPathFinder(ASTAR_MAX_NODES), enemy, target);
|
||||
this.range = range;
|
||||
this.idle = new RandomMovementAI(enemy, IDLE_MOVEMENT_INTERVAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean sees(Enemy enemy, Character target, ObjectLayer layer, int distance) {
|
||||
return distance < range;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void interact(Enemy enemy, Character target, ObjectLayer layer, float dt) {
|
||||
enemy.attack();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void follow(Enemy enemy, Character target, ObjectLayer layer, float dt) {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void idle(Enemy enemy, Character target, ObjectLayer layer, float dt) {
|
||||
idle.nextActivity(layer, dt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.bartlomiejpluta.demo.database.dao;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
import com.bartlomiejpluta.base.api.context.Context;
|
||||
|
||||
import com.bartlomiejpluta.demo.database.model.EnemyModel;
|
||||
|
||||
public class EnemyDAO {
|
||||
private final Map<String, EnemyModel> enemies = new HashMap<>();
|
||||
|
||||
public void init(Context context) {
|
||||
context.withDatabase(db -> {
|
||||
var result = db.prepareStatement("SELECT * FROM `enemy`").executeQuery();
|
||||
|
||||
while(result.next()) {
|
||||
var enemy = EnemyModel.builder()
|
||||
.id(result.getString("id"))
|
||||
.name(result.getString("name"))
|
||||
.entitySet(result.getString("entset"))
|
||||
.deadEntitySet(result.getString("dead_entset"))
|
||||
.hp(result.getInt("hp"))
|
||||
.speed(result.getFloat("speed"))
|
||||
.animationSpeed(result.getFloat("animation_speed"))
|
||||
.blocking(result.getBoolean("blocking"))
|
||||
.meleeWeapon(result.getString("melee_weapon"))
|
||||
.build();
|
||||
enemies.put(result.getString("id"), enemy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public EnemyModel get(String id) {
|
||||
return enemies.get(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.bartlomiejpluta.demo.database.dao;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
import com.bartlomiejpluta.base.api.context.Context;
|
||||
|
||||
import com.bartlomiejpluta.demo.database.model.MeleeWeaponModel;
|
||||
|
||||
public class MeleeWeaponDAO {
|
||||
private final Map<String, MeleeWeaponModel> items = new HashMap<>();
|
||||
|
||||
public void init(Context context) {
|
||||
context.withDatabase(db -> {
|
||||
var result = db.prepareStatement("SELECT * FROM `melee_weapon`").executeQuery();
|
||||
|
||||
while(result.next()) {
|
||||
var weapon = MeleeWeaponModel.builder()
|
||||
.id(result.getString("id"))
|
||||
.name(result.getString("name"))
|
||||
.damage(result.getString("damage"))
|
||||
.cooldown(result.getInt("cooldown"))
|
||||
.build();
|
||||
items.put(result.getString("id"), weapon);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MeleeWeaponModel get(String id) {
|
||||
return items.get(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.bartlomiejpluta.demo.database.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class EnemyModel {
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final String entitySet;
|
||||
private final String deadEntitySet;
|
||||
private final int hp;
|
||||
private final float speed;
|
||||
private final float animationSpeed;
|
||||
private final boolean blocking;
|
||||
private final String meleeWeapon;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.bartlomiejpluta.demo.database.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class MeleeWeaponModel {
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final String damage;
|
||||
private final int cooldown;
|
||||
}
|
||||
@@ -1,15 +1,80 @@
|
||||
package com.bartlomiejpluta.demo.entity;
|
||||
|
||||
import lombok.*;
|
||||
import org.slf4j.*;
|
||||
import org.joml.Vector2i;
|
||||
import com.bartlomiejpluta.base.api.context.Context;
|
||||
import com.bartlomiejpluta.base.api.entity.Entity;
|
||||
import com.bartlomiejpluta.base.lib.entity.EntityDelegate;
|
||||
|
||||
import com.bartlomiejpluta.demo.runner.DemoRunner;
|
||||
import com.bartlomiejpluta.demo.world.weapon.MeleeWeapon;
|
||||
|
||||
public class Character extends EntityDelegate {
|
||||
private static final Logger log = LoggerFactory.getLogger(Character.class);
|
||||
protected final Context context;
|
||||
|
||||
protected final DemoRunner runner;
|
||||
|
||||
protected int attackCooldown = 0;
|
||||
|
||||
@Getter
|
||||
protected boolean alive = true;
|
||||
|
||||
@Getter
|
||||
protected boolean immortal = false;
|
||||
|
||||
@Getter
|
||||
protected int hp;
|
||||
|
||||
@Setter
|
||||
private MeleeWeapon weapon;
|
||||
|
||||
public Character(@NonNull Context context, @NonNull Entity entity) {
|
||||
super(entity);
|
||||
this.context = context;
|
||||
this.runner = (DemoRunner) context.getGameRunner();
|
||||
}
|
||||
|
||||
public void attack() {
|
||||
if(weapon == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(attackCooldown >= weapon.getCooldown()) {
|
||||
var facingNeighbour = getCoordinates().add(getFaceDirection().vector, new Vector2i());
|
||||
for(var entity : getLayer().getEntities()) {
|
||||
if(entity.getCoordinates().equals(facingNeighbour) && entity.isBlocking() && entity instanceof Character) {
|
||||
weapon.attack((Character) entity);
|
||||
attackCooldown = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void hit(int dmg) {
|
||||
if(immortal) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(toString() + " received " + dmg + " damage");
|
||||
hp -= dmg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
super.update(dt);
|
||||
|
||||
if(weapon != null && attackCooldown < weapon.getCooldown()) {
|
||||
attackCooldown += (int) (dt * 1000f);
|
||||
}
|
||||
|
||||
if(hp <= 0 && alive && getLayer() != null) {
|
||||
alive = false;
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
protected void die() {
|
||||
log.info(toString() + " died with HP = " + hp);
|
||||
}
|
||||
}
|
||||
67
src/main/java/com/bartlomiejpluta/demo/entity/Enemy.java
Normal file
67
src/main/java/com/bartlomiejpluta/demo/entity/Enemy.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package com.bartlomiejpluta.demo.entity;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import com.bartlomiejpluta.base.api.context.Context;
|
||||
import com.bartlomiejpluta.base.api.entity.Entity;
|
||||
import com.bartlomiejpluta.base.api.ai.AI;
|
||||
import com.bartlomiejpluta.base.api.ai.NPC;
|
||||
import com.bartlomiejpluta.base.api.move.MoveEvent;
|
||||
|
||||
import com.bartlomiejpluta.base.lib.ai.NoopAI;
|
||||
|
||||
import com.bartlomiejpluta.demo.runner.DemoRunner;
|
||||
import com.bartlomiejpluta.demo.database.model.EnemyModel;
|
||||
import com.bartlomiejpluta.demo.world.weapon.MeleeWeapon;
|
||||
import com.bartlomiejpluta.demo.event.EnemyDiedEvent;
|
||||
import com.bartlomiejpluta.demo.ai.*;
|
||||
|
||||
|
||||
public class Enemy extends Character implements NPC {
|
||||
private final EnemyModel template;
|
||||
private AI ai = NoopAI.INSTANCE;
|
||||
|
||||
public Enemy(@NonNull Context context, @NonNull EnemyModel template) {
|
||||
super(context, context.createEntity(template.getEntitySet()));
|
||||
this.template = template;
|
||||
hp = template.getHp();
|
||||
setSpeed(template.getSpeed());
|
||||
setAnimationSpeed(template.getAnimationSpeed());
|
||||
setBlocking(template.isBlocking());
|
||||
setWeapon(new MeleeWeapon(((DemoRunner) context.getGameRunner()).getMeleeWeaponDAO().get(template.getMeleeWeapon())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AI getStrategy() {
|
||||
return ai;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
changeEntitySet(template.getDeadEntitySet());
|
||||
setScale(0.5f);
|
||||
setBlocking(false);
|
||||
setZIndex(-1);
|
||||
|
||||
ai = NoopAI.INSTANCE;
|
||||
|
||||
getLayer().handleEvent(new EnemyDiedEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return template.getName() + "@" + hashCode();
|
||||
}
|
||||
|
||||
public Enemy followAndAttack(Character target, int range) {
|
||||
var ai = new SimpleEnemyAI(this, target, range);
|
||||
|
||||
addEventListener(MoveEvent.TYPE, e -> ai.recomputePath());
|
||||
addEventListener(EnemyDiedEvent.TYPE, e -> ai.recomputePath());
|
||||
|
||||
this.ai = ai;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,20 @@
|
||||
package com.bartlomiejpluta.demo.entity;
|
||||
|
||||
import lombok.*;
|
||||
import org.slf4j.*;
|
||||
import com.bartlomiejpluta.base.api.context.Context;
|
||||
import com.bartlomiejpluta.base.api.entity.Entity;
|
||||
|
||||
public class Player extends Character {
|
||||
private static final Logger log = LoggerFactory.getLogger(Player.class);
|
||||
|
||||
public Player(@NonNull Context context, @NonNull Entity entity) {
|
||||
super(context, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
runner.returnToStartMenu();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.bartlomiejpluta.demo.event;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import com.bartlomiejpluta.base.api.event.*;
|
||||
import com.bartlomiejpluta.base.lib.event.*;
|
||||
import com.bartlomiejpluta.demo.entity.Enemy;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class EnemyDiedEvent extends BaseEvent {
|
||||
public static final EventType<EnemyDiedEvent> TYPE = new EventType<>("ENEMY_DIED_EVENT");
|
||||
|
||||
private final Enemy enemy;
|
||||
|
||||
@Override
|
||||
public EventType<EnemyDiedEvent> getType() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.bartlomiejpluta.demo.map;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import com.bartlomiejpluta.base.api.map.handler.MapHandler;
|
||||
import com.bartlomiejpluta.base.api.map.model.GameMap;
|
||||
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
|
||||
@@ -12,7 +14,7 @@ import com.bartlomiejpluta.base.api.input.*;
|
||||
import com.bartlomiejpluta.base.lib.camera.*;
|
||||
|
||||
import com.bartlomiejpluta.demo.runner.DemoRunner;
|
||||
import com.bartlomiejpluta.demo.entity.Player;
|
||||
import com.bartlomiejpluta.demo.entity.*;
|
||||
|
||||
public abstract class BaseMapHandler implements MapHandler {
|
||||
protected Screen screen;
|
||||
@@ -41,6 +43,10 @@ public abstract class BaseMapHandler implements MapHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
if(input.isKeyPressed(Key.KEY_SPACE)) {
|
||||
player.attack();
|
||||
}
|
||||
|
||||
if(input.isKeyPressed(Key.KEY_LEFT_CONTROL)) {
|
||||
if(input.isKeyPressed(Key.KEY_DOWN)) {
|
||||
player.setFaceDirection(Direction.DOWN);
|
||||
@@ -68,4 +74,11 @@ public abstract class BaseMapHandler implements MapHandler {
|
||||
public void update(Context context, GameMap map, float dt) {
|
||||
cameraController.update();
|
||||
}
|
||||
|
||||
public Enemy enemy(int x, int y, @NonNull String id) {
|
||||
var enemy = new Enemy(context, runner.getEnemyDAO().get(id));
|
||||
enemy.setCoordinates(x, y);
|
||||
mainLayer.addEntity(enemy);
|
||||
return enemy;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,9 @@ import com.bartlomiejpluta.base.api.runner.GameRunner;
|
||||
import com.bartlomiejpluta.demo.map.ForrestTempleHandler;
|
||||
import com.bartlomiejpluta.demo.entity.Player;
|
||||
import com.bartlomiejpluta.demo.menu.MenuManager;
|
||||
import com.bartlomiejpluta.demo.database.dao.*;
|
||||
|
||||
import com.bartlomiejpluta.demo.world.weapon.MeleeWeapon;
|
||||
|
||||
public class DemoRunner implements GameRunner {
|
||||
private static final Logger log = LoggerFactory.getLogger(DemoRunner.class);
|
||||
@@ -20,6 +23,12 @@ public class DemoRunner implements GameRunner {
|
||||
private Context context;
|
||||
private MenuManager menu;
|
||||
|
||||
@Getter
|
||||
private MeleeWeaponDAO meleeWeaponDAO = new MeleeWeaponDAO();
|
||||
|
||||
@Getter
|
||||
private EnemyDAO enemyDAO = new EnemyDAO();
|
||||
|
||||
@Getter
|
||||
private Player player;
|
||||
|
||||
@@ -27,9 +36,10 @@ public class DemoRunner implements GameRunner {
|
||||
public void init(Context context) {
|
||||
this.context = context;
|
||||
this.screen = context.getScreen();
|
||||
|
||||
|
||||
configureScreen();
|
||||
configureCamera();
|
||||
initDAOs();
|
||||
initMenu();
|
||||
initPlayer();
|
||||
|
||||
@@ -37,17 +47,22 @@ public class DemoRunner implements GameRunner {
|
||||
|
||||
screen.show();
|
||||
}
|
||||
|
||||
|
||||
private void configureScreen() {
|
||||
var resolution = screen.getCurrentResolution();
|
||||
screen.setSize(800, 600);
|
||||
screen.setPosition((resolution.x() - 800)/2, (resolution.y() - 600)/2);
|
||||
}
|
||||
|
||||
|
||||
private void configureCamera() {
|
||||
context.getCamera().setScale(2f);
|
||||
}
|
||||
|
||||
|
||||
private void initDAOs() {
|
||||
meleeWeaponDAO.init(context);
|
||||
enemyDAO.init(context);
|
||||
}
|
||||
|
||||
private void initMenu() {
|
||||
this.menu = new MenuManager(this, context);
|
||||
}
|
||||
@@ -55,7 +70,7 @@ public class DemoRunner implements GameRunner {
|
||||
private void initPlayer() {
|
||||
this.player = new Player(context, context.createEntity("815a5c5c-4979-42f5-a42a-ccbbff9a97e5"));
|
||||
}
|
||||
|
||||
|
||||
private void resetPlayer() {
|
||||
this.player.changeEntitySet("815a5c5c-4979-42f5-a42a-ccbbff9a97e5");
|
||||
this.player.setScale(1.0f);
|
||||
@@ -63,8 +78,9 @@ public class DemoRunner implements GameRunner {
|
||||
this.player.setAnimationSpeed(0.005f);
|
||||
this.player.setBlocking(true);
|
||||
this.player.setCoordinates(0, 11);
|
||||
this.player.setWeapon(new MeleeWeapon(meleeWeaponDAO.get("wooden_sword")));
|
||||
}
|
||||
|
||||
|
||||
public void newGame() {
|
||||
menu.closeAll();
|
||||
menu.enableGameMenu();
|
||||
@@ -95,6 +111,4 @@ public class DemoRunner implements GameRunner {
|
||||
public void dispose() {
|
||||
// Do something after game loop is end
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
31
src/main/java/com/bartlomiejpluta/demo/util/DiceRoller.java
Normal file
31
src/main/java/com/bartlomiejpluta/demo/util/DiceRoller.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.bartlomiejpluta.demo.util;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import java.util.regex.*;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class DiceRoller {
|
||||
private static final Pattern CODE_PATTERN = Pattern.compile("(\\d+)d(\\d+)([+-]\\d+)?");
|
||||
private final Random random = new Random();
|
||||
private int rolls;
|
||||
private int dice;
|
||||
private int modifier;
|
||||
|
||||
public int roll() {
|
||||
var sum = modifier;
|
||||
|
||||
for(int i=0; i<rolls; ++i) {
|
||||
sum += random.nextInt(dice) + 1;
|
||||
}
|
||||
|
||||
return Math.max(0, sum);
|
||||
}
|
||||
|
||||
public static DiceRoller of(String code) {
|
||||
var matcher = CODE_PATTERN.matcher(code);
|
||||
matcher.matches();
|
||||
return new DiceRoller(Integer.valueOf(matcher.group(1)), Integer.valueOf(matcher.group(2)), Integer.valueOf(matcher.group(3)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.bartlomiejpluta.demo.world.weapon;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import lombok.*;
|
||||
import com.bartlomiejpluta.demo.database.model.MeleeWeaponModel;
|
||||
import com.bartlomiejpluta.demo.entity.Character;
|
||||
import com.bartlomiejpluta.demo.util.DiceRoller;
|
||||
|
||||
public class MeleeWeapon {
|
||||
private final Random random = new Random();
|
||||
private final DiceRoller roller;
|
||||
|
||||
@Getter
|
||||
private String name;
|
||||
|
||||
@Getter
|
||||
private int cooldown;
|
||||
|
||||
public MeleeWeapon(MeleeWeaponModel template) {
|
||||
this.name = template.getName();
|
||||
this.roller = DiceRoller.of(template.getDamage());
|
||||
this.cooldown = template.getCooldown();
|
||||
}
|
||||
|
||||
public void attack(Character character) {
|
||||
character.hit(roller.roll());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user