From 6761b69b634d496aaad55b1b8e4f3360555a88c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Wed, 23 Apr 2014 01:15:07 +0200 Subject: [PATCH] New 16px textures, player sprite, entity system. --- res/img/dudes.png | Bin 0 -> 835 bytes res/img/dudes.xcf | Bin 0 -> 8401 bytes res/img/tiles16.png | Bin 0 -> 3744 bytes res/img/tiles16.xcf | Bin 0 -> 10208 bytes src/mightypork/gamecore/render/Render.java | 100 +++++-------- .../gamecore/render/Screenshot.java | 1 + .../gamecore/render/textures/TxQuad.java | 39 +++++ .../gamecore/render/textures/TxSheet.java | 19 ++- src/mightypork/rogue/Res.java | 49 ++++-- .../rogue/screens/ingame/WorldLayer.java | 139 +++++++++++------- .../rogue/screens/ingame/WorldRenderer.java | 2 +- src/mightypork/rogue/world/MapGenerator.java | 4 +- src/mightypork/rogue/world/PathStep.java | 37 ++++- src/mightypork/rogue/world/PlayerControl.java | 46 ++++++ src/mightypork/rogue/world/World.java | 23 ++- src/mightypork/rogue/world/WorldPos.java | 12 ++ src/mightypork/rogue/world/entity/Entity.java | 121 ++++++++++++--- .../world/entity/models/EntityModel.java | 13 +- .../entity/models/EntityMoveListener.java | 28 ++++ .../world/entity/models/PlayerModel.java | 8 + .../entity/renderers/EntityRenderer.java | 9 +- .../entity/renderers/NullEntityRenderer.java | 10 ++ .../entity/renderers/PlayerRenderer.java | 43 ++++++ src/mightypork/rogue/world/level/Level.java | 64 ++++++-- .../world/level/render/TileRenderContext.java | 4 +- src/mightypork/rogue/world/tile/Tile.java | 21 ++- src/mightypork/rogue/world/tile/Tiles.java | 29 ++-- .../world/tile/models/AbstractNullTile.java | 6 + .../rogue/world/tile/models/Floor.java | 6 + .../rogue/world/tile/models/TileModel.java | 3 + .../rogue/world/tile/models/Wall.java | 7 + .../tile/renderers/BasicTileRenderer.java | 62 +++++++- 32 files changed, 703 insertions(+), 202 deletions(-) create mode 100644 res/img/dudes.png create mode 100644 res/img/dudes.xcf create mode 100644 res/img/tiles16.png create mode 100644 res/img/tiles16.xcf create mode 100644 src/mightypork/rogue/world/PlayerControl.java create mode 100644 src/mightypork/rogue/world/entity/models/EntityMoveListener.java create mode 100644 src/mightypork/rogue/world/entity/renderers/PlayerRenderer.java diff --git a/res/img/dudes.png b/res/img/dudes.png new file mode 100644 index 0000000000000000000000000000000000000000..46fc775b964f86b4914f0b89ffef2f2bb4b64d7a GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSY)RhkE)1U;9x^=m_xGeMP=vF< zBeIx*fm;}a85w5HkpK#^mw5WRvfpD76Eom8(e*qE6p}1)jVN)>&&^HED`9XhN=+EaktaqI0(!+ha%3HA@i4+I<(Sh7OHd&*2b$v2Es z_$RDvcK>!lTSKTs(?_Rw!U-9})R*iIQ%|uw%PC0X5U}C|Cc}S`8aoOl*sD-pS9L%tJmwg27Nj5IL>6*8sqnWPFZ}{m9|*( zd#B&;X#Rpze@^8$L`p^6znjy?v%d0goy^zYg>GW*}Af8TyN-Fjbk>F(LIUkkU-uY2)!dA9e&Z@cGix&PK@mErpu z>4Y}6YunAkF1_uYS`wjLenc zcXo8Fz4j`^wcT{nwy4z`chneeGY^|&=scsmPW9?1W(hlsJJqt=%jVTwJ?Abnc6_f&(Qsycy}$jB*L{|2(XV?|9woeq58T#x+_L6#ypGrV8t-#vDy^`pE_oUHEg&wJ(7`3mO!oO+MJ*kr@r&l)RT zUB2)g;4Px z<2Yr$c0uFuQ|tb}eYn5({`-0VONzf2eB$I~uQ>Fl% zA0XI;$`q_ps5B6$N@E~@L6E)cZQx*6WMSBaJNgdxa=DZD=Erg=`Ro8Ll0pQA-;ejr z47u~>+xcdF|z zF660o414a%=Jo4qH@0C5fui7h%I3Art(CJzoZDKzd}-x_pM79HuTeg9(EI3m`88cV zzViJFyMA%&=A|neH`Z4^Jnsi=oxS}!r}Lfr^No$|m5m!$uCCo;|IL2?*4lRY1L3-T z)MY*MUHKf`N8ZN@{KZ?4cU|LCZG5`<<)z-g{sC3g(YP!ct>JXWG@TA1ep=C675zj- zKUvXFRrE#Z9M^vqpm08ZJSCJh`K>NH{VpUMV%3-UFP}r_=dNw)Z=l*U_EiPq4KWI@-_8c9tz(Te1rx|fZge3K+PoOyD3B=F!KRbAKLWxL~hS(c2)FoJs% zc%SQ9)m_uymNA(Q^duV$cE`bZx|?C>7c-2Y926EC11k+8MK&lj*d2reOh~I7Lnc*--R1-He)d;%ll`JH z2AkCfn7H4&!_njF9SwdTN5ESsxE!lI#oyJ8H*TRisFEf*m=?vp(aB z?VWH3{}5}mGszAPsMU95R@ajutQ|>kLCXV)*0eHhYIRWP19{NUGIanY0AqtYDlK#> zQv@Uqpah{5q=KxQwxAb4F5iNr&|pzqVPF$r9j$?88Q6qv*;v>4H&4dkW78}6q0gOf z!Tai3j$bBOc5j@GLBMab@z`1{8Q|F!hw^hn^r7FGPc@6zsQ>)Eq-G~y1}n!x**S!(76V@e}smP&iQ?kE^d zyD5f#F~bPTUSY8ju+kt>q&;KHQQqzKW@z5UqXS0{!-^xhVD#?xR8MtP4`j2z1f!Ua z9x3Lnm~`s)KI?_O{Ieddats+)A$FSSJoy2)-)8DxS%VrHolv>oHQ(D;*TM~87f z3`R(Gk)=$~H0|OcOybpEZ&j^YtBMryYOpGMdD>-M@yTkqihqbTTAieOd(`TyGDViU z4{KEt1TXi%|2+_hav#*%EA*b+LlW9|03`rpgF9-!(ED;90kH!pK_~^OAnT@qcp#T= zL0o9C2wAFRAhJ}9EQR0&$G|3R%SL3WuOE)UM`S6h;D8oo)?ze4XU>CM_IjG%k8Q7RmtnNnOLj5fQ3!K&HRhV$=guv< zZ&Z<`(&9e3K!Ge(u^bz?*oGCzL3{iAq=Wa&Xkh377EJcBs^Eh|DD7H5;I4i&XLV zzKa%z7oR>ALuTaQ;soAD%u+Kq7*iS%vsBb>FAjs@bTPuvFJ>4)*)A+L1XdbEil}XD zIm{Q^?HQUcMiDu37*-s~1*3PTt=ei)wLvxuOfZV+=#gUH5~Ne7eWo3@^D}K)_ zA$FS&%sbIf&`oxV${-UABABI0&~_Aap<=1p(P5kqgAr04WGNFgjXHP;6S3TGFRNv1 zRgpq02g|aZM;*o$OUvOh{vp*qD{JCmR53i72xJT*WT_||st8%i zNpGu24MX6Rz;x)Ow_8!sAw5LYpk^M>ybGBl5>YM61r`l#5wJpQF`A$==Rq!eJ<6Aa z?bYcpj23&z4hB35VXltGT+=1)+@kYF65`qZRlaHtyy>5s?ve54(Mvo(-B%uG~HdV|WHlcBg1{u&j{1)N@gp^N9JJ*TLU&!en(#Y!Z3 z0==1igx0aOLMf&R59~5Ik7M{$C;B7E3+~hnX-Y0gQ(0Z`=jS_(jy5yKm@&qTk8zHi z;n8tho%NVn!Qyp{G6tkGOD5N<;L7I~iX0`9b za#n#^1!jGO_rer!FU%UfVwMmOIBOI z(;cVWg=E8x>I?vGQ-|{M@ze^i?6+AH)B5w0{x^%hQKFh1hMw^9Hw16L^u}ABHe- zF;TH(LLWnXC^JK-TP8!8dy$qgLwy1puO*C&>It(CytI3Q+u@|h6YLiYdw0c!Lqs1} zW<>B)uzhK9Li6KzVPRE?>kj@h+b}KCs!LgKlkDPSsE2};CAA<4#hK%~2YZWfeD}bs zD7-LvD=~lf@L%kw*zYG(#du4`Z`@C;s1NNYy56#%;-mX%=Hk_X-%l*xjpa8Hsy(kt z6y|m>aZjO`ey9C}`p4|2*zBj{DjBDR<0{!)n!L73e*1pnuHZ|^?+&u-dtOQ`__!}3;S}iZ={*cn$~QeQ+OpA)o&QoAYPRy7b|-wdWXHk_mUk7@1f(mji>D6 zx(&zF*Vb*JIhEOBzER!+9In5JvkvpO1c&j%_1Ov3imcNpPoR)ISxV|}YpmlKGpqAB lFURxqTj>vAZwJ0wx>gF)mFgyIt$>6xO`oAiz{sZ(`T}uD} literal 0 HcmV?d00001 diff --git a/res/img/tiles16.png b/res/img/tiles16.png new file mode 100644 index 0000000000000000000000000000000000000000..c972b97d7e07ea94a6d896f420c72acaeb52b44c GIT binary patch literal 3744 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 count) { - throw new IndexOutOfBoundsException("Index out of bounds: " + index + ", allowed: 0.." + count); + if (index < 0 || index >= count) { + Log.w("Index out of bounds: " + index + ", allowed: 0.." + count); + index = index % count; } // lazy - init only when needed diff --git a/src/mightypork/rogue/Res.java b/src/mightypork/rogue/Res.java index 475d674..65cce3d 100644 --- a/src/mightypork/rogue/Res.java +++ b/src/mightypork/rogue/Res.java @@ -61,10 +61,13 @@ public final class Res { private static void loadTextures() { GLTexture texture; + QuadGrid tiles; + // tests texture = textures.loadTexture("test.kitten", "/res/img/kitten.png", FilterMode.LINEAR, WrapMode.CLAMP); texture = textures.loadTexture("test.kitten2", "/res/img/kitten_npot.png", FilterMode.LINEAR, WrapMode.CLAMP); + // gui texture = textures.loadTexture("gui1", "/res/img/gui1.png", FilterMode.NEAREST, WrapMode.CLAMP); final QuadGrid gui = texture.grid(4, 4); textures.addQuad("item_frame", gui.makeQuad(0, 0)); @@ -76,19 +79,41 @@ public final class Res { textures.addQuad("xp_off", gui.makeQuad(.5, 1.5, .5, .5)); textures.addQuad("panel", gui.makeQuad(0, 3.75, 4, .25)); - texture = textures.loadTexture("tiles", "/res/img/tiles.png", FilterMode.NEAREST, WrapMode.CLAMP); - final QuadGrid tiles = texture.grid(32, 32); + // huge sheet +// texture = textures.loadTexture("tiles", "/res/img/tiles.png", FilterMode.NEAREST, WrapMode.CLAMP); +// tiles = texture.grid(32, 32); +// textures.addSheet("tile.wall.mossy_bricks", tiles.makeSheet(4, 0, 7, 1)); +// textures.addSheet("tile.wall.small_bricks", tiles.makeSheet(0, 0, 4, 1)); +// textures.addSheet("tile.floor.mossy_bricks", tiles.makeSheet(16, 5, 7, 1)); +// textures.addSheet("tile.floor.rect_bricks", tiles.makeSheet(23, 5, 4, 1)); +// textures.addSheet("tile.wall.sandstone", tiles.makeSheet(0, 3, 10, 1)); +// textures.addSheet("tile.floor.sandstone", tiles.makeSheet(0, 6, 10, 1)); +// textures.addSheet("tile.wall.brown_cobble", tiles.makeSheet(0, 8, 8, 1)); +// textures.addSheet("tile.floor.brown_cobble", tiles.makeSheet(0, 11, 9, 1)); +// textures.addSheet("tile.floor.crystal", tiles.makeSheet(4, 5, 6, 1)); +// textures.addSheet("tile.wall.crystal", tiles.makeSheet(12, 2, 14, 1)); - textures.addSheet("tile.wall.mossy_bricks", tiles.makeSheet(4, 0, 7, 1)); - textures.addSheet("tile.wall.small_bricks", tiles.makeSheet(0, 0, 4, 1)); - textures.addSheet("tile.floor.mossy_bricks", tiles.makeSheet(16, 5, 7, 1)); - textures.addSheet("tile.floor.rect_bricks", tiles.makeSheet(23, 5, 4, 1)); - textures.addSheet("tile.wall.sandstone", tiles.makeSheet(0, 3, 10, 1)); - textures.addSheet("tile.floor.sandstone", tiles.makeSheet(0, 6, 10, 1)); - textures.addSheet("tile.wall.brown_cobble", tiles.makeSheet(0, 8, 8, 1)); - textures.addSheet("tile.floor.brown_cobble", tiles.makeSheet(0, 11, 9, 1)); - textures.addSheet("tile.floor.crystal", tiles.makeSheet(4, 5, 6, 1)); - textures.addSheet("tile.wall.crystal", tiles.makeSheet(12, 2, 14, 1)); + // sprites + texture = textures.loadTexture("mob", "/res/img/dudes.png", FilterMode.NEAREST, WrapMode.CLAMP); + tiles = texture.grid(8, 8); + textures.addSheet("player", tiles.makeSheet(0, 0, 4, 1)); + + // small sheet + texture = textures.loadTexture("tiles16", "/res/img/tiles16.png", FilterMode.NEAREST, WrapMode.CLAMP); + tiles = texture.grid(8, 8); + + textures.addSheet("tile16.floor.dark", tiles.makeSheet(0, 1, 5, 1)); + textures.addSheet("tile16.wall.brick", tiles.makeSheet(0, 0, 5, 1)); + + textures.addQuad("tile16.shadow.n", tiles.makeQuad(0, 7)); + textures.addQuad("tile16.shadow.s", tiles.makeQuad(0, 7).flipY()); + textures.addQuad("tile16.shadow.w", tiles.makeQuad(2, 7)); + textures.addQuad("tile16.shadow.e", tiles.makeQuad(2, 7).flipX()); + + textures.addQuad("tile16.shadow.nw", tiles.makeQuad(1, 7)); + textures.addQuad("tile16.shadow.ne", tiles.makeQuad(1, 7).flipX()); + textures.addQuad("tile16.shadow.sw", tiles.makeQuad(1, 7).flipY()); + textures.addQuad("tile16.shadow.se", tiles.makeQuad(1, 7).flipY().flipX()); } diff --git a/src/mightypork/rogue/screens/ingame/WorldLayer.java b/src/mightypork/rogue/screens/ingame/WorldLayer.java index 6d0be6d..e3722ff 100644 --- a/src/mightypork/rogue/screens/ingame/WorldLayer.java +++ b/src/mightypork/rogue/screens/ingame/WorldLayer.java @@ -7,9 +7,16 @@ import java.util.Random; import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.ScreenLayer; +import mightypork.gamecore.input.InputSystem; +import mightypork.gamecore.input.KeyStroke; +import mightypork.gamecore.input.Keys; import mightypork.rogue.Paths; import mightypork.rogue.world.MapGenerator; +import mightypork.rogue.world.PlayerControl; import mightypork.rogue.world.World; +import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.entity.models.EntityMoveListener; +import mightypork.rogue.world.level.Level; import mightypork.util.ion.Ion; @@ -46,63 +53,81 @@ public class WorldLayer extends ScreenLayer { wr.setRect(root); root.add(wr); -// bindKey(new KeyStroke(true, Keys.LEFT), new Runnable() { -// -// @Override -// public void run() -// { -// w.getPlayer().walk(-1, 0); -// } -// }); -// bindKey(new KeyStroke(true, Keys.RIGHT), new Runnable() { -// -// @Override -// public void run() -// { -// w.getPlayer().walk(1, 0); -// } -// }); -// bindKey(new KeyStroke(true, Keys.UP), new Runnable() { -// -// @Override -// public void run() -// { -// w.getPlayer().walk(0, -1); -// } -// }); -// bindKey(new KeyStroke(true, Keys.DOWN), new Runnable() { -// -// @Override -// public void run() -// { -// w.getPlayer().walk(0, 1); -// } -// }); -// bindKey(new KeyStroke(true, Keys.SPACE), new Runnable() { -// -// @Override -// public void run() -// { -// w.getPlayer().walk(5, 5); -// } -// }); -// -// w.getPlayer().setMoveListener(new Runnable() { -// -// @Override -// public void run() -// { -// if (InputSystem.isKeyDown(Keys.LEFT)) { -// w.getPlayer().walk(-1, 0); -// } else if (InputSystem.isKeyDown(Keys.RIGHT)) { -// w.getPlayer().walk(1, 0); -// } else if (InputSystem.isKeyDown(Keys.UP)) { -// w.getPlayer().walk(0, -1); -// } else if (InputSystem.isKeyDown(Keys.DOWN)) { -// w.getPlayer().walk(0, 1); -// } -// } -// }); + final PlayerControl c = w.getPlayerControl(); + + bindKey(new KeyStroke(true, Keys.LEFT), new Runnable() { + + @Override + public void run() + { + c.walkWest(); + } + }); + + bindKey(new KeyStroke(true, Keys.RIGHT), new Runnable() { + + @Override + public void run() + { + c.walkEast(); + } + }); + + bindKey(new KeyStroke(true, Keys.UP), new Runnable() { + + @Override + public void run() + { + c.walkNorth(); + } + }); + + bindKey(new KeyStroke(true, Keys.DOWN), new Runnable() { + + @Override + public void run() + { + c.walkSouth(); + } + }); + + c.addMoveListener(new EntityMoveListener() { + + private void tryGo(Entity entity) + { + if (InputSystem.isKeyDown(Keys.LEFT)) { + c.walkWest(); + } else if (InputSystem.isKeyDown(Keys.RIGHT)) { + c.walkEast(); + } else if (InputSystem.isKeyDown(Keys.UP)) { + c.walkNorth(); + } else if (InputSystem.isKeyDown(Keys.DOWN)) { + c.walkSouth(); + } + } + + + @Override + public void onStepFinished(Entity entity, World world, Level level) + { + entity.cancelPath(); // halt + tryGo(entity); + } + + + @Override + public void onPathFinished(Entity entity, World world, Level level) + { + entity.cancelPath(); // halt + tryGo(entity); + } + + + @Override + public void onPathAborted(Entity entity, World world, Level level) + { + } + }); } diff --git a/src/mightypork/rogue/screens/ingame/WorldRenderer.java b/src/mightypork/rogue/screens/ingame/WorldRenderer.java index 524c84f..868618e 100644 --- a/src/mightypork/rogue/screens/ingame/WorldRenderer.java +++ b/src/mightypork/rogue/screens/ingame/WorldRenderer.java @@ -48,7 +48,7 @@ public class WorldRenderer extends InputComponent implements Updateable { @Override protected void renderComponent() { - world.render(this, 8, 6, 64); + world.render(this, 8, 6, 110); Render.quadGradH(leftShadow, RGB.BLACK, RGB.NONE); Render.quadGradH(rightShadow, RGB.NONE, RGB.BLACK); diff --git a/src/mightypork/rogue/world/MapGenerator.java b/src/mightypork/rogue/world/MapGenerator.java index 65797bd..6e9fc48 100644 --- a/src/mightypork/rogue/world/MapGenerator.java +++ b/src/mightypork/rogue/world/MapGenerator.java @@ -21,8 +21,8 @@ public class MapGenerator { final World w = new World(); w.setSeed(seed); - w.addLevel(createLevel(rand.nextLong(), Tiles.CRYSTAL_FLOOR, Tiles.CRYSTAL_WALL)); - w.addLevel(createLevel(rand.nextLong(), Tiles.BRCOBBLE_FLOOR, Tiles.BRCOBBLE_WALL)); + w.addLevel(createLevel(rand.nextLong(), Tiles.FLOOR_DARK, Tiles.WALL_BRICK)); + //w.addLevel(createLevel(rand.nextLong(), Tiles.BRCOBBLE_FLOOR, Tiles.BRCOBBLE_WALL)); // TODO place on start position w.createPlayer(10, 10, 0); diff --git a/src/mightypork/rogue/world/PathStep.java b/src/mightypork/rogue/world/PathStep.java index ada46a2..b5b7174 100644 --- a/src/mightypork/rogue/world/PathStep.java +++ b/src/mightypork/rogue/world/PathStep.java @@ -10,6 +10,37 @@ import mightypork.util.ion.IonOutput; public class PathStep implements IonBinary { + public static final PathStep NORTH = new PathStep(0, -1); + public static final PathStep SOUTH = new PathStep(0, 1); + public static final PathStep EAST = new PathStep(1, 0); + public static final PathStep WEST = new PathStep(-1, 0); + public static final PathStep NORTH_EAST = new PathStep(1, -1); + public static final PathStep NORTH_WEST = new PathStep(-1, -1); + public static final PathStep SOUTH_EAST = new PathStep(1, 1); + public static final PathStep SOUTH_WEST = new PathStep(-1, 1); + public static final PathStep NONE = new PathStep(0, 0); + + + public static PathStep make(int x, int y) + { + x = x < 0 ? -1 : x > 0 ? 1 : 0; + y = y < 0 ? -1 : y > 0 ? 1 : 0; + + if (x == 0 && y == -1) return NORTH; + if (x == 0 && y == 1) return SOUTH; + if (x == -1 && y == 0) return WEST; + if (x == 1 && y == 0) return EAST; + + if (x == -1 && y == -1) return NORTH_WEST; + if (x == 1 && y == -1) return NORTH_EAST; + if (x == -1 && y == 1) return SOUTH_WEST; + if (x == 1 && y == 1) return SOUTH_EAST; + + if (x == 0 && y == 0) return NONE; + + return new PathStep(x, y); + } + public static final int ION_MARK = 0; public int x; @@ -18,10 +49,8 @@ public class PathStep implements IonBinary { public PathStep(int x, int y) { - this.x = x < 1 ? -1 : x > 0 ? 1 : 0; - this.y = y < 1 ? -1 : y > 0 ? 1 : 0; - - y = (int) Math.signum(x); + this.x = x < 0 ? -1 : x > 0 ? 1 : 0; + this.y = y < 0 ? -1 : y > 0 ? 1 : 0; } diff --git a/src/mightypork/rogue/world/PlayerControl.java b/src/mightypork/rogue/world/PlayerControl.java new file mode 100644 index 0000000..14982ca --- /dev/null +++ b/src/mightypork/rogue/world/PlayerControl.java @@ -0,0 +1,46 @@ +package mightypork.rogue.world; + + +import mightypork.rogue.world.entity.models.EntityMoveListener; + + +public class PlayerControl { + + private final World world; + + + public PlayerControl(World w) + { + this.world = w; + } + + + public void walkNorth() + { + world.playerEntity.addStep(PathStep.NORTH); + } + + + public void walkSouth() + { + world.playerEntity.addStep(PathStep.SOUTH); + } + + + public void walkEast() + { + world.playerEntity.addStep(PathStep.EAST); + } + + + public void walkWest() + { + world.playerEntity.addStep(PathStep.WEST); + } + + + public void addMoveListener(EntityMoveListener eml) + { + world.playerEntity.addMoveListener(eml); + } +} diff --git a/src/mightypork/rogue/world/World.java b/src/mightypork/rogue/world/World.java index 25553aa..a0ca94e 100644 --- a/src/mightypork/rogue/world/World.java +++ b/src/mightypork/rogue/world/World.java @@ -22,7 +22,10 @@ public class World implements IonBundled, Updateable { private final ArrayList levels = new ArrayList<>(); - private final PlayerInfo player = new PlayerInfo(); + final PlayerInfo player = new PlayerInfo(); + Entity playerEntity; + + private final PlayerControl control = new PlayerControl(this); private long seed; // world seed private int eid; // next entity ID @@ -57,7 +60,7 @@ public class World implements IonBundled, Updateable { @Override public void update(double delta) { - getCurrentLevel().update(delta); + getCurrentLevel().update(this, delta); } @@ -89,14 +92,14 @@ public class World implements IonBundled, Updateable { } // make entity - int playerEid = getNewEID(); + final int playerEid = getNewEID(); - final Entity entity = Entities.PLAYER.createEntity(playerEid, new WorldPos(x, y)); + playerEntity = Entities.PLAYER.createEntity(playerEid, new WorldPos(x, y)); player.setLevel(level); player.setEID(playerEid); - levels.get(level).addEntity(entity); + levels.get(level).addEntity(playerEntity); } @@ -108,9 +111,9 @@ public class World implements IonBundled, Updateable { * @param yTiles Desired nr of tiles vertically * @param minSize minimum tile size */ - public void render(RectBound viewport, final int yTiles, final int xTiles, final int minSize) + public void render(RectBound viewport, final int xTiles, final int yTiles, final int minSize) { - getCurrentLevel().render(player, viewport, yTiles, xTiles, minSize); + getCurrentLevel().render(playerEntity.getPosition(), viewport, xTiles, yTiles, minSize); } @@ -118,4 +121,10 @@ public class World implements IonBundled, Updateable { { return levels.get(player.getLevel()); } + + + public PlayerControl getPlayerControl() + { + return control; + } } diff --git a/src/mightypork/rogue/world/WorldPos.java b/src/mightypork/rogue/world/WorldPos.java index bdecdda..d6703ff 100644 --- a/src/mightypork/rogue/world/WorldPos.java +++ b/src/mightypork/rogue/world/WorldPos.java @@ -82,6 +82,18 @@ public class WorldPos implements IonBundled, Updateable { } + public double getVisualXOffset() + { + return walkOffset.x(); + } + + + public double getVisualYOffset() + { + return walkOffset.y(); + } + + public void setTo(int x, int y) { this.x = x; diff --git a/src/mightypork/rogue/world/entity/Entity.java b/src/mightypork/rogue/world/entity/Entity.java index 82ca2b1..abd0f30 100644 --- a/src/mightypork/rogue/world/entity/Entity.java +++ b/src/mightypork/rogue/world/entity/Entity.java @@ -2,14 +2,18 @@ package mightypork.rogue.world.entity; import java.io.IOException; +import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; import java.util.Queue; import mightypork.rogue.world.PathStep; import mightypork.rogue.world.World; import mightypork.rogue.world.WorldPos; import mightypork.rogue.world.entity.models.EntityModel; +import mightypork.rogue.world.entity.models.EntityMoveListener; import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.level.render.EntityRenderContext; import mightypork.util.ion.IonBinary; import mightypork.util.ion.IonBundle; import mightypork.util.ion.IonBundled; @@ -22,23 +26,32 @@ import mightypork.util.ion.IonOutput; * * @author MightyPork */ -public final class Entity implements IonBinary, IonBundled { +public final class Entity implements IonBinary, IonBundled, EntityMoveListener { // binary & bundled - binary stores via a bundle public static final int ION_MARK = 52; - private final WorldPos position = new WorldPos(); + private final WorldPos position = new WorldPos(); // saved /** Entity ID */ - private int eid = 0; + private int eid = 0; // saved /** Model ID */ - private int id; + private int id; // saved - private final Queue path = new LinkedList<>(); + private final Queue path = new LinkedList<>(); // saved private EntityModel model; - private final IonBundle metadata = new IonBundle(); + public final IonBundle metadata = new IonBundle(); // saved + public final IonBundle tmpdata = new IonBundle(); // NOT saved + + // used for rendering "facing" sprite + public int lastXMove = 1; + public int lastYMove = 1; + + private final List moveListeners = new ArrayList<>(); + + private boolean walking = false; public Entity(int eid, WorldPos pos, EntityModel entityModel) @@ -52,6 +65,10 @@ public final class Entity implements IonBinary, IonBundled { private void setModel(EntityModel entityModel) { + // replace listener + if (model != null) moveListeners.remove(model); + moveListeners.add(entityModel); + this.id = entityModel.id; this.model = entityModel; } @@ -93,7 +110,10 @@ public final class Entity implements IonBinary, IonBundled { bundle.putBundled("pos", position); bundle.putSequence("steps", path); bundle.put("eid", eid); - bundle.put("metadata", metadata); + + if (model.hasMetadata()) { + bundle.put("metadata", metadata); + } } @@ -110,11 +130,16 @@ public final class Entity implements IonBinary, IonBundled { bundle.loadSequence("path", path); eid = bundle.get("eid", eid); - metadata.clear(); - bundle.loadBundle("metadata", metadata); + if (model.hasMetadata()) { + metadata.clear(); + bundle.loadBundle("metadata", metadata); + } } + /** + * @return unique entity id + */ public int getEID() { return eid; @@ -150,19 +175,49 @@ public final class Entity implements IonBinary, IonBundled { position.update(delta); } - if (position.isFinished()) { + if (walking && position.isFinished()) { + walking = false; - model.onStepFinished(this, world, level); + onStepFinished(this, world, level); - if (!path.isEmpty()) { - // get next step to walk - final PathStep step = path.poll(); - position.walk(step.x, step.y, getStepTime()); + if (path.isEmpty()) { + onPathFinished(this, world, level); + } + } + + if (!walking && !path.isEmpty()) { + + walking = true; + + final PathStep step = path.poll(); + + final int projX = position.x + step.x, projY = position.y + step.y; + + if (!level.canWalkInto(projX, projY)) { + cancelPath(); + onPathAborted(this, world, level); + walking = false; } else { - // notify AI or whatever - model.onPathFinished(this, world, level); + + // tmp for renderer + if (step.x != 0) lastXMove = step.x; + if (step.y != 0) lastYMove = step.y; + + position.walk(step.x, step.y, getStepTime()); + level.occupyTile(projX, projY); + level.freeTile(position.x, position.y); } } + + if (!walking) { + model.update(this, level, delta); + } + } + + + public void render(EntityRenderContext context) + { + model.renderer.render(this, context); } @@ -189,4 +244,36 @@ public final class Entity implements IonBinary, IonBundled { return model.getStepTime(this); } + + @Override + public void onStepFinished(Entity entity, World world, Level level) + { + for (final EntityMoveListener l : moveListeners) { + l.onStepFinished(entity, world, level); + } + } + + + @Override + public void onPathFinished(Entity entity, World world, Level level) + { + for (final EntityMoveListener l : moveListeners) { + l.onStepFinished(entity, world, level); + } + } + + + @Override + public void onPathAborted(Entity entity, World world, Level level) + { + for (final EntityMoveListener l : moveListeners) { + l.onPathAborted(entity, world, level); + } + } + + + public void addMoveListener(EntityMoveListener listener) + { + moveListeners.add(listener); + } } diff --git a/src/mightypork/rogue/world/entity/models/EntityModel.java b/src/mightypork/rogue/world/entity/models/EntityModel.java index ea0de63..c9c126a 100644 --- a/src/mightypork/rogue/world/entity/models/EntityModel.java +++ b/src/mightypork/rogue/world/entity/models/EntityModel.java @@ -14,7 +14,7 @@ import mightypork.rogue.world.level.Level; * * @author MightyPork */ -public abstract class EntityModel { +public abstract class EntityModel implements EntityMoveListener { /** Model ID */ public final int id; @@ -45,7 +45,7 @@ public abstract class EntityModel { /** - * Update entity + * Entity is idle, waiting for action. */ public abstract void update(Entity entity, Level level, double delta); @@ -57,15 +57,20 @@ public abstract class EntityModel { /** - * @param entity the value is valid for - * @return step time (seconds) + * Get one path step duration (in seconds) */ public abstract double getStepTime(Entity entity); + @Override public abstract void onStepFinished(Entity entity, World world, Level level); + @Override public abstract void onPathFinished(Entity entity, World world, Level level); + + @Override + public abstract void onPathAborted(Entity entity, World world, Level level); + } diff --git a/src/mightypork/rogue/world/entity/models/EntityMoveListener.java b/src/mightypork/rogue/world/entity/models/EntityMoveListener.java new file mode 100644 index 0000000..110e1df --- /dev/null +++ b/src/mightypork/rogue/world/entity/models/EntityMoveListener.java @@ -0,0 +1,28 @@ +package mightypork.rogue.world.entity.models; + + +import mightypork.rogue.world.World; +import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.level.Level; + + +public interface EntityMoveListener { + + /** + * One step of a path finished + */ + void onStepFinished(Entity entity, World world, Level level); + + + /** + * Scheduled path finished + */ + void onPathFinished(Entity entity, World world, Level level); + + + /** + * Path was aborted (bumped into a wall or entity) + */ + void onPathAborted(Entity entity, World world, Level level); + +} diff --git a/src/mightypork/rogue/world/entity/models/PlayerModel.java b/src/mightypork/rogue/world/entity/models/PlayerModel.java index 1cf2ca2..937c7fb 100644 --- a/src/mightypork/rogue/world/entity/models/PlayerModel.java +++ b/src/mightypork/rogue/world/entity/models/PlayerModel.java @@ -4,6 +4,7 @@ package mightypork.rogue.world.entity.models; import mightypork.rogue.world.World; import mightypork.rogue.world.WorldPos; import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.entity.renderers.PlayerRenderer; import mightypork.rogue.world.level.Level; @@ -20,6 +21,7 @@ public class PlayerModel extends EntityModel { public PlayerModel(int id) { super(id); + setRenderer(new PlayerRenderer("player")); } @@ -64,4 +66,10 @@ public class PlayerModel extends EntityModel { public void onPathFinished(Entity entity, World world, Level level) { } + + + @Override + public void onPathAborted(Entity entity, World world, Level level) + { + } } diff --git a/src/mightypork/rogue/world/entity/renderers/EntityRenderer.java b/src/mightypork/rogue/world/entity/renderers/EntityRenderer.java index 7858a73..3251867 100644 --- a/src/mightypork/rogue/world/entity/renderers/EntityRenderer.java +++ b/src/mightypork/rogue/world/entity/renderers/EntityRenderer.java @@ -1,8 +1,15 @@ package mightypork.rogue.world.entity.renderers; -public class EntityRenderer { +import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.level.render.EntityRenderContext; + + +public abstract class EntityRenderer { public static final EntityRenderer NONE = new NullEntityRenderer(); + + public abstract void render(Entity entity, EntityRenderContext context); + } diff --git a/src/mightypork/rogue/world/entity/renderers/NullEntityRenderer.java b/src/mightypork/rogue/world/entity/renderers/NullEntityRenderer.java index 37e9bd2..012d658 100644 --- a/src/mightypork/rogue/world/entity/renderers/NullEntityRenderer.java +++ b/src/mightypork/rogue/world/entity/renderers/NullEntityRenderer.java @@ -1,6 +1,16 @@ package mightypork.rogue.world.entity.renderers; +import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.level.render.EntityRenderContext; + + public class NullEntityRenderer extends EntityRenderer { + @Override + public void render(Entity entity, EntityRenderContext context) + { + // hell no + } + } diff --git a/src/mightypork/rogue/world/entity/renderers/PlayerRenderer.java b/src/mightypork/rogue/world/entity/renderers/PlayerRenderer.java new file mode 100644 index 0000000..4d55216 --- /dev/null +++ b/src/mightypork/rogue/world/entity/renderers/PlayerRenderer.java @@ -0,0 +1,43 @@ +package mightypork.rogue.world.entity.renderers; + + +import mightypork.gamecore.render.Render; +import mightypork.gamecore.render.textures.TxQuad; +import mightypork.gamecore.render.textures.TxSheet; +import mightypork.rogue.Res; +import mightypork.rogue.world.WorldPos; +import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.level.render.EntityRenderContext; +import mightypork.util.constraints.rect.Rect; +import mightypork.util.math.Calc; + + +public class PlayerRenderer extends EntityRenderer { + + TxSheet sheet; + + + public PlayerRenderer(String sheetKey) + { + this.sheet = Res.getTxSheet(sheetKey); // expects 1x4 + } + + + @Override + public void render(Entity entity, EntityRenderContext context) + { + TxQuad q = sheet.getQuad(Calc.frag(entity.getPosition().getProgress())); + + if (entity.lastXMove == -1) q = q.flipX(); + + final WorldPos pos = entity.getPosition(); + + final Rect tileRect = context.getRectForTile(pos.x, pos.y); + final double w = tileRect.width().value(); + + Rect spriteRect = tileRect.move(pos.getVisualXOffset() * w, pos.getVisualYOffset() * w + w * 0.1); + spriteRect = spriteRect.shrink(w * 0.1); + + Render.quadTextured(spriteRect, q); + } +} diff --git a/src/mightypork/rogue/world/level/Level.java b/src/mightypork/rogue/world/level/Level.java index 0c050d7..83c6367 100644 --- a/src/mightypork/rogue/world/level/Level.java +++ b/src/mightypork/rogue/world/level/Level.java @@ -7,13 +7,12 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.lwjgl.opengl.GL11; - import mightypork.gamecore.render.Render; import mightypork.rogue.Res; -import mightypork.rogue.world.PlayerInfo; +import mightypork.rogue.world.World; import mightypork.rogue.world.WorldPos; import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.level.render.EntityRenderContext; import mightypork.rogue.world.level.render.TileRenderContext; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tiles; @@ -170,6 +169,11 @@ public class Level implements MapAccess, IonBinary { tiles[y][x].load(in); } } + + // mark tiles as occupied + for (final Entity e : entity_set) { + occupyTile(e.getPosition().x, e.getPosition().y); + } } @@ -201,7 +205,7 @@ public class Level implements MapAccess, IonBinary { } - public void update(double delta) + public void update(World w, double delta) { // just update them all for (int y = 0; y < height; y++) { @@ -209,6 +213,10 @@ public class Level implements MapAccess, IonBinary { getTile(x, y).update(this, delta); } } + + for (final Entity e : entity_set) { + e.update(w, this, delta); + } } @@ -232,16 +240,8 @@ public class Level implements MapAccess, IonBinary { * @param yTiles Desired nr of tiles vertically * @param minSize minimum tile size */ - public void render(PlayerInfo playerInfo, RectBound viewport, final int yTiles, final int xTiles, final int minSize) + public void render(WorldPos pos, RectBound viewport, final int xTiles, final int yTiles, final int minSize) { - final WorldPos pos; - - try { - pos = getEntity(playerInfo.getEID()).getPosition(); - } catch (NullPointerException e) { - throw new RuntimeException("Player entity not found in level.", e); - } - final Rect r = viewport.getRect(); final double vpH = r.height().value(); final double vpW = r.width().value(); @@ -250,9 +250,9 @@ public class Level implements MapAccess, IonBinary { final double allowedSizeW = vpW / xTiles; final double allowedSizeH = vpH / yTiles; - int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize)); + final int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize)); - tileSize -= tileSize % 16; + //tileSize -= tileSize % 8; final VectConst vpCenter = r.center().sub(tileSize * 0.5, tileSize).freeze(); // 0.5 to center, 1 to move up (down is teh navbar) @@ -280,7 +280,7 @@ public class Level implements MapAccess, IonBinary { // batch rendering of the tiles if (USE_BATCH_RENDERING) { - Render.enterBatchTexturedQuadMode(Res.getTexture("tiles")); + Render.enterBatchTexturedQuadMode(Res.getTexture("tiles16")); } for (trc.y = y1; trc.y <= y2; trc.y++) { @@ -299,6 +299,12 @@ public class Level implements MapAccess, IonBinary { trc.renderItems(); } } + + // render entities + final EntityRenderContext erc = new EntityRenderContext(this, mapRect); + for (final Entity e : entity_set) { + e.render(erc); + } } @@ -327,4 +333,30 @@ public class Level implements MapAccess, IonBinary { final Entity removed = entity_map.remove(eid); entity_set.remove(removed); } + + + public boolean canWalkInto(int x, int y) + { + final Tile t = getTile(x, y); + + return t.isWalkable() && !t.isOccupied(); + } + + + /** + * Mark tile as occupied by an entity + */ + public void occupyTile(int x, int y) + { + getTile(x, y).setOccupied(true); + } + + + /** + * Mark tile as free (no longet occupied) + */ + public void freeTile(int x, int y) + { + getTile(x, y).setOccupied(false); + } } diff --git a/src/mightypork/rogue/world/level/render/TileRenderContext.java b/src/mightypork/rogue/world/level/render/TileRenderContext.java index f5e79b8..8f9aa42 100644 --- a/src/mightypork/rogue/world/level/render/TileRenderContext.java +++ b/src/mightypork/rogue/world/level/render/TileRenderContext.java @@ -65,12 +65,14 @@ public final class TileRenderContext extends MapRenderContext implements RectBou { map.getTile(x, y).renderTile(this); } - + + public void renderItems() { map.getTile(x, y).renderItems(this); } + /** * Rect of the current tile to draw */ diff --git a/src/mightypork/rogue/world/tile/Tile.java b/src/mightypork/rogue/world/tile/Tile.java index 42b962b..169b6bb 100644 --- a/src/mightypork/rogue/world/tile/Tile.java +++ b/src/mightypork/rogue/world/tile/Tile.java @@ -34,6 +34,13 @@ public final class Tile implements IonBinary { /** persistent field for model, reflected by renderer */ public final IonBundle metadata = new IonBundle(); + // temporary flag for map. + private boolean occupied; + + // for renderer of AO shadows + public byte shadows; + public boolean shadowsComputed; + public Tile(int id) { @@ -75,6 +82,7 @@ public final class Tile implements IonBinary { /** * Render items + * * @param context */ public void renderItems(TileRenderContext context) @@ -85,7 +93,6 @@ public final class Tile implements IonBinary { } - @Override public void save(IonOutput out) throws IOException { @@ -156,4 +163,16 @@ public final class Tile implements IonBinary { { return ION_MARK; } + + + public boolean isOccupied() + { + return occupied; + } + + + public void setOccupied(boolean occupied) + { + this.occupied = occupied; + } } diff --git a/src/mightypork/rogue/world/tile/Tiles.java b/src/mightypork/rogue/world/tile/Tiles.java index 65597af..d3bcb06 100644 --- a/src/mightypork/rogue/world/tile/Tiles.java +++ b/src/mightypork/rogue/world/tile/Tiles.java @@ -20,21 +20,24 @@ public final class Tiles { public static final TileModel NULL_SOLID = new NullWall(0); public static final TileModel NULL_EMPTY = new NullFloor(1); - public static final TileModel BRICK_FLOOR_VINES = new Floor(2).setTexture("tile.floor.mossy_bricks"); - public static final TileModel BRICK_WALL_VINES = new Wall(3).setTexture("tile.wall.mossy_bricks"); + public static final TileModel FLOOR_DARK = new Floor(2).setTexture("tile16.floor.dark"); + public static final TileModel WALL_BRICK = new Wall(3).setTexture("tile16.wall.brick"); - public static final TileModel BRICK_FLOOR_RECT = new Floor(4).setTexture("tile.floor.rect_bricks"); - public static final TileModel BRICK_WALL_SMALL = new Wall(5).setTexture("tile.wall.small_bricks"); - - public static final TileModel SANDSTONE_FLOOR = new Floor(6).setTexture("tile.floor.sandstone"); - public static final TileModel SANDSTONE_WALL = new Wall(7).setTexture("tile.wall.sandstone"); - - public static final TileModel BRCOBBLE_FLOOR = new Floor(8).setTexture("tile.floor.brown_cobble"); - public static final TileModel BRCOBBLE_WALL = new Wall(9).setTexture("tile.wall.brown_cobble"); - - public static final TileModel CRYSTAL_FLOOR = new Floor(10).setTexture("tile.floor.crystal"); - public static final TileModel CRYSTAL_WALL = new Wall(11).setTexture("tile.wall.crystal"); +// public static final TileModel BRICK_FLOOR_VINES = new Floor(2).setTexture("tile.floor.mossy_bricks"); +// public static final TileModel BRICK_WALL_VINES = new Wall(3).setTexture("tile.wall.mossy_bricks"); +// +// public static final TileModel BRICK_FLOOR_RECT = new Floor(4).setTexture("tile.floor.rect_bricks"); +// public static final TileModel BRICK_WALL_SMALL = new Wall(5).setTexture("tile.wall.small_bricks"); +// +// public static final TileModel SANDSTONE_FLOOR = new Floor(6).setTexture("tile.floor.sandstone"); +// public static final TileModel SANDSTONE_WALL = new Wall(7).setTexture("tile.wall.sandstone"); +// +// public static final TileModel BRCOBBLE_FLOOR = new Floor(8).setTexture("tile.floor.brown_cobble"); +// public static final TileModel BRCOBBLE_WALL = new Wall(9).setTexture("tile.wall.brown_cobble"); +// +// public static final TileModel CRYSTAL_FLOOR = new Floor(10).setTexture("tile.floor.crystal"); +// public static final TileModel CRYSTAL_WALL = new Wall(11).setTexture("tile.wall.crystal"); public static void register(int id, TileModel model) { diff --git a/src/mightypork/rogue/world/tile/models/AbstractNullTile.java b/src/mightypork/rogue/world/tile/models/AbstractNullTile.java index 0e26c70..d9cc8a9 100644 --- a/src/mightypork/rogue/world/tile/models/AbstractNullTile.java +++ b/src/mightypork/rogue/world/tile/models/AbstractNullTile.java @@ -55,4 +55,10 @@ public abstract class AbstractNullTile extends SimpleTile { @Override public abstract boolean isWalkable(); + + @Override + public boolean doesCastShadow() + { + return false; + } } diff --git a/src/mightypork/rogue/world/tile/models/Floor.java b/src/mightypork/rogue/world/tile/models/Floor.java index 6baf9bd..636bc45 100644 --- a/src/mightypork/rogue/world/tile/models/Floor.java +++ b/src/mightypork/rogue/world/tile/models/Floor.java @@ -27,4 +27,10 @@ public class Floor extends SimpleTile { return true; } + + @Override + public boolean doesCastShadow() + { + return false; + } } diff --git a/src/mightypork/rogue/world/tile/models/TileModel.java b/src/mightypork/rogue/world/tile/models/TileModel.java index 9d3147b..f3bfef2 100644 --- a/src/mightypork/rogue/world/tile/models/TileModel.java +++ b/src/mightypork/rogue/world/tile/models/TileModel.java @@ -63,6 +63,9 @@ public abstract class TileModel { public abstract boolean isWalkable(); + public abstract boolean doesCastShadow(); + + public boolean isNullTile() { return false; diff --git a/src/mightypork/rogue/world/tile/models/Wall.java b/src/mightypork/rogue/world/tile/models/Wall.java index c18d431..36ce59e 100644 --- a/src/mightypork/rogue/world/tile/models/Wall.java +++ b/src/mightypork/rogue/world/tile/models/Wall.java @@ -27,4 +27,11 @@ public class Wall extends SimpleTile { return false; } + + @Override + public boolean doesCastShadow() + { + return true; + } + } diff --git a/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java b/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java index 7ca2e71..bc0e9d1 100644 --- a/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java +++ b/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java @@ -2,25 +2,85 @@ package mightypork.rogue.world.tile.renderers; import mightypork.gamecore.render.Render; +import mightypork.gamecore.render.textures.TxQuad; import mightypork.gamecore.render.textures.TxSheet; import mightypork.rogue.Res; import mightypork.rogue.world.level.render.TileRenderContext; +import mightypork.rogue.world.tile.Tile; +import mightypork.util.constraints.rect.Rect; public class BasicTileRenderer extends TileRenderer { private final TxSheet sheet; + private static boolean inited; + private static TxQuad SH_N, SH_S, SH_E, SH_W, SH_NW, SH_NE, SH_SW, SH_SE; + public BasicTileRenderer(String sheetKey) { this.sheet = Res.getTxSheet(sheetKey); + + if (!inited) { + SH_N = Res.getTxQuad("tile16.shadow.n"); + SH_S = Res.getTxQuad("tile16.shadow.s"); + SH_E = Res.getTxQuad("tile16.shadow.e"); + SH_W = Res.getTxQuad("tile16.shadow.w"); + SH_NW = Res.getTxQuad("tile16.shadow.nw"); + SH_NE = Res.getTxQuad("tile16.shadow.ne"); + SH_SW = Res.getTxQuad("tile16.shadow.sw"); + SH_SE = Res.getTxQuad("tile16.shadow.se"); + } } @Override public void render(TileRenderContext context) { - Render.quadTextured(context.getRect(), sheet.getRandomQuad(context.getTileNoise())); + final Rect rect = context.getRect(); + Render.quadTextured(rect, sheet.getRandomQuad(context.getTileNoise())); + + final Tile t = context.getTile(); + + if (t.getModel().doesCastShadow()) return; // no shadows for wall + + Tile t2; + + if (!t.shadowsComputed) { + // no shadows computed yet + + t.shadows = 0; // reset the mask + + int move = 0; + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + if (x == 0 && y == 0) continue; + + t2 = context.getAdjacentTile(x, y); + + if (t2.getModel().doesCastShadow()) { + t.shadows |= 1 << move; + } + + move++; + } + } + + t.shadowsComputed = true; + } + + if (t.shadows == 0) return; + + if ((t.shadows & (1 << 0)) != 0) Render.quadTextured(rect, SH_NW); + if ((t.shadows & (1 << 1)) != 0) Render.quadTextured(rect, SH_N); + if ((t.shadows & (1 << 2)) != 0) Render.quadTextured(rect, SH_NE); + + if ((t.shadows & (1 << 3)) != 0) Render.quadTextured(rect, SH_W); + if ((t.shadows & (1 << 4)) != 0) Render.quadTextured(rect, SH_E); + + if ((t.shadows & (1 << 5)) != 0) Render.quadTextured(rect, SH_SW); + if ((t.shadows & (1 << 6)) != 0) Render.quadTextured(rect, SH_S); + if ((t.shadows & (1 << 7)) != 0) Render.quadTextured(rect, SH_SE); } }