I have used MapEditor for my choice of map creation with my particular TileMaps that i have made. My question is this:
When exporting a created map VIA JSON, Usually it seems most map's are shown as their tile id as shown in the snippet below.
{
"data":[1, 2, 1, 2, 3, 1, 3, 1, 2, 2, 3, 3, 4, 4, 4, 1], <------ TIle Id's
"height":4,
"name":"ground",
"opacity":1,
"properties":
{
"tileLayerProp":"1"
},
"type":"tilelayer",
"visible":true,
"width":4,
"x":0,
"y":0
}
however, when i check my own exported JSON map in the same fields i see,
{
"compression":"zlib",
"data":"eJzt1UFqwzAQQFFvus1Juizdldz\/ViULgQmWItmyJMtv4JGQBirNT9NlmXO+L2qEaXHP30K9u\/RWuq9SYR4rqenZ5+xdlOzrzHlsyJ2Wbe4yWz1KmoS5W4\/UmcLPfiKPsYm10CM9qTPlnDW231SPkiaP5T49UufKbbG1308tcpqs33eHHkfPFttvbouSHmc3GWGOnK9k53uabL1vth7PwjPG1GyRa7bvq9Biz\/TY\/8w9jrR4Te8Wo\/fY871TY2ZtcWQ\/Rz\/rtUaPcVq8z\/peV2wRdvp6\/Fs9XwqejzJndWjdY\/37QpOrTOwuM\/So3ST2v77WtGjQu0etJqFF7F5HptXfQ48WqZ3tbZJqUaNJyw6j9PjU5Cvyek6LVJP312LvuWOPvedocc9ZW\/T4rF2NHuNo3UKPsVrooccV9GqhR\/\/96zFui1F6tDhj7z2P2KPXeXvveOYepXfovd879gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4v4BxPaYbQ==",
"encoding":"base64",
"height":100,
"name":"solids",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":100,
"x":0,
"y":0
},
both of these are real samples, the first pulled from their documentation and the second from my raw export. As you can see the 'data' field of theirs differs from mine in that theirs is a JSONArray and as a result I believe this function,
public static void load(String path) throws Exception
{
JSONParser parser = new JSONParser();
Object obj = parser.parse(new FileReader(path));
JSONObject jObj = (JSONObject) obj;
JSONArray layers = (JSONArray) jObj.get("layers");
int amount = layers.size();
for (int i = 0; i < amount; i++)
{
JSONObject layer = (JSONObject) layers.get(i);
String type = (String) layer.get("name");
if (type.equals("solids"))
{
WIDTH = (int) ((long)layer.get("width"));
HEIGHT = (int) ((long)layer.get("height"));
solids = parse((JSONArray) layer.get("data"));
}
has been giving me problems. Is it because in the 'data' field of my map, i believe that is a JSONString and an encoded one at that.
After reasearching it seems I would need to decode the 'data' and somehow eventually that will turn into the 'data' field you see in the first block of code.
Any tips on how i might do this or JUST DISABLE ENCODING ALL TOGETHER?
EDIT: MY PARSE FUNCTION UPON REQUEST
private static Image[][] parse(JSONArray array)
{
Image[][] layer = new Image[WIDTH][HEIGHT];
int index;
for (int x = 0; x < WIDTH; ++x)
{
for (int y = 0; y < HEIGHT; ++y)
{
index = (int)((long)array.get((y * WIDTH) + x)); //must cast because JSON returns long
layer[x][y] = getSpriteImage(index);
}
}
return layer;
}
EDIT 2: my editted load function
public static void load(String path) throws Exception
{
JSONParser parser = new JSONParser();
Object obj = parser.parse(new FileReader(path));
JSONObject jObj = (JSONObject) obj;
JSONArray layers = (JSONArray) jObj.get("layers");
int amount = layers.size();
for (int i = 0; i < amount; i++)
{
JSONObject layer = (JSONObject) layers.get(i);
String type = (String) layer.get("name");
if (type.equals("solids"))
{
Decoder decoder = Base64.getDecoder();
byte[] decodedBytes = decoder.decode((byte[]) layer.get("data"));
Inflater decompresser = new Inflater();
solids = parse((JSONArray)decompresser.inflate(decodedBytes));
EDIT 3: my getSpriteImage function
private static Image getSpriteImage(int index)
{
if (index == 0 )
{
return null;
}
index -= 1;
SpriteSheet sheet = Resources.getSprite("tileset");
int verti = sheet.getVerticalCount();
int horiz = sheet.getHorizontalCount();
int y = (index / verti);
int x = (index % horiz);
return sheet.getSubImage(x, y);
}
EDIT 5: how the map looks
[44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, etcccccccccccccccccccccccccccccccccccccccccccccccc]
EDIT 6: RENDER Method for World & GameState
world- the final value of Tile.SIZE = 5;
public static void render(float xRend, float yRend)
{
int offset = 2;
int xStart = (int)(xRend / Tile.SIZE) - offset;
int yStart = (int)(yRend / Tile.SIZE) - offset;
int xEnd = (Window.WIDTH / Tile.SIZE) + xStart + (offset * 2);
int yEnd = (Window.HEIGHT / Tile.SIZE) + yStart + (offset * 2);
for (int x = xStart; x < xEnd; ++x)
{
for (int y = yStart; y < yEnd; ++y)
{
if (solidTileBound(x, y))
{
solids[x][y].draw(x * Tile.SIZE, y * Tile.SIZE, Tile.SIZE, Tile.SIZE);
}
}
}
}
and GameState:
@Override
public void render(GameContainer gc, StateBasedGame stateGame, Graphics gfx) throws SlickException
{
gfx.drawString(("Game State"), 50, 50);
//gfx.translate(-1500, -1500);
World.render(500, 500);
//gfx.resetTransform();
}
EDIT 7:
[LOG] Loading C:\Users\William.William-PC\Desktop\testMap.json
Sun Dec 06 18:51:33 EST 2015 ERROR:Error loading World
org.newdawn.slick.SlickException: Error loading World
at main.java.TestGame.init(TestGame.java:39)
at org.newdawn.slick.AppGameContainer.setup(AppGameContainer.java:390)
at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:314)
at main.java.Main.main(Main.java:40)
Caused by: java.lang.RuntimeException: Resource not found: tileset.png
at org.newdawn.slick.util.ResourceLoader.getResourceAsStream(ResourceLoader.java:69)
at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.java:169)
at org.newdawn.slick.Image.<init>(Image.java:196)
at org.newdawn.slick.SpriteSheet.<init>(SpriteSheet.java:129)
at org.newdawn.slick.SpriteSheet.<init>(SpriteSheet.java:115)
at org.newdawn.slick.SpriteSheet.<init>(SpriteSheet.java:102)
at main.java.Resources.addTileSet(Resources.java:55)
at main.java.JSONLoader.load(JSONLoader.java:33)
at main.java.TestGame.init(TestGame.java:31)
... 3 more
I looked through it thoroughly and I'm no sure where i'm supposed to be putting tileset.png or why the world won't load for that matter. Did you create your own .json export of a world to test this?
Very close. Unfortunately Inflater
is more complicated than that:
Instead of
Decoder decoder = Base64.getDecoder();
byte[] decodedBytes = decoder.decode((byte[]) layer.get("data"));
Inflater decompresser = new Inflater();
solids = parse((JSONArray)decompresser.inflate(decodedBytes));
try this:
Object o = layer.get("data");
if ( o instanceof JSONArray )
solids = parseJSONArray( (JSONArray) o );
else if ( o instanceof String
&& "base64".equals( layer.get( "encoding" ) )
&& "zlib".equals( layer.get( "compression" ) )
)
{
// base64 decode
Decoder decoder = Base64.getDecoder();
byte[] decodedBytes = decoder.decode((String) o);
// zlib decompress
Inflater decompresser = new Inflater();
decompresser.setInput(decodedBytes);
byte[] decompressedBytes = new byte[WIDTH * HEIGHT * 4];
int resultLength = decompresser.inflate(decompressedBytes);
decompresser.end();
// convert `byte[N*4]` to `int[N]`
int[] result = new int[WIDTH * HEIGHT];
ByteBuffer bb = ByteBuffer.wrap(decompressedBytes);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.asIntBuffer().get(result);
solids = parseIntArray( result );
}
else
throw new RuntimeException( "Unimplemented data type: "
+ o.getClass().getName() );
Rename your original parse
function to parseJSONArray
(for instance),
then copy it to a new function parseByteArray
like this:
private static Image[][] parseIntArray( int[] array )
{
Image[][] layer = new Image[WIDTH][HEIGHT];
for (int x = 0; x < WIDTH; ++x)
for (int y = 0; y < HEIGHT; ++y)
layer[x][y] = getSpriteImage( array[ y * WIDTH + x ] );
return layer;
}