diff --git a/data/map project.tiled-session b/data/map project.tiled-session index 367c074..0cc20a5 100644 --- a/data/map project.tiled-session +++ b/data/map project.tiled-session @@ -1,33 +1,41 @@ { - "activeFile": "map.tmj", + "activeFile": "overworld.tsx", "expandedProjectPaths": [ - "templates", - "." + ".", + "templates" ], "fileStates": { + "entities.tsx": { + "scaleInDock": 1, + "scaleInEditor": 1 + }, "map.tmj": { - "scale": 1.5, - "selectedLayer": 0, + "scale": 4, + "selectedLayer": 1, "viewCenter": { - "x": 669.3333333333334, - "y": 305 + "x": 6622.75, + "y": 6689.625 } }, "overworld.tsx": { "scaleInDock": 1, - "scaleInEditor": 1 + "scaleInEditor": 8 } }, + "last.externalTilesetPath": "/home/yourwishes/htdocs/dusk/data", "last.imagePath": "/home/yourwishes/htdocs/dusk/data", "last.objectTemplatePath": "/home/yourwishes/htdocs/dusk/data/templates", "openFiles": [ - "map.tmj" + "map.tmj", + "overworld.tsx" ], "project": "map project.tiled-project", "recentFiles": [ + "map.tmj", "overworld.tsx", - "map.tmj" + "entities.tsx" ], + "tileset.lastUsedFilter": "Tiled tileset files (*.tsx *.xml)", "tileset.lastUsedFormat": "tsx", "tileset.tileSize": { "height": 16, diff --git a/data/map.tmj b/data/map.tmj index 1e39f4c..b639e2b 100644 --- a/data/map.tmj +++ b/data/map.tmj @@ -27,13 +27,13 @@ "y":416 }, { - "data":[1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -54,8 +54,8 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -281,6 +281,65 @@ "x":0, "y":0 }, + { + "chunks":[ + { + "data":[0, 0, 0, 2, 3, 3, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 11, 11, 11, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 11, 11, 11, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 11, 11, 11, 6, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 0, 0, 0, 10, 11, 11, 11, 11, 14, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 0, 10, 11, 11, 11, 11, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 11, 11, 11, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 11, 11, 11, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 11, 11, 11, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 18, 19, 19, 19, 19, 20, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":16, + "width":16, + "x":400, + "y":416 + }, + { + "data":[0, 0, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 5, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 13, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":16, + "width":16, + "x":416, + "y":416 + }], + "height":32, + "id":5, + "locked":true, + "name":"Overlay Base Layer", + "opacity":1, + "startx":400, + "starty":400, + "type":"tilelayer", + "visible":true, + "width":32, + "x":0, + "y":0 + }, { "draworder":"topdown", "id":3, @@ -289,14 +348,14 @@ { "id":3, "template":"templates\/NPC.tx", - "x":6527.97727272727, - "y":6736.13636363636 + "x":6434.3106060606, + "y":6672.13636363636 }, { "id":4, "template":"templates\/NPC.tx", - "x":6726, - "y":6713.25 + "x":6737, + "y":6672.91666666667 }], "opacity":1, "type":"objectgroup", @@ -304,7 +363,7 @@ "x":0, "y":0 }], - "nextlayerid":5, + "nextlayerid":6, "nextobjectid":5, "orientation":"orthogonal", "renderorder":"right-down", @@ -318,6 +377,10 @@ { "firstgid":65, "source":"entities.tsx" + }, + { + "firstgid":129, + "source":":\/automap-tiles.tsx" }], "tilewidth":16, "type":"map", diff --git a/data/overworld.tsx b/data/overworld.tsx index 22f7090..7109f0e 100644 --- a/data/overworld.tsx +++ b/data/overworld.tsx @@ -1,4 +1,4 @@ - + diff --git a/data/tilemap.png b/data/tilemap.png index 17cc71a..51b3391 100644 Binary files a/data/tilemap.png and b/data/tilemap.png differ diff --git a/data/tilemap.pxo b/data/tilemap.pxo index f89df41..bd4b351 100644 Binary files a/data/tilemap.pxo and b/data/tilemap.pxo differ diff --git a/src/dusk/world/chunk.c b/src/dusk/world/chunk.c index 994309f..a7e2363 100644 --- a/src/dusk/world/chunk.c +++ b/src/dusk/world/chunk.c @@ -181,23 +181,30 @@ void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { // Only load data if the chunk is within bounds. if(x >= WORLD_WIDTH || y >= WORLD_HEIGHT) { - memorySet(chunk->tiles, 0, sizeof(chunk->tiles)); + memorySet(chunk->tilesBase, 0, sizeof(chunk->tilesBase)); + memorySet(chunk->tilesBaseOverlay, 0, sizeof(chunk->tilesBaseOverlay)); return; } // Is chunk data defined? const chunkdata_t *chunkData = WORLD_CHUNKS[y * WORLD_WIDTH + x]; if(chunkData == NULL) { - memorySet(chunk->tiles, 0, sizeof(chunk->tiles)); + memorySet(chunk->tilesBase, 0, sizeof(chunk->tilesBase)); + memorySet(chunk->tilesBaseOverlay, 0, sizeof(chunk->tilesBaseOverlay)); return; } // Load tile data into chunk printf("Loading chunk at (%u, %u)\n", x, y); memoryCopy( - chunk->tiles, + chunk->tilesBase, chunkData->layerBase, - sizeof(chunk->tiles) + sizeof(chunk->tilesBase) + ); + memoryCopy( + chunk->tilesBaseOverlay, + chunkData->layerBaseOverlay, + sizeof(chunk->tilesBaseOverlay) ); // Load chunk entities diff --git a/src/dusk/world/chunk.h b/src/dusk/world/chunk.h index 928544c..30b0f3a 100644 --- a/src/dusk/world/chunk.h +++ b/src/dusk/world/chunk.h @@ -19,7 +19,8 @@ typedef struct { uint16_t x, y; - tile_t tiles[CHUNK_TILE_COUNT]; + tile_t tilesBase[CHUNK_TILE_COUNT]; + tile_t tilesBaseOverlay[CHUNK_TILE_COUNT]; uint32_t entityIDs[CHUNK_ENTITY_COUNT_MAX]; uint8_t entityCount; } chunk_t; diff --git a/src/dusk/world/chunkdata.h b/src/dusk/world/chunkdata.h index a477bd3..42b054c 100644 --- a/src/dusk/world/chunkdata.h +++ b/src/dusk/world/chunkdata.h @@ -18,6 +18,6 @@ typedef struct { typedef struct { uint8_t layerBase[CHUNK_TILE_COUNT]; - uint8_t layerOverlay[CHUNK_TILE_COUNT]; + uint8_t layerBaseOverlay[CHUNK_TILE_COUNT]; chunkentity_t entities[CHUNK_ENTITY_COUNT_MAX]; } chunkdata_t; \ No newline at end of file diff --git a/src/duskraylib/display/draw/drawoverworld.c b/src/duskraylib/display/draw/drawoverworld.c index 9c5c6e1..3f1f7b7 100644 --- a/src/duskraylib/display/draw/drawoverworld.c +++ b/src/duskraylib/display/draw/drawoverworld.c @@ -48,8 +48,33 @@ void drawOverworldDraw(void) { uint8_t colorCount = sizeof(colors) / sizeof(Color); do { + // Base layer for(uint8_t i = 0; i < CHUNK_TILE_COUNT; i++) { - tile_t tile = chunk->tiles[i]; + tile_t tile = chunk->tilesBase[i]; + if(tile == 0) continue; // Skip empty tiles + + uint32_t tilemapIndex = tile - 1; // Convert to zero-based index + uint32_t x = (uint32_t)chunk->x * CHUNK_WIDTH * TILE_WIDTH + (i % CHUNK_WIDTH) * TILE_WIDTH; + uint32_t y = (uint32_t)chunk->y * CHUNK_HEIGHT * TILE_HEIGHT + (i / CHUNK_WIDTH) * TILE_HEIGHT; + uint32_t tilemapX = (tilemapIndex % (RENDER_TILEMAP_TEXTURE.width / TILE_WIDTH)) * TILE_WIDTH; + uint32_t tilemapY = (tilemapIndex / (RENDER_TILEMAP_TEXTURE.width / TILE_WIDTH)) * TILE_HEIGHT; + + DrawTextureRec( + RENDER_TILEMAP_TEXTURE, + (Rectangle){ + tilemapX, + tilemapY, + TILE_WIDTH, + TILE_HEIGHT + }, + (Vector2){ x, y }, + WHITE + ); + } + + // Base overlay layer + for(uint8_t i = 0; i < CHUNK_TILE_COUNT; i++) { + tile_t tile = chunk->tilesBaseOverlay[i]; if(tile == 0) continue; // Skip empty tiles uint32_t tilemapIndex = tile - 1; // Convert to zero-based index @@ -69,17 +94,8 @@ void drawOverworldDraw(void) { (Vector2){ x, y }, WHITE ); - - // DrawRectangle(x, y, TILE_WIDTH, TILE_HEIGHT, colors[tile % colorCount]); } - // DrawRectangle( - // ((int32_t)chunk->x) * CHUNK_WIDTH * TILE_WIDTH, - // ((int32_t)chunk->y) * CHUNK_HEIGHT * TILE_HEIGHT, - // CHUNK_WIDTH * TILE_WIDTH, - // CHUNK_HEIGHT * TILE_HEIGHT, - // (chunk->tiles[0] == 0) ? RED : GREEN - // ); chunk++; } while(chunk < CHUNK_MAP.chunks + CHUNK_MAP_COUNT); diff --git a/tools/mapcompile/mapcompile.py b/tools/mapcompile/mapcompile.py index 44e6ee1..dceab99 100644 --- a/tools/mapcompile/mapcompile.py +++ b/tools/mapcompile/mapcompile.py @@ -172,9 +172,6 @@ print(f"Input map lowest Y: {inputMapLowestY}, highest Y: {inputMapHighestY}") # We now offset all chunks by the lowest X/Y values to make them start at (0, 0). for layerIndex, layer in enumerate(tileLayers): - if layer['startx'] != inputMapLowestX or layer['starty'] != inputMapLowestY: - continue - for chunkIndex, chunk in enumerate(layer['chunks']): chunk['x'] -= inputMapLowestX chunk['y'] -= inputMapLowestY @@ -208,7 +205,6 @@ mapWidthInTiles = inputMapHighestX - inputMapLowestX mapHeightInTiles = inputMapHighestY - inputMapLowestY mapWidthInRealChunks = math.ceil(float(mapWidthInTiles) / float(CHUNK_WIDTH)) mapHeightInRealChunks = math.ceil(float(mapHeightInTiles) / float(CHUNK_HEIGHT)) -print(f"Map width in chunks: {mapWidthInRealChunks}, height in chunks: {mapHeightInRealChunks}") if inputLayerWidthInTiles < CHUNK_WIDTH or inputLayerHeightInTiles < CHUNK_HEIGHT: print(f"Error: Input layer size {inputLayerWidthInTiles}x{inputLayerHeightInTiles} is smaller than chunk size {CHUNK_WIDTH}x{CHUNK_HEIGHT}.") @@ -231,52 +227,46 @@ for chunkY in range(mapHeightInRealChunks): # Get the layers for this chunk. chunkLayers = [] - for layerIndex, layer in enumerate(tileLayers): + for layer in tileLayers: foundChunk = None + if 'chunks' not in layer or not isinstance(layer['chunks'], list): - print(f"Error: Layer {layerIndex} in '{inputFile}' does not contain 'chunks' key.") + print(f"Error: Layer '{layer['name']}' does not contain 'chunks' key or it is not a list.") sys.exit(1) - # Find the chunk in this layer that matches the output chunk coordinates. - chunks = layer['chunks'] - for chunk in chunks: + for chunk in layer['chunks']: if 'x' not in chunk or 'y' not in chunk: - print(f"Error: Chunk in layer {layerIndex} does not contain 'x' or 'y' key.") + print(f"Error: Chunk in layer '{layer['name']}' does not contain 'x' or 'y' key.") sys.exit(1) - if chunk['x'] == inputTopLeftTileX and chunk['y'] == inputTopLeftTileY: - foundChunk = chunk - break - - # If we did not find a chunk for this layer, append None. + # Check if this chunk is within the bounds of the top left tile. + if chunk['x'] != inputTopLeftTileX or chunk['y'] != inputTopLeftTileY: + continue + + foundChunk = chunk + break + if foundChunk is None: chunkLayers.append(None) continue - - # Is this chunk layer just empty? + + # Is layer empty? layerEmpty = True - for tile in foundChunk.get('data', []): + for tile in foundChunk['data']: if tile == 0: continue layerEmpty = False break - + if layerEmpty: chunkLayers.append(None) - continue - - # Append the found chunk to the chunkLayers list. - chunkLayers.append(foundChunk) - + else: + chunkLayers.append(foundChunk) + # Now we have a chunkLayers list with the found chunks for each layer. if all(chunk is None for chunk in chunkLayers) or len(chunkLayers) == 0: continue - # If we have more than 2 layers, we cannot handle this (yet). - if len(chunkLayers) > 2: - print(f"Error: Expected 2 layers for chunk at ({chunkX}, {chunkY}), found {len(chunkLayers)}.") - sys.exit(1) - entities = [] for ob in objectLayer['objects']: if 'x' not in ob or 'y' not in ob: @@ -302,23 +292,43 @@ for chunkY in range(mapHeightInRealChunks): def getInputLocalTileY(absoluteTileY): return absoluteTileY % inputLayerHeightInTiles - # Determine base layer data. + def getInputTileIndex(localX, localY): + absoluteTileX = topLeftTileX + localX + absoluteTileY = topLeftTileY + localY + inputLocalTileX = getInputLocalTileX(absoluteTileX) + inputLocalTileY = getInputLocalTileY(absoluteTileY) + return inputLocalTileY * inputLayerWidthInTiles + inputLocalTileX + + def getOutputTileIndex(localX, localY): + return localY * CHUNK_WIDTH + localX + + # Determine the layer base. layerBase = chunkLayers[0] + layerBaseOverlay = None + if len(chunkLayers) > 1: + layerBaseOverlay = chunkLayers[1] + + # Determine base layer data. layerBaseData = [] for y in range(CHUNK_HEIGHT): for x in range(CHUNK_WIDTH): - absoluteTileX = topLeftTileX + x - absoluteTileY = topLeftTileY + y - inputLocalTileX = getInputLocalTileX(absoluteTileX) - inputLocalTileY = getInputLocalTileY(absoluteTileY) - inputTileIndex = inputLocalTileY * inputLayerWidthInTiles + inputLocalTileX - outputTileIndex = y * CHUNK_WIDTH + x + inputTileIndex = getInputTileIndex(x, y) + outputTileIndex = getOutputTileIndex(x, y) layerBaseData.append(layerBase['data'][inputTileIndex]) if len(layerBaseData) != CHUNK_TILE_COUNT: print(f"Error: Layer base data length {len(layerBaseData)} does not match expected chunk tile count {CHUNK_TILE_COUNT}.") sys.exit(1) + # Layer base overlay. + layerOverlayData = [] + if layerBaseOverlay is not None: + for y in range(CHUNK_HEIGHT): + for x in range(CHUNK_WIDTH): + inputTileIndex = getInputTileIndex(x, y) + outputTileIndex = getOutputTileIndex(x, y) + layerOverlayData.append(layerBaseOverlay['data'][inputTileIndex]) + # This is a valid chunk. worldWidth = max(worldWidth, chunkX + 1) worldHeight = max(worldHeight, chunkY + 1) @@ -341,7 +351,16 @@ for chunkY in range(mapHeightInRealChunks): f.write(f"\n") f.write(" },\n\n") - f.write(f" .layerOverlay = {{}},\n") + f.write(" .layerBaseOverlay = {\n") + if layerBaseOverlay is not None: + for y in range(CHUNK_HEIGHT): + f.write(f" ") + for x in range(CHUNK_WIDTH): + i = y * CHUNK_WIDTH + x + byte = layerOverlayData[i] + f.write(f"0x{byte:02x}, ") + f.write(f"\n") + f.write(" },\n\n") f.write(f" .entities = {{\n") for entity in entities: @@ -349,8 +368,6 @@ for chunkY in range(mapHeightInRealChunks): localX = entity['x'] - (topLeftTileX * TILE_WIDTH) localY = entity['y'] - (topLeftTileY * TILE_HEIGHT) - print(f"Entity at ({entity['x']}, {entity['y']}) in chunk ({chunkX}, {chunkY}) is at local position ({localX}, {localY})") - f.write(" {\n") f.write(f" .id = {entity['id']},\n") f.write(f" .type = ENTITY_TYPE_NPC,\n")