hurt&death anim, item sheet (item sys still 2bd)

v5stable
Ondřej Hruška 10 years ago
parent aac26f47f4
commit 8fa0dd927f
  1. BIN
      res/img/gui1.png
  2. BIN
      res/img/gui1.xcf
  3. BIN
      res/img/items16.png
  4. BIN
      res/img/items16.xcf
  5. 2
      src/mightypork/gamecore/util/math/color/Color.java
  6. 64
      src/mightypork/rogue/Res.java
  7. 21
      src/mightypork/rogue/screens/game/HeartBar.java
  8. 36
      src/mightypork/rogue/screens/game/HudLayer.java
  9. 22
      src/mightypork/rogue/world/entity/Entity.java
  10. 10
      src/mightypork/rogue/world/entity/entities/MonsterAi.java
  11. 16
      src/mightypork/rogue/world/entity/entities/PlayerEntity.java
  12. 6
      src/mightypork/rogue/world/entity/entities/RatAi.java
  13. 4
      src/mightypork/rogue/world/entity/entities/RatEntity.java
  14. 18
      src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java
  15. 28
      src/mightypork/rogue/world/entity/modules/EntityModulePosition.java
  16. 33
      src/mightypork/rogue/world/entity/renderers/EntityRendererMobLR.java
  17. 35
      src/mightypork/rogue/world/level/Level.java

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

@ -66,7 +66,7 @@ public abstract class Color {
@FactoryMethod
public static final Color rgba(Num r, Num g, Num b)
public static final Color rgb(Num r, Num g, Num b)
{
return rgba(r, g, b, Num.ONE);
}

@ -62,7 +62,7 @@ public final class Res {
private static void loadTextures()
{
GLTexture texture;
QuadGrid tiles;
QuadGrid grid;
// gui
texture = textures.loadTexture("gui1", "/res/img/gui1.png", FilterMode.NEAREST, WrapMode.CLAMP);
@ -72,15 +72,16 @@ public final class Res {
textures.addQuad("meat", gui.makeQuad(2, 0));
textures.addQuad("heart_on", gui.makeQuad(.0, 1, .5, .5));
textures.addQuad("heart_off", gui.makeQuad(.5, 1, .5, .5));
textures.addQuad("heart_half", gui.makeQuad(1, 1, .5, .5));
textures.addQuad("xp_on", gui.makeQuad(0, 1.5, .5, .5));
textures.addQuad("xp_off", gui.makeQuad(.5, 1.5, .5, .5));
textures.addQuad("panel", gui.makeQuad(0, 3.75, 4, .25));
// sprites
texture = textures.loadTexture("mob", "/res/img/dudes.png", FilterMode.NEAREST, WrapMode.CLAMP);
tiles = texture.grid(8, 8);
textures.addSheet("sprite.player", tiles.makeSheet(0, 0, 4, 1));
textures.addSheet("sprite.rat", tiles.makeSheet(0, 1, 4, 1));
grid = texture.grid(8, 8);
textures.addSheet("sprite.player", grid.makeSheet(0, 0, 4, 1));
textures.addSheet("sprite.rat", grid.makeSheet(0, 1, 4, 1));
// sprites
texture = textures.loadTexture("logo2", "/res/img/logo2.png", FilterMode.NEAREST, WrapMode.CLAMP);
@ -88,38 +89,43 @@ public final class Res {
// small sheet
texture = textures.loadTexture("tiles", "/res/img/tiles16.png", FilterMode.NEAREST, WrapMode.CLAMP);
tiles = texture.grid(8, 8);
grid = texture.grid(8, 8);
textures.addSheet("tile.brick.floor", tiles.makeSheet(0, 1, 5, 1));
textures.addSheet("tile.brick.wall", tiles.makeSheet(0, 0, 8, 1));
textures.addSheet("tile.brick.floor", grid.makeSheet(0, 1, 5, 1));
textures.addSheet("tile.brick.wall", grid.makeSheet(0, 0, 8, 1));
textures.addSheet("tile.brick.door.locked", tiles.makeSheet(1, 2, 1, 1));//TODO unique tx
textures.addSheet("tile.brick.door.closed", tiles.makeSheet(1, 2, 1, 1));
textures.addSheet("tile.brick.door.open", tiles.makeSheet(2, 2, 1, 1));
textures.addSheet("tile.brick.door.secret", tiles.makeSheet(0, 3, 2, 1));
textures.addSheet("tile.brick.door.locked", grid.makeSheet(1, 2, 1, 1));//TODO unique tx
textures.addSheet("tile.brick.door.closed", grid.makeSheet(1, 2, 1, 1));
textures.addSheet("tile.brick.door.open", grid.makeSheet(2, 2, 1, 1));
textures.addSheet("tile.brick.door.secret", grid.makeSheet(0, 3, 2, 1));
textures.addSheet("tile.brick.passage", tiles.makeSheet(3, 2, 4, 1));
textures.addSheet("tile.brick.passage", grid.makeSheet(3, 2, 4, 1));
textures.addQuad("tile.shadow.n", tiles.makeQuad(0, 7));
textures.addQuad("tile.shadow.s", tiles.makeQuad(0, 7).flipY());
textures.addQuad("tile.shadow.w", tiles.makeQuad(1, 7));
textures.addQuad("tile.shadow.e", tiles.makeQuad(1, 7).flipX());
textures.addQuad("tile.shadow.n", grid.makeQuad(0, 7));
textures.addQuad("tile.shadow.s", grid.makeQuad(0, 7).flipY());
textures.addQuad("tile.shadow.w", grid.makeQuad(1, 7));
textures.addQuad("tile.shadow.e", grid.makeQuad(1, 7).flipX());
textures.addQuad("tile.shadow.nw", tiles.makeQuad(2, 7));
textures.addQuad("tile.shadow.ne", tiles.makeQuad(2, 7).flipX());
textures.addQuad("tile.shadow.sw", tiles.makeQuad(2, 7).flipY());
textures.addQuad("tile.shadow.se", tiles.makeQuad(2, 7).flipY().flipX());
textures.addQuad("tile.shadow.nw", grid.makeQuad(2, 7));
textures.addQuad("tile.shadow.ne", grid.makeQuad(2, 7).flipX());
textures.addQuad("tile.shadow.sw", grid.makeQuad(2, 7).flipY());
textures.addQuad("tile.shadow.se", grid.makeQuad(2, 7).flipY().flipX());
// unexplored fog
textures.addQuad("tile.ufog.n", tiles.makeQuad(3, 7));
textures.addQuad("tile.ufog.s", tiles.makeQuad(3, 7).flipY());
textures.addQuad("tile.ufog.w", tiles.makeQuad(4, 7));
textures.addQuad("tile.ufog.e", tiles.makeQuad(4, 7).flipX());
textures.addQuad("tile.ufog.nw", tiles.makeQuad(5, 7));
textures.addQuad("tile.ufog.ne", tiles.makeQuad(5, 7).flipX());
textures.addQuad("tile.ufog.sw", tiles.makeQuad(5, 7).flipY());
textures.addQuad("tile.ufog.se", tiles.makeQuad(5, 7).flipY().flipX());
textures.addQuad("tile.ufog.n", grid.makeQuad(3, 7));
textures.addQuad("tile.ufog.s", grid.makeQuad(3, 7).flipY());
textures.addQuad("tile.ufog.w", grid.makeQuad(4, 7));
textures.addQuad("tile.ufog.e", grid.makeQuad(4, 7).flipX());
textures.addQuad("tile.ufog.nw", grid.makeQuad(5, 7));
textures.addQuad("tile.ufog.ne", grid.makeQuad(5, 7).flipX());
textures.addQuad("tile.ufog.sw", grid.makeQuad(5, 7).flipY());
textures.addQuad("tile.ufog.se", grid.makeQuad(5, 7).flipY().flipX());
texture = textures.loadTexture("items", "/res/img/items16.png", FilterMode.NEAREST, WrapMode.CLAMP);
grid = texture.grid(8, 8);
textures.addQuad("item.meat", grid.makeQuad(0, 0));
}

@ -14,27 +14,30 @@ public class HeartBar extends VisualComponent {
private final TxQuad img_on;
private final TxQuad img_off;
private final int total;
private final int active;
private final TxQuad img_half;
private Num total;
private Num active;
NumVar index = new NumVar(0);
Rect heart;
/**
* @param total
* @param active
* @param img_on
* @param img_half
* @param img_off
* @param align
*/
public HeartBar(int total, int active, TxQuad img_on, TxQuad img_off, AlignX align)
public HeartBar(Num total, Num active, TxQuad img_on, TxQuad img_half, TxQuad img_off, AlignX align)
{
super();
this.total = total;
this.active = active;
this.img_on = img_on;
this.img_off = img_off;
this.img_half = img_half;
final Num h = height();
final Num w = width();
@ -44,10 +47,10 @@ public class HeartBar extends VisualComponent {
heart = leftEdge().growRight(h).moveX(index.mul(h));
break;
case RIGHT:
heart = rightEdge().growLeft(h).moveX(h.mul(-total + 1).add(index.mul(h)));
heart = rightEdge().growLeft(h).moveX(h.mul(Num.ONE.sub(total)).add(index.mul(h)));
break;
case CENTER:
heart = leftEdge().moveX(w.half().add(h.mul(-total / 2D))).growRight(h).moveX(index.mul(h));
heart = leftEdge().moveX(w.half().add(h.mul(total.half().neg()))).growRight(h).moveX(index.mul(h));
break;
}
@ -57,10 +60,12 @@ public class HeartBar extends VisualComponent {
@Override
protected void renderComponent()
{
for (int i = 0; i < total; i++) {
for (int i = 0; i < total.value(); i++) {
index.setTo(i);
Render.quadTextured(heart, (i < active ? img_on : img_off));
double rem = active.value()-i;
Render.quadTextured(heart, (rem>0.6 ? img_on : rem>0.25 ? img_half: img_off));
}
}

@ -11,11 +11,31 @@ import mightypork.gamecore.input.Keys;
import mightypork.gamecore.util.math.constraints.num.Num;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.rogue.Res;
import mightypork.rogue.world.WorldProvider;
import mightypork.rogue.world.gui.Minimap;
public class HudLayer extends ScreenLayer {
private Num playerHealthTotal = new Num() {
@Override
public double value()
{
return WorldProvider.get().getPlayerEntity().health.getMaxHealth() / 2D;
}
};
private Num playerHealthActive = new Num() {
@Override
public double value()
{
return WorldProvider.get().getPlayerEntity().health.getHealth() / 2D;
}
};
public HudLayer(Screen screen)
{
super(screen);
@ -38,15 +58,25 @@ public class HudLayer extends ScreenLayer {
final Rect shrunk = root.shrink(minWH.perc(3));
final Num displays_height = minWH.perc(6);
final HeartBar hearts = new HeartBar(6, 3, Res.getTxQuad("heart_on"), Res.getTxQuad("heart_off"), AlignX.LEFT);
//@formatter:off
final HeartBar hearts = new HeartBar(
playerHealthTotal,
playerHealthActive,
Res.getTxQuad("heart_on"),
Res.getTxQuad("heart_half"),
Res.getTxQuad("heart_off"),
AlignX.LEFT);
//@formatter:on
final Rect hearts_box = shrunk.topLeft().startRect().growDown(displays_height);
hearts.setRect(hearts_box);
root.add(hearts);
final HeartBar experience = new HeartBar(6, 2, Res.getTxQuad("xp_on"), Res.getTxQuad("xp_off"), AlignX.RIGHT);
/*final HeartBar experience = new HeartBar(6, 2, Res.getTxQuad("xp_on"), Res.getTxQuad("xp_off"), AlignX.RIGHT);
final Rect xp_box = shrunk.topRight().startRect().growDown(displays_height);
experience.setRect(xp_box);
root.add(experience);
root.add(experience);*/
final Minimap mm = new Minimap();

@ -5,6 +5,7 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import mightypork.gamecore.eventbus.events.Updateable;
import mightypork.gamecore.util.annot.DefaultImpl;
@ -31,6 +32,8 @@ public abstract class Entity implements IonObjBundled, Updateable {
private Level level;
private final EntityModel model;
protected final Random rand = new Random();
/** Entity ID */
private int entityId;
@ -39,11 +42,11 @@ public abstract class Entity implements IonObjBundled, Updateable {
// default modules
public final EntityModulePosition pos = new EntityModulePosition(this);
public final EntityModuleHealth health = new EntityModuleHealth(this);
private double despawnDelay = 1;
public Entity(EntityModel model, int eid)
{
this.entityId = eid;
this.model = model;
@ -218,16 +221,7 @@ public abstract class Entity implements IonObjBundled, Updateable {
@DefaultImpl
public boolean canRemoveCorpse()
{
return isDead();
}
/**
* Called when the dead entity was removed from the level.
*/
@DefaultImpl
public void onCorpseRemoved()
{
return isDead() && health.getTimeSinceLastDamage() > despawnDelay;
}
@ -244,4 +238,10 @@ public abstract class Entity implements IonObjBundled, Updateable {
health.receiveDamage(attackStrength);
}
public void setDespawnDelay(double despawnDelay)
{
this.despawnDelay = despawnDelay;
}
}

@ -179,6 +179,11 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
if (chasing && !entity.pos.isMoving()) {
final Entity prey = getPreyEntity();
if(prey==null) {
// prey killed and cleaned from level
stopChasing();
return;
}
if (!isPreyInAttackRange(prey)) {
//System.out.println("-upd STEP--");
@ -214,10 +219,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
}
startChasing(prey);
} else {
//System.out.println("-- Prey is null.");
}
}
}

@ -21,8 +21,10 @@ public class PlayerEntity extends Entity {
public PlayerAi(Entity entity)
{
super(entity);
health.setMaxHealth(24);
health.fill();
setDespawnDelay(3);
health.setMaxHealth(12);
health.fill(); // fill health bar to max
}
@ -117,9 +119,9 @@ public class PlayerEntity extends Entity {
return EntityType.PLAYER;
}
@Override
public void receiveAttack(Entity attacker, int attackStrength)
{
// FIXME ignore attack
}
// @Override
// public void receiveAttack(Entity attacker, int attackStrength)
// {
// // FIXME ignore attack
// }
}

@ -11,8 +11,8 @@ public class RatAi extends MonsterAi {
super(entity);
setAttackTime(1);
setScanTime(2);
setSleepTime(100);
setScanTime(1);
setSleepTime(10);
}
@ -33,7 +33,7 @@ public class RatAi extends MonsterAi {
@Override
protected int getAttackStrength()
{
return 1 + rand.nextInt(2);
return 1 + (rand.nextInt(5) == 0 ? 1 : 0);
}

@ -28,6 +28,10 @@ public class RatEntity extends Entity {
pos.addMoveListener(ai);
pos.setStepTime(0.5);
setDespawnDelay(3);
health.setMaxHealth(3 + rand.nextInt(3));
health.fill(); // fill health bar to max
}

@ -21,6 +21,8 @@ public class EntityModuleHealth extends EntityModule {
protected int maxHealth = 1;
protected boolean dead = false;
private double timeSinceLastDamage = Integer.MAX_VALUE;
@Override
public void load(IonBundle bundle) throws IOException
@ -93,6 +95,7 @@ public class EntityModuleHealth extends EntityModule {
public void receiveDamage(int attackStrength)
{
setHealth(health - attackStrength);
timeSinceLastDamage = 0;
}
@ -101,4 +104,19 @@ public class EntityModuleHealth extends EntityModule {
setHealth(maxHealth);
}
@Override
public void update(double delta)
{
if(timeSinceLastDamage < 3600) timeSinceLastDamage += delta;
}
/**
* @return seconds since last attack received (can be used for rendering)
*/
public double getTimeSinceLastDamage()
{
return timeSinceLastDamage;
}
}

@ -43,6 +43,7 @@ public class EntityModulePosition extends EntityModule {
public void save(IonBundle bundle) throws IOException
{
bundle.putSequence("path", path);
bundle.putBundled("lpos", lastPos);
bundle.putBundled("pos", entityPos);
bundle.put("step_time", stepTime);
}
@ -52,6 +53,7 @@ public class EntityModulePosition extends EntityModule {
public void load(IonBundle bundle) throws IOException
{
bundle.loadSequence("path", path);
bundle.loadBundled("lpos", lastPos);
bundle.loadBundled("pos", entityPos);
stepTime = bundle.get("step_time", stepTime);
@ -67,9 +69,29 @@ public class EntityModulePosition extends EntityModule {
public void setCoord(Coord coord)
{
freeTile(); // release old tile
entityPos.setTo(coord);
lastPos.setTo(coord);
cancelPath(); // discard remaining steps
occupyTile();
}
public void occupyTile()
{
if (entity.getLevel() != null) {
entity.getLevel().occupyTile(getCoord());
}
}
public void freeTile()
{
if (entity.getLevel() != null) {
entity.getLevel().freeTile(getCoord());
}
}
@ -79,6 +101,8 @@ public class EntityModulePosition extends EntityModule {
@Override
public void update(double delta)
{
if (entity.isDead()) return; // corpses dont walk
if (!entityPos.isFinished()) {
entityPos.update(delta);
}
@ -119,10 +143,10 @@ public class EntityModulePosition extends EntityModule {
if (step.x() != 0) this.lastXDir = step.x();
if (step.y() != 0) this.lastYDir = step.y();
freeTile();
lastPos.setTo(entityPos.getCoord());
entity.getLevel().freeTile(lastPos);//
entityPos.walk(step, stepTime);
entity.getLevel().occupyTile(planned);
occupyTile();
}
}
}

@ -5,6 +5,13 @@ import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.Easing;
import mightypork.gamecore.util.math.color.Color;
import mightypork.gamecore.util.math.color.pal.RGB;
import mightypork.gamecore.util.math.constraints.num.Num;
import mightypork.gamecore.util.math.constraints.num.NumConst;
import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated;
import mightypork.gamecore.util.math.constraints.num.mutable.NumVar;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.rogue.Res;
@ -24,6 +31,10 @@ public class EntityRendererMobLR extends EntityRenderer {
protected final Entity entity;
private NumVar animRedVar = Num.makeVar(0);
private Color hue = Color.rgb(Num.ONE, animRedVar, animRedVar);
public EntityRendererMobLR(Entity entity, String sheetKey)
{
@ -35,6 +46,8 @@ public class EntityRendererMobLR extends EntityRenderer {
@Override
public void render(MapRenderContext context)
{
double hurtTime = entity.health.getTimeSinceLastDamage();
TxQuad q = sheet.getQuad(Calc.frag(entity.pos.getProgress()));
if (entity.pos.lastXDir == -1) q = q.flipX();
@ -43,9 +56,25 @@ public class EntityRendererMobLR extends EntityRenderer {
final double w = tileRect.width().value();
final Vect visualPos = entity.pos.getVisualPos();
Rect spriteRect = Rect.make(visualPos.x() * w, visualPos.y() * w, w, w);
double hurtOffset = (1 - Calc.clamp(hurtTime / 0.1, 0, 1)) * (entity.isDead() ? 0.3 : 0.05);
Rect spriteRect = Rect.make(visualPos.x() * w, (visualPos.y() - hurtOffset) * w, w, w);
spriteRect = spriteRect.shrink(w * 0.05);
Render.quadTextured(spriteRect, q);
animRedVar.setTo(hurtTime / 0.3);
Render.pushMatrix();
Render.translate(spriteRect.center());
if (entity.isDead()) {
Render.rotateZ(Calc.clamp(hurtTime / 0.3, 0, 1) * 90);
}
double hw = spriteRect.width().half().value();
Render.quadTextured(Vect.ZERO.expand(hw, hw, hw, hw), q, hue.withAlpha(entity.isDead() ? 1 - hurtTime / 3 : 1));
Render.popMatrix();
}
}

@ -2,11 +2,9 @@ package mightypork.rogue.world.level;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import javax.print.attribute.standard.MediaSize.ISO;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.util.ion.IonBundle;
@ -218,8 +216,15 @@ public class Level implements MapAccess, IonObjBinary {
}
}
List<Entity> toRemove = new ArrayList<>();
for (final Entity e : entitySet) {
e.update(delta);
if (e.isDead() && e.canRemoveCorpse()) toRemove.add(e);
}
for (Entity e : toRemove) {
removeEntity(e);
}
}
@ -251,7 +256,7 @@ public class Level implements MapAccess, IonObjBinary {
public boolean addEntity(Entity entity, Coord pos)
{
final Tile t = getTile(pos);
if (!t.isWalkable()) return false;
if (!t.isWalkable() || isOccupied(pos)) return false;
addEntity(entity);
@ -273,13 +278,13 @@ public class Level implements MapAccess, IonObjBinary {
// join to level & world
entity.setLevel(this);
occupyTile(entity.getCoord());
}
public void removeEntity(Entity entity)
{
entityMap.remove(entity.getEntityId());
entitySet.remove(entity);
removeEntity(entity.getEntityId());
}
@ -287,6 +292,7 @@ public class Level implements MapAccess, IonObjBinary {
{
final Entity removed = entityMap.remove(eid);
entitySet.remove(removed);
freeTile(removed.getCoord());
}
@ -316,14 +322,13 @@ public class Level implements MapAccess, IonObjBinary {
}
public void cleanCorpses()
/**
* @param pos tile coord
* @return true if something is standing there.
*/
public boolean isOccupied(Coord pos)
{
for (final Entity e : entitySet) {
if (e.isDead() && e.canRemoveCorpse()) {
e.onCorpseRemoved();
removeEntity(e);
}
}
return getTile(pos).isOccupied();
}

Loading…
Cancel
Save