├── .github ├── FUNDING.yml └── workflows │ └── unitTests.yml ├── .gitignore ├── .vscode ├── commandbar.json ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── haxelib.json ├── samples ├── Flixel - Render tile layer │ ├── .vscode │ │ ├── launch.json │ │ └── tasks.json │ ├── Project.xml │ └── src │ │ ├── Main.hx │ │ └── PlayState.hx ├── Generic - Read project │ ├── ReadProject.hx │ ├── build.hxml │ └── index.html ├── Heaps - Object tiles │ ├── Heaps_ObjectTiles.hx │ ├── build.hxml │ └── index.html ├── Heaps - Render IntGrid layer │ ├── Heaps_IntGrid.hx │ ├── build.hxml │ └── index.html ├── Heaps - Render full world │ ├── Heaps_FullWorld.hx │ ├── build.hxml │ └── index.html ├── Heaps - Render tile layers │ ├── Heaps_TileLayers.hx │ ├── build.hxml │ └── index.html ├── _assets │ ├── Cavernas_by_Adam_Saltsman-Extended.png │ ├── Cavernas_by_Adam_Saltsman-Extended_hued.png │ ├── Minecraft_texture_pack.gif │ ├── N2D - SpaceWallpaper1280x448.png │ ├── RPG_Assets_by_ssugmi.png │ ├── sample.cdb │ ├── sample.ldtk │ ├── sample │ │ ├── 0000-West.ldtkl │ │ ├── 0001-East.ldtkl │ │ ├── 0002-Pit.ldtkl │ │ ├── 0003-Treasure_room.ldtkl │ │ └── png │ │ │ ├── East.png │ │ │ ├── Pit.png │ │ │ ├── Treasure_room.png │ │ │ └── West.png │ ├── unitTest.ldtk │ └── unitTest │ │ ├── Main_tests.ldtkl │ │ ├── Offset_tests.ldtkl │ │ ├── Target_level_ref.ldtkl │ │ ├── World1_Level_3.ldtkl │ │ ├── World2_Level_0.ldtkl │ │ ├── v1_4_0.ldtkl │ │ └── v1_4_0_overlap.ldtkl ├── _initSamples │ ├── README.md │ ├── SamplesInitializer.hx │ └── initSamples.hxml ├── _srcCommon │ ├── ExternCastleDbTest.hx │ ├── ExternEnumTest.hx │ └── LdtkProject.hx └── buildAll.hxml ├── src └── ldtk │ ├── Entity.hx │ ├── Json.hx │ ├── Layer.hx │ ├── Layer_AutoLayer.hx │ ├── Layer_Entities.hx │ ├── Layer_IntGrid.hx │ ├── Layer_IntGrid_AutoLayer.hx │ ├── Layer_Tiles.hx │ ├── Level.hx │ ├── Point.hx │ ├── Project.hx │ ├── Tileset.hx │ ├── World.hx │ └── macro │ └── TypeBuilder.hx ├── tests ├── ProjectNoPackage.hx ├── Tests.hx ├── _base.hxml ├── hl.hxml ├── js.hxml ├── lab │ ├── .gitignore │ ├── .vscode │ │ ├── launch.json │ │ └── tasks.json │ ├── README.md │ ├── hl.hxml │ ├── res │ │ ├── Cavernas_by_Adam_Saltsman-Extended.png │ │ └── apiLab.ldtk │ └── src │ │ ├── Boot.hx │ │ ├── LdtkProject.hx │ │ └── Main.hx └── packageTest │ └── ProjectPackage.hx └── tidy.cmd /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: deepnight -------------------------------------------------------------------------------- /.github/workflows/unitTests.yml: -------------------------------------------------------------------------------- 1 | name: Unit tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - dev* 8 | pull_request: 9 | branches: 10 | - master 11 | - dev* 12 | 13 | jobs: 14 | build: 15 | 16 | strategy: 17 | matrix: 18 | os: [windows-latest] 19 | haxe: [4.3.3] 20 | fail-fast: true 21 | runs-on: windows-latest 22 | 23 | steps: 24 | # Checkout & install haxe 25 | - uses: actions/checkout@v2 26 | - uses: krdlab/setup-haxe@v1 27 | with: 28 | haxe-version: ${{ matrix.haxe }} 29 | - run: haxe -version 30 | 31 | # Install libs 32 | - run: haxelib install tests/js.hxml --always 33 | - run: haxelib git deepnightLibs https://github.com/deepnight/deepnightLibs.git 34 | - run: haxelib git heaps https://github.com/deepnight/heaps.git 35 | - run: haxelib git hlsdl https://github.com/HaxeFoundation/hashlink.git master libs/sdl 36 | - run: haxelib list 37 | 38 | # Run tests 39 | - name: JS tests 40 | run: haxe tests/js.hxml 41 | 42 | # Samples 43 | - name: Samples building 44 | working-directory: ./samples/_initSamples 45 | run: haxe initSamples.hxml 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.vscode/extensions.json 2 | bin 3 | dump 4 | *.hl 5 | *.js 6 | -------------------------------------------------------------------------------- /.vscode/commandbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "skipTerminateQuickPick": true, 3 | "skipSwitchToOutput": false, 4 | "skipErrorMessage": true, 5 | "commands": [ 6 | { 7 | "text": "JS", 8 | "color": "#cfdd40", 9 | "command": "haxe tests/js.hxml", 10 | "alignment": "right", 11 | "skipTerminateQuickPick": false, 12 | "priority": 0 13 | }, 14 | { 15 | "text": "HL", 16 | "color": "#1edd8e", 17 | "command": "haxe tests/hl.hxml", 18 | "alignment": "right", 19 | "skipTerminateQuickPick": false, 20 | "priority": -1 21 | }, 22 | { 23 | "text": "Samples", 24 | "color": "#ff8600", 25 | "command": "cd samples && cd _initSamples && haxe initSamples.hxml", 26 | "alignment": "right", 27 | "skipTerminateQuickPick": false, 28 | "priority": -21 29 | }, 30 | { 31 | "text": "🖥️ Term", 32 | "color": "#aaaaaa", 33 | "command": "start /d samples cmd", 34 | "alignment": "right", 35 | "skipTerminateQuickPick": false, 36 | "priority": -30 37 | }, 38 | { 39 | "text": "➠ Submit to haxelib", 40 | "color": "white", 41 | "command": "start haxelib submit .", 42 | "alignment": "right", 43 | "skipTerminateQuickPick": false, 44 | "priority": -40 45 | } 46 | 47 | ] 48 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug macros", 9 | "type": "haxe-eval", 10 | "request": "launch", 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "haxe.configurations": [ 3 | ["tests/hl.hxml"], 4 | ["tests/js.hxml"], 5 | ["tests/neko.hxml"], 6 | ], 7 | "haxe.enableServerView": true 8 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "haxe", 8 | "args": "active configuration", 9 | "problemMatcher": [ 10 | "$haxe-absolute", 11 | "$haxe", 12 | "$haxe-error", 13 | "$haxe-trace" 14 | ], 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | }, 19 | "presentation": { 20 | "reveal": "never", 21 | "panel": "dedicated", 22 | "clear": true 23 | }, 24 | "label": "haxe: active configuration" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020, Sébastien Benard - Deepnight Games 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | ## What is this? 4 | 5 | This is the Haxe API to load **LDtk Project JSON** files. 6 | 7 | *LDtk is a modern and open-source 2D level editor.* 8 | 9 | [Issue tracker (shared)](https://github.com/deepnight/ldtk/issues) | 10 | [API documentation](https://ldtk.io/docs/game-dev/haxe-in-game-api/) | 11 | [LDtk official page](https://ldtk.io) 12 | 13 | [![Unit tests](https://github.com/deepnight/ldtk-haxe-api/actions/workflows/unitTests.yml/badge.svg)](https://github.com/deepnight/ldtk-haxe-api/actions/workflows/unitTests.yml) 14 | 15 | ## Features 16 | 17 | - Compatible with all Haxe based frameworks and engines. 18 | - Dedicated API for the following frameworks: 19 | - Heaps.io 20 | - [HaxeFlixel](https://haxeflixel.com/) 21 | - **Completely typed at compilation**: if you rename any element in your project (ie. level, layer, entity, etc.), the corresponding references in your code will break accordingly, avoiding typical errors or mistypings. 22 | - **Full completion in VScode**: if you have vs-haxe installed, you will get full completion while exploring your project file, based on its actual content, right from VScode. 23 | 24 | # Usage 25 | 26 | ## Install 27 | 28 | ``` 29 | haxelib install ldtk-haxe-api 30 | ``` 31 | ## Documentation 32 | 33 | Please check the **full documentation and tutorials** here: 34 | 35 | https://deepnight.net/docs/ldtk/haxe-api/ 36 | 37 | ## Samples 38 | 39 | You can check some examples in [samples](samples) folder. 40 | 41 | Samples are built to **WebGL** (Javascript) and **Hashlink** targets, but you can try them on other compatible platforms too. 42 | 43 | ### Requirements 44 | 45 | You need a standard **Haxe** install, and the following libraries installed: *heaps* (from source), *deepnightLibs* (from source), *hlsdl*: 46 | 47 | ``` 48 | haxelib git heaps https://github.com/HeapsIO/heaps.git 49 | 50 | haxelib git deepnightLibs https://github.com/deepnight/deepnightLibs.git 51 | 52 | haxelib install hlsdl 53 | ``` 54 | 55 | ### Building samples 56 | 57 | Open a folder in the `samples` folder (eg. `samples\Generic - Generic - Read project`) and run: 58 | 59 | ``` 60 | haxe build.hxml 61 | ``` 62 | 63 | You can also build all samples in one go. Go in `samples` folder and run: 64 | 65 | ``` 66 | haxe buildAll.hxml 67 | ``` 68 | 69 | ### Rebuild samples HXMLs 70 | 71 | If you modify the API, you might need to rebuild samples `HXML`s files themselves. In the root of the repo, run: 72 | 73 | ``` 74 | haxe genSamples.hxml 75 | ``` 76 | 77 | ## Unit tests 78 | 79 | You can build and run unit tests manually using the following commands **from the repository root**. 80 | 81 | ### JS/WebGL target 82 | 83 | You will need Node interpreter to run the tests. 84 | 85 | ``` 86 | haxe tests\js.hxml 87 | ``` 88 | 89 | ### Neko target 90 | 91 | You will need Neko VM interpreter to run the tests. 92 | 93 | ``` 94 | haxe tests\neko.hxml 95 | ``` 96 | -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ldtk-haxe-api", 3 | "url" : "https://github.com/deepnight/ldtk-haxe-api", 4 | "license": "Apache", 5 | "tags": ["Haxe","Heaps","Hashlink","LDtk","Led","L-Ed","api","level","editor","deepnight"], 6 | "description": "The haxe API for LDtk JSON files - https://deepnight.net/tools/led-2d-level-editor/", 7 | "version": "1.5.3-rc.1", 8 | "classPath": "src/", 9 | "releasenote": "See https://ldtk.io/ for more information", 10 | "contributors": ["sbenard"], 11 | "dependencies": { 12 | "deepnightLibs": "" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /samples/Flixel - Render tile layer/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Build + Debug", 6 | "type": "lime", 7 | "request": "launch" 8 | }, 9 | { 10 | "name": "Debug", 11 | "type": "lime", 12 | "request": "launch", 13 | "preLaunchTask": null 14 | }, 15 | { 16 | "name": "Macro", 17 | "type": "haxe-eval", 18 | "request": "launch" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /samples/Flixel - Render tile layer/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "lime", 6 | "command": "test", 7 | "presentation": { 8 | "echo": true, 9 | "reveal": "never", 10 | "focus": false, 11 | "panel": "shared", 12 | "showReuseMessage": false, 13 | "clear": false 14 | }, 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | } 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /samples/Flixel - Render tile layer/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /samples/Flixel - Render tile layer/src/Main.hx: -------------------------------------------------------------------------------- 1 | package; 2 | 3 | import flixel.FlxGame; 4 | import openfl.display.Sprite; 5 | 6 | class Main extends Sprite 7 | { 8 | public function new() 9 | { 10 | super(); 11 | addChild(new FlxGame(800, 400, PlayState)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/Flixel - Render tile layer/src/PlayState.hx: -------------------------------------------------------------------------------- 1 | package; 2 | 3 | import flixel.FlxG; 4 | import flixel.FlxState; 5 | 6 | class PlayState extends FlxState 7 | { 8 | override public function create() 9 | { 10 | super.create(); 11 | 12 | // Create project instance 13 | var project = new LdtkProject(); 14 | 15 | 16 | // Iterate all world levels 17 | for( level in project.all_worlds.SampleWorld.levels ) { 18 | // Create a FlxGroup for all level layers 19 | var container = new flixel.group.FlxSpriteGroup(); 20 | add(container); 21 | 22 | // Place it using level world coordinates (in pixels) 23 | container.x = level.worldX; 24 | container.y = level.worldY; 25 | 26 | // Attach level background image, if any 27 | if( level.hasBgImage() ) 28 | container.add( level.getBgSprite() ); 29 | 30 | // Render layer "Background" 31 | level.l_Cavern_background.render( container ); 32 | 33 | // Render layer "Collisions" 34 | level.l_Collisions.render( container ); 35 | 36 | // Render layer "Custom_Tiles" 37 | level.l_Custom_tiles.render( container ); 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /samples/Generic - Read project/ReadProject.hx: -------------------------------------------------------------------------------- 1 | /** 2 | This sample shows how to access some of the Project data using Haxe API. 3 | **/ 4 | 5 | import ExternEnumTest; 6 | 7 | class ReadProject { 8 | static function main() { 9 | hxd.Res.initEmbed(); 10 | var project = new LdtkProject(); 11 | 12 | var myLevel = project.all_worlds.SampleWorld.all_levels.West; 13 | 14 | // IntGrid ASCII render 15 | var layer = myLevel.l_Collisions; 16 | for( cy in 0...layer.cHei ) { 17 | var row = ""; 18 | for( cx in 0...layer.cWid ) 19 | if( layer.hasValue(cx,cy) ) 20 | row+="#"; 21 | else 22 | row+="."; 23 | print(row+" "+cy); 24 | } 25 | 26 | // Entity access 27 | for( playerEntity in myLevel.l_Entities.all_Player ) 28 | print( "Found: "+playerEntity.identifier ); 29 | 30 | for( itemEntity in myLevel.l_Entities.all_Item ) { 31 | print( "Found: "+itemEntity.identifier ); 32 | print( " type = "+itemEntity.f_type ); 33 | 34 | var displayName = switch itemEntity.f_type { 35 | case Pickaxe: 'A rusty pickaxe'; 36 | case Potion: 'A fresh vial of Healing potion'; 37 | case Food: 'Some tasty food'; 38 | } 39 | print(' "$displayName"'); 40 | } 41 | } 42 | 43 | 44 | 45 | 46 | /** 47 | Print some text 48 | **/ 49 | #if js 50 | static var _htmlLog : js.html.Element; 51 | #end 52 | 53 | static function print(msg:String) { 54 | #if sys 55 | 56 | Sys.println(msg); 57 | 58 | #elseif js 59 | 60 | if( _htmlLog==null ) { 61 | // Hide HTML canvas 62 | js.Browser.document.querySelector("canvas").remove(); 63 | 64 | // Create a PRE element to display text 65 | _htmlLog = js.Browser.document.createPreElement(); 66 | js.Browser.document.body.appendChild(_htmlLog); 67 | _htmlLog.style.marginLeft = "16px"; 68 | _htmlLog.innerText = "CONSOLE OUTPUT:\n\n"; 69 | } 70 | _htmlLog.append(msg+"\n"); 71 | js.html.Console.info(msg); 72 | 73 | #else 74 | 75 | trace(msg); 76 | 77 | #end 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /samples/Generic - Read project/build.hxml: -------------------------------------------------------------------------------- 1 | 2 | # ReadProject (Javascript/WebGL) 3 | -cp . 4 | -cp ../_srcCommon 5 | -cp ../../src 6 | -lib heaps 7 | -lib deepnightLibs 8 | -D resourcesPath=../_assets 9 | --dce full 10 | -main ReadProject 11 | -js _javascript.js 12 | 13 | # ReadProject (Hashlink) 14 | --next 15 | -cp . 16 | -cp ../_srcCommon 17 | -cp ../../src 18 | -lib heaps 19 | -lib deepnightLibs 20 | -D resourcesPath=../_assets 21 | -lib hlsdl 22 | --dce full 23 | -main ReadProject 24 | -hl _hashlink.hl 25 | -------------------------------------------------------------------------------- /samples/Generic - Read project/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ReadProject 7 | 50 | 51 | 52 | 53 | 54 |
Failed to load JS script! Please build it using the HXML file (run: haxe build.hxml).
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /samples/Heaps - Object tiles/Heaps_ObjectTiles.hx: -------------------------------------------------------------------------------- 1 | /** 2 | This sample for Heaps.io engine demonstrates how to render any layer using the 3 | provided render() method. 4 | **/ 5 | 6 | import LdtkProject; 7 | 8 | class Heaps_ObjectTiles extends hxd.App { 9 | 10 | static function main() { 11 | // Boot 12 | new Heaps_ObjectTiles(); 13 | } 14 | 15 | override function init() { 16 | super.init(); 17 | 18 | // Init general heaps stuff 19 | hxd.Res.initEmbed(); 20 | s2d.setScale( dn.heaps.Scaler.bestFit_i(256,256) ); // scale view to fit 21 | 22 | // Read project JSON 23 | var project = new LdtkProject(); 24 | 25 | // Get level data 26 | var level = project.all_worlds.SampleWorld.all_levels.West; 27 | 28 | // Prepare a container for the level layers 29 | var levelBg = new h2d.Object(); 30 | s2d.addChild(levelBg); 31 | levelBg.alpha = 0.5; // opacity 32 | levelBg.filter = new h2d.filter.Blur(4,1,2); // blur it a little bit 33 | 34 | // Render IntGrid layer named "Collisions" 35 | levelBg.addChild( level.l_Collisions.render() ); 36 | 37 | // Render tiles layer named "Custom_tiles" 38 | levelBg.addChild( level.l_Custom_tiles.render() ); 39 | 40 | 41 | // Render each "Item" entity 42 | for( item in level.l_Entities.all_Item ) { 43 | // Read h2d.Tile based on the "type" enum value from the entity 44 | var tile = project.getEnumTile( item.f_type ); 45 | 46 | // Apply the same pivot coord as the Entity to the Tile 47 | // (in this case, the pivot is the bottom-center point of the tile) 48 | tile.setCenterRatio( item.pivotX, item.pivotY ); 49 | 50 | // Display it 51 | var bitmap = new h2d.Bitmap(tile); 52 | s2d.addChild(bitmap); 53 | bitmap.x = item.pixelX; 54 | bitmap.y = item.pixelY; 55 | } 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /samples/Heaps - Object tiles/build.hxml: -------------------------------------------------------------------------------- 1 | 2 | # Heaps_ObjectTiles (Javascript/WebGL) 3 | -cp . 4 | -cp ../_srcCommon 5 | -cp ../../src 6 | -lib heaps 7 | -lib deepnightLibs 8 | -D resourcesPath=../_assets 9 | --dce full 10 | -main Heaps_ObjectTiles 11 | -js _javascript.js 12 | 13 | # Heaps_ObjectTiles (Hashlink) 14 | --next 15 | -cp . 16 | -cp ../_srcCommon 17 | -cp ../../src 18 | -lib heaps 19 | -lib deepnightLibs 20 | -D resourcesPath=../_assets 21 | -lib hlsdl 22 | --dce full 23 | -main Heaps_ObjectTiles 24 | -hl _hashlink.hl 25 | -------------------------------------------------------------------------------- /samples/Heaps - Object tiles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Heaps_ObjectTiles 7 | 50 | 51 | 52 | 53 | 54 |
Failed to load JS script! Please build it using the HXML file (run: haxe build.hxml).
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /samples/Heaps - Render IntGrid layer/Heaps_IntGrid.hx: -------------------------------------------------------------------------------- 1 | /** 2 | This sample for Heaps.io engine demonstrates how to manually render a "raw" IntGrid layer (ie. "without tiles") 3 | using Heaps API. 4 | **/ 5 | 6 | import LdtkProject; 7 | 8 | class Heaps_IntGrid extends hxd.App { 9 | static function main() { 10 | // Boot 11 | new Heaps_IntGrid(); 12 | } 13 | 14 | override function init() { 15 | super.init(); 16 | 17 | // Init general stuff 18 | hxd.Res.initEmbed(); 19 | s2d.setScale( dn.heaps.Scaler.bestFit_i(256,256) ); // scale view to fit 20 | 21 | // Read project JSON 22 | var project = new LdtkProject(); 23 | 24 | // Layer data 25 | var layer = project.all_worlds.SampleWorld.all_levels.West.l_Collisions; 26 | 27 | // Prepare a h2d.Graphics to render layer 28 | var g = new h2d.Graphics(s2d); 29 | 30 | // Render background 31 | g.beginFill(project.bgColor_int); 32 | g.drawRect(0, 0, layer.cWid*layer.gridSize, layer.cHei*layer.gridSize); 33 | g.endFill(); 34 | 35 | // Render IntGrid layer cells 36 | for(cx in 0...layer.cWid) 37 | for(cy in 0...layer.cHei) { 38 | if( !layer.hasValue(cx,cy) ) // skip empty cells 39 | continue; 40 | 41 | var color = layer.getColorInt(cx,cy); 42 | g.beginFill(color); 43 | g.drawRect(cx*layer.gridSize, cy*layer.gridSize, layer.gridSize, layer.gridSize); 44 | } 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /samples/Heaps - Render IntGrid layer/build.hxml: -------------------------------------------------------------------------------- 1 | 2 | # Heaps_IntGrid (Javascript/WebGL) 3 | -cp . 4 | -cp ../_srcCommon 5 | -cp ../../src 6 | -lib heaps 7 | -lib deepnightLibs 8 | -D resourcesPath=../_assets 9 | --dce full 10 | -main Heaps_IntGrid 11 | -js _javascript.js 12 | 13 | # Heaps_IntGrid (Hashlink) 14 | --next 15 | -cp . 16 | -cp ../_srcCommon 17 | -cp ../../src 18 | -lib heaps 19 | -lib deepnightLibs 20 | -D resourcesPath=../_assets 21 | -lib hlsdl 22 | --dce full 23 | -main Heaps_IntGrid 24 | -hl _hashlink.hl 25 | -------------------------------------------------------------------------------- /samples/Heaps - Render IntGrid layer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Heaps_IntGrid 7 | 50 | 51 | 52 | 53 | 54 |
Failed to load JS script! Please build it using the HXML file (run: haxe build.hxml).
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /samples/Heaps - Render full world/Heaps_FullWorld.hx: -------------------------------------------------------------------------------- 1 | /** 2 | This sample for Heaps.io engine demonstrates how to render all layers and all levels in the project world. 3 | **/ 4 | 5 | import LdtkProject; 6 | 7 | class Heaps_FullWorld extends hxd.App { 8 | 9 | static function main() { 10 | // Boot 11 | new Heaps_FullWorld(); 12 | } 13 | 14 | override function init() { 15 | super.init(); 16 | 17 | // Init general heaps stuff 18 | hxd.Res.initEmbed(); 19 | s2d.setScale( dn.heaps.Scaler.bestFit_i(650,256) ); // scale view to fit 20 | 21 | // Read project JSON 22 | var project = new LdtkProject(); 23 | 24 | // Render each level 25 | for( level in project.all_worlds.SampleWorld.levels ) { 26 | // Create a wrapper to render all layers in it 27 | var levelWrapper = new h2d.Object( s2d ); 28 | 29 | // Position accordingly to world pixel coords 30 | levelWrapper.x = level.worldX; 31 | levelWrapper.y = level.worldY; 32 | 33 | // Level background image 34 | if( level.hasBgImage() ) 35 | levelWrapper.addChild( level.getBgBitmap() ); 36 | 37 | // Render background layer 38 | levelWrapper.addChild( level.l_Cavern_background.render() ); 39 | 40 | // Render collision layer tiles 41 | levelWrapper.addChild( level.l_Collisions.render() ); 42 | 43 | // Render custom tiles layer 44 | levelWrapper.addChild( level.l_Custom_tiles.render() ); 45 | } 46 | 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /samples/Heaps - Render full world/build.hxml: -------------------------------------------------------------------------------- 1 | 2 | # Heaps_FullWorld (Javascript/WebGL) 3 | -cp . 4 | -cp ../_srcCommon 5 | -cp ../../src 6 | -lib heaps 7 | -lib deepnightLibs 8 | -D resourcesPath=../_assets 9 | --dce full 10 | -main Heaps_FullWorld 11 | -js _javascript.js 12 | 13 | # Heaps_FullWorld (Hashlink) 14 | --next 15 | -cp . 16 | -cp ../_srcCommon 17 | -cp ../../src 18 | -lib heaps 19 | -lib deepnightLibs 20 | -D resourcesPath=../_assets 21 | -lib hlsdl 22 | --dce full 23 | -main Heaps_FullWorld 24 | -hl _hashlink.hl 25 | -------------------------------------------------------------------------------- /samples/Heaps - Render full world/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Heaps_FullWorld 7 | 50 | 51 | 52 | 53 | 54 |
Failed to load JS script! Please build it using the HXML file (run: haxe build.hxml).
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /samples/Heaps - Render tile layers/Heaps_TileLayers.hx: -------------------------------------------------------------------------------- 1 | /** 2 | This sample for Heaps.io engine demonstrates how to render any layer using the 3 | provided render() method. 4 | **/ 5 | 6 | import LdtkProject; 7 | 8 | class Heaps_TileLayers extends hxd.App { 9 | 10 | static function main() { 11 | // Boot 12 | new Heaps_TileLayers(); 13 | } 14 | 15 | override function init() { 16 | super.init(); 17 | 18 | // Init general heaps stuff 19 | hxd.Res.initEmbed(); 20 | s2d.setScale( dn.heaps.Scaler.bestFit_i(256,256) ); // scale view to fit 21 | 22 | // Read project JSON 23 | var project = new LdtkProject(); 24 | 25 | // Get level data 26 | var level = project.all_worlds.SampleWorld.all_levels.West; 27 | 28 | // Level background image 29 | s2d.addChild( level.getBgBitmap() ); 30 | 31 | // Render "pure" auto-layer (ie. background walls) 32 | s2d.addChild( level.l_Cavern_background.render() ); 33 | 34 | // Render IntGrid Auto-layer tiles (ie. walls, ladders, etc.) 35 | s2d.addChild( level.l_Collisions.render() ); 36 | 37 | // Render traditional Tiles layer (ie. manually added details) 38 | s2d.addChild( level.l_Custom_tiles.render() ); 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /samples/Heaps - Render tile layers/build.hxml: -------------------------------------------------------------------------------- 1 | 2 | # Heaps_TileLayers (Javascript/WebGL) 3 | -cp . 4 | -cp ../_srcCommon 5 | -cp ../../src 6 | -lib heaps 7 | -lib deepnightLibs 8 | -D resourcesPath=../_assets 9 | --dce full 10 | -main Heaps_TileLayers 11 | -js _javascript.js 12 | 13 | # Heaps_TileLayers (Hashlink) 14 | --next 15 | -cp . 16 | -cp ../_srcCommon 17 | -cp ../../src 18 | -lib heaps 19 | -lib deepnightLibs 20 | -D resourcesPath=../_assets 21 | -lib hlsdl 22 | --dce full 23 | -main Heaps_TileLayers 24 | -hl _hashlink.hl 25 | -------------------------------------------------------------------------------- /samples/Heaps - Render tile layers/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Heaps_TileLayers 7 | 50 | 51 | 52 | 53 | 54 |
Failed to load JS script! Please build it using the HXML file (run: haxe build.hxml).
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /samples/_assets/Cavernas_by_Adam_Saltsman-Extended.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/Cavernas_by_Adam_Saltsman-Extended.png -------------------------------------------------------------------------------- /samples/_assets/Cavernas_by_Adam_Saltsman-Extended_hued.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/Cavernas_by_Adam_Saltsman-Extended_hued.png -------------------------------------------------------------------------------- /samples/_assets/Minecraft_texture_pack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/Minecraft_texture_pack.gif -------------------------------------------------------------------------------- /samples/_assets/N2D - SpaceWallpaper1280x448.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/N2D - SpaceWallpaper1280x448.png -------------------------------------------------------------------------------- /samples/_assets/RPG_Assets_by_ssugmi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/RPG_Assets_by_ssugmi.png -------------------------------------------------------------------------------- /samples/_assets/sample.cdb: -------------------------------------------------------------------------------- 1 | { 2 | "sheets": [ 3 | { 4 | "name": "CdbEnumTest", 5 | "columns": [ 6 | { 7 | "typeStr": "0", 8 | "name": "id" 9 | } 10 | ], 11 | "lines": [ 12 | { 13 | "id": "CdbA" 14 | }, 15 | { 16 | "id": "CdbB" 17 | }, 18 | { 19 | "id": "CdbC" 20 | } 21 | ], 22 | "separators": [], 23 | "props": {} 24 | } 25 | ], 26 | "customTypes": [], 27 | "compress": false 28 | } -------------------------------------------------------------------------------- /samples/_assets/sample/0003-Treasure_room.ldtkl: -------------------------------------------------------------------------------- 1 | { 2 | "__header__": { 3 | "fileType": "LDtk Project JSON", 4 | "app": "LDtk", 5 | "doc": "https://ldtk.io/json", 6 | "schema": "https://ldtk.io/files/JSON_SCHEMA.json", 7 | "appAuthor": "Sebastien 'deepnight' Benard", 8 | "appVersion": "1.5.3", 9 | "url": "https://ldtk.io" 10 | }, 11 | "identifier": "Treasure_room", 12 | "iid": "6004c190-66b0-11ec-a36b-37ad7b095a6c", 13 | "uid": 41, 14 | "worldX": 544, 15 | "worldY": 224, 16 | "worldDepth": 0, 17 | "pxWid": 160, 18 | "pxHei": 128, 19 | "__bgColor": "#121331", 20 | "bgColor": null, 21 | "useAutoIdentifier": false, 22 | "bgRelPath": "N2D - SpaceWallpaper1280x448.png", 23 | "bgPos": "Cover", 24 | "bgPivotX": 0.5, 25 | "bgPivotY": 0.5, 26 | "__smartColor": "#7D7D8E", 27 | "__bgPos": { "topLeftPx": [0,0], "scale": [0.5714285714285714,0.5714285714285714], "cropRect": [180,0,280,224] }, 28 | "externalRelPath": null, 29 | "fieldInstances": [], 30 | "layerInstances": [ 31 | { 32 | "__identifier": "Entities", 33 | "__type": "Entities", 34 | "__cWid": 20, 35 | "__cHei": 16, 36 | "__gridSize": 8, 37 | "__opacity": 1, 38 | "__pxTotalOffsetX": 0, 39 | "__pxTotalOffsetY": 0, 40 | "__tilesetDefUid": null, 41 | "__tilesetRelPath": null, 42 | "iid": "6004c195-66b0-11ec-a36b-7deaadd71cf6", 43 | "levelId": 41, 44 | "layerDefUid": 28, 45 | "pxOffsetX": 0, 46 | "pxOffsetY": 0, 47 | "visible": true, 48 | "optionalRules": [], 49 | "intGridCsv": [], 50 | "autoLayerTiles": [], 51 | "seed": 7317663, 52 | "overrideTilesetUid": null, 53 | "gridTiles": [], 54 | "entityInstances": [ 55 | { 56 | "__identifier": "Item", 57 | "__grid": [10,9], 58 | "__pivot": [0.5,1], 59 | "__tags": [], 60 | "__tile": { "tilesetUid": 31, "x": 0, "y": 0, "w": 16, "h": 16 }, 61 | "__smartColor": "#FFDD00", 62 | "iid": "6004c196-66b0-11ec-a36b-230838ef99d1", 63 | "width": 10, 64 | "height": 10, 65 | "defUid": 29, 66 | "px": [84,80], 67 | "fieldInstances": [{ "__identifier": "type", "__type": "LocalEnum.Items", "__value": "Pickaxe", "__tile": { "tilesetUid": 31, "x": 0, "y": 0, "w": 16, "h": 16 }, "defUid": 32, "realEditorValues": [{ 68 | "id": "V_String", 69 | "params": ["Pickaxe"] 70 | }] }], 71 | "__worldX": 628, 72 | "__worldY": 304 73 | } 74 | ] 75 | }, 76 | { 77 | "__identifier": "Custom_tiles", 78 | "__type": "Tiles", 79 | "__cWid": 20, 80 | "__cHei": 16, 81 | "__gridSize": 8, 82 | "__opacity": 1, 83 | "__pxTotalOffsetX": 0, 84 | "__pxTotalOffsetY": 0, 85 | "__tilesetDefUid": 1, 86 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 87 | "iid": "6004c197-66b0-11ec-a36b-a73c51bcd20e", 88 | "levelId": 41, 89 | "layerDefUid": 34, 90 | "pxOffsetX": 0, 91 | "pxOffsetY": 0, 92 | "visible": true, 93 | "optionalRules": [], 94 | "intGridCsv": [], 95 | "autoLayerTiles": [], 96 | "seed": 5965368, 97 | "overrideTilesetUid": null, 98 | "gridTiles": [], 99 | "entityInstances": [] 100 | }, 101 | { 102 | "__identifier": "Collisions", 103 | "__type": "IntGrid", 104 | "__cWid": 20, 105 | "__cHei": 16, 106 | "__gridSize": 8, 107 | "__opacity": 1, 108 | "__pxTotalOffsetX": 0, 109 | "__pxTotalOffsetY": 0, 110 | "__tilesetDefUid": 58, 111 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended_hued.png", 112 | "iid": "6004c198-66b0-11ec-a36b-010522b658ac", 113 | "levelId": 41, 114 | "layerDefUid": 2, 115 | "pxOffsetX": 0, 116 | "pxOffsetY": 0, 117 | "visible": true, 118 | "optionalRules": [], 119 | "intGridCsv": [ 120 | 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, 121 | 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1, 122 | 1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0, 123 | 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, 124 | 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 125 | 0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1, 126 | 1,1,0,0,0,0,0,0,1,1,1,1,1,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,1,1,1,1,1,1,3, 127 | 3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 128 | 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, 129 | 1,1,1,1,1 130 | ], 131 | "autoLayerTiles": [ 132 | { "px": [8,0], "src": [0,0], "f": 0, "t": 0, "d": [36,1], "a": 1 }, 133 | { "px": [16,0], "src": [0,0], "f": 0, "t": 0, "d": [36,2], "a": 1 }, 134 | { "px": [48,0], "src": [0,0], "f": 0, "t": 0, "d": [36,6], "a": 1 }, 135 | { "px": [56,0], "src": [0,0], "f": 0, "t": 0, "d": [36,7], "a": 1 }, 136 | { "px": [88,0], "src": [0,0], "f": 0, "t": 0, "d": [36,11], "a": 1 }, 137 | { "px": [96,0], "src": [0,0], "f": 0, "t": 0, "d": [36,12], "a": 1 }, 138 | { "px": [104,0], "src": [0,0], "f": 0, "t": 0, "d": [36,13], "a": 1 }, 139 | { "px": [112,0], "src": [0,0], "f": 0, "t": 0, "d": [36,14], "a": 1 }, 140 | { "px": [120,0], "src": [0,0], "f": 0, "t": 0, "d": [36,15], "a": 1 }, 141 | { "px": [128,0], "src": [0,0], "f": 0, "t": 0, "d": [36,16], "a": 1 }, 142 | { "px": [152,0], "src": [0,0], "f": 0, "t": 0, "d": [36,19], "a": 1 }, 143 | { "px": [72,8], "src": [0,0], "f": 0, "t": 0, "d": [36,29], "a": 1 }, 144 | { "px": [88,8], "src": [0,0], "f": 0, "t": 0, "d": [36,31], "a": 1 }, 145 | { "px": [152,8], "src": [0,0], "f": 0, "t": 0, "d": [36,39], "a": 1 }, 146 | { "px": [80,16], "src": [0,0], "f": 0, "t": 0, "d": [36,50], "a": 1 }, 147 | { "px": [152,16], "src": [0,0], "f": 0, "t": 0, "d": [36,59], "a": 1 }, 148 | { "px": [152,24], "src": [0,0], "f": 0, "t": 0, "d": [36,79], "a": 1 }, 149 | { "px": [152,32], "src": [0,0], "f": 0, "t": 0, "d": [36,99], "a": 1 }, 150 | { "px": [0,40], "src": [0,0], "f": 0, "t": 0, "d": [36,100], "a": 1 }, 151 | { "px": [0,48], "src": [0,0], "f": 0, "t": 0, "d": [36,120], "a": 1 }, 152 | { "px": [152,48], "src": [0,0], "f": 0, "t": 0, "d": [36,139], "a": 1 }, 153 | { "px": [0,64], "src": [0,0], "f": 0, "t": 0, "d": [36,160], "a": 1 }, 154 | { "px": [0,72], "src": [0,0], "f": 0, "t": 0, "d": [36,180], "a": 1 }, 155 | { "px": [8,72], "src": [0,0], "f": 0, "t": 0, "d": [36,181], "a": 1 }, 156 | { "px": [0,80], "src": [0,0], "f": 0, "t": 0, "d": [36,200], "a": 1 }, 157 | { "px": [8,80], "src": [0,0], "f": 0, "t": 0, "d": [36,201], "a": 1 }, 158 | { "px": [152,80], "src": [0,0], "f": 0, "t": 0, "d": [36,219], "a": 1 }, 159 | { "px": [16,96], "src": [0,0], "f": 0, "t": 0, "d": [36,242], "a": 1 }, 160 | { "px": [152,96], "src": [0,0], "f": 0, "t": 0, "d": [36,259], "a": 1 }, 161 | { "px": [0,104], "src": [0,0], "f": 0, "t": 0, "d": [36,260], "a": 1 }, 162 | { "px": [16,104], "src": [0,0], "f": 0, "t": 0, "d": [36,262], "a": 1 }, 163 | { "px": [24,104], "src": [0,0], "f": 0, "t": 0, "d": [36,263], "a": 1 }, 164 | { "px": [144,104], "src": [0,0], "f": 0, "t": 0, "d": [36,278], "a": 1 }, 165 | { "px": [152,104], "src": [0,0], "f": 0, "t": 0, "d": [36,279], "a": 1 }, 166 | { "px": [0,112], "src": [0,0], "f": 0, "t": 0, "d": [36,280], "a": 1 }, 167 | { "px": [8,112], "src": [0,0], "f": 0, "t": 0, "d": [36,281], "a": 1 }, 168 | { "px": [16,112], "src": [0,0], "f": 0, "t": 0, "d": [36,282], "a": 1 }, 169 | { "px": [24,112], "src": [0,0], "f": 0, "t": 0, "d": [36,283], "a": 1 }, 170 | { "px": [32,112], "src": [0,0], "f": 0, "t": 0, "d": [36,284], "a": 1 }, 171 | { "px": [48,112], "src": [0,0], "f": 0, "t": 0, "d": [36,286], "a": 1 }, 172 | { "px": [56,112], "src": [0,0], "f": 0, "t": 0, "d": [36,287], "a": 1 }, 173 | { "px": [64,112], "src": [0,0], "f": 0, "t": 0, "d": [36,288], "a": 1 }, 174 | { "px": [72,112], "src": [0,0], "f": 0, "t": 0, "d": [36,289], "a": 1 }, 175 | { "px": [80,112], "src": [0,0], "f": 0, "t": 0, "d": [36,290], "a": 1 }, 176 | { "px": [88,112], "src": [0,0], "f": 0, "t": 0, "d": [36,291], "a": 1 }, 177 | { "px": [112,112], "src": [0,0], "f": 0, "t": 0, "d": [36,294], "a": 1 }, 178 | { "px": [120,112], "src": [0,0], "f": 0, "t": 0, "d": [36,295], "a": 1 }, 179 | { "px": [136,112], "src": [0,0], "f": 0, "t": 0, "d": [36,297], "a": 1 }, 180 | { "px": [152,112], "src": [0,0], "f": 0, "t": 0, "d": [36,299], "a": 1 }, 181 | { "px": [0,120], "src": [0,0], "f": 0, "t": 0, "d": [36,300], "a": 1 }, 182 | { "px": [8,120], "src": [0,0], "f": 0, "t": 0, "d": [36,301], "a": 1 }, 183 | { "px": [16,120], "src": [0,0], "f": 0, "t": 0, "d": [36,302], "a": 1 }, 184 | { "px": [56,120], "src": [0,0], "f": 0, "t": 0, "d": [36,307], "a": 1 }, 185 | { "px": [64,120], "src": [0,0], "f": 0, "t": 0, "d": [36,308], "a": 1 }, 186 | { "px": [72,120], "src": [0,0], "f": 0, "t": 0, "d": [36,309], "a": 1 }, 187 | { "px": [80,120], "src": [0,0], "f": 0, "t": 0, "d": [36,310], "a": 1 }, 188 | { "px": [88,120], "src": [0,0], "f": 0, "t": 0, "d": [36,311], "a": 1 }, 189 | { "px": [120,120], "src": [0,0], "f": 0, "t": 0, "d": [36,315], "a": 1 }, 190 | { "px": [128,120], "src": [0,0], "f": 0, "t": 0, "d": [36,316], "a": 1 }, 191 | { "px": [136,120], "src": [0,0], "f": 0, "t": 0, "d": [36,317], "a": 1 }, 192 | { "px": [144,120], "src": [0,0], "f": 0, "t": 0, "d": [36,318], "a": 1 }, 193 | { "px": [152,120], "src": [0,0], "f": 0, "t": 0, "d": [36,319], "a": 1 }, 194 | { "px": [0,0], "src": [8,16], "f": 0, "t": 25, "d": [57,0], "a": 1 }, 195 | { "px": [24,0], "src": [8,16], "f": 0, "t": 25, "d": [57,3], "a": 1 }, 196 | { "px": [32,0], "src": [8,16], "f": 0, "t": 25, "d": [57,4], "a": 1 }, 197 | { "px": [40,0], "src": [8,16], "f": 0, "t": 25, "d": [57,5], "a": 1 }, 198 | { "px": [64,0], "src": [8,16], "f": 0, "t": 25, "d": [57,8], "a": 1 }, 199 | { "px": [72,0], "src": [8,16], "f": 0, "t": 25, "d": [57,9], "a": 1 }, 200 | { "px": [80,0], "src": [8,16], "f": 0, "t": 25, "d": [57,10], "a": 1 }, 201 | { "px": [136,0], "src": [8,16], "f": 0, "t": 25, "d": [57,17], "a": 1 }, 202 | { "px": [144,0], "src": [8,16], "f": 0, "t": 25, "d": [57,18], "a": 1 }, 203 | { "px": [80,8], "src": [8,16], "f": 0, "t": 25, "d": [57,30], "a": 1 }, 204 | { "px": [144,8], "src": [8,16], "f": 0, "t": 25, "d": [57,38], "a": 1 }, 205 | { "px": [8,40], "src": [8,16], "f": 0, "t": 25, "d": [57,101], "a": 1 }, 206 | { "px": [152,40], "src": [8,16], "f": 0, "t": 25, "d": [57,119], "a": 1 }, 207 | { "px": [8,48], "src": [8,16], "f": 0, "t": 25, "d": [57,121], "a": 1 }, 208 | { "px": [0,56], "src": [8,16], "f": 0, "t": 25, "d": [57,140], "a": 1 }, 209 | { "px": [8,56], "src": [8,16], "f": 0, "t": 25, "d": [57,141], "a": 1 }, 210 | { "px": [152,56], "src": [8,16], "f": 0, "t": 25, "d": [57,159], "a": 1 }, 211 | { "px": [8,64], "src": [8,16], "f": 0, "t": 25, "d": [57,161], "a": 1 }, 212 | { "px": [152,64], "src": [8,16], "f": 0, "t": 25, "d": [57,179], "a": 1 }, 213 | { "px": [152,72], "src": [8,16], "f": 0, "t": 25, "d": [57,199], "a": 1 }, 214 | { "px": [0,88], "src": [8,16], "f": 0, "t": 25, "d": [57,220], "a": 1 }, 215 | { "px": [8,88], "src": [8,16], "f": 0, "t": 25, "d": [57,221], "a": 1 }, 216 | { "px": [152,88], "src": [8,16], "f": 0, "t": 25, "d": [57,239], "a": 1 }, 217 | { "px": [0,96], "src": [8,16], "f": 0, "t": 25, "d": [57,240], "a": 1 }, 218 | { "px": [8,96], "src": [8,16], "f": 0, "t": 25, "d": [57,241], "a": 1 }, 219 | { "px": [8,104], "src": [8,16], "f": 0, "t": 25, "d": [57,261], "a": 1 }, 220 | { "px": [40,112], "src": [8,16], "f": 0, "t": 25, "d": [57,285], "a": 1 }, 221 | { "px": [96,112], "src": [8,16], "f": 0, "t": 25, "d": [57,292], "a": 1 }, 222 | { "px": [104,112], "src": [8,16], "f": 0, "t": 25, "d": [57,293], "a": 1 }, 223 | { "px": [128,112], "src": [8,16], "f": 0, "t": 25, "d": [57,296], "a": 1 }, 224 | { "px": [144,112], "src": [8,16], "f": 0, "t": 25, "d": [57,298], "a": 1 }, 225 | { "px": [24,120], "src": [8,16], "f": 0, "t": 25, "d": [57,303], "a": 1 }, 226 | { "px": [32,120], "src": [8,16], "f": 0, "t": 25, "d": [57,304], "a": 1 }, 227 | { "px": [40,120], "src": [8,16], "f": 0, "t": 25, "d": [57,305], "a": 1 }, 228 | { "px": [48,120], "src": [8,16], "f": 0, "t": 25, "d": [57,306], "a": 1 }, 229 | { "px": [96,120], "src": [8,16], "f": 0, "t": 25, "d": [57,312], "a": 1 }, 230 | { "px": [104,120], "src": [8,16], "f": 0, "t": 25, "d": [57,313], "a": 1 }, 231 | { "px": [112,120], "src": [8,16], "f": 0, "t": 25, "d": [57,314], "a": 1 }, 232 | { "px": [72,16], "src": [0,16], "f": 0, "t": 24, "d": [6,49], "a": 1 }, 233 | { "px": [88,16], "src": [0,16], "f": 1, "t": 24, "d": [6,51], "a": 1 }, 234 | { "px": [144,16], "src": [0,16], "f": 0, "t": 24, "d": [6,58], "a": 1 }, 235 | { "px": [144,24], "src": [0,16], "f": 0, "t": 24, "d": [6,78], "a": 1 }, 236 | { "px": [144,32], "src": [0,16], "f": 0, "t": 24, "d": [6,98], "a": 1 }, 237 | { "px": [16,40], "src": [0,16], "f": 1, "t": 24, "d": [6,102], "a": 1 }, 238 | { "px": [144,40], "src": [0,16], "f": 0, "t": 24, "d": [6,118], "a": 1 }, 239 | { "px": [16,48], "src": [0,16], "f": 1, "t": 24, "d": [6,122], "a": 1 }, 240 | { "px": [144,48], "src": [0,16], "f": 0, "t": 24, "d": [6,138], "a": 1 }, 241 | { "px": [16,56], "src": [0,16], "f": 1, "t": 24, "d": [6,142], "a": 1 }, 242 | { "px": [144,56], "src": [0,16], "f": 0, "t": 24, "d": [6,158], "a": 1 }, 243 | { "px": [16,64], "src": [0,16], "f": 1, "t": 24, "d": [6,162], "a": 1 }, 244 | { "px": [144,64], "src": [0,16], "f": 0, "t": 24, "d": [6,178], "a": 1 }, 245 | { "px": [16,72], "src": [0,16], "f": 1, "t": 24, "d": [6,182], "a": 1 }, 246 | { "px": [144,72], "src": [0,16], "f": 0, "t": 24, "d": [6,198], "a": 1 }, 247 | { "px": [16,80], "src": [0,16], "f": 1, "t": 24, "d": [6,202], "a": 1 }, 248 | { "px": [144,80], "src": [0,16], "f": 0, "t": 24, "d": [6,218], "a": 1 }, 249 | { "px": [16,88], "src": [0,16], "f": 1, "t": 24, "d": [6,222], "a": 1 }, 250 | { "px": [144,88], "src": [0,16], "f": 0, "t": 24, "d": [6,238], "a": 1 }, 251 | { "px": [144,96], "src": [0,16], "f": 0, "t": 24, "d": [6,258], "a": 1 }, 252 | { "px": [0,8], "src": [8,8], "f": 2, "t": 13, "d": [7,20], "a": 1 }, 253 | { "px": [8,8], "src": [8,8], "f": 2, "t": 13, "d": [7,21], "a": 1 }, 254 | { "px": [16,8], "src": [8,8], "f": 2, "t": 13, "d": [7,22], "a": 1 }, 255 | { "px": [24,8], "src": [8,8], "f": 2, "t": 13, "d": [7,23], "a": 1 }, 256 | { "px": [32,8], "src": [8,8], "f": 2, "t": 13, "d": [7,24], "a": 1 }, 257 | { "px": [40,8], "src": [8,8], "f": 2, "t": 13, "d": [7,25], "a": 1 }, 258 | { "px": [48,8], "src": [8,8], "f": 2, "t": 13, "d": [7,26], "a": 1 }, 259 | { "px": [56,8], "src": [8,8], "f": 2, "t": 13, "d": [7,27], "a": 1 }, 260 | { "px": [64,8], "src": [8,8], "f": 2, "t": 13, "d": [7,28], "a": 1 }, 261 | { "px": [96,8], "src": [8,8], "f": 2, "t": 13, "d": [7,32], "a": 1 }, 262 | { "px": [104,8], "src": [8,8], "f": 2, "t": 13, "d": [7,33], "a": 1 }, 263 | { "px": [112,8], "src": [8,8], "f": 2, "t": 13, "d": [7,34], "a": 1 }, 264 | { "px": [120,8], "src": [8,8], "f": 2, "t": 13, "d": [7,35], "a": 1 }, 265 | { "px": [128,8], "src": [8,8], "f": 2, "t": 13, "d": [7,36], "a": 1 }, 266 | { "px": [136,8], "src": [8,8], "f": 2, "t": 13, "d": [7,37], "a": 1 }, 267 | { "px": [80,24], "src": [8,8], "f": 2, "t": 13, "d": [7,70], "a": 1 }, 268 | { "px": [0,32], "src": [8,8], "f": 0, "t": 13, "d": [7,80], "a": 1 }, 269 | { "px": [8,32], "src": [8,8], "f": 0, "t": 13, "d": [7,81], "a": 1 }, 270 | { "px": [80,80], "src": [8,8], "f": 0, "t": 13, "d": [7,210], "a": 1 }, 271 | { "px": [80,88], "src": [8,8], "f": 2, "t": 13, "d": [7,230], "a": 1 }, 272 | { "px": [32,104], "src": [8,8], "f": 0, "t": 13, "d": [7,264], "a": 1 }, 273 | { "px": [40,104], "src": [8,8], "f": 0, "t": 13, "d": [7,265], "a": 1 }, 274 | { "px": [48,104], "src": [8,8], "f": 0, "t": 13, "d": [7,266], "a": 1 }, 275 | { "px": [56,104], "src": [8,8], "f": 0, "t": 13, "d": [7,267], "a": 1 }, 276 | { "px": [64,104], "src": [8,8], "f": 0, "t": 13, "d": [7,268], "a": 1 }, 277 | { "px": [72,104], "src": [8,8], "f": 0, "t": 13, "d": [7,269], "a": 1 }, 278 | { "px": [80,104], "src": [8,8], "f": 0, "t": 13, "d": [7,270], "a": 1 }, 279 | { "px": [88,104], "src": [8,8], "f": 0, "t": 13, "d": [7,271], "a": 1 }, 280 | { "px": [96,104], "src": [8,8], "f": 0, "t": 13, "d": [7,272], "a": 1 }, 281 | { "px": [104,104], "src": [8,8], "f": 0, "t": 13, "d": [7,273], "a": 1 }, 282 | { "px": [112,104], "src": [8,8], "f": 0, "t": 13, "d": [7,274], "a": 1 }, 283 | { "px": [120,104], "src": [8,8], "f": 0, "t": 13, "d": [7,275], "a": 1 }, 284 | { "px": [128,104], "src": [8,8], "f": 0, "t": 13, "d": [7,276], "a": 1 }, 285 | { "px": [136,104], "src": [8,8], "f": 0, "t": 13, "d": [7,277], "a": 1 }, 286 | { "px": [72,24], "src": [0,8], "f": 2, "t": 12, "d": [5,69], "a": 1 }, 287 | { "px": [88,24], "src": [0,8], "f": 3, "t": 12, "d": [5,71], "a": 1 }, 288 | { "px": [16,32], "src": [0,8], "f": 1, "t": 12, "d": [5,82], "a": 1 }, 289 | { "px": [72,80], "src": [0,8], "f": 0, "t": 12, "d": [5,209], "a": 1 }, 290 | { "px": [88,80], "src": [0,8], "f": 1, "t": 12, "d": [5,211], "a": 1 }, 291 | { "px": [72,88], "src": [0,8], "f": 2, "t": 12, "d": [5,229], "a": 1 }, 292 | { "px": [88,88], "src": [0,8], "f": 3, "t": 12, "d": [5,231], "a": 1 }, 293 | { "px": [24,96], "src": [0,8], "f": 1, "t": 12, "d": [5,243], "a": 1 }, 294 | { "px": [0,16], "src": [80,56], "f": 0, "t": 94, "d": [47,40], "a": 1 }, 295 | { "px": [8,16], "src": [80,56], "f": 0, "t": 94, "d": [47,41], "a": 1 }, 296 | { "px": [16,16], "src": [80,56], "f": 0, "t": 94, "d": [47,42], "a": 1 }, 297 | { "px": [24,16], "src": [80,56], "f": 0, "t": 94, "d": [47,43], "a": 1 }, 298 | { "px": [32,16], "src": [80,56], "f": 0, "t": 94, "d": [47,44], "a": 1 }, 299 | { "px": [40,16], "src": [80,56], "f": 0, "t": 94, "d": [47,45], "a": 1 }, 300 | { "px": [48,16], "src": [80,56], "f": 0, "t": 94, "d": [47,46], "a": 1 }, 301 | { "px": [56,16], "src": [80,56], "f": 0, "t": 94, "d": [47,47], "a": 1 }, 302 | { "px": [64,16], "src": [80,56], "f": 0, "t": 94, "d": [47,48], "a": 1 }, 303 | { "px": [96,16], "src": [80,56], "f": 0, "t": 94, "d": [47,52], "a": 1 }, 304 | { "px": [104,16], "src": [80,56], "f": 0, "t": 94, "d": [47,53], "a": 1 }, 305 | { "px": [112,16], "src": [80,56], "f": 0, "t": 94, "d": [47,54], "a": 1 }, 306 | { "px": [120,16], "src": [80,56], "f": 0, "t": 94, "d": [47,55], "a": 1 }, 307 | { "px": [128,16], "src": [80,56], "f": 0, "t": 94, "d": [47,56], "a": 1 }, 308 | { "px": [136,16], "src": [80,56], "f": 0, "t": 94, "d": [47,57], "a": 1 }, 309 | { "px": [72,32], "src": [80,56], "f": 0, "t": 94, "d": [47,89], "a": 1 }, 310 | { "px": [80,32], "src": [80,56], "f": 0, "t": 94, "d": [47,90], "a": 1 }, 311 | { "px": [88,32], "src": [80,56], "f": 0, "t": 94, "d": [47,91], "a": 1 }, 312 | { "px": [80,72], "src": [32,40], "f": 0, "t": 64, "d": [38,190], "a": 1 }, 313 | { "px": [16,24], "src": [64,16], "f": 0, "t": 32, "d": [12,62], "a": 1 }, 314 | { "px": [0,24], "src": [72,32], "f": 0, "t": 57, "d": [11,60], "a": 1 }, 315 | { "px": [8,24], "src": [88,32], "f": 0, "t": 59, "d": [11,61], "a": 1 }, 316 | { "px": [16,24], "src": [80,32], "f": 0, "t": 58, "d": [11,62], "a": 1 }, 317 | { "px": [72,72], "src": [88,32], "f": 0, "t": 59, "d": [11,189], "a": 1 }, 318 | { "px": [80,72], "src": [88,32], "f": 0, "t": 59, "d": [11,190], "a": 1 }, 319 | { "px": [88,72], "src": [64,32], "f": 0, "t": 56, "d": [11,191], "a": 1 }, 320 | { "px": [8,16], "src": [24,96], "f": 0, "t": 147, "d": [14,41], "a": 1 }, 321 | { "px": [56,16], "src": [56,80], "f": 0, "t": 127, "d": [14,47], "a": 1 }, 322 | { "px": [72,32], "src": [32,96], "f": 0, "t": 148, "d": [14,89], "a": 1 }, 323 | { "px": [88,32], "src": [32,96], "f": 0, "t": 148, "d": [14,91], "a": 1 }, 324 | { "px": [32,96], "src": [32,64], "f": 0, "t": 100, "d": [43,244], "a": 1 }, 325 | { "px": [40,96], "src": [32,64], "f": 0, "t": 100, "d": [43,245], "a": 1 }, 326 | { "px": [48,96], "src": [32,64], "f": 0, "t": 100, "d": [43,246], "a": 1 }, 327 | { "px": [56,96], "src": [32,64], "f": 0, "t": 100, "d": [43,247], "a": 1 }, 328 | { "px": [64,96], "src": [32,64], "f": 0, "t": 100, "d": [43,248], "a": 1 }, 329 | { "px": [72,96], "src": [32,64], "f": 0, "t": 100, "d": [43,249], "a": 1 }, 330 | { "px": [80,96], "src": [32,64], "f": 0, "t": 100, "d": [43,250], "a": 1 }, 331 | { "px": [88,96], "src": [32,64], "f": 0, "t": 100, "d": [43,251], "a": 1 }, 332 | { "px": [96,96], "src": [32,64], "f": 0, "t": 100, "d": [43,252], "a": 1 }, 333 | { "px": [104,96], "src": [32,64], "f": 0, "t": 100, "d": [43,253], "a": 1 }, 334 | { "px": [112,96], "src": [32,64], "f": 0, "t": 100, "d": [43,254], "a": 1 }, 335 | { "px": [120,96], "src": [32,64], "f": 0, "t": 100, "d": [43,255], "a": 1 }, 336 | { "px": [128,96], "src": [32,64], "f": 0, "t": 100, "d": [43,256], "a": 1 }, 337 | { "px": [136,96], "src": [32,64], "f": 0, "t": 100, "d": [43,257], "a": 1 }, 338 | { "px": [24,88], "src": [32,80], "f": 0, "t": 124, "d": [44,223], "a": 1 }, 339 | { "px": [32,88], "src": [32,80], "f": 0, "t": 124, "d": [44,224], "a": 1 }, 340 | { "px": [40,88], "src": [32,80], "f": 0, "t": 124, "d": [44,225], "a": 1 }, 341 | { "px": [48,88], "src": [32,80], "f": 0, "t": 124, "d": [44,226], "a": 1 }, 342 | { "px": [56,88], "src": [32,80], "f": 0, "t": 124, "d": [44,227], "a": 1 }, 343 | { "px": [64,88], "src": [32,80], "f": 0, "t": 124, "d": [44,228], "a": 1 }, 344 | { "px": [96,88], "src": [32,80], "f": 0, "t": 124, "d": [44,232], "a": 1 }, 345 | { "px": [104,88], "src": [32,80], "f": 0, "t": 124, "d": [44,233], "a": 1 }, 346 | { "px": [112,88], "src": [32,80], "f": 0, "t": 124, "d": [44,234], "a": 1 }, 347 | { "px": [120,88], "src": [32,80], "f": 0, "t": 124, "d": [44,235], "a": 1 }, 348 | { "px": [128,88], "src": [32,80], "f": 0, "t": 124, "d": [44,236], "a": 1 }, 349 | { "px": [136,88], "src": [32,80], "f": 0, "t": 124, "d": [44,237], "a": 1 } 350 | ], 351 | "seed": 4561620, 352 | "overrideTilesetUid": 58, 353 | "gridTiles": [], 354 | "entityInstances": [] 355 | }, 356 | { 357 | "__identifier": "Cavern_background", 358 | "__type": "IntGrid", 359 | "__cWid": 20, 360 | "__cHei": 16, 361 | "__gridSize": 8, 362 | "__opacity": 1, 363 | "__pxTotalOffsetX": 0, 364 | "__pxTotalOffsetY": 0, 365 | "__tilesetDefUid": 1, 366 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 367 | "iid": "6004e8a0-66b0-11ec-a36b-81200e7178cb", 368 | "levelId": 41, 369 | "layerDefUid": 48, 370 | "pxOffsetX": 0, 371 | "pxOffsetY": 0, 372 | "visible": true, 373 | "optionalRules": [], 374 | "intGridCsv": [ 375 | 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,1,0,0,0,0,0,0,0,0,0, 376 | 1,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0, 377 | 0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0, 378 | 1,0,0,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,0,0,1,0,0,0,0, 379 | 0,0,0,0,0,1,0,0,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,0,0, 380 | 1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0, 381 | 0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 382 | 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, 383 | 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, 384 | 0,0,0,0,0 385 | ], 386 | "autoLayerTiles": [ 387 | { "px": [72,40], "src": [0,0], "f": 0, "t": 0, "d": [50,109], "a": 1 }, 388 | { "px": [72,48], "src": [0,0], "f": 0, "t": 0, "d": [50,129], "a": 1 }, 389 | { "px": [72,56], "src": [0,0], "f": 0, "t": 0, "d": [50,149], "a": 1 }, 390 | { "px": [80,56], "src": [0,0], "f": 0, "t": 0, "d": [50,150], "a": 1 }, 391 | { "px": [88,56], "src": [0,0], "f": 0, "t": 0, "d": [50,151], "a": 1 }, 392 | { "px": [80,64], "src": [0,0], "f": 0, "t": 0, "d": [50,170], "a": 1 }, 393 | { "px": [80,40], "src": [32,0], "f": 0, "t": 4, "d": [51,110], "a": 1 }, 394 | { "px": [88,40], "src": [48,0], "f": 0, "t": 6, "d": [51,111], "a": 1 }, 395 | { "px": [80,48], "src": [40,0], "f": 0, "t": 5, "d": [51,130], "a": 1 }, 396 | { "px": [88,48], "src": [8,0], "f": 0, "t": 1, "d": [51,131], "a": 1 }, 397 | { "px": [72,64], "src": [8,0], "f": 0, "t": 1, "d": [51,169], "a": 1 }, 398 | { "px": [88,64], "src": [24,0], "f": 0, "t": 3, "d": [51,171], "a": 1 }, 399 | { "px": [40,16], "src": [40,88], "f": 0, "t": 137, "d": [52,45], "a": 1 }, 400 | { "px": [120,16], "src": [40,88], "f": 0, "t": 137, "d": [52,55], "a": 1 }, 401 | { "px": [40,24], "src": [40,88], "f": 0, "t": 137, "d": [52,65], "a": 1 }, 402 | { "px": [64,24], "src": [40,88], "f": 0, "t": 137, "d": [52,68], "a": 1 }, 403 | { "px": [96,24], "src": [40,88], "f": 0, "t": 137, "d": [52,72], "a": 1 }, 404 | { "px": [120,24], "src": [40,88], "f": 0, "t": 137, "d": [52,75], "a": 1 }, 405 | { "px": [40,32], "src": [40,88], "f": 0, "t": 137, "d": [52,85], "a": 1 }, 406 | { "px": [64,32], "src": [40,88], "f": 1, "t": 137, "d": [52,88], "a": 1 }, 407 | { "px": [96,32], "src": [40,88], "f": 0, "t": 137, "d": [52,92], "a": 1 }, 408 | { "px": [120,32], "src": [40,88], "f": 0, "t": 137, "d": [52,95], "a": 1 }, 409 | { "px": [40,40], "src": [40,88], "f": 0, "t": 137, "d": [52,105], "a": 1 }, 410 | { "px": [64,40], "src": [40,88], "f": 1, "t": 137, "d": [52,108], "a": 1 }, 411 | { "px": [96,40], "src": [40,88], "f": 0, "t": 137, "d": [52,112], "a": 1 }, 412 | { "px": [120,40], "src": [40,88], "f": 0, "t": 137, "d": [52,115], "a": 1 }, 413 | { "px": [40,48], "src": [40,88], "f": 0, "t": 137, "d": [52,125], "a": 1 }, 414 | { "px": [64,48], "src": [40,88], "f": 1, "t": 137, "d": [52,128], "a": 1 }, 415 | { "px": [96,48], "src": [40,88], "f": 0, "t": 137, "d": [52,132], "a": 1 }, 416 | { "px": [120,48], "src": [40,88], "f": 0, "t": 137, "d": [52,135], "a": 1 }, 417 | { "px": [40,56], "src": [40,88], "f": 0, "t": 137, "d": [52,145], "a": 1 }, 418 | { "px": [64,56], "src": [40,88], "f": 1, "t": 137, "d": [52,148], "a": 1 }, 419 | { "px": [96,56], "src": [40,88], "f": 0, "t": 137, "d": [52,152], "a": 1 }, 420 | { "px": [120,56], "src": [40,88], "f": 0, "t": 137, "d": [52,155], "a": 1 }, 421 | { "px": [40,64], "src": [40,88], "f": 0, "t": 137, "d": [52,165], "a": 1 }, 422 | { "px": [64,64], "src": [40,88], "f": 1, "t": 137, "d": [52,168], "a": 1 }, 423 | { "px": [96,64], "src": [40,88], "f": 0, "t": 137, "d": [52,172], "a": 1 }, 424 | { "px": [120,64], "src": [40,88], "f": 0, "t": 137, "d": [52,175], "a": 1 }, 425 | { "px": [40,72], "src": [40,88], "f": 0, "t": 137, "d": [52,185], "a": 1 }, 426 | { "px": [64,72], "src": [40,88], "f": 1, "t": 137, "d": [52,188], "a": 1 }, 427 | { "px": [96,72], "src": [40,88], "f": 0, "t": 137, "d": [52,192], "a": 1 }, 428 | { "px": [120,72], "src": [40,88], "f": 0, "t": 137, "d": [52,195], "a": 1 }, 429 | { "px": [40,80], "src": [40,88], "f": 0, "t": 137, "d": [52,205], "a": 1 }, 430 | { "px": [120,80], "src": [40,88], "f": 0, "t": 137, "d": [52,215], "a": 1 }, 431 | { "px": [40,8], "src": [40,96], "f": 0, "t": 149, "d": [54,25], "a": 1 }, 432 | { "px": [120,8], "src": [40,96], "f": 0, "t": 149, "d": [54,35], "a": 1 }, 433 | { "px": [64,16], "src": [40,96], "f": 0, "t": 149, "d": [54,48], "a": 1 }, 434 | { "px": [96,16], "src": [40,96], "f": 0, "t": 149, "d": [54,52], "a": 1 }, 435 | { "px": [72,32], "src": [40,96], "f": 0, "t": 149, "d": [54,89], "a": 1 }, 436 | { "px": [80,32], "src": [40,96], "f": 0, "t": 149, "d": [54,90], "a": 1 }, 437 | { "px": [88,32], "src": [40,96], "f": 0, "t": 149, "d": [54,91], "a": 1 }, 438 | { "px": [72,72], "src": [40,96], "f": 2, "t": 149, "d": [54,189], "a": 1 }, 439 | { "px": [80,72], "src": [40,96], "f": 2, "t": 149, "d": [54,190], "a": 1 }, 440 | { "px": [88,72], "src": [40,96], "f": 2, "t": 149, "d": [54,191], "a": 1 }, 441 | { "px": [64,80], "src": [40,96], "f": 2, "t": 149, "d": [54,208], "a": 1 }, 442 | { "px": [96,80], "src": [40,96], "f": 2, "t": 149, "d": [54,212], "a": 1 }, 443 | { "px": [40,88], "src": [40,96], "f": 2, "t": 149, "d": [54,225], "a": 1 }, 444 | { "px": [120,88], "src": [40,96], "f": 2, "t": 149, "d": [54,235], "a": 1 }, 445 | { "px": [32,8], "src": [88,56], "f": 1, "t": 95, "d": [55,24], "a": 1 }, 446 | { "px": [48,8], "src": [88,56], "f": 0, "t": 95, "d": [55,26], "a": 1 }, 447 | { "px": [112,8], "src": [88,56], "f": 1, "t": 95, "d": [55,34], "a": 1 }, 448 | { "px": [128,8], "src": [88,56], "f": 0, "t": 95, "d": [55,36], "a": 1 }, 449 | { "px": [32,16], "src": [88,56], "f": 1, "t": 95, "d": [55,44], "a": 1 }, 450 | { "px": [48,16], "src": [88,56], "f": 0, "t": 95, "d": [55,46], "a": 1 }, 451 | { "px": [56,16], "src": [88,56], "f": 1, "t": 95, "d": [55,47], "a": 1 }, 452 | { "px": [72,16], "src": [88,56], "f": 0, "t": 95, "d": [55,49], "a": 1 }, 453 | { "px": [88,16], "src": [88,56], "f": 1, "t": 95, "d": [55,51], "a": 1 }, 454 | { "px": [104,16], "src": [88,56], "f": 0, "t": 95, "d": [55,53], "a": 1 }, 455 | { "px": [112,16], "src": [88,56], "f": 1, "t": 95, "d": [55,54], "a": 1 }, 456 | { "px": [128,16], "src": [88,56], "f": 0, "t": 95, "d": [55,56], "a": 1 }, 457 | { "px": [32,24], "src": [88,56], "f": 1, "t": 95, "d": [55,64], "a": 1 }, 458 | { "px": [48,24], "src": [88,56], "f": 0, "t": 95, "d": [55,66], "a": 1 }, 459 | { "px": [56,24], "src": [88,56], "f": 1, "t": 95, "d": [55,67], "a": 1 }, 460 | { "px": [104,24], "src": [88,56], "f": 0, "t": 95, "d": [55,73], "a": 1 }, 461 | { "px": [112,24], "src": [88,56], "f": 1, "t": 95, "d": [55,74], "a": 1 }, 462 | { "px": [128,24], "src": [88,56], "f": 0, "t": 95, "d": [55,76], "a": 1 }, 463 | { "px": [32,32], "src": [88,56], "f": 1, "t": 95, "d": [55,84], "a": 1 }, 464 | { "px": [48,32], "src": [88,56], "f": 0, "t": 95, "d": [55,86], "a": 1 }, 465 | { "px": [56,32], "src": [88,56], "f": 1, "t": 95, "d": [55,87], "a": 1 }, 466 | { "px": [104,32], "src": [88,56], "f": 0, "t": 95, "d": [55,93], "a": 1 }, 467 | { "px": [112,32], "src": [88,56], "f": 1, "t": 95, "d": [55,94], "a": 1 }, 468 | { "px": [128,32], "src": [88,56], "f": 0, "t": 95, "d": [55,96], "a": 1 }, 469 | { "px": [32,40], "src": [88,56], "f": 1, "t": 95, "d": [55,104], "a": 1 }, 470 | { "px": [48,40], "src": [88,56], "f": 0, "t": 95, "d": [55,106], "a": 1 }, 471 | { "px": [56,40], "src": [88,56], "f": 1, "t": 95, "d": [55,107], "a": 1 }, 472 | { "px": [104,40], "src": [88,56], "f": 0, "t": 95, "d": [55,113], "a": 1 }, 473 | { "px": [112,40], "src": [88,56], "f": 1, "t": 95, "d": [55,114], "a": 1 }, 474 | { "px": [128,40], "src": [88,56], "f": 0, "t": 95, "d": [55,116], "a": 1 }, 475 | { "px": [32,48], "src": [88,56], "f": 1, "t": 95, "d": [55,124], "a": 1 }, 476 | { "px": [48,48], "src": [88,56], "f": 0, "t": 95, "d": [55,126], "a": 1 }, 477 | { "px": [56,48], "src": [88,56], "f": 1, "t": 95, "d": [55,127], "a": 1 }, 478 | { "px": [104,48], "src": [88,56], "f": 0, "t": 95, "d": [55,133], "a": 1 }, 479 | { "px": [112,48], "src": [88,56], "f": 1, "t": 95, "d": [55,134], "a": 1 }, 480 | { "px": [128,48], "src": [88,56], "f": 0, "t": 95, "d": [55,136], "a": 1 }, 481 | { "px": [32,56], "src": [88,56], "f": 1, "t": 95, "d": [55,144], "a": 1 }, 482 | { "px": [48,56], "src": [88,56], "f": 0, "t": 95, "d": [55,146], "a": 1 }, 483 | { "px": [56,56], "src": [88,56], "f": 1, "t": 95, "d": [55,147], "a": 1 }, 484 | { "px": [104,56], "src": [88,56], "f": 0, "t": 95, "d": [55,153], "a": 1 }, 485 | { "px": [112,56], "src": [88,56], "f": 1, "t": 95, "d": [55,154], "a": 1 }, 486 | { "px": [128,56], "src": [88,56], "f": 0, "t": 95, "d": [55,156], "a": 1 }, 487 | { "px": [32,64], "src": [88,56], "f": 1, "t": 95, "d": [55,164], "a": 1 }, 488 | { "px": [48,64], "src": [88,56], "f": 0, "t": 95, "d": [55,166], "a": 1 }, 489 | { "px": [56,64], "src": [88,56], "f": 1, "t": 95, "d": [55,167], "a": 1 }, 490 | { "px": [104,64], "src": [88,56], "f": 0, "t": 95, "d": [55,173], "a": 1 }, 491 | { "px": [112,64], "src": [88,56], "f": 1, "t": 95, "d": [55,174], "a": 1 }, 492 | { "px": [128,64], "src": [88,56], "f": 0, "t": 95, "d": [55,176], "a": 1 }, 493 | { "px": [32,72], "src": [88,56], "f": 1, "t": 95, "d": [55,184], "a": 1 }, 494 | { "px": [48,72], "src": [88,56], "f": 0, "t": 95, "d": [55,186], "a": 1 }, 495 | { "px": [56,72], "src": [88,56], "f": 1, "t": 95, "d": [55,187], "a": 1 }, 496 | { "px": [104,72], "src": [88,56], "f": 0, "t": 95, "d": [55,193], "a": 1 }, 497 | { "px": [112,72], "src": [88,56], "f": 1, "t": 95, "d": [55,194], "a": 1 }, 498 | { "px": [128,72], "src": [88,56], "f": 0, "t": 95, "d": [55,196], "a": 1 }, 499 | { "px": [32,80], "src": [88,56], "f": 1, "t": 95, "d": [55,204], "a": 1 }, 500 | { "px": [48,80], "src": [88,56], "f": 0, "t": 95, "d": [55,206], "a": 1 }, 501 | { "px": [56,80], "src": [88,56], "f": 1, "t": 95, "d": [55,207], "a": 1 }, 502 | { "px": [104,80], "src": [88,56], "f": 0, "t": 95, "d": [55,213], "a": 1 }, 503 | { "px": [112,80], "src": [88,56], "f": 1, "t": 95, "d": [55,214], "a": 1 }, 504 | { "px": [128,80], "src": [88,56], "f": 0, "t": 95, "d": [55,216], "a": 1 }, 505 | { "px": [32,88], "src": [88,56], "f": 1, "t": 95, "d": [55,224], "a": 1 }, 506 | { "px": [48,88], "src": [88,56], "f": 0, "t": 95, "d": [55,226], "a": 1 }, 507 | { "px": [112,88], "src": [88,56], "f": 1, "t": 95, "d": [55,234], "a": 1 }, 508 | { "px": [128,88], "src": [88,56], "f": 0, "t": 95, "d": [55,236], "a": 1 }, 509 | { "px": [40,0], "src": [80,56], "f": 2, "t": 94, "d": [56,5], "a": 1 }, 510 | { "px": [120,0], "src": [80,56], "f": 2, "t": 94, "d": [56,15], "a": 1 }, 511 | { "px": [64,8], "src": [80,56], "f": 2, "t": 94, "d": [56,28], "a": 1 }, 512 | { "px": [96,8], "src": [80,56], "f": 2, "t": 94, "d": [56,32], "a": 1 }, 513 | { "px": [72,24], "src": [80,56], "f": 2, "t": 94, "d": [56,69], "a": 1 }, 514 | { "px": [80,24], "src": [80,56], "f": 2, "t": 94, "d": [56,70], "a": 1 }, 515 | { "px": [88,24], "src": [80,56], "f": 2, "t": 94, "d": [56,71], "a": 1 }, 516 | { "px": [72,80], "src": [80,56], "f": 0, "t": 94, "d": [56,209], "a": 1 }, 517 | { "px": [80,80], "src": [80,56], "f": 0, "t": 94, "d": [56,210], "a": 1 }, 518 | { "px": [88,80], "src": [80,56], "f": 0, "t": 94, "d": [56,211], "a": 1 }, 519 | { "px": [64,88], "src": [80,56], "f": 0, "t": 94, "d": [56,228], "a": 1 }, 520 | { "px": [96,88], "src": [80,56], "f": 0, "t": 94, "d": [56,232], "a": 1 }, 521 | { "px": [40,96], "src": [80,56], "f": 0, "t": 94, "d": [56,245], "a": 1 }, 522 | { "px": [120,96], "src": [80,56], "f": 0, "t": 94, "d": [56,255], "a": 1 } 523 | ], 524 | "seed": 7498828, 525 | "overrideTilesetUid": null, 526 | "gridTiles": [], 527 | "entityInstances": [] 528 | } 529 | ], 530 | "__neighbours": [{ "levelIid": "60038910-66b0-11ec-a36b-1ff7a8a0ffd4", "dir": "w" }] 531 | } -------------------------------------------------------------------------------- /samples/_assets/sample/png/East.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/sample/png/East.png -------------------------------------------------------------------------------- /samples/_assets/sample/png/Pit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/sample/png/Pit.png -------------------------------------------------------------------------------- /samples/_assets/sample/png/Treasure_room.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/sample/png/Treasure_room.png -------------------------------------------------------------------------------- /samples/_assets/sample/png/West.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/samples/_assets/sample/png/West.png -------------------------------------------------------------------------------- /samples/_assets/unitTest/Offset_tests.ldtkl: -------------------------------------------------------------------------------- 1 | { 2 | "__header__": { 3 | "fileType": "LDtk Project JSON", 4 | "app": "LDtk", 5 | "doc": "https://ldtk.io/json", 6 | "schema": "https://ldtk.io/files/JSON_SCHEMA.json", 7 | "appAuthor": "Sebastien 'deepnight' Benard", 8 | "appVersion": "1.5.3", 9 | "url": "https://ldtk.io" 10 | }, 11 | "identifier": "Offset_tests", 12 | "iid": "f2f66840-66b0-11ec-91ab-e506cb005a35", 13 | "uid": 88, 14 | "worldX": 512, 15 | "worldY": 256, 16 | "worldDepth": 0, 17 | "pxWid": 256, 18 | "pxHei": 256, 19 | "__bgColor": "#7F8093", 20 | "bgColor": null, 21 | "useAutoIdentifier": false, 22 | "bgRelPath": null, 23 | "bgPos": null, 24 | "bgPivotX": 0.5, 25 | "bgPivotY": 0.5, 26 | "__smartColor": "#B9B9C4", 27 | "__bgPos": null, 28 | "externalRelPath": null, 29 | "fieldInstances": [ 30 | { "__identifier": "level_int", "__type": "Int", "__value": 2, "__tile": null, "defUid": 93, "realEditorValues": [{ "id": "V_Int", "params": [2] }] }, 31 | { "__identifier": "level_string", "__type": "String", "__value": "other", "__tile": null, "defUid": 94, "realEditorValues": [{ 32 | "id": "V_String", 33 | "params": ["other"] 34 | }] }, 35 | { "__identifier": "level_reward", "__type": "ExternEnum.DroppedItemType", "__value": "Key", "__tile": null, "defUid": 95, "realEditorValues": [{ 36 | "id": "V_String", 37 | "params": ["Key"] 38 | }] }, 39 | { "__identifier": "lowercase_enum", "__type": "Array", "__value": [], "__tile": null, "defUid": 106, "realEditorValues": [] } 40 | ], 41 | "layerInstances": [ 42 | { 43 | "__identifier": "IntGrid_AutoLayer", 44 | "__type": "IntGrid", 45 | "__cWid": 32, 46 | "__cHei": 32, 47 | "__gridSize": 8, 48 | "__opacity": 1, 49 | "__pxTotalOffsetX": 0, 50 | "__pxTotalOffsetY": 0, 51 | "__tilesetDefUid": 46, 52 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 53 | "iid": "2737c0a6-66b0-11ec-8446-3f4faacc597c", 54 | "levelId": 88, 55 | "layerDefUid": 41, 56 | "pxOffsetX": 0, 57 | "pxOffsetY": 0, 58 | "visible": true, 59 | "optionalRules": [], 60 | "intGridCsv": [ 61 | 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, 62 | 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, 63 | 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, 64 | 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, 65 | 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, 66 | 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, 67 | 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, 68 | 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, 69 | 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, 70 | 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, 71 | 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, 72 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 73 | 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, 74 | 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, 75 | 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, 76 | 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, 77 | 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, 78 | 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, 79 | 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, 80 | 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, 81 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, 82 | 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, 83 | 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, 84 | 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, 85 | 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, 86 | 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, 87 | 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, 88 | 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, 89 | 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, 90 | 0,0,0,0,0,0,0,0,0 91 | ], 92 | "autoLayerTiles": [ 93 | { "px": [152,96], "src": [32,32], "f": 0, "t": 52, "d": [53,403], "a": 1 }, 94 | { "px": [152,88], "src": [80,32], "f": 0, "t": 58, "d": [48,371], "a": 1 }, 95 | { "px": [144,104], "src": [80,32], "f": 2, "t": 58, "d": [48,434], "a": 1 }, 96 | { "px": [152,104], "src": [80,32], "f": 2, "t": 58, "d": [48,435], "a": 1 }, 97 | { "px": [160,104], "src": [88,32], "f": 2, "t": 59, "d": [48,436], "a": 1 }, 98 | { "px": [160,184], "src": [80,32], "f": 2, "t": 58, "d": [48,756], "a": 1 }, 99 | { "px": [152,88], "src": [72,16], "f": 0, "t": 33, "d": [54,371], "a": 1 }, 100 | { "px": [144,80], "src": [0,112], "f": 0, "t": 168, "d": [80,370], "a": 1 }, 101 | { "px": [144,88], "src": [0,120], "f": 0, "t": 180, "d": [80,370], "a": 1 }, 102 | { "px": [160,80], "src": [0,112], "f": 0, "t": 168, "d": [80,372], "a": 1 }, 103 | { "px": [160,88], "src": [0,120], "f": 0, "t": 180, "d": [80,372], "a": 1 }, 104 | { "px": [160,160], "src": [0,112], "f": 0, "t": 168, "d": [80,692], "a": 1 }, 105 | { "px": [160,168], "src": [0,120], "f": 0, "t": 180, "d": [80,692], "a": 1 }, 106 | { "px": [140,92], "src": [0,152], "f": 0, "t": 228, "d": [81,402], "a": 1 }, 107 | { "px": [140,100], "src": [0,160], "f": 0, "t": 240, "d": [81,402], "a": 1 }, 108 | { "px": [148,92], "src": [8,152], "f": 0, "t": 229, "d": [81,402], "a": 1 }, 109 | { "px": [148,100], "src": [8,160], "f": 0, "t": 241, "d": [81,402], "a": 1 }, 110 | { "px": [164,92], "src": [0,152], "f": 1, "t": 228, "d": [81,404], "a": 1 }, 111 | { "px": [164,100], "src": [0,160], "f": 1, "t": 240, "d": [81,404], "a": 1 }, 112 | { "px": [156,92], "src": [8,152], "f": 1, "t": 229, "d": [81,404], "a": 1 }, 113 | { "px": [156,100], "src": [8,160], "f": 1, "t": 241, "d": [81,404], "a": 1 }, 114 | { "px": [156,172], "src": [0,152], "f": 0, "t": 228, "d": [81,724], "a": 1 }, 115 | { "px": [156,180], "src": [0,160], "f": 0, "t": 240, "d": [81,724], "a": 1 }, 116 | { "px": [164,172], "src": [8,152], "f": 0, "t": 229, "d": [81,724], "a": 1 }, 117 | { "px": [164,180], "src": [8,160], "f": 0, "t": 241, "d": [81,724], "a": 1 } 118 | ], 119 | "seed": 2453189, 120 | "overrideTilesetUid": null, 121 | "gridTiles": [], 122 | "entityInstances": [] 123 | }, 124 | { 125 | "__identifier": "Pure_AutoLayer", 126 | "__type": "AutoLayer", 127 | "__cWid": 32, 128 | "__cHei": 32, 129 | "__gridSize": 8, 130 | "__opacity": 1, 131 | "__pxTotalOffsetX": 0, 132 | "__pxTotalOffsetY": 0, 133 | "__tilesetDefUid": 46, 134 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 135 | "iid": "2737c0a7-66b0-11ec-8446-67da903cc393", 136 | "levelId": 88, 137 | "layerDefUid": 82, 138 | "pxOffsetX": 0, 139 | "pxOffsetY": 0, 140 | "visible": true, 141 | "optionalRules": [], 142 | "intGridCsv": [], 143 | "autoLayerTiles": [ 144 | { "px": [144,104], "src": [32,96], "f": 0, "t": 148, "d": [85,434], "a": 1 }, 145 | { "px": [152,104], "src": [48,80], "f": 0, "t": 126, "d": [85,435], "a": 1 }, 146 | { "px": [160,104], "src": [56,80], "f": 0, "t": 127, "d": [85,436], "a": 1 }, 147 | { "px": [160,184], "src": [24,96], "f": 0, "t": 147, "d": [85,756], "a": 1 }, 148 | { "px": [144,88], "src": [80,32], "f": 0, "t": 58, "d": [84,370], "a": 1 }, 149 | { "px": [152,88], "src": [64,32], "f": 0, "t": 56, "d": [84,371], "a": 1 }, 150 | { "px": [160,88], "src": [80,32], "f": 0, "t": 58, "d": [84,372], "a": 1 }, 151 | { "px": [160,168], "src": [88,32], "f": 0, "t": 59, "d": [84,692], "a": 1 } 152 | ], 153 | "seed": 8276094, 154 | "overrideTilesetUid": null, 155 | "gridTiles": [], 156 | "entityInstances": [] 157 | }, 158 | { 159 | "__identifier": "EntityWithTag", 160 | "__type": "Entities", 161 | "__cWid": 16, 162 | "__cHei": 16, 163 | "__gridSize": 16, 164 | "__opacity": 1, 165 | "__pxTotalOffsetX": 0, 166 | "__pxTotalOffsetY": 0, 167 | "__tilesetDefUid": null, 168 | "__tilesetRelPath": null, 169 | "iid": "b4eeea40-b4d0-11ec-a74c-ab342815632c", 170 | "levelId": 88, 171 | "layerDefUid": 118, 172 | "pxOffsetX": 0, 173 | "pxOffsetY": 0, 174 | "visible": true, 175 | "optionalRules": [], 176 | "intGridCsv": [], 177 | "autoLayerTiles": [], 178 | "seed": 1220562, 179 | "overrideTilesetUid": null, 180 | "gridTiles": [], 181 | "entityInstances": [] 182 | }, 183 | { 184 | "__identifier": "EntityTest", 185 | "__type": "Entities", 186 | "__cWid": 16, 187 | "__cHei": 16, 188 | "__gridSize": 16, 189 | "__opacity": 1, 190 | "__pxTotalOffsetX": 8, 191 | "__pxTotalOffsetY": 8, 192 | "__tilesetDefUid": null, 193 | "__tilesetRelPath": null, 194 | "iid": "2737e7b0-66b0-11ec-8446-8d36042559a5", 195 | "levelId": 88, 196 | "layerDefUid": 4, 197 | "pxOffsetX": 8, 198 | "pxOffsetY": 8, 199 | "visible": true, 200 | "optionalRules": [], 201 | "intGridCsv": [], 202 | "autoLayerTiles": [], 203 | "seed": 9962612, 204 | "overrideTilesetUid": null, 205 | "gridTiles": [], 206 | "entityInstances": [ 207 | { 208 | "__identifier": "OffsetTest", 209 | "__grid": [0,0], 210 | "__pivot": [0,0], 211 | "__tags": [], 212 | "__tile": null, 213 | "__smartColor": "#FF00C8", 214 | "iid": "f2f66841-66b0-11ec-91ab-554b0e889009", 215 | "width": 16, 216 | "height": 16, 217 | "defUid": 89, 218 | "px": [0,0], 219 | "fieldInstances": [], 220 | "__worldX": 512, 221 | "__worldY": 256 222 | } 223 | ] 224 | }, 225 | { 226 | "__identifier": "TileTest", 227 | "__type": "Tiles", 228 | "__cWid": 8, 229 | "__cHei": 8, 230 | "__gridSize": 32, 231 | "__opacity": 1, 232 | "__pxTotalOffsetX": 8, 233 | "__pxTotalOffsetY": 8, 234 | "__tilesetDefUid": 14, 235 | "__tilesetRelPath": "Minecraft_texture_pack.gif", 236 | "iid": "2737e7b1-66b0-11ec-8446-3f9ba678aab8", 237 | "levelId": 88, 238 | "layerDefUid": 15, 239 | "pxOffsetX": 8, 240 | "pxOffsetY": 8, 241 | "visible": true, 242 | "optionalRules": [], 243 | "intGridCsv": [], 244 | "autoLayerTiles": [], 245 | "seed": 1968104, 246 | "overrideTilesetUid": null, 247 | "gridTiles": [], 248 | "entityInstances": [] 249 | }, 250 | { 251 | "__identifier": "IntGridTest", 252 | "__type": "IntGrid", 253 | "__cWid": 16, 254 | "__cHei": 16, 255 | "__gridSize": 16, 256 | "__opacity": 0.62, 257 | "__pxTotalOffsetX": 8, 258 | "__pxTotalOffsetY": 8, 259 | "__tilesetDefUid": null, 260 | "__tilesetRelPath": null, 261 | "iid": "2737e7b2-66b0-11ec-8446-dfadd425d977", 262 | "levelId": 88, 263 | "layerDefUid": 13, 264 | "pxOffsetX": 8, 265 | "pxOffsetY": 8, 266 | "visible": true, 267 | "optionalRules": [], 268 | "intGridCsv": [ 269 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 270 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 271 | 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, 272 | 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, 273 | 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, 274 | 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, 275 | 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, 276 | 0,0,0,0,0,0,0,0,0,0,0 277 | ], 278 | "autoLayerTiles": [], 279 | "seed": 5650967, 280 | "overrideTilesetUid": null, 281 | "gridTiles": [], 282 | "entityInstances": [] 283 | }, 284 | { 285 | "__identifier": "IntGrid8", 286 | "__type": "IntGrid", 287 | "__cWid": 32, 288 | "__cHei": 32, 289 | "__gridSize": 8, 290 | "__opacity": 1, 291 | "__pxTotalOffsetX": 4, 292 | "__pxTotalOffsetY": 4, 293 | "__tilesetDefUid": null, 294 | "__tilesetRelPath": null, 295 | "iid": "2737e7b3-66b0-11ec-8446-51880ef2561a", 296 | "levelId": 88, 297 | "layerDefUid": 87, 298 | "pxOffsetX": 0, 299 | "pxOffsetY": 0, 300 | "visible": true, 301 | "optionalRules": [], 302 | "intGridCsv": [ 303 | 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, 304 | 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, 305 | 1,0,0,0,0,0,1,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, 306 | 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, 307 | 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, 308 | 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, 309 | 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, 310 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 311 | 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, 312 | 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, 313 | 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, 314 | 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, 315 | 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, 316 | 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, 317 | 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, 318 | 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, 319 | 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, 320 | 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, 321 | 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, 322 | 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, 323 | 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, 324 | 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, 325 | 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, 326 | 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, 327 | 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, 328 | 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, 329 | 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, 330 | 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, 331 | 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, 332 | 0,0,0,0,0,0,0,0,0 333 | ], 334 | "autoLayerTiles": [], 335 | "seed": 9897278, 336 | "overrideTilesetUid": null, 337 | "gridTiles": [], 338 | "entityInstances": [] 339 | } 340 | ], 341 | "__neighbours": [ { "levelIid": "f2f3d030-66b0-11ec-91ab-fd4b3030ab4e", "dir": "w" }, { "levelIid": "bdabeb40-66b0-11ec-88f3-5d5bfa64cc93", "dir": "n" } ] 342 | } -------------------------------------------------------------------------------- /samples/_assets/unitTest/Target_level_ref.ldtkl: -------------------------------------------------------------------------------- 1 | { 2 | "__header__": { 3 | "fileType": "LDtk Project JSON", 4 | "app": "LDtk", 5 | "doc": "https://ldtk.io/json", 6 | "schema": "https://ldtk.io/files/JSON_SCHEMA.json", 7 | "appAuthor": "Sebastien 'deepnight' Benard", 8 | "appVersion": "1.5.3", 9 | "url": "https://ldtk.io" 10 | }, 11 | "identifier": "Target_level_ref", 12 | "iid": "bdabeb40-66b0-11ec-88f3-5d5bfa64cc93", 13 | "uid": 109, 14 | "worldX": 512, 15 | "worldY": 0, 16 | "worldDepth": 0, 17 | "pxWid": 256, 18 | "pxHei": 256, 19 | "__bgColor": "#7F8093", 20 | "bgColor": null, 21 | "useAutoIdentifier": false, 22 | "bgRelPath": null, 23 | "bgPos": null, 24 | "bgPivotX": 0.5, 25 | "bgPivotY": 0.5, 26 | "__smartColor": "#B9B9C4", 27 | "__bgPos": null, 28 | "externalRelPath": null, 29 | "fieldInstances": [ 30 | { "__identifier": "level_int", "__type": "Int", "__value": 0, "__tile": null, "defUid": 93, "realEditorValues": [] }, 31 | { "__identifier": "level_string", "__type": "String", "__value": "", "__tile": null, "defUid": 94, "realEditorValues": [] }, 32 | { "__identifier": "level_reward", "__type": "ExternEnum.DroppedItemType", "__value": "Ammo", "__tile": null, "defUid": 95, "realEditorValues": [{ 33 | "id": "V_String", 34 | "params": ["Ammo"] 35 | }] }, 36 | { "__identifier": "lowercase_enum", "__type": "Array", "__value": [], "__tile": null, "defUid": 106, "realEditorValues": [] } 37 | ], 38 | "layerInstances": [ 39 | { 40 | "__identifier": "IntGrid_AutoLayer", 41 | "__type": "IntGrid", 42 | "__cWid": 32, 43 | "__cHei": 32, 44 | "__gridSize": 8, 45 | "__opacity": 1, 46 | "__pxTotalOffsetX": 0, 47 | "__pxTotalOffsetY": 0, 48 | "__tilesetDefUid": 46, 49 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 50 | "iid": "bdabeb41-66b0-11ec-88f3-b9a751052e5d", 51 | "levelId": 109, 52 | "layerDefUid": 41, 53 | "pxOffsetX": 0, 54 | "pxOffsetY": 0, 55 | "visible": true, 56 | "optionalRules": [], 57 | "intGridCsv": [ 58 | 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, 59 | 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, 60 | 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, 61 | 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, 62 | 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, 63 | 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, 64 | 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, 65 | 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, 66 | 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, 67 | 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, 68 | 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, 69 | 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, 70 | 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, 71 | 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, 72 | 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, 73 | 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, 74 | 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, 75 | 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, 76 | 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, 77 | 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, 78 | 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, 79 | 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, 80 | 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, 81 | 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, 82 | 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, 83 | 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, 84 | 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, 85 | 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, 86 | 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, 87 | 0,0,0,0,0,0,0,0,0 88 | ], 89 | "autoLayerTiles": [], 90 | "seed": 3402616, 91 | "overrideTilesetUid": null, 92 | "gridTiles": [], 93 | "entityInstances": [] 94 | }, 95 | { 96 | "__identifier": "Pure_AutoLayer", 97 | "__type": "AutoLayer", 98 | "__cWid": 32, 99 | "__cHei": 32, 100 | "__gridSize": 8, 101 | "__opacity": 1, 102 | "__pxTotalOffsetX": 0, 103 | "__pxTotalOffsetY": 0, 104 | "__tilesetDefUid": 46, 105 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 106 | "iid": "bdabeb42-66b0-11ec-88f3-870d6a0bd606", 107 | "levelId": 109, 108 | "layerDefUid": 82, 109 | "pxOffsetX": 0, 110 | "pxOffsetY": 0, 111 | "visible": true, 112 | "optionalRules": [], 113 | "intGridCsv": [], 114 | "autoLayerTiles": [], 115 | "seed": 9463295, 116 | "overrideTilesetUid": null, 117 | "gridTiles": [], 118 | "entityInstances": [] 119 | }, 120 | { 121 | "__identifier": "EntityWithTag", 122 | "__type": "Entities", 123 | "__cWid": 16, 124 | "__cHei": 16, 125 | "__gridSize": 16, 126 | "__opacity": 1, 127 | "__pxTotalOffsetX": 0, 128 | "__pxTotalOffsetY": 0, 129 | "__tilesetDefUid": null, 130 | "__tilesetRelPath": null, 131 | "iid": "b4ef5f70-b4d0-11ec-a74c-d36276c61819", 132 | "levelId": 109, 133 | "layerDefUid": 118, 134 | "pxOffsetX": 0, 135 | "pxOffsetY": 0, 136 | "visible": true, 137 | "optionalRules": [], 138 | "intGridCsv": [], 139 | "autoLayerTiles": [], 140 | "seed": 7874079, 141 | "overrideTilesetUid": null, 142 | "gridTiles": [], 143 | "entityInstances": [] 144 | }, 145 | { 146 | "__identifier": "EntityTest", 147 | "__type": "Entities", 148 | "__cWid": 16, 149 | "__cHei": 16, 150 | "__gridSize": 16, 151 | "__opacity": 1, 152 | "__pxTotalOffsetX": 0, 153 | "__pxTotalOffsetY": 0, 154 | "__tilesetDefUid": null, 155 | "__tilesetRelPath": null, 156 | "iid": "bdabeb43-66b0-11ec-88f3-f17ff25d77e6", 157 | "levelId": 109, 158 | "layerDefUid": 4, 159 | "pxOffsetX": 0, 160 | "pxOffsetY": 0, 161 | "visible": true, 162 | "optionalRules": [], 163 | "intGridCsv": [], 164 | "autoLayerTiles": [], 165 | "seed": 7619210, 166 | "overrideTilesetUid": null, 167 | "gridTiles": [], 168 | "entityInstances": [ 169 | { 170 | "__identifier": "SymRef", 171 | "__grid": [7,7], 172 | "__pivot": [0,0], 173 | "__tags": [], 174 | "__tile": null, 175 | "__smartColor": "#FF6700", 176 | "iid": "be92c8d0-66b0-11ec-88f3-df87634ca4af", 177 | "width": 16, 178 | "height": 16, 179 | "defUid": 107, 180 | "px": [112,112], 181 | "fieldInstances": [{ "__identifier": "ref", "__type": "EntityRef", "__value": { 182 | "entityIid": "bcf852b0-66b0-11ec-88f3-f1c676c28598", 183 | "layerIid": "27359dc1-66b0-11ec-8446-ff4b9136ca03", 184 | "levelIid": "f2f3d030-66b0-11ec-91ab-fd4b3030ab4e", 185 | "worldIid": "9df6b3c0-c640-11ed-b633-f10db708ef70" 186 | }, "__tile": null, "defUid": 108, "realEditorValues": [{ 187 | "id": "V_String", 188 | "params": ["bcf852b0-66b0-11ec-88f3-f1c676c28598"] 189 | }] }], 190 | "__worldX": 624, 191 | "__worldY": 112 192 | } 193 | ] 194 | }, 195 | { 196 | "__identifier": "TileTest", 197 | "__type": "Tiles", 198 | "__cWid": 8, 199 | "__cHei": 8, 200 | "__gridSize": 32, 201 | "__opacity": 1, 202 | "__pxTotalOffsetX": 0, 203 | "__pxTotalOffsetY": 0, 204 | "__tilesetDefUid": 14, 205 | "__tilesetRelPath": "Minecraft_texture_pack.gif", 206 | "iid": "bdabeb44-66b0-11ec-88f3-e5d422c87149", 207 | "levelId": 109, 208 | "layerDefUid": 15, 209 | "pxOffsetX": 0, 210 | "pxOffsetY": 0, 211 | "visible": true, 212 | "optionalRules": [], 213 | "intGridCsv": [], 214 | "autoLayerTiles": [], 215 | "seed": 8025879, 216 | "overrideTilesetUid": null, 217 | "gridTiles": [], 218 | "entityInstances": [] 219 | }, 220 | { 221 | "__identifier": "IntGridTest", 222 | "__type": "IntGrid", 223 | "__cWid": 16, 224 | "__cHei": 16, 225 | "__gridSize": 16, 226 | "__opacity": 0.62, 227 | "__pxTotalOffsetX": 0, 228 | "__pxTotalOffsetY": 0, 229 | "__tilesetDefUid": null, 230 | "__tilesetRelPath": null, 231 | "iid": "bdabeb45-66b0-11ec-88f3-bb4e53d38c23", 232 | "levelId": 109, 233 | "layerDefUid": 13, 234 | "pxOffsetX": 0, 235 | "pxOffsetY": 0, 236 | "visible": true, 237 | "optionalRules": [], 238 | "intGridCsv": [ 239 | 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, 240 | 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, 241 | 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, 242 | 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, 243 | 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, 244 | 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, 245 | 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, 246 | 0,0,0,0,0,0,0,0,0,0,0 247 | ], 248 | "autoLayerTiles": [], 249 | "seed": 4729756, 250 | "overrideTilesetUid": null, 251 | "gridTiles": [], 252 | "entityInstances": [] 253 | }, 254 | { 255 | "__identifier": "IntGrid8", 256 | "__type": "IntGrid", 257 | "__cWid": 32, 258 | "__cHei": 32, 259 | "__gridSize": 8, 260 | "__opacity": 1, 261 | "__pxTotalOffsetX": 4, 262 | "__pxTotalOffsetY": 4, 263 | "__tilesetDefUid": null, 264 | "__tilesetRelPath": null, 265 | "iid": "bdabeb46-66b0-11ec-88f3-63b465c9499f", 266 | "levelId": 109, 267 | "layerDefUid": 87, 268 | "pxOffsetX": 0, 269 | "pxOffsetY": 0, 270 | "visible": true, 271 | "optionalRules": [], 272 | "intGridCsv": [ 273 | 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, 274 | 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, 275 | 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, 276 | 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, 277 | 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, 278 | 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, 279 | 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, 280 | 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, 281 | 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, 282 | 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, 283 | 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, 284 | 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, 285 | 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, 286 | 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, 287 | 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, 288 | 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, 289 | 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, 290 | 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, 291 | 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, 292 | 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, 293 | 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, 294 | 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, 295 | 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, 296 | 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, 297 | 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, 298 | 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, 299 | 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, 300 | 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, 301 | 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, 302 | 0,0,0,0,0,0,0,0,0 303 | ], 304 | "autoLayerTiles": [], 305 | "seed": 6195883, 306 | "overrideTilesetUid": null, 307 | "gridTiles": [], 308 | "entityInstances": [] 309 | } 310 | ], 311 | "__neighbours": [ { "levelIid": "f2f3d030-66b0-11ec-91ab-fd4b3030ab4e", "dir": "w" }, { "levelIid": "f2f66840-66b0-11ec-91ab-e506cb005a35", "dir": "s" } ] 312 | } -------------------------------------------------------------------------------- /samples/_assets/unitTest/World1_Level_3.ldtkl: -------------------------------------------------------------------------------- 1 | { 2 | "__header__": { 3 | "fileType": "LDtk Project JSON", 4 | "app": "LDtk", 5 | "doc": "https://ldtk.io/json", 6 | "schema": "https://ldtk.io/files/JSON_SCHEMA.json", 7 | "appAuthor": "Sebastien 'deepnight' Benard", 8 | "appVersion": "1.5.3", 9 | "url": "https://ldtk.io" 10 | }, 11 | "identifier": "World1_Level_3", 12 | "iid": "b1e31860-7820-11ed-b18d-6339f608f11d", 13 | "uid": 120, 14 | "worldX": 0, 15 | "worldY": 768, 16 | "worldDepth": 0, 17 | "pxWid": 256, 18 | "pxHei": 256, 19 | "__bgColor": "#7F8093", 20 | "bgColor": null, 21 | "useAutoIdentifier": true, 22 | "bgRelPath": null, 23 | "bgPos": null, 24 | "bgPivotX": 0.5, 25 | "bgPivotY": 0.5, 26 | "__smartColor": "#B9B9C4", 27 | "__bgPos": null, 28 | "externalRelPath": null, 29 | "fieldInstances": [ 30 | { "__identifier": "level_int", "__type": "Int", "__value": 0, "__tile": null, "defUid": 93, "realEditorValues": [] }, 31 | { "__identifier": "level_string", "__type": "String", "__value": "", "__tile": null, "defUid": 94, "realEditorValues": [] }, 32 | { "__identifier": "level_reward", "__type": "ExternEnum.DroppedItemType", "__value": null, "__tile": null, "defUid": 95, "realEditorValues": [] }, 33 | { "__identifier": "lowercase_enum", "__type": "Array", "__value": [], "__tile": null, "defUid": 106, "realEditorValues": [] } 34 | ], 35 | "layerInstances": [ 36 | { 37 | "__identifier": "IntGrid_AutoLayer", 38 | "__type": "IntGrid", 39 | "__cWid": 32, 40 | "__cHei": 32, 41 | "__gridSize": 8, 42 | "__opacity": 1, 43 | "__pxTotalOffsetX": 0, 44 | "__pxTotalOffsetY": 0, 45 | "__tilesetDefUid": 46, 46 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 47 | "iid": "b1e33f70-7820-11ed-b18d-e705c345d973", 48 | "levelId": 120, 49 | "layerDefUid": 41, 50 | "pxOffsetX": 0, 51 | "pxOffsetY": 0, 52 | "visible": true, 53 | "optionalRules": [], 54 | "intGridCsv": [ 55 | 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, 56 | 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, 57 | 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, 58 | 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, 59 | 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, 60 | 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, 61 | 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, 62 | 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, 63 | 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, 64 | 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, 65 | 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, 66 | 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, 67 | 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, 68 | 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, 69 | 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, 70 | 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, 71 | 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, 72 | 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, 73 | 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, 74 | 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, 75 | 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, 76 | 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, 77 | 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, 78 | 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, 79 | 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, 80 | 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, 81 | 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, 82 | 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, 83 | 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, 84 | 0,0,0,0,0,0,0,0,0 85 | ], 86 | "autoLayerTiles": [], 87 | "seed": 7573409, 88 | "overrideTilesetUid": null, 89 | "gridTiles": [], 90 | "entityInstances": [] 91 | }, 92 | { 93 | "__identifier": "Pure_AutoLayer", 94 | "__type": "AutoLayer", 95 | "__cWid": 32, 96 | "__cHei": 32, 97 | "__gridSize": 8, 98 | "__opacity": 1, 99 | "__pxTotalOffsetX": 0, 100 | "__pxTotalOffsetY": 0, 101 | "__tilesetDefUid": 46, 102 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 103 | "iid": "b1e33f71-7820-11ed-b18d-6b1e8f1612eb", 104 | "levelId": 120, 105 | "layerDefUid": 82, 106 | "pxOffsetX": 0, 107 | "pxOffsetY": 0, 108 | "visible": true, 109 | "optionalRules": [], 110 | "intGridCsv": [], 111 | "autoLayerTiles": [], 112 | "seed": 1804637, 113 | "overrideTilesetUid": null, 114 | "gridTiles": [], 115 | "entityInstances": [] 116 | }, 117 | { 118 | "__identifier": "EntityWithTag", 119 | "__type": "Entities", 120 | "__cWid": 16, 121 | "__cHei": 16, 122 | "__gridSize": 16, 123 | "__opacity": 1, 124 | "__pxTotalOffsetX": 0, 125 | "__pxTotalOffsetY": 0, 126 | "__tilesetDefUid": null, 127 | "__tilesetRelPath": null, 128 | "iid": "b1e33f72-7820-11ed-b18d-b79666e3e725", 129 | "levelId": 120, 130 | "layerDefUid": 118, 131 | "pxOffsetX": 0, 132 | "pxOffsetY": 0, 133 | "visible": true, 134 | "optionalRules": [], 135 | "intGridCsv": [], 136 | "autoLayerTiles": [], 137 | "seed": 5544938, 138 | "overrideTilesetUid": null, 139 | "gridTiles": [], 140 | "entityInstances": [] 141 | }, 142 | { 143 | "__identifier": "EntityTest", 144 | "__type": "Entities", 145 | "__cWid": 16, 146 | "__cHei": 16, 147 | "__gridSize": 16, 148 | "__opacity": 1, 149 | "__pxTotalOffsetX": 0, 150 | "__pxTotalOffsetY": 0, 151 | "__tilesetDefUid": null, 152 | "__tilesetRelPath": null, 153 | "iid": "b1e33f73-7820-11ed-b18d-c3f6df89dcec", 154 | "levelId": 120, 155 | "layerDefUid": 4, 156 | "pxOffsetX": 0, 157 | "pxOffsetY": 0, 158 | "visible": true, 159 | "optionalRules": [], 160 | "intGridCsv": [], 161 | "autoLayerTiles": [], 162 | "seed": 2307796, 163 | "overrideTilesetUid": null, 164 | "gridTiles": [], 165 | "entityInstances": [ 166 | { 167 | "__identifier": "Hero", 168 | "__grid": [1,2], 169 | "__pivot": [0.5,1], 170 | "__tags": [], 171 | "__tile": null, 172 | "__smartColor": "#BAF236", 173 | "iid": "bee74f40-7820-11ed-b18d-b5db23763aff", 174 | "width": 16, 175 | "height": 24, 176 | "defUid": 23, 177 | "px": [24,48], 178 | "fieldInstances": [{ "__identifier": "startWeapon", "__type": "LocalEnum.Weapons", "__value": "Grenade", "__tile": null, "defUid": 39, "realEditorValues": [{ 179 | "id": "V_String", 180 | "params": ["Grenade"] 181 | }] }], 182 | "__worldX": 24, 183 | "__worldY": 816 184 | } 185 | ] 186 | }, 187 | { 188 | "__identifier": "TileTest", 189 | "__type": "Tiles", 190 | "__cWid": 8, 191 | "__cHei": 8, 192 | "__gridSize": 32, 193 | "__opacity": 1, 194 | "__pxTotalOffsetX": 0, 195 | "__pxTotalOffsetY": 0, 196 | "__tilesetDefUid": 14, 197 | "__tilesetRelPath": "Minecraft_texture_pack.gif", 198 | "iid": "b1e33f74-7820-11ed-b18d-a93114fcbf75", 199 | "levelId": 120, 200 | "layerDefUid": 15, 201 | "pxOffsetX": 0, 202 | "pxOffsetY": 0, 203 | "visible": true, 204 | "optionalRules": [], 205 | "intGridCsv": [], 206 | "autoLayerTiles": [], 207 | "seed": 7003341, 208 | "overrideTilesetUid": null, 209 | "gridTiles": [], 210 | "entityInstances": [] 211 | }, 212 | { 213 | "__identifier": "IntGridTest", 214 | "__type": "IntGrid", 215 | "__cWid": 16, 216 | "__cHei": 16, 217 | "__gridSize": 16, 218 | "__opacity": 0.62, 219 | "__pxTotalOffsetX": 0, 220 | "__pxTotalOffsetY": 0, 221 | "__tilesetDefUid": null, 222 | "__tilesetRelPath": null, 223 | "iid": "b1e33f75-7820-11ed-b18d-6792610805ca", 224 | "levelId": 120, 225 | "layerDefUid": 13, 226 | "pxOffsetX": 0, 227 | "pxOffsetY": 0, 228 | "visible": true, 229 | "optionalRules": [], 230 | "intGridCsv": [ 231 | 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, 232 | 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, 233 | 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, 234 | 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, 235 | 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, 236 | 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, 237 | 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, 238 | 0,0,0,0,0,0,0,0,0,0,0 239 | ], 240 | "autoLayerTiles": [], 241 | "seed": 3817194, 242 | "overrideTilesetUid": null, 243 | "gridTiles": [], 244 | "entityInstances": [] 245 | }, 246 | { 247 | "__identifier": "IntGrid8", 248 | "__type": "IntGrid", 249 | "__cWid": 32, 250 | "__cHei": 32, 251 | "__gridSize": 8, 252 | "__opacity": 1, 253 | "__pxTotalOffsetX": 4, 254 | "__pxTotalOffsetY": 4, 255 | "__tilesetDefUid": null, 256 | "__tilesetRelPath": null, 257 | "iid": "b1e33f76-7820-11ed-b18d-33642a8a18c6", 258 | "levelId": 120, 259 | "layerDefUid": 87, 260 | "pxOffsetX": 0, 261 | "pxOffsetY": 0, 262 | "visible": true, 263 | "optionalRules": [], 264 | "intGridCsv": [ 265 | 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, 266 | 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, 267 | 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, 268 | 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, 269 | 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, 270 | 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, 271 | 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, 272 | 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, 273 | 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, 274 | 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, 275 | 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, 276 | 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, 277 | 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, 278 | 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, 279 | 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, 280 | 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, 281 | 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, 282 | 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, 283 | 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, 284 | 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, 285 | 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, 286 | 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, 287 | 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, 288 | 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, 289 | 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, 290 | 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, 291 | 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, 292 | 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, 293 | 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, 294 | 0,0,0,0,0,0,0,0,0 295 | ], 296 | "autoLayerTiles": [], 297 | "seed": 4152312, 298 | "overrideTilesetUid": null, 299 | "gridTiles": [], 300 | "entityInstances": [] 301 | } 302 | ], 303 | "__neighbours": [] 304 | } -------------------------------------------------------------------------------- /samples/_assets/unitTest/World2_Level_0.ldtkl: -------------------------------------------------------------------------------- 1 | { 2 | "__header__": { 3 | "fileType": "LDtk Project JSON", 4 | "app": "LDtk", 5 | "doc": "https://ldtk.io/json", 6 | "schema": "https://ldtk.io/files/JSON_SCHEMA.json", 7 | "appAuthor": "Sebastien 'deepnight' Benard", 8 | "appVersion": "1.5.3", 9 | "url": "https://ldtk.io" 10 | }, 11 | "identifier": "World2_Level_0", 12 | "iid": "746c2ab0-c640-11ed-ad34-b9f1e407c5b4", 13 | "uid": 121, 14 | "worldX": 0, 15 | "worldY": 0, 16 | "worldDepth": 0, 17 | "pxWid": 256, 18 | "pxHei": 256, 19 | "__bgColor": "#7F8093", 20 | "bgColor": null, 21 | "useAutoIdentifier": true, 22 | "bgRelPath": null, 23 | "bgPos": null, 24 | "bgPivotX": 0.5, 25 | "bgPivotY": 0.5, 26 | "__smartColor": "#B9B9C4", 27 | "__bgPos": null, 28 | "externalRelPath": null, 29 | "fieldInstances": [ 30 | { "__identifier": "level_int", "__type": "Int", "__value": 0, "__tile": null, "defUid": 93, "realEditorValues": [] }, 31 | { "__identifier": "level_string", "__type": "String", "__value": "", "__tile": null, "defUid": 94, "realEditorValues": [] }, 32 | { "__identifier": "level_reward", "__type": "ExternEnum.DroppedItemType", "__value": null, "__tile": null, "defUid": 95, "realEditorValues": [] }, 33 | { "__identifier": "lowercase_enum", "__type": "Array", "__value": [], "__tile": null, "defUid": 106, "realEditorValues": [] } 34 | ], 35 | "layerInstances": [ 36 | { 37 | "__identifier": "IntGrid_AutoLayer", 38 | "__type": "IntGrid", 39 | "__cWid": 32, 40 | "__cHei": 32, 41 | "__gridSize": 8, 42 | "__opacity": 1, 43 | "__pxTotalOffsetX": 0, 44 | "__pxTotalOffsetY": 0, 45 | "__tilesetDefUid": 46, 46 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 47 | "iid": "746c2ab1-c640-11ed-ad34-fb2471a87c8b", 48 | "levelId": 121, 49 | "layerDefUid": 41, 50 | "pxOffsetX": 0, 51 | "pxOffsetY": 0, 52 | "visible": true, 53 | "optionalRules": [], 54 | "intGridCsv": [ 55 | 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, 56 | 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, 57 | 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, 58 | 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, 59 | 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, 60 | 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, 61 | 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, 62 | 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, 63 | 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, 64 | 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, 65 | 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, 66 | 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, 67 | 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, 68 | 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, 69 | 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, 70 | 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, 71 | 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, 72 | 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, 73 | 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, 74 | 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, 75 | 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, 76 | 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, 77 | 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, 78 | 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, 79 | 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, 80 | 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, 81 | 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, 82 | 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, 83 | 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, 84 | 0,0,0,0,0,0,0,0,0 85 | ], 86 | "autoLayerTiles": [], 87 | "seed": 9488732, 88 | "overrideTilesetUid": null, 89 | "gridTiles": [], 90 | "entityInstances": [] 91 | }, 92 | { 93 | "__identifier": "Pure_AutoLayer", 94 | "__type": "AutoLayer", 95 | "__cWid": 32, 96 | "__cHei": 32, 97 | "__gridSize": 8, 98 | "__opacity": 1, 99 | "__pxTotalOffsetX": 0, 100 | "__pxTotalOffsetY": 0, 101 | "__tilesetDefUid": 46, 102 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 103 | "iid": "746c2ab2-c640-11ed-ad34-c1e8f59038fd", 104 | "levelId": 121, 105 | "layerDefUid": 82, 106 | "pxOffsetX": 0, 107 | "pxOffsetY": 0, 108 | "visible": true, 109 | "optionalRules": [], 110 | "intGridCsv": [], 111 | "autoLayerTiles": [], 112 | "seed": 2752519, 113 | "overrideTilesetUid": null, 114 | "gridTiles": [], 115 | "entityInstances": [] 116 | }, 117 | { 118 | "__identifier": "EntityWithTag", 119 | "__type": "Entities", 120 | "__cWid": 16, 121 | "__cHei": 16, 122 | "__gridSize": 16, 123 | "__opacity": 1, 124 | "__pxTotalOffsetX": 0, 125 | "__pxTotalOffsetY": 0, 126 | "__tilesetDefUid": null, 127 | "__tilesetRelPath": null, 128 | "iid": "746c2ab3-c640-11ed-ad34-bbe9b1181dc1", 129 | "levelId": 121, 130 | "layerDefUid": 118, 131 | "pxOffsetX": 0, 132 | "pxOffsetY": 0, 133 | "visible": true, 134 | "optionalRules": [], 135 | "intGridCsv": [], 136 | "autoLayerTiles": [], 137 | "seed": 3039604, 138 | "overrideTilesetUid": null, 139 | "gridTiles": [], 140 | "entityInstances": [] 141 | }, 142 | { 143 | "__identifier": "EntityTest", 144 | "__type": "Entities", 145 | "__cWid": 16, 146 | "__cHei": 16, 147 | "__gridSize": 16, 148 | "__opacity": 1, 149 | "__pxTotalOffsetX": 0, 150 | "__pxTotalOffsetY": 0, 151 | "__tilesetDefUid": null, 152 | "__tilesetRelPath": null, 153 | "iid": "746c2ab4-c640-11ed-ad34-594e17ac196c", 154 | "levelId": 121, 155 | "layerDefUid": 4, 156 | "pxOffsetX": 0, 157 | "pxOffsetY": 0, 158 | "visible": true, 159 | "optionalRules": [], 160 | "intGridCsv": [], 161 | "autoLayerTiles": [], 162 | "seed": 486717, 163 | "overrideTilesetUid": null, 164 | "gridTiles": [], 165 | "entityInstances": [] 166 | }, 167 | { 168 | "__identifier": "TileTest", 169 | "__type": "Tiles", 170 | "__cWid": 8, 171 | "__cHei": 8, 172 | "__gridSize": 32, 173 | "__opacity": 1, 174 | "__pxTotalOffsetX": 0, 175 | "__pxTotalOffsetY": 0, 176 | "__tilesetDefUid": 14, 177 | "__tilesetRelPath": "Minecraft_texture_pack.gif", 178 | "iid": "746c2ab5-c640-11ed-ad34-45684508f2a2", 179 | "levelId": 121, 180 | "layerDefUid": 15, 181 | "pxOffsetX": 0, 182 | "pxOffsetY": 0, 183 | "visible": true, 184 | "optionalRules": [], 185 | "intGridCsv": [], 186 | "autoLayerTiles": [], 187 | "seed": 2524189, 188 | "overrideTilesetUid": null, 189 | "gridTiles": [], 190 | "entityInstances": [] 191 | }, 192 | { 193 | "__identifier": "IntGridTest", 194 | "__type": "IntGrid", 195 | "__cWid": 16, 196 | "__cHei": 16, 197 | "__gridSize": 16, 198 | "__opacity": 0.62, 199 | "__pxTotalOffsetX": 0, 200 | "__pxTotalOffsetY": 0, 201 | "__tilesetDefUid": null, 202 | "__tilesetRelPath": null, 203 | "iid": "746c2ab6-c640-11ed-ad34-c9abfa814d11", 204 | "levelId": 121, 205 | "layerDefUid": 13, 206 | "pxOffsetX": 0, 207 | "pxOffsetY": 0, 208 | "visible": true, 209 | "optionalRules": [], 210 | "intGridCsv": [ 211 | 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, 212 | 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, 213 | 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, 214 | 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, 215 | 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, 216 | 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, 217 | 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, 218 | 0,0,0,0,0,0,0,0,0,0,0 219 | ], 220 | "autoLayerTiles": [], 221 | "seed": 9866733, 222 | "overrideTilesetUid": null, 223 | "gridTiles": [], 224 | "entityInstances": [] 225 | }, 226 | { 227 | "__identifier": "IntGrid8", 228 | "__type": "IntGrid", 229 | "__cWid": 32, 230 | "__cHei": 32, 231 | "__gridSize": 8, 232 | "__opacity": 1, 233 | "__pxTotalOffsetX": 4, 234 | "__pxTotalOffsetY": 4, 235 | "__tilesetDefUid": null, 236 | "__tilesetRelPath": null, 237 | "iid": "746c2ab7-c640-11ed-ad34-71cebfe841cc", 238 | "levelId": 121, 239 | "layerDefUid": 87, 240 | "pxOffsetX": 0, 241 | "pxOffsetY": 0, 242 | "visible": true, 243 | "optionalRules": [], 244 | "intGridCsv": [ 245 | 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, 246 | 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, 247 | 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, 248 | 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, 249 | 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, 250 | 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, 251 | 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, 252 | 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, 253 | 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, 254 | 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, 255 | 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, 256 | 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, 257 | 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, 258 | 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, 259 | 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, 260 | 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, 261 | 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, 262 | 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, 263 | 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, 264 | 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, 265 | 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, 266 | 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, 267 | 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, 268 | 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, 269 | 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, 270 | 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, 271 | 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, 272 | 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, 273 | 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, 274 | 0,0,0,0,0,0,0,0,0 275 | ], 276 | "autoLayerTiles": [], 277 | "seed": 1549651, 278 | "overrideTilesetUid": null, 279 | "gridTiles": [], 280 | "entityInstances": [] 281 | } 282 | ], 283 | "__neighbours": [] 284 | } -------------------------------------------------------------------------------- /samples/_assets/unitTest/v1_4_0.ldtkl: -------------------------------------------------------------------------------- 1 | { 2 | "__header__": { 3 | "fileType": "LDtk Project JSON", 4 | "app": "LDtk", 5 | "doc": "https://ldtk.io/json", 6 | "schema": "https://ldtk.io/files/JSON_SCHEMA.json", 7 | "appAuthor": "Sebastien 'deepnight' Benard", 8 | "appVersion": "1.5.3", 9 | "url": "https://ldtk.io" 10 | }, 11 | "identifier": "v1_4_0", 12 | "iid": "fdf5dd10-3b70-11ee-a4c1-2d98aa7c2075", 13 | "uid": 122, 14 | "worldX": 0, 15 | "worldY": 1280, 16 | "worldDepth": 0, 17 | "pxWid": 256, 18 | "pxHei": 256, 19 | "__bgColor": "#7F8093", 20 | "bgColor": null, 21 | "useAutoIdentifier": false, 22 | "bgRelPath": null, 23 | "bgPos": null, 24 | "bgPivotX": 0.5, 25 | "bgPivotY": 0.5, 26 | "__smartColor": "#B9B9C4", 27 | "__bgPos": null, 28 | "externalRelPath": null, 29 | "fieldInstances": [ 30 | { "__identifier": "level_int", "__type": "Int", "__value": 0, "__tile": null, "defUid": 93, "realEditorValues": [] }, 31 | { "__identifier": "level_string", "__type": "String", "__value": "", "__tile": null, "defUid": 94, "realEditorValues": [] }, 32 | { "__identifier": "level_reward", "__type": "ExternEnum.DroppedItemType", "__value": null, "__tile": null, "defUid": 95, "realEditorValues": [] }, 33 | { "__identifier": "lowercase_enum", "__type": "Array", "__value": [], "__tile": null, "defUid": 106, "realEditorValues": [] } 34 | ], 35 | "layerInstances": [ 36 | { 37 | "__identifier": "IntGrid_AutoLayer", 38 | "__type": "IntGrid", 39 | "__cWid": 32, 40 | "__cHei": 32, 41 | "__gridSize": 8, 42 | "__opacity": 1, 43 | "__pxTotalOffsetX": 0, 44 | "__pxTotalOffsetY": 0, 45 | "__tilesetDefUid": 46, 46 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 47 | "iid": "fdf5dd11-3b70-11ee-a4c1-6b9ec23ac76b", 48 | "levelId": 122, 49 | "layerDefUid": 41, 50 | "pxOffsetX": 0, 51 | "pxOffsetY": 0, 52 | "visible": true, 53 | "optionalRules": [], 54 | "intGridCsv": [ 55 | 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, 56 | 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, 57 | 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, 58 | 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, 59 | 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, 60 | 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, 61 | 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, 62 | 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, 63 | 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, 64 | 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, 65 | 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, 66 | 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, 67 | 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, 68 | 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, 69 | 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, 70 | 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, 71 | 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, 72 | 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, 73 | 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, 74 | 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, 75 | 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, 76 | 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, 77 | 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, 78 | 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, 79 | 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, 80 | 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, 81 | 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, 82 | 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, 83 | 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, 84 | 0,0,0,0,0,0,0,0,0 85 | ], 86 | "autoLayerTiles": [], 87 | "seed": 1878600, 88 | "overrideTilesetUid": null, 89 | "gridTiles": [], 90 | "entityInstances": [] 91 | }, 92 | { 93 | "__identifier": "Pure_AutoLayer", 94 | "__type": "AutoLayer", 95 | "__cWid": 32, 96 | "__cHei": 32, 97 | "__gridSize": 8, 98 | "__opacity": 1, 99 | "__pxTotalOffsetX": 0, 100 | "__pxTotalOffsetY": 0, 101 | "__tilesetDefUid": 46, 102 | "__tilesetRelPath": "Cavernas_by_Adam_Saltsman-Extended.png", 103 | "iid": "fdf5dd12-3b70-11ee-a4c1-2775e4f1138a", 104 | "levelId": 122, 105 | "layerDefUid": 82, 106 | "pxOffsetX": 0, 107 | "pxOffsetY": 0, 108 | "visible": true, 109 | "optionalRules": [], 110 | "intGridCsv": [], 111 | "autoLayerTiles": [], 112 | "seed": 9183880, 113 | "overrideTilesetUid": null, 114 | "gridTiles": [], 115 | "entityInstances": [] 116 | }, 117 | { 118 | "__identifier": "EntityWithTag", 119 | "__type": "Entities", 120 | "__cWid": 16, 121 | "__cHei": 16, 122 | "__gridSize": 16, 123 | "__opacity": 1, 124 | "__pxTotalOffsetX": 0, 125 | "__pxTotalOffsetY": 0, 126 | "__tilesetDefUid": null, 127 | "__tilesetRelPath": null, 128 | "iid": "fdf60420-3b70-11ee-a4c1-87adcca9456d", 129 | "levelId": 122, 130 | "layerDefUid": 118, 131 | "pxOffsetX": 0, 132 | "pxOffsetY": 0, 133 | "visible": true, 134 | "optionalRules": [], 135 | "intGridCsv": [], 136 | "autoLayerTiles": [], 137 | "seed": 7863463, 138 | "overrideTilesetUid": null, 139 | "gridTiles": [], 140 | "entityInstances": [] 141 | }, 142 | { 143 | "__identifier": "EntityTest", 144 | "__type": "Entities", 145 | "__cWid": 16, 146 | "__cHei": 16, 147 | "__gridSize": 16, 148 | "__opacity": 1, 149 | "__pxTotalOffsetX": 0, 150 | "__pxTotalOffsetY": 0, 151 | "__tilesetDefUid": null, 152 | "__tilesetRelPath": null, 153 | "iid": "fdf60421-3b70-11ee-a4c1-5bde7a085fb6", 154 | "levelId": 122, 155 | "layerDefUid": 4, 156 | "pxOffsetX": 0, 157 | "pxOffsetY": 0, 158 | "visible": true, 159 | "optionalRules": [], 160 | "intGridCsv": [], 161 | "autoLayerTiles": [], 162 | "seed": 5042540, 163 | "overrideTilesetUid": null, 164 | "gridTiles": [], 165 | "entityInstances": [ 166 | { 167 | "__identifier": "Hero", 168 | "__grid": [2,5], 169 | "__pivot": [0.5,1], 170 | "__tags": [], 171 | "__tile": null, 172 | "__smartColor": "#BAF236", 173 | "iid": "0fa3ecf0-3b70-11ee-a4c1-b76253be54be", 174 | "width": 16, 175 | "height": 24, 176 | "defUid": 23, 177 | "px": [40,96], 178 | "fieldInstances": [{ "__identifier": "startWeapon", "__type": "LocalEnum.Weapons", "__value": "LongBow", "__tile": null, "defUid": 39, "realEditorValues": [{ 179 | "id": "V_String", 180 | "params": ["LongBow"] 181 | }] }], 182 | "__worldX": 40, 183 | "__worldY": 1376 184 | } 185 | ] 186 | }, 187 | { 188 | "__identifier": "TileTest", 189 | "__type": "Tiles", 190 | "__cWid": 8, 191 | "__cHei": 8, 192 | "__gridSize": 32, 193 | "__opacity": 1, 194 | "__pxTotalOffsetX": 0, 195 | "__pxTotalOffsetY": 0, 196 | "__tilesetDefUid": 14, 197 | "__tilesetRelPath": "Minecraft_texture_pack.gif", 198 | "iid": "fdf60422-3b70-11ee-a4c1-87ae3b51a044", 199 | "levelId": 122, 200 | "layerDefUid": 15, 201 | "pxOffsetX": 0, 202 | "pxOffsetY": 0, 203 | "visible": true, 204 | "optionalRules": [], 205 | "intGridCsv": [], 206 | "autoLayerTiles": [], 207 | "seed": 8933106, 208 | "overrideTilesetUid": null, 209 | "gridTiles": [], 210 | "entityInstances": [] 211 | }, 212 | { 213 | "__identifier": "IntGridTest", 214 | "__type": "IntGrid", 215 | "__cWid": 16, 216 | "__cHei": 16, 217 | "__gridSize": 16, 218 | "__opacity": 0.62, 219 | "__pxTotalOffsetX": 0, 220 | "__pxTotalOffsetY": 0, 221 | "__tilesetDefUid": null, 222 | "__tilesetRelPath": null, 223 | "iid": "fdf60423-3b70-11ee-a4c1-9538d0fb3cbb", 224 | "levelId": 122, 225 | "layerDefUid": 13, 226 | "pxOffsetX": 0, 227 | "pxOffsetY": 0, 228 | "visible": true, 229 | "optionalRules": [], 230 | "intGridCsv": [ 231 | 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, 232 | 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, 233 | 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, 234 | 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, 235 | 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, 236 | 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, 237 | 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, 238 | 0,0,0,0,0,0,0,0,0,0,0 239 | ], 240 | "autoLayerTiles": [], 241 | "seed": 6300247, 242 | "overrideTilesetUid": null, 243 | "gridTiles": [], 244 | "entityInstances": [] 245 | }, 246 | { 247 | "__identifier": "IntGrid8", 248 | "__type": "IntGrid", 249 | "__cWid": 32, 250 | "__cHei": 32, 251 | "__gridSize": 8, 252 | "__opacity": 1, 253 | "__pxTotalOffsetX": 4, 254 | "__pxTotalOffsetY": 4, 255 | "__tilesetDefUid": null, 256 | "__tilesetRelPath": null, 257 | "iid": "fdf60424-3b70-11ee-a4c1-492dd034147d", 258 | "levelId": 122, 259 | "layerDefUid": 87, 260 | "pxOffsetX": 0, 261 | "pxOffsetY": 0, 262 | "visible": true, 263 | "optionalRules": [], 264 | "intGridCsv": [ 265 | 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, 266 | 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, 267 | 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, 268 | 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, 269 | 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, 270 | 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, 271 | 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, 272 | 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, 273 | 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, 274 | 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, 275 | 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, 276 | 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, 277 | 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, 278 | 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, 279 | 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, 280 | 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, 281 | 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, 282 | 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, 283 | 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, 284 | 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, 285 | 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, 286 | 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, 287 | 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, 288 | 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, 289 | 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, 290 | 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, 291 | 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, 292 | 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, 293 | 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, 294 | 0,0,0,0,0,0,0,0,0 295 | ], 296 | "autoLayerTiles": [], 297 | "seed": 6555422, 298 | "overrideTilesetUid": null, 299 | "gridTiles": [], 300 | "entityInstances": [] 301 | } 302 | ], 303 | "__neighbours": [{ "levelIid": "b32d7710-3b70-11ee-a4c1-ada3a8497e3b", "dir": "<" }] 304 | } -------------------------------------------------------------------------------- /samples/_initSamples/README.md: -------------------------------------------------------------------------------- 1 | # NOTE 2 | 3 | This class is *not* a sample nor a demo: it only generates the HXML and HTML files of each sample. 4 | -------------------------------------------------------------------------------- /samples/_initSamples/SamplesInitializer.hx: -------------------------------------------------------------------------------- 1 | /** 2 | NOTE: this class is not a sample nor a demo: it only generates the HXML and HTML files of each sample. 3 | **/ 4 | 5 | class SamplesInitializer{ 6 | public static function run() { 7 | var baseDir = ".."; // no trailing "/" 8 | 9 | Sys.println(""); 10 | Sys.println('NOTE: please check the README for more infos.'); 11 | Sys.println(""); 12 | 13 | 14 | // List all sample HX files 15 | var hxFiles : Array = []; 16 | var allowedDirs = [ "Heaps -", "Generic -" ]; 17 | var pendingDirs = [ baseDir ]; 18 | while( pendingDirs.length>0 ) { 19 | var dir = pendingDirs.shift(); 20 | for(f in sys.FileSystem.readDirectory(dir)) { 21 | if( sys.FileSystem.isDirectory(dir+"/"+f) ) { 22 | for( allow in allowedDirs ) 23 | if( f.indexOf(allow)>=0 ) { 24 | pendingDirs.push(dir+"/"+f); 25 | break; 26 | } 27 | } 28 | else if( dir!=baseDir && f.indexOf(".hx")==f.length-3 ) 29 | hxFiles.push( dn.FilePath.fromFile(dir+"/"+f) ); 30 | } 31 | } 32 | 33 | 34 | var removeCmdRegEx = ~/--cmd (.*$)/gm; 35 | var allHxmls = []; 36 | var htmlToc = []; 37 | // var htmlToc = hxFiles.map( (fp)->{ 38 | // var name = fp.fileName; 39 | // return '
  • $name
  • '; 40 | // }); 41 | for(fp in hxFiles) { 42 | var name = fp.fileName; 43 | var dir = fp.directory; 44 | 45 | // Build HXML 46 | Sys.println('Creating $dir/build.hxml...'); 47 | var hxml = StringTools.replace(BASE_HXML, "%name%", name); 48 | hxml = StringTools.replace(hxml, "\t", ""); 49 | sys.io.File.saveContent('$dir/build.hxml', hxml ); 50 | 51 | // Build HTML 52 | Sys.println('Creating $dir/index.html...'); 53 | var html = StringTools.replace( BASE_HTML, "%name%", name ); 54 | html = StringTools.replace( html, "%toc%", htmlToc.join("") ); 55 | 56 | sys.io.File.saveContent('$dir/index.html', html ); 57 | allHxmls.push('$dir/build.hxml'); 58 | } 59 | 60 | // Create buildAll.hxml 61 | var allHxml = allHxmls.map( path->{ 62 | var fp = dn.FilePath.fromFile(path); 63 | fp.makeRelativeTo(baseDir); 64 | return ' 65 | --cwd "${fp.directory}" 66 | "${fp.fileWithExt}" 67 | --next 68 | --cwd .. 69 | '; 70 | } ).join("--next\n"); 71 | allHxml = StringTools.replace(allHxml, "\t", ""); 72 | sys.io.File.saveContent('$baseDir/buildAll.hxml', allHxml); 73 | 74 | Sys.println('Generated ${allHxmls.length} sample build files successfully.'); 75 | } 76 | 77 | public static function print(msg:String) { // Used in HXML macro calls 78 | Sys.println(""); 79 | Sys.println(msg); 80 | } 81 | 82 | 83 | 84 | 85 | static var BASE_HXML = " 86 | # %name% (Javascript/WebGL) 87 | -cp . 88 | -cp ../_srcCommon 89 | -cp ../../src 90 | -lib heaps 91 | -lib deepnightLibs 92 | -D resourcesPath=../_assets 93 | --dce full 94 | -main %name% 95 | -js _javascript.js 96 | 97 | # %name% (Hashlink) 98 | --next 99 | -cp . 100 | -cp ../_srcCommon 101 | -cp ../../src 102 | -lib heaps 103 | -lib deepnightLibs 104 | -D resourcesPath=../_assets 105 | -lib hlsdl 106 | --dce full 107 | -main %name% 108 | -hl _hashlink.hl 109 | "; 110 | 111 | 112 | static var BASE_HTML = ' 113 | 114 | 115 | 116 | 117 | %name% 118 | 161 | 162 | 163 |
      %toc%
    164 | 165 |
    Failed to load JS script! Please build it using the HXML file (run: haxe build.hxml).
    166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | '; 174 | } 175 | -------------------------------------------------------------------------------- /samples/_initSamples/initSamples.hxml: -------------------------------------------------------------------------------- 1 | -lib deepnightLibs 2 | --macro SamplesInitializer.run() 3 | --macro SamplesInitializer.print("Compiling all samples...") 4 | 5 | --next 6 | --cmd haxe --cwd .. buildAll.hxml 7 | 8 | --next 9 | -lib deepnightLibs 10 | --macro SamplesInitializer.print("Done!") -------------------------------------------------------------------------------- /samples/_srcCommon/ExternCastleDbTest.hx: -------------------------------------------------------------------------------- 1 | private typedef Init = haxe.macro.MacroType<[cdb.Module.build("sample.cdb")]>; 2 | -------------------------------------------------------------------------------- /samples/_srcCommon/ExternEnumTest.hx: -------------------------------------------------------------------------------- 1 | /** 2 | This enum file is imported in the LDtk project. 3 | It demonstrates the ability for LDtk to use external Enums as entity field values. 4 | **/ 5 | 6 | enum DroppedItemType { 7 | Food; 8 | Gold; 9 | Ammo; 10 | Key; 11 | // SomeNewObject; 12 | } 13 | 14 | enum SomeEnum { 15 | Foo; 16 | Bar; 17 | Pouet; 18 | } -------------------------------------------------------------------------------- /samples/_srcCommon/LdtkProject.hx: -------------------------------------------------------------------------------- 1 | /** 2 | This file will contain all the classes and types generated 3 | from the "sample.ldtk" project 4 | **/ 5 | 6 | private typedef _Tmp = haxe.macro.MacroType<[ 7 | ldtk.Project.build("../_assets/sample.ldtk") 8 | ]>; -------------------------------------------------------------------------------- /samples/buildAll.hxml: -------------------------------------------------------------------------------- 1 | 2 | --cwd "Generic - Read project" 3 | "build.hxml" 4 | --next 5 | --cwd .. 6 | --next 7 | 8 | --cwd "Heaps - Object tiles" 9 | "build.hxml" 10 | --next 11 | --cwd .. 12 | --next 13 | 14 | --cwd "Heaps - Render full world" 15 | "build.hxml" 16 | --next 17 | --cwd .. 18 | --next 19 | 20 | --cwd "Heaps - Render IntGrid layer" 21 | "build.hxml" 22 | --next 23 | --cwd .. 24 | --next 25 | 26 | --cwd "Heaps - Render tile layers" 27 | "build.hxml" 28 | --next 29 | --cwd .. 30 | -------------------------------------------------------------------------------- /src/ldtk/Entity.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | class Entity { 4 | var untypedProject : ldtk.Project; 5 | 6 | /** Original JSON object **/ 7 | public var json(default,null) : ldtk.Json.EntityInstanceJson; 8 | 9 | /** Original entity definition JSON object **/ 10 | public var defJson(default,null) : ldtk.Json.EntityDefJson; 11 | 12 | public var identifier : String; 13 | 14 | /** Unique instance identifier **/ 15 | public var iid : String; 16 | 17 | /** Grid-based X coordinate **/ 18 | public var cx : Int; 19 | 20 | /** Grid-based Y coordinate **/ 21 | public var cy : Int; 22 | 23 | /** Pixel-based X coordinate **/ 24 | public var pixelX : Int; 25 | 26 | /** Pixel-based Y coordinate **/ 27 | public var pixelY : Int; 28 | 29 | /** Pivot X coord (0-1) **/ 30 | public var pivotX : Float; 31 | 32 | /** Pivot Y coord (0-1) **/ 33 | public var pivotY : Float; 34 | 35 | /** Pixel-based X world coordinate **/ 36 | public var worldPixelX : Int; 37 | 38 | /** Pixel-based Y world coordinate **/ 39 | public var worldPixelY : Int; 40 | 41 | /** Width in pixels **/ 42 | public var width : Int; 43 | 44 | /** Height in pixels**/ 45 | public var height : Int; 46 | 47 | /** Tile infos if the entity has one (it could have be overridden by a Field value, such as Enums) **/ 48 | public var tileInfos : Null; 49 | 50 | var _fields : Map = new Map(); 51 | 52 | 53 | public function new(p:ldtk.Project, json:ldtk.Json.EntityInstanceJson) { 54 | untypedProject = p; 55 | this.json = json; 56 | this.defJson = p.getEntityDefJson(json.defUid); 57 | identifier = json.__identifier; 58 | iid = json.iid; 59 | cx = json.__grid[0]; 60 | cy = json.__grid[1]; 61 | pixelX = json.px[0]; 62 | pixelY = json.px[1]; 63 | pivotX = json.__pivot==null ? 0 : json.__pivot[0]; 64 | pivotY = json.__pivot==null ? 0 : json.__pivot[1]; 65 | worldPixelX = json.__worldX; 66 | worldPixelY = json.__worldY; 67 | width = json.width; 68 | height = json.height; 69 | 70 | tileInfos = json.__tile; 71 | 72 | p._assignFieldInstanceValues(this, json.fieldInstances); 73 | } 74 | 75 | 76 | #if heaps 77 | public function getTile() : Null { 78 | if( tileInfos==null ) 79 | return null; 80 | 81 | var tileset = untypedProject._untypedTilesets.get(tileInfos.tilesetUid); 82 | if( tileset==null ) 83 | return null; 84 | 85 | return tileset.getFreeTile(tileInfos.x, tileInfos.y, tileInfos.w, tileInfos.h); 86 | } 87 | #end 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/ldtk/Layer.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | import ldtk.Json; 4 | 5 | class Layer { 6 | var untypedProject: ldtk.Project; 7 | 8 | /** Original JSON object **/ 9 | public var json(default,null) : LayerInstanceJson; 10 | 11 | /** Original layer definition JSON object **/ 12 | public var defJson(default,null) : LayerDefJson; 13 | 14 | public var identifier : String; 15 | public var type : LayerType; 16 | 17 | /** Unique instance identifier **/ 18 | public var iid : String; 19 | 20 | /** Layer instance visibility **/ 21 | public var visible : Bool; 22 | 23 | /** Grid size in pixels **/ 24 | public var gridSize : Int; 25 | 26 | /** Grid-based layer width **/ 27 | public var cWid : Int; 28 | /** Grid-based layer height **/ 29 | public var cHei : Int; 30 | 31 | /** Pixel-based layer width **/ 32 | public var pxWid : Int; 33 | /** Pixel-based layer height **/ 34 | public var pxHei : Int; 35 | 36 | /** 37 | Pixel-based layer X offset (includes both instance and definition offsets) 38 | **/ 39 | public var pxTotalOffsetX: Int; 40 | 41 | /** 42 | Pixel-based layer Y offset (includes both instance and definition offsets) 43 | **/ 44 | public var pxTotalOffsetY : Int; 45 | 46 | /** Layer opacity (0-1) **/ 47 | public var opacity : Float; 48 | 49 | 50 | public function new(p:ldtk.Project, json:ldtk.Json.LayerInstanceJson) { 51 | this.json = json; 52 | this.defJson = p.getLayerDefJson(json.layerDefUid); 53 | untypedProject = p; 54 | identifier = json.__identifier; 55 | type = 56 | try LayerType.createByName(json.__type) 57 | catch(e:Dynamic) throw 'Unknown layer type ${json.__type} in $identifier'; 58 | iid = json.iid; 59 | gridSize = json.__gridSize; 60 | cWid = json.__cWid; 61 | cHei = json.__cHei; 62 | pxWid = cWid * json.__gridSize; 63 | pxHei = cHei * json.__gridSize; 64 | pxTotalOffsetX = json.__pxTotalOffsetX; 65 | pxTotalOffsetY = json.__pxTotalOffsetY; 66 | opacity = json.__opacity; 67 | visible = json.visible==true; 68 | } 69 | 70 | /** Print class debug info **/ 71 | @:keep public function toString() { 72 | return 'ldtk.Layer[#$identifier, type=$type]'; 73 | } 74 | 75 | 76 | /** 77 | Return TRUE if grid-based coordinates are within layer bounds. 78 | **/ 79 | public inline function isCoordValid(cx,cy) { 80 | return cx>=0 && cx=0 && cy no flipping, 1=> X flip, 2=> Y flip, 3=> X and Y flips **/ 15 | var flips: Int; 16 | 17 | /** Opacity (0-1)**/ 18 | var alpha: Float; 19 | 20 | /** ID of the auto-rule that generated this tile **/ 21 | var ruleId: Int; 22 | 23 | /** Coord ID of the auto-rule that generated this tile **/ 24 | var coordId: Int; 25 | } 26 | 27 | 28 | class Layer_AutoLayer extends ldtk.Layer { 29 | /** 30 | A single array containing all AutoLayer tiles informations, in "render" order 31 | **/ 32 | public var autoTiles : Array; 33 | 34 | 35 | /** Getter to layer untyped Tileset instance. The typed value is created in macro. **/ 36 | var untypedTileset(get,never) : ldtk.Tileset; 37 | inline function get_untypedTileset() return untypedProject._untypedTilesets.get(tilesetUid); 38 | 39 | /** Tileset UID **/ 40 | public var tilesetUid(default,null) : Int; 41 | 42 | 43 | public function new(p,json) { 44 | super(p,json); 45 | 46 | autoTiles = []; 47 | tilesetUid = json.__tilesetDefUid; 48 | 49 | for(jsonAutoTile in json.autoLayerTiles) 50 | autoTiles.push({ 51 | tileId: jsonAutoTile.t, 52 | flips: jsonAutoTile.f, 53 | alpha: jsonAutoTile.a, 54 | renderX: jsonAutoTile.px[0], 55 | renderY: jsonAutoTile.px[1], 56 | ruleId: jsonAutoTile.d[0], 57 | coordId: jsonAutoTile.d[1], 58 | }); 59 | } 60 | 61 | 62 | 63 | #if !macro 64 | 65 | #if heaps 66 | /** 67 | Render layer to a `h2d.TileGroup`. If `target` isn't provided, a new h2d.TileGroup is created. If `target` is provided, it **must** have the same tile source as the layer tileset! 68 | **/ 69 | public inline function render(?target:h2d.TileGroup) : h2d.TileGroup { 70 | if( target==null ) 71 | target = new h2d.TileGroup( untypedTileset.getAtlasTile() ); 72 | 73 | for( autoTile in autoTiles ) 74 | target.addAlpha( 75 | autoTile.renderX + pxTotalOffsetX, 76 | autoTile.renderY + pxTotalOffsetY, 77 | autoTile.alpha, 78 | untypedTileset.getAutoLayerTile(autoTile) 79 | ); 80 | 81 | return target; 82 | } 83 | #end 84 | 85 | 86 | #if flixel 87 | /** 88 | Render layer to a `FlxGroup`. If `target` isn't provided, a new one is created. 89 | **/ 90 | public function render(?target:flixel.group.FlxSpriteGroup) : flixel.group.FlxSpriteGroup { 91 | if( target==null ) { 92 | target = new flixel.group.FlxSpriteGroup(); 93 | target.active = false; 94 | } 95 | 96 | 97 | for( autoTile in autoTiles ) { 98 | var s = new flixel.FlxSprite(autoTile.renderX, autoTile.renderY); 99 | s.flipX = autoTile.flips & 1 != 0; 100 | s.flipY = autoTile.flips & 2 != 0; 101 | s.frame = untypedTileset.getFrame(autoTile.tileId); 102 | target.add(s); 103 | } 104 | 105 | return target; 106 | } 107 | #end 108 | 109 | #end 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/ldtk/Layer_Entities.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | class Layer_Entities extends ldtk.Layer { 4 | var _entities : Array = []; 5 | 6 | public function new(p,json) { 7 | super(p,json); 8 | 9 | for(json in json.entityInstances) { 10 | var e = _instanciateEntity(json); 11 | _entities.push(e); 12 | 13 | if( Reflect.field(this, "all_"+e.identifier)==null ) 14 | Reflect.setField(this, "all_"+e.identifier, []); 15 | 16 | var arr : Array = Reflect.field(this, "all_"+e.identifier); 17 | arr.push(e); 18 | } 19 | } 20 | 21 | function _instanciateEntity(json:ldtk.Json.EntityInstanceJson) : Entity { 22 | return null; // overriden by Macros.hx 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ldtk/Layer_IntGrid.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | class Layer_IntGrid extends ldtk.Layer { 4 | var valueInfos : Map, color:UInt }> = new Map(); 5 | 6 | /** 7 | IntGrid integer values, map is based on coordIds 8 | **/ 9 | public var intGrid : Map = new Map(); 10 | 11 | 12 | public function new(p,json) { 13 | super(p,json); 14 | 15 | if( json.intGridCsv!=null ) { 16 | // Read new CSV format 17 | for(i in 0...json.intGridCsv.length) 18 | if( json.intGridCsv[i]>=0 ) 19 | intGrid.set(i, json.intGridCsv[i]); 20 | } 21 | else { 22 | // Read old pre-CSV format 23 | for(ig in json.intGrid) 24 | intGrid.set(ig.coordId, ig.v+1); 25 | } 26 | } 27 | 28 | /** 29 | Get the Integer value at selected coordinates 30 | 31 | Return -1 if none. 32 | **/ 33 | public inline function getInt(cx:Int, cy:Int) { 34 | return isCoordValid(cx,cy) ? intGrid.get( getCoordId(cx,cy) ) : 0; 35 | // return !isCoordValid(cx,cy) || !intGrid.exists( getCoordId(cx,cy) ) ? 0 : intGrid.get( getCoordId(cx,cy) ); 36 | } 37 | 38 | /** 39 | Return TRUE if there is any value at selected coordinates. 40 | 41 | Optional parameter "val" allows to check for a specific integer value. 42 | **/ 43 | public inline function hasValue(cx:Int, cy:Int, val=0) { 44 | return !isCoordValid(cx,cy) 45 | ? false 46 | : val==0 47 | ? intGrid.get( getCoordId(cx,cy) )>0 48 | : intGrid.get( getCoordId(cx,cy) )==val; 49 | } 50 | 51 | 52 | inline function getValueInfos(v:Int) { 53 | return valueInfos.get(v); 54 | } 55 | 56 | /** 57 | Get the value String identifier at selected coordinates. 58 | 59 | Return null if none. 60 | **/ 61 | public inline function getName(cx:Int, cy:Int) : Null { 62 | return !hasValue(cx,cy) ? null : getValueInfos(getInt(cx,cy)).identifier; 63 | } 64 | 65 | /** 66 | Get the value color (0xrrggbb Unsigned-Int format) at selected coordinates. 67 | 68 | Return null if none. 69 | **/ 70 | public inline function getColorInt(cx:Int, cy:Int) : Null { 71 | return !hasValue(cx,cy) ? null : getValueInfos(getInt(cx,cy)).color; 72 | } 73 | 74 | /** 75 | Get the value color ("#rrggbb" string format) at selected coordinates. 76 | 77 | Return null if none. 78 | **/ 79 | public inline function getColorHex(cx:Int, cy:Int) : Null { 80 | return !hasValue(cx,cy) ? null : ldtk.Project.intToHex( getValueInfos(getInt(cx,cy)).color ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/ldtk/Layer_IntGrid_AutoLayer.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | class Layer_IntGrid_AutoLayer extends ldtk.Layer_IntGrid { 4 | /** 5 | A single array containing all AutoLayer tiles informations, in "render" order (ie. 1st is behind, last is on top) 6 | **/ 7 | public var autoTiles : Array; 8 | 9 | 10 | /** Getter to layer untyped Tileset instance. The typed value is created in macro. **/ 11 | public var untypedTileset(get,never) : ldtk.Tileset; 12 | inline function get_untypedTileset() return untypedProject._untypedTilesets.get(tilesetUid); 13 | 14 | /** Tileset UID **/ 15 | public var tilesetUid(default,null) : Int; 16 | 17 | 18 | public function new(p,json) { 19 | super(p,json); 20 | 21 | autoTiles = []; 22 | tilesetUid = json.__tilesetDefUid; 23 | 24 | for(jsonAutoTile in json.autoLayerTiles) 25 | autoTiles.push({ 26 | tileId: jsonAutoTile.t, 27 | flips: jsonAutoTile.f, 28 | alpha: jsonAutoTile.a, 29 | renderX: jsonAutoTile.px[0], 30 | renderY: jsonAutoTile.px[1], 31 | ruleId: jsonAutoTile.d[0], 32 | coordId: jsonAutoTile.d[1], 33 | }); 34 | } 35 | 36 | 37 | 38 | #if !macro 39 | 40 | #if heaps 41 | /** 42 | Render layer to a `h2d.TileGroup`. If `target` isn't provided, a new h2d.TileGroup is created. If `target` is provided, it **must** have the same tile source as the layer tileset! 43 | **/ 44 | public inline function render(?target:h2d.TileGroup) : h2d.TileGroup { 45 | if( target==null ) 46 | target = new h2d.TileGroup( untypedTileset.getAtlasTile() ); 47 | 48 | for( autoTile in autoTiles ) 49 | target.addAlpha( 50 | autoTile.renderX + pxTotalOffsetX, 51 | autoTile.renderY + pxTotalOffsetY, 52 | autoTile.alpha, 53 | untypedTileset.getAutoLayerTile(autoTile) 54 | ); 55 | 56 | return target; 57 | } 58 | #end 59 | 60 | 61 | #if flixel 62 | /** 63 | Render layer to a `FlxGroup`. If `target` isn't provided, a new one is created. 64 | **/ 65 | public function render(?target:flixel.group.FlxSpriteGroup) : flixel.group.FlxSpriteGroup { 66 | if( target==null ) { 67 | target = new flixel.group.FlxSpriteGroup(); 68 | target.active = false; 69 | } 70 | 71 | 72 | for( autoTile in autoTiles ) { 73 | var s = new flixel.FlxSprite(autoTile.renderX, autoTile.renderY); 74 | s.flipX = autoTile.flips & 1 != 0; 75 | s.flipY = autoTile.flips & 2 != 0; 76 | s.frame = untypedTileset.getFrame(autoTile.tileId); 77 | target.add(s); 78 | } 79 | 80 | return target; 81 | } 82 | #end 83 | 84 | #end 85 | } 86 | -------------------------------------------------------------------------------- /src/ldtk/Layer_Tiles.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | class Layer_Tiles extends ldtk.Layer { 4 | var tiles : Map>; 5 | 6 | /** Getter to layer untyped Tileset instance. The typed value is created in macro. **/ 7 | var untypedTileset(get,never) : ldtk.Tileset; 8 | inline function get_untypedTileset() return untypedProject._untypedTilesets.get(tilesetUid); 9 | 10 | /** Tileset UID **/ 11 | public var tilesetUid(default,null) : Int; 12 | 13 | 14 | public function new(p,json) { 15 | super(p,json); 16 | 17 | tilesetUid = json.__tilesetDefUid; 18 | 19 | tiles = new Map(); 20 | for(t in json.gridTiles) 21 | if( !tiles.exists(t.d[0]) ) 22 | tiles.set(t.d[0], [{ tileId:t.t, flipBits:t.f }]); 23 | else 24 | tiles.get(t.d[0]).push({ tileId:t.t, flipBits:t.f }); 25 | 26 | } 27 | 28 | /** 29 | Return the stack of tiles at coords, or empty array if there is none. To avoid useless memory allocations, you should check `hasAnyTileAt` before using this method. 30 | **/ 31 | public inline function getTileStackAt(cx:Int,cy:Int) : Array<{ tileId:Int, flipBits:Int }> { 32 | return isCoordValid(cx,cy) && tiles.exists(getCoordId(cx,cy)) 33 | ? tiles.get( getCoordId(cx,cy) ) 34 | : []; 35 | } 36 | 37 | /** 38 | Return TRUE if any tile exists at specified coords 39 | **/ 40 | public inline function hasAnyTileAt(cx,cy) { 41 | return tiles.exists( getCoordId(cx,cy) ); 42 | } 43 | 44 | 45 | #if !macro 46 | 47 | #if heaps 48 | /** 49 | Render layer to a `h2d.TileGroup`. If `target` isn't provided, a new h2d.TileGroup is created. If `target` is provided, it **must** have the same tile source as the layer tileset! 50 | **/ 51 | public inline function render(?target:h2d.TileGroup) : h2d.TileGroup { 52 | if( target==null ) 53 | target = new h2d.TileGroup( untypedTileset.getAtlasTile() ); 54 | 55 | for( cy in 0...cHei ) 56 | for( cx in 0...cWid ) 57 | if( hasAnyTileAt(cx,cy) ) { 58 | for( tile in getTileStackAt(cx,cy) ) { 59 | target.add( 60 | cx*gridSize + pxTotalOffsetX, 61 | cy*gridSize + pxTotalOffsetY, 62 | untypedTileset.getTile(tile.tileId, tile.flipBits) 63 | ); 64 | } 65 | } 66 | 67 | return target; 68 | } 69 | #end 70 | 71 | 72 | #if flixel 73 | /** 74 | Render layer to a `FlxGroup`. If `target` isn't provided, a new one is created. 75 | **/ 76 | public function render(?target:flixel.group.FlxSpriteGroup) : flixel.group.FlxSpriteGroup { 77 | if( target==null ) { 78 | target = new flixel.group.FlxSpriteGroup(); 79 | target.active = false; 80 | } 81 | 82 | 83 | for( cy in 0...cHei ) 84 | for( cx in 0...cWid ) 85 | if( hasAnyTileAt(cx,cy) ) 86 | for( tile in getTileStackAt(cx,cy) ) { 87 | var s = new flixel.FlxSprite(cx*gridSize + pxTotalOffsetX, cy*gridSize + pxTotalOffsetY); 88 | s.flipX = tile.flipBits & 1 != 0; 89 | s.flipY = tile.flipBits & 2 != 0; 90 | s.frame = untypedTileset.getFrame(tile.tileId); 91 | s.width = gridSize; 92 | s.height = gridSize; 93 | target.add(s); 94 | } 95 | 96 | return target; 97 | } 98 | #end 99 | #end 100 | 101 | } -------------------------------------------------------------------------------- /src/ldtk/Level.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | enum NeighbourDir { 4 | NorthEastCorner; 5 | NorthWestCorner; 6 | SouthEastCorner; 7 | SouthWestCorner; 8 | North; 9 | South; 10 | West; 11 | East; 12 | SameDepthOverlap; 13 | DepthBelow; 14 | DepthAbove; 15 | } 16 | 17 | typedef LevelBgImage = { 18 | var relFilePath: String; 19 | 20 | /** Top-left X coordinate of background image **/ 21 | var topLeftX: Int; 22 | 23 | /** Top-left Y coordinate of background image **/ 24 | var topLeftY: Int; 25 | 26 | /** X scale factor of background image **/ 27 | var scaleX: Float; 28 | 29 | /** Y scale factor of background image **/ 30 | var scaleY: Float; 31 | 32 | /** Cropped sub rectangle in background image **/ 33 | var cropRect: { 34 | x: Float, 35 | y: Float, 36 | w: Float, 37 | h: Float, 38 | } 39 | } 40 | 41 | class Level { 42 | var untypedProject: ldtk.Project; // WARNING: the var type isn't the "complete" project type as generated by macros! 43 | 44 | /** Original parsed JSON object **/ 45 | public var json(default,null) : ldtk.Json.LevelJson; 46 | 47 | public var iid(default,null) : String; 48 | public var uid(default,null) : Int; 49 | public var identifier(default,null) : String; 50 | public var pxWid(default,null) : Int; 51 | public var pxHei(default,null) : Int; 52 | public var worldX(default,null) : Int; 53 | public var worldY(default,null) : Int; 54 | public var worldDepth(default,null) : Int; 55 | 56 | /** Level background color (as Hex "#rrggbb") **/ 57 | public var bgColor_hex(default,null): String; 58 | 59 | /** Level background color (as Int 0xrrggbb) **/ 60 | public var bgColor_int(default,null): UInt; 61 | 62 | @:deprecated("Use bgColor_int instead") @:noCompletion 63 | public var bgColor(get,never) : UInt; 64 | @:noCompletion inline function get_bgColor() return bgColor_int; 65 | 66 | public var allUntypedLayers(default,null) : Array; 67 | public var neighbours : Array<{ levelIid:String, dir: NeighbourDir }>; 68 | public var bgImageInfos(default,null) : Null; 69 | 70 | /** Index in project `levels` array **/ 71 | public var arrayIndex(default,null) : Int; 72 | 73 | /** Only exists if levels are stored in separate level files **/ 74 | var externalRelPath(default,null) : Null; 75 | 76 | 77 | public function new(project:ldtk.Project, arrayIdx:Int, json:ldtk.Json.LevelJson) { 78 | this.untypedProject = project; 79 | this.arrayIndex = arrayIdx; 80 | fromJson(json); 81 | project._assignFieldInstanceValues(this, json.fieldInstances); 82 | } 83 | 84 | /** Print class debug info **/ 85 | @:keep public function toString() { 86 | return 'ldtk.Level[#$identifier, ${pxWid}x$pxHei]'; 87 | } 88 | 89 | 90 | /** Parse level JSON **/ 91 | function fromJson(json:ldtk.Json.LevelJson) { 92 | this.json = json; 93 | neighbours = []; 94 | allUntypedLayers = []; 95 | 96 | iid = json.iid; 97 | uid = json.uid; 98 | identifier = json.identifier; 99 | pxWid = json.pxWid; 100 | pxHei = json.pxHei; 101 | worldX = json.worldX; 102 | worldY = json.worldY; 103 | worldDepth = json.worldDepth; 104 | bgColor_hex = json.__bgColor; 105 | bgColor_int = Project.hexToInt(json.__bgColor); 106 | 107 | bgImageInfos = json.bgRelPath==null || json.__bgPos==null ? null : { 108 | relFilePath: json.bgRelPath, 109 | topLeftX: json.__bgPos.topLeftPx[0], 110 | topLeftY: json.__bgPos.topLeftPx[1], 111 | scaleX: json.__bgPos.scale[0], 112 | scaleY: json.__bgPos.scale[1], 113 | cropRect: { 114 | x: json.__bgPos.cropRect[0], 115 | y: json.__bgPos.cropRect[1], 116 | w: json.__bgPos.cropRect[2], 117 | h: json.__bgPos.cropRect[3], 118 | }, 119 | } 120 | 121 | externalRelPath = json.externalRelPath; 122 | 123 | if( json.layerInstances!=null ) 124 | for(json in json.layerInstances) 125 | allUntypedLayers.push( _instanciateLayer(json) ); 126 | 127 | if( json.__neighbours!=null ) 128 | for(n in json.__neighbours) 129 | neighbours.push({ 130 | levelIid: n.levelIid, 131 | dir: switch n.dir { 132 | case "nw": NorthWestCorner; 133 | case "ne": NorthEastCorner; 134 | case "sw": SouthWestCorner; 135 | case "se": SouthEastCorner; 136 | 137 | case "n": North; 138 | case "s": South; 139 | case "w": West; 140 | case "e": East; 141 | 142 | case "<": DepthBelow; 143 | case ">": DepthAbove; 144 | case "o": SameDepthOverlap; 145 | 146 | case _: trace("WARNING: unknown neighbour level dir: "+n.dir); North; 147 | }, 148 | }); 149 | } 150 | 151 | 152 | function _instanciateLayer(json:ldtk.Json.LayerInstanceJson) : ldtk.Layer { 153 | return null; // overriden by Macros.hx 154 | } 155 | 156 | 157 | /** 158 | Return TRUE if the level was previously loaded and is ready for usage (always TRUE if levels are embedded in the project file). 159 | **/ 160 | public inline function isLoaded() return this.externalRelPath==null || allUntypedLayers!=null && allUntypedLayers.length>0; 161 | 162 | /** 163 | Load level if it's stored in an external file. **IMPORTANT**: this probably doesn't need to be used in most scenario, as `load()` is *automatically* called when trying to use a level variable in your project. 164 | **/ 165 | public function load() { 166 | if( isLoaded() ) 167 | return true; 168 | 169 | 170 | var bytes = untypedProject.getAsset(externalRelPath); 171 | try { 172 | var raw = bytes.toString(); 173 | var json : ldtk.Json.LevelJson = haxe.Json.parse(raw); 174 | fromJson(json); 175 | return true; 176 | } 177 | catch(e:Dynamic) { 178 | Project.error('Failed to parse external level $identifier: $externalRelPath ($e)'); 179 | return false; 180 | } 181 | } 182 | 183 | 184 | public inline function hasBgImage() { 185 | return bgImageInfos!=null; 186 | } 187 | 188 | 189 | #if !macro 190 | 191 | #if heaps 192 | var _cachedBgTile : Null; 193 | 194 | /** 195 | Get the full "raw" (ie. non-cropped, scaled or positioned) background Tile. Use `getBgBitmap()` instead to get the "ready for display" background image. 196 | **/ 197 | public function getRawBgImageTile() : Null { 198 | if( bgImageInfos==null ) 199 | return null; 200 | 201 | if( _cachedBgTile==null ) { 202 | var bytes = untypedProject.getAsset(bgImageInfos.relFilePath); 203 | _cachedBgTile = dn.ImageDecoder.decodeTile(bytes); 204 | if( _cachedBgTile==null ) 205 | _cachedBgTile = h2d.Tile.fromColor(0xff0000, pxWid, pxHei); 206 | } 207 | return _cachedBgTile; 208 | } 209 | 210 | /** 211 | Return the level background image, ready for display. The bitmap coordinates and scaling also match level background settings. 212 | **/ 213 | public function getBgBitmap(?parent:h2d.Object) : Null { 214 | var t = getRawBgImageTile(); 215 | if( t==null ) 216 | return null; 217 | 218 | t = t.sub( 219 | bgImageInfos.cropRect.x, 220 | bgImageInfos.cropRect.y, 221 | bgImageInfos.cropRect.w, 222 | bgImageInfos.cropRect.h 223 | ); 224 | var bmp = new h2d.Bitmap(t, parent); 225 | bmp.x = bgImageInfos.topLeftX; 226 | bmp.y = bgImageInfos.topLeftY; 227 | bmp.scaleX = bgImageInfos.scaleX; 228 | bmp.scaleY = bgImageInfos.scaleY; 229 | return bmp; 230 | } 231 | #end 232 | 233 | #if flixel 234 | public function getBgSprite() : Null< flixel.FlxSprite > { 235 | if( bgImageInfos==null ) 236 | return null; 237 | 238 | // Full image 239 | var graphic = untypedProject.getFlxGraphicAsset( bgImageInfos.relFilePath ); 240 | if( graphic==null ) 241 | return null; 242 | 243 | // Cropped sub section 244 | var f = flixel.graphics.frames.FlxImageFrame.fromGraphic(graphic, flixel.math.FlxRect.weak( 245 | bgImageInfos.cropRect.x, 246 | bgImageInfos.cropRect.y, 247 | bgImageInfos.cropRect.w, 248 | bgImageInfos.cropRect.h 249 | )); 250 | 251 | // FlxSprite 252 | var spr = new flixel.FlxSprite(); 253 | spr.frame = f.frame; 254 | spr.x = bgImageInfos.topLeftX; 255 | spr.y = bgImageInfos.topLeftY; 256 | spr.origin.set(0,0); 257 | spr.scale.set(bgImageInfos.scaleX, bgImageInfos.scaleY); 258 | return spr; 259 | } 260 | #end 261 | 262 | #end // End of "if !macro" 263 | } 264 | -------------------------------------------------------------------------------- /src/ldtk/Point.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | class Point { 4 | public var cx : Int; 5 | public var cy : Int; 6 | 7 | public function new(cx,cy) { 8 | this.cx = cx; 9 | this.cy = cy; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ldtk/Project.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | /** 4 | LDtk Project JSON importer for Haxe. 5 | 6 | USAGE: 7 | 8 | Create a HX file for each LDtk project JSON. The filename isn’t important, pick whatever you like. 9 | This HX will host all the the typed data extracted from the project file: 10 | 11 | ``` 12 | private typedef _Tmp = 13 | haxe.macro.MacroType<[ ldtk.Project.build("path/to/myProject.ldtk") ]>; 14 | ``` 15 | 16 | See full documentation here: https://ldtk.io/docs 17 | **/ 18 | 19 | 20 | #if macro 21 | 22 | 23 | /* MACRO TYPE BUILDER *****************************************************/ 24 | 25 | import haxe.macro.Context; 26 | import haxe.macro.Expr; 27 | using haxe.macro.Tools; 28 | 29 | class Project { 30 | 31 | /** Build project types based on Project JSON **/ 32 | public static function build(projectFilePath:String) { 33 | #if !macro 34 | error("Should only be used in macros"); 35 | #else 36 | 37 | return ldtk.macro.TypeBuilder.buildTypes(projectFilePath); 38 | #end 39 | } 40 | } 41 | 42 | 43 | #else 44 | 45 | 46 | /* ACTUAL PROJECT CLASS *****************************************************/ 47 | 48 | import ldtk.Json; 49 | 50 | class Project { 51 | /** Contains the full path to the project JSON, as provided to the macro (using slashes) **/ 52 | public var projectFilePath : String; 53 | 54 | /** Contains the directory of the project JSON (using slashes, no trailing slash) **/ 55 | public var projectDir : Null; 56 | 57 | /** Project background color (as Int 0xrrggbb) **/ 58 | public var bgColor_int: UInt; 59 | 60 | /** Project background color (as Hex "#rrggbb") **/ 61 | public var bgColor_hex: String; 62 | 63 | var _untypedWorlds : Array; 64 | 65 | /** Full access to the JSON project definitions **/ 66 | public var defs : ldtk.Json.DefinitionsJson; 67 | 68 | /** A map containing all untyped Tilesets, indexed using their JSON `uid` (integer unique ID). The typed tilesets will be added in a field called `all_tilesets` by macros. **/ 69 | @:allow(ldtk.Layer_Tiles, ldtk.Layer_AutoLayer, ldtk.Layer_IntGrid_AutoLayer, ldtk.Entity) 70 | var _untypedTilesets : Map; 71 | 72 | /** Internal asset cache to avoid reloading of previously loaded data. **/ 73 | var assetCache : Map; // TODO support hot reloading 74 | 75 | var _untypedToc : Map>; 76 | 77 | function new() {} 78 | 79 | /** 80 | Replace current project using another project-JSON data. 81 | 82 | WARNING: types and classes are generated at compilation-time, not at runtime. 83 | **/ 84 | public function parseJson(jsonString:String) { 85 | // Init 86 | _untypedTilesets = new Map(); 87 | _untypedToc = new Map(); 88 | assetCache = new Map(); 89 | 90 | // Parse json 91 | var untypedJson : Dynamic = haxe.Json.parse(jsonString); 92 | var json : ProjectJson = untypedJson; 93 | 94 | // Init misc fields 95 | defs = json.defs; 96 | bgColor_hex = json.bgColor; 97 | bgColor_int = ldtk.Project.hexToInt(json.bgColor); 98 | 99 | // Add dummy JSON world 100 | if( json.worlds==null || json.worlds.length==0 ) 101 | json.worlds = [ World.createDummyJson(json) ]; 102 | 103 | // Populate worlds 104 | _untypedWorlds = []; 105 | var idx = 0; 106 | for(json in json.worlds) 107 | _untypedWorlds.push( _instanciateWorld(this, idx++, json) ); 108 | 109 | 110 | // Populate tilesets 111 | Reflect.setField(this, "all_tilesets", {}); 112 | for(tsJson in json.defs.tilesets) { 113 | _untypedTilesets.set( tsJson.uid, _instanciateTileset(this, tsJson) ); 114 | Reflect.setField( Reflect.field(this,"all_tilesets"), tsJson.identifier, _instanciateTileset(this, tsJson)); 115 | } 116 | 117 | // Init toc 118 | var classToc : Dynamic = Reflect.field(this,"toc"); 119 | for( k in Reflect.fields(classToc) ) 120 | Reflect.setField(classToc, k, []); 121 | 122 | // Populate toc 123 | if( json.toc!=null ) { 124 | var jsonToc : Array = json.toc; 125 | for(te in jsonToc) 126 | if( Reflect.hasField(classToc, te.identifier) ) 127 | Reflect.setField(classToc, te.identifier, te.instancesData.copy()); 128 | } 129 | } 130 | 131 | /** Transform an identifier string by capitalizing its first letter **/ 132 | @:noCompletion 133 | public function capitalize(id:String) { 134 | if( id==null ) 135 | id = ""; 136 | 137 | var reg = ~/^(_*)([a-z])([a-zA-Z0-9_]*)/g; // extract first letter, if it's lowercase 138 | if( reg.match(id) ) 139 | id = reg.matched(1) + reg.matched(2).toUpperCase() + reg.matched(3); 140 | 141 | return id; 142 | } 143 | 144 | 145 | var _enumTypePrefix : String; 146 | 147 | function _resolveExternalEnumValue(name:String, enumValueId:String) : T { 148 | return null; 149 | } 150 | 151 | 152 | /** Used to populated field instances with actual values **/ 153 | @:allow(ldtk.Entity, ldtk.Level) 154 | function _assignFieldInstanceValues(target:Dynamic, fieldInstances:Array) { 155 | var arrayReg = ~/Array<(.*)>/gi; 156 | for(f in fieldInstances) { 157 | if( f.__value==null ) 158 | continue; 159 | 160 | var isArray = arrayReg.match(f.__type); 161 | var typeName = isArray ? arrayReg.matched(1) : f.__type; 162 | 163 | switch typeName { 164 | case "Int", "Float", "Bool", "String" : 165 | Reflect.setField(target, "f_"+f.__identifier, f.__value); 166 | 167 | case "FilePath" : 168 | Reflect.setField(target, "f_"+f.__identifier, f.__value); 169 | 170 | case "Color": 171 | Reflect.setField(target, "f_"+f.__identifier+"_hex", f.__value); 172 | if( !isArray ) 173 | Reflect.setField(target, "f_"+f.__identifier+"_int", ldtk.Project.hexToInt(f.__value)); 174 | else { 175 | var arr : Array = f.__value; 176 | Reflect.setField(target, "f_"+f.__identifier+"_int", arr.map( (c)->ldtk.Project.hexToInt(c) ) ); 177 | } 178 | 179 | case "Point": 180 | if( !isArray ) 181 | Reflect.setField(target, "f_"+f.__identifier, new ldtk.Point(f.__value.cx, f.__value.cy)); 182 | else { 183 | var arr : Array<{ cx:Int, cy:Int }> = f.__value; 184 | Reflect.setField(target, "f_"+f.__identifier, arr.map( (pt)->new ldtk.Point(pt.cx, pt.cy) ) ); 185 | } 186 | 187 | case "EntityRef": 188 | Reflect.setField(target, "f_"+f.__identifier, f.__value); 189 | 190 | case _.indexOf("LocalEnum.") => 0: 191 | var type = _enumTypePrefix + typeName.substr( typeName.indexOf(".")+1 ); 192 | var e = Type.resolveEnum( type ); 193 | if( !isArray ) 194 | Reflect.setField(target, "f_"+f.__identifier, Type.createEnum(e, capitalize(f.__value)) ); 195 | else { 196 | var arr : Array = f.__value; 197 | Reflect.setField(target, "f_"+f.__identifier, arr.map( (k)->Type.createEnum(e,capitalize(k)) ) ); 198 | } 199 | 200 | 201 | case _.indexOf("ExternEnum.") => 0: 202 | var type = typeName.substr( typeName.indexOf(".")+1 ); 203 | if( !isArray ) 204 | Reflect.setField(target, "f_"+f.__identifier, _resolveExternalEnumValue(type, f.__value) ); 205 | else { 206 | var arr : Array = f.__value; 207 | Reflect.setField(target, "f_"+f.__identifier, arr.map( (k)->_resolveExternalEnumValue(type, k) ) ); 208 | } 209 | 210 | case "Tile": 211 | function _checkTile(tileRect : TilesetRect) { 212 | if( tileRect==null || !dn.M.isValidNumber(tileRect.x) ) 213 | return null; // old format 214 | else 215 | return tileRect; 216 | } 217 | #if heaps 218 | function _heapsTileGetter(tileRect:TilesetRect) { 219 | if( tileRect==null || !dn.M.isValidNumber(tileRect.x) || !_untypedTilesets.exists(tileRect.tilesetUid)) 220 | return null; 221 | 222 | var tileset = _untypedTilesets.get(tileRect.tilesetUid); 223 | var tile = tileset.getFreeTile( tileRect.x, tileRect.y, tileRect.w, tileRect.h ); 224 | return tile; 225 | } 226 | #end 227 | 228 | if( isArray ) { 229 | var arr : Array = f.__value; 230 | Reflect.setField(target, "f_"+f.__identifier+"_infos", arr.map( tr->_checkTile(tr) ) ); 231 | #if heaps 232 | Reflect.setField(target, "f_"+f.__identifier+"_getTile", arr.map( tr->_heapsTileGetter.bind(tr) ) ); 233 | #end 234 | 235 | } 236 | else { 237 | Reflect.setField(target, "f_"+f.__identifier+"_infos", _checkTile(f.__value)); 238 | #if heaps 239 | Reflect.setField(target, "f_"+f.__identifier+"_getTile", _heapsTileGetter.bind(f.__value)); 240 | #end 241 | } 242 | 243 | case _ : 244 | Project.error('Unknown field type $typeName at runtime'); // TODO add some helpful context here 245 | } 246 | } 247 | } 248 | 249 | 250 | @:keep public function toString() { 251 | return 'ldtk.Project[${_untypedWorlds.length} worlds]'; 252 | } 253 | 254 | 255 | /** 256 | Get an asset from current Asset management system. The path should be **relative to the project JSON file**. 257 | **/ 258 | public function getAsset(projectRelativePath:String) : haxe.io.Bytes { 259 | if( assetCache.exists(projectRelativePath) ) 260 | return assetCache.get(projectRelativePath); 261 | else { 262 | var bytes = loadAssetBytes(projectRelativePath); 263 | assetCache.set(projectRelativePath, bytes); 264 | return bytes; 265 | } 266 | } 267 | 268 | 269 | /** 270 | Try to resolve the Project file location in the current Asset management system 271 | **/ 272 | function makeAssetRelativePath(projectRelativePath:String) { 273 | // Get project file name 274 | var p = StringTools.replace(projectFilePath, "\\", "/"); 275 | var projectFileName = p.lastIndexOf("/")<0 ? p : p.substr( p.lastIndexOf("/")+1 ); 276 | 277 | #if heaps 278 | 279 | // Browser all folders in Heaps res/ folder recursively to locate Project file 280 | var pendingDirs = [ 281 | hxd.Res.loader.fs.getRoot() 282 | ]; 283 | while( pendingDirs.length>0 ) { 284 | var curDir = pendingDirs.shift(); 285 | for(f in curDir) { 286 | if( f.isDirectory ) { 287 | // Found another dir 288 | pendingDirs.push(f); 289 | } 290 | else if( f.name==projectFileName ) { 291 | // Found it 292 | return dn.FilePath.cleanUp( ( f.directory.length==0 ? "" : f.directory+"/" ) + projectRelativePath, true ); 293 | } 294 | } 295 | } 296 | error('Project file is not in Heaps res/ folder!'); 297 | return ""; 298 | 299 | #elseif openfl 300 | 301 | // Browse openFL assets to locate project file 302 | for( e in openfl.Assets.list() ) 303 | if( e.indexOf(projectFileName)>=0 ) { 304 | // Found it 305 | var baseDir = e.indexOf("/")<0 ? "" : e.substr( 0, e.lastIndexOf("/") ); 306 | return dn.FilePath.cleanUp( baseDir + "/" + projectRelativePath, true ); 307 | } 308 | 309 | error('Project file is not in OpenFL assets!'); 310 | return ""; 311 | 312 | #else 313 | 314 | // Generic Haxe Resource Loading for Unsupported Frameworks 315 | // Browse resources to locate project file 316 | for(key => value in haxe.Resource.listNames()) { 317 | if(value == projectFilePath) { 318 | // Found it 319 | var baseDir = value.indexOf("/")<0 ? "" : value.substr( 0, value.lastIndexOf("/") ); 320 | return dn.FilePath.cleanUp( baseDir + "/" + projectRelativePath, true ); 321 | } 322 | } 323 | 324 | error('Project file is not loaded properly.\nPlease add "-r " and "-r " to your project.hxml build file and try again.'); 325 | return ""; 326 | 327 | #end 328 | } 329 | 330 | 331 | /** 332 | Load an Asset as haxe.io.Bytes 333 | **/ 334 | function loadAssetBytes(projectRelativePath:String) : haxe.io.Bytes { 335 | #if heaps 336 | 337 | var resPath = makeAssetRelativePath(projectRelativePath); 338 | if( !hxd.Res.loader.exists(resPath) ) 339 | error('Asset not found in Heaps res/ folder: $resPath'); 340 | 341 | var res = hxd.Res.load(resPath); 342 | return res.entry.getBytes(); 343 | 344 | #elseif openfl 345 | 346 | var assetId = makeAssetRelativePath(projectRelativePath); 347 | var bytes : haxe.io.Bytes = try openfl.Assets.getBytes(assetId) catch(e:Dynamic) { 348 | error('OpenFL asset not found or could not be accessed synchronously: $assetId ; error=$e'); 349 | null; 350 | } 351 | return bytes; 352 | 353 | 354 | #else 355 | 356 | // Generic Haxe Resource Loading for Unsupported Frameworks 357 | var assetId = makeAssetRelativePath(projectRelativePath); 358 | var bytes : haxe.io.Bytes = try haxe.Resource.getBytes(assetId) catch(e:Dynamic) { 359 | error('Asset not found or was not loaded properly at runtime: $assetId ; error=$e'); 360 | null; 361 | } 362 | return bytes; 363 | 364 | #end 365 | } 366 | 367 | 368 | #if flixel 369 | /** 370 | Get an asset image as FlxGraphic 371 | **/ 372 | public function getFlxGraphicAsset(projectRelativePath:String) : flixel.graphics.FlxGraphic { 373 | var assetId = makeAssetRelativePath(projectRelativePath); 374 | var g = try flixel.graphics.FlxGraphic.fromAssetKey(assetId) 375 | catch(e:Dynamic) { 376 | error('FlxGraphic not found in assets: $assetId ; error=$e'); 377 | null; 378 | } 379 | return g; 380 | } 381 | #end 382 | 383 | 384 | /** 385 | Crash with an error message 386 | **/ 387 | public static function error(str:String) { 388 | throw '[ldtk-api] $str'; 389 | } 390 | 391 | 392 | function _instanciateWorld(project:ldtk.Project, arrayIndex:Int, json:ldtk.Json.WorldJson) { 393 | return null; // overriden by Macros.hx 394 | } 395 | 396 | 397 | function _instanciateTileset(project:ldtk.Project, json:ldtk.Json.TilesetDefJson) { 398 | return null; 399 | } 400 | 401 | 402 | function searchDef(arr:Array, ?uid:Int, ?identifier:String) { 403 | if( uid==null && identifier==null ) 404 | return null; 405 | 406 | for(e in arr) 407 | if( uid!=null && e.uid==uid || identifier!=null && e.identifier==identifier ) 408 | return e; 409 | 410 | return null; 411 | } 412 | 413 | /** 414 | Get a Layer definition using either its uid (Int) or identifier (String) 415 | **/ 416 | public function getLayerDefJson(?uid:Int, ?identifier:String) : Null { 417 | return searchDef( defs.layers, uid, identifier ); 418 | } 419 | @:noCompletion @:deprecated("Method was renamed to: getLayerDefJson") 420 | public function getLayerDef(?uid,?identifier) return getLayerDefJson(uid,identifier); 421 | 422 | /** 423 | Get an Entity definition using either its uid (Int) or identifier (String) 424 | **/ 425 | public inline function getEntityDefJson(?uid:Int, ?identifier:String) : Null { 426 | return searchDef( defs.entities, uid, identifier ); 427 | } 428 | @:noCompletion @:deprecated("Method was renamed to: getEntityDefJson") 429 | public function getEntityDef(?uid,?identifier) return getEntityDefJson(uid,identifier); 430 | 431 | 432 | 433 | /** 434 | Get a Tileset definition using either its uid (Int) or identifier (String) 435 | **/ 436 | public inline function getTilesetDefJson(?uid:Int, ?identifier:String) : Null { 437 | return searchDef( defs.tilesets, uid, identifier ); 438 | } 439 | @:noCompletion @:deprecated("Method was renamed to: getTilesetDefJson") 440 | public function getTilesetDef(?uid,?identifier) return getTilesetDefJson(uid,identifier); 441 | 442 | 443 | /** 444 | Get an Enum definition using either its uid (Int) or identifier (String) 445 | **/ 446 | public inline function getEnumDefJson(?uid:Int, ?identifier:String) : Null { 447 | var e = searchDef( defs.enums, uid, identifier ); 448 | if( e!=null ) 449 | return e; 450 | else 451 | return searchDef( defs.externalEnums, uid, identifier ); 452 | } 453 | @:noCompletion @:deprecated("Method was renamed to: getEnumDefJson") 454 | public function getEnumDef(?uid,?identifier) return getEnumDefJson(uid,identifier); 455 | 456 | 457 | /** 458 | Get an Enum definition using an Enum value 459 | **/ 460 | public function getEnumDefFromValue(v:EnumValue) : Null { 461 | try { 462 | var name = Type.getEnum(v).getName(); 463 | var defId = name.substr( name.indexOf("_")+1 ); // get rid of the Macro prefix 464 | defId = defId.substr( defId.lastIndexOf(".")+1 ); 465 | return getEnumDefJson(defId); 466 | } 467 | catch(err:Dynamic) { 468 | return null; 469 | } 470 | } 471 | 472 | function getEnumTileInfosFromValue(v:EnumValue) : Null<{ x:Int, y:Int, w:Int, h:Int, tilesetUid:Int }> { 473 | var ed = getEnumDefFromValue(v); 474 | if( ed==null ) 475 | return null; 476 | 477 | for(ev in ed.values) 478 | if( ev.id==v.getName() && ev.tileRect!=null ) 479 | return { 480 | tilesetUid: ed.iconTilesetUid, 481 | x: ev.tileRect.x, 482 | y: ev.tileRect.y, 483 | w: ev.tileRect.w, 484 | h: ev.tileRect.h, 485 | }; 486 | 487 | return null; 488 | } 489 | 490 | #if heaps 491 | 492 | public function getEnumTile(enumValue:EnumValue) : Null { 493 | var tileInfos = getEnumTileInfosFromValue(enumValue); 494 | if( tileInfos==null ) 495 | return null; 496 | 497 | var tileset = _untypedTilesets.get(tileInfos.tilesetUid); 498 | if( tileset==null ) 499 | return null; 500 | 501 | return tileset.getFreeTile(tileInfos.x, tileInfos.y, tileInfos.w, tileInfos.h); 502 | } 503 | #end 504 | 505 | public function getEnumColor(enumValue:EnumValue) : UInt { 506 | var ed = getEnumDefFromValue(enumValue); 507 | for(v in ed.values) 508 | if( v.id==enumValue.getName() ) 509 | return v.color; 510 | return 0xff00ff; 511 | } 512 | 513 | @:noCompletion 514 | public static inline function hexToInt(hex:String) : Int { 515 | return hex==null ? 0x0 : Std.parseInt( "0x"+hex.substr(1) ); 516 | } 517 | 518 | @:noCompletion 519 | public static inline function intToHex(c:Int, ?leadingZeros=6) : String { 520 | var h = StringTools.hex(c); 521 | while( h.length >; 36 | 37 | 38 | public function new(p:ldtk.Project, json:ldtk.Json.TilesetDefJson) { 39 | this.json = json; 40 | untypedProject = p; 41 | identifier = json.identifier; 42 | tileGridSize = json.tileGridSize; 43 | relPath = json.relPath; 44 | pxWid = json.pxWid; 45 | pxHei = json.pxHei; 46 | padding = json.padding; 47 | spacing = json.spacing; 48 | 49 | // Init untyped enum tags 50 | untypedTags = new Map(); 51 | if( json.enumTags!=null ) { 52 | for(t in json.enumTags) { 53 | untypedTags.set( p.capitalize(t.enumValueId), [] ); 54 | for(tid in t.tileIds) 55 | untypedTags.get( p.capitalize(t.enumValueId) ).set(tid,tid); 56 | } 57 | } 58 | } 59 | 60 | /** Print class debug info **/ 61 | @:keep public function toString() { 62 | return 'ldtk.Tileset[#$identifier, path=$relPath]'; 63 | } 64 | 65 | 66 | /** 67 | Get X pixel coordinate (in atlas image) from a specified tile ID 68 | **/ 69 | public inline function getAtlasX(tileId:Int) { 70 | return ( tileId - Std.int( tileId / cWid ) * cWid ) * tileGridSize; 71 | } 72 | 73 | /** 74 | Get Y pixel coordinate (in atlas image) from a specified tile ID 75 | **/ 76 | public inline function getAtlasY(tileId:Int) { 77 | return Std.int( tileId / cWid ) * tileGridSize; 78 | } 79 | 80 | /** 81 | Resolve an atlas coordinate to a tile ID. The result is only relevant if the coordinates are over a tile (ie. in atlas bounds, not in margins etc.). 82 | WARNING: tile spacing is not supported yet! 83 | **/ 84 | public inline function getTileIdFromCoords(pixelX:Int, pixelY:Int) { 85 | return Std.int( (pixelX-padding) / tileGridSize ) + cWid * Std.int( pixelY / tileGridSize ); 86 | } 87 | 88 | 89 | /*************************************************************************** 90 | HEAPS API 91 | ***************************************************************************/ 92 | 93 | #if( !macro && heaps ) 94 | var _cachedAtlasTile : Null; 95 | 96 | /** Get the main tileset h2d.Tile **/ 97 | public inline function getAtlasTile() : Null { 98 | if( _cachedAtlasTile!=null ) 99 | return _cachedAtlasTile; 100 | else { 101 | var bytes = untypedProject.getAsset(relPath); 102 | _cachedAtlasTile = dn.ImageDecoder.decodeTile(bytes); 103 | if( _cachedAtlasTile==null ) 104 | _cachedAtlasTile = h2d.Tile.fromColor(0xff0000, pxWid, pxHei); 105 | return _cachedAtlasTile; 106 | } 107 | } 108 | 109 | /** 110 | Get a h2d.Tile from a Tile ID. 111 | 112 | "flipBits" can be: 0=no flip, 1=flipX, 2=flipY, 3=bothXY 113 | **/ 114 | public inline function getTile(tileId:Int, flipBits:Int=0) : Null { 115 | if( tileId<0 ) 116 | return null; 117 | else { 118 | var atlas = getAtlasTile(); 119 | var t = atlas.sub( getAtlasX(tileId), getAtlasY(tileId), tileGridSize, tileGridSize ); 120 | return switch flipBits { 121 | case 0: t; 122 | case 1: t.flipX(); t.setCenterRatio(0,0); t; 123 | case 2: t.flipY(); t.setCenterRatio(0,0); t; 124 | case 3: t.flipX(); t.flipY(); t.setCenterRatio(0,0); t; 125 | case _: Project.error("Unsupported flipBits value"); null; 126 | } 127 | } 128 | } 129 | 130 | /** 131 | Get a h2d.Tile using given rectangle pixel coords. 132 | **/ 133 | public inline function getFreeTile(x:Int, y:Int, wid:Int, hei:Int) : Null { 134 | var atlas = getAtlasTile(); 135 | return atlas==null ? null : atlas.sub(x,y,wid,hei); 136 | } 137 | 138 | @:deprecated("Use getTile() instead") @:noCompletion 139 | public inline function getHeapsTile(oldAtlasTile:h2d.Tile, tileId:Int, flipBits:Int=0) { 140 | return getTile(tileId, flipBits); 141 | } 142 | 143 | 144 | /** Get a h2d.Tile from a Auto-Layer tile. **/ 145 | public inline function getAutoLayerTile(autoLayerTile:ldtk.Layer_AutoLayer.AutoTile) : Null { 146 | if( autoLayerTile.tileId<0 ) 147 | return null; 148 | else 149 | return getTile(autoLayerTile.tileId, autoLayerTile.flips); 150 | } 151 | 152 | @:deprecated("Use getAutoLayerTile() instead") @:noCompletion 153 | public inline function getAutoLayerHeapsTile(oldAtlasTile:h2d.Tile, autoLayerTile:ldtk.Layer_AutoLayer.AutoTile) { 154 | return getAutoLayerTile(autoLayerTile); 155 | } 156 | 157 | #end // End of Heaps API 158 | 159 | 160 | 161 | 162 | /*************************************************************************** 163 | Flixel API 164 | ***************************************************************************/ 165 | 166 | #if( !macro && flixel ) 167 | 168 | var _tileFrames: Null< flixel.graphics.frames.FlxTileFrames >; 169 | var _atlas: Null< flixel.graphics.FlxGraphic >; 170 | 171 | /** Read Atlas and cache it locally **/ 172 | function readAtlas() { 173 | if( _tileFrames==null ) { 174 | _atlas = untypedProject.getFlxGraphicAsset(relPath); 175 | _tileFrames = flixel.graphics.frames.FlxTileFrames.fromBitmapAddSpacesAndBorders( 176 | _atlas, 177 | flixel.math.FlxPoint.weak( tileGridSize, tileGridSize ) 178 | ); 179 | } 180 | } 181 | 182 | /** Get the main tileset FlxTileFrames **/ 183 | public inline function getTileFrames() : flixel.graphics.frames.FlxTileFrames { 184 | readAtlas(); 185 | return _tileFrames; 186 | } 187 | 188 | /** Get the main tileset FlxGraphic **/ 189 | public inline function getAtlasGraphic() : flixel.graphics.FlxGraphic { 190 | readAtlas(); 191 | return _atlas; 192 | } 193 | 194 | /** Get a FlxFrame using its ID **/ 195 | public inline function getFrame(tileId:Int) : flixel.graphics.frames.FlxFrame { 196 | return getTileFrames().getByIndex(tileId); 197 | } 198 | 199 | #end // End of Flixel API 200 | } 201 | -------------------------------------------------------------------------------- /src/ldtk/World.hx: -------------------------------------------------------------------------------- 1 | package ldtk; 2 | 3 | import ldtk.Json; 4 | 5 | class World { 6 | #if !macro 7 | 8 | var untypedProject: ldtk.Project; // WARNING: the var type isn't the "complete" project type as generated by macros! 9 | var json : ldtk.Json.WorldJson; 10 | var _untypedLevels : Array; 11 | 12 | /** Index in project `worlds` array **/ 13 | public var arrayIndex(default,null) : Int; 14 | public var identifier(default,null) : String; 15 | public var iid(default,null) : String; 16 | 17 | public var layout: WorldLayout; 18 | public var gridWid : Int; 19 | public var gridHei : Int; 20 | 21 | 22 | 23 | public function new(project:Project, arrayIdx:Int, json:ldtk.Json.WorldJson) { 24 | this.untypedProject = project; 25 | this.arrayIndex = arrayIdx; 26 | if( json!=null ) 27 | fromJson(json); 28 | } 29 | 30 | @:keep public function toString() { 31 | return 'ldtk.World[$identifier, $layout, ${_untypedLevels.length} levels]'; 32 | } 33 | 34 | function fromJson(untypedJson:Dynamic) { 35 | this.json = untypedJson; 36 | iid = json.iid; 37 | identifier = json.identifier; 38 | layout = WorldLayout.createByName( Std.string(untypedJson.worldLayout) ); 39 | gridWid = json.worldGridWidth; 40 | gridHei = json.worldGridHeight; 41 | 42 | 43 | // Populate levels 44 | _untypedLevels = []; 45 | var idx = 0; 46 | for(json in json.levels) 47 | _untypedLevels.push( _instanciateLevel(untypedProject, idx++, json) ); 48 | } 49 | 50 | 51 | function _instanciateLevel(project:ldtk.Project, arrayIndex:Int, json:ldtk.Json.LevelJson) { 52 | return null; // overriden by Macros.hx 53 | } 54 | 55 | #end 56 | 57 | 58 | @:allow(ldtk.macro.TypeBuilder, ldtk.Project) 59 | static function createDummyJson(projectJson:ProjectJson) : WorldJson { 60 | var untypedJson : Dynamic = projectJson; 61 | return { 62 | iid: "Default_iid", 63 | identifier: "Default", 64 | 65 | worldLayout: WorldLayout.createByName( Std.string(untypedJson.worldLayout) ), 66 | worldGridWidth: projectJson.worldGridWidth, 67 | worldGridHeight: projectJson.worldGridHeight, 68 | 69 | defaultLevelWidth: projectJson.defaultLevelWidth, 70 | defaultLevelHeight: projectJson.defaultLevelHeight, 71 | levels: projectJson.levels, 72 | 73 | } 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/ProjectNoPackage.hx: -------------------------------------------------------------------------------- 1 | private typedef _Tmp = haxe.macro.MacroType<[ 2 | ldtk.Project.build("samples/_assets/unitTest.ldtk") 3 | ]>; -------------------------------------------------------------------------------- /tests/Tests.hx: -------------------------------------------------------------------------------- 1 | import dn.CiAssert; 2 | import ExternEnumTest; 3 | import ExternCastleDbTest; 4 | import ProjectNoPackage; 5 | 6 | class Tests { 7 | 8 | static function exit(code=0) { 9 | #if hxnodejs 10 | js.node.Require.require("process").exit(code); 11 | #elseif js 12 | // unsupported 13 | #else 14 | Sys.exit(code); 15 | #end 16 | } 17 | 18 | static inline function section(v:String) { 19 | if( CiAssert.VERBOSE ) { 20 | print(""); 21 | print(v); 22 | } 23 | } 24 | 25 | static function print(v:Dynamic) { 26 | #if js 27 | js.html.Console.log( Std.string(v) ); 28 | #else 29 | Sys.println( Std.string(v) ); 30 | #end 31 | } 32 | 33 | 34 | static function main() { 35 | // Init 36 | #if hl 37 | hxd.Res.initLocal(); 38 | #else 39 | hxd.Res.initEmbed(); 40 | #end 41 | 42 | // Load castle DB 43 | ExternCastleDbTest.load( hxd.Res.sample_cdb.entry.getText() ); 44 | 45 | // Check args 46 | CiAssert.VERBOSE = false; 47 | for( a in Sys.args() ) 48 | if( a=="-v" ) 49 | CiAssert.VERBOSE = true; 50 | 51 | print("Running tests..."); 52 | 53 | // Run tests 54 | var project = new ProjectNoPackage(); 55 | 56 | try { 57 | section("PROJECT (NO PACKAGE)..."); 58 | 59 | section("Project..."); 60 | CiAssert.isNotNull( project ); 61 | 62 | // Project asset loader 63 | CiAssert.isNotNull( project.getAsset("unitTest.ldtk") ); 64 | 65 | // Project defs 66 | CiAssert.isNotNull( project.defs ); 67 | CiAssert.isNotNull( project.defs.entities ); 68 | CiAssert.isNotNull( project.defs.enums ); 69 | CiAssert.isNotNull( project.defs.externalEnums ); 70 | CiAssert.isNotNull( project.defs.layers ); 71 | CiAssert.isNotNull( project.defs.tilesets ); 72 | 73 | var defaultWorld = project.all_worlds.World1; 74 | CiAssert.equals( defaultWorld.layout, ldtk.Json.WorldLayout.GridVania ); 75 | CiAssert.isTrue( project.defs.entities.length>0 ); 76 | CiAssert.isTrue( project.defs.enums.length>0 ); 77 | CiAssert.isTrue( project.defs.externalEnums.length>0 ); 78 | CiAssert.isTrue( project.defs.layers.length>0 ); 79 | CiAssert.isTrue( project.defs.tilesets.length>0 ); 80 | 81 | CiAssert.isNotNull( project.getLayerDefJson("IntGrid_AutoLayer") ); 82 | CiAssert.isNotNull( project.getEntityDefJson("Hero") ); 83 | CiAssert.isNotNull( project.getEnumDefJson("Weapons") ); 84 | CiAssert.isNotNull( project.getEnumDefJson("lowercase_enum") ); 85 | CiAssert.isNotNull( project.getTilesetDefJson("Minecraft_texture_pack") ); 86 | 87 | CiAssert.equals( project.getEnumDefFromValue(Trash).identifier, "Mobs" ); 88 | CiAssert.equals( project.getEnumDefFromValue(LongBow).identifier, "Weapons" ); 89 | CiAssert.equals( project.getEnumDefFromValue(Lc_a).identifier, "lowercase_enum" ); 90 | CiAssert.equals( project.getEnumDefFromValue(Ammo).identifier, "DroppedItemType" ); // extern 91 | CiAssert.equals( project.getEnumDefFromValue(Foo).identifier, "SomeEnum" ); // extern 92 | CiAssert.equals( project.getEnumDefFromValue(null), null ); 93 | 94 | // Original JSON fields 95 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.json ); 96 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_IntGrid8.json ); 97 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_EntityTest.all_Mob[0].json ); 98 | CiAssert.isNotNull( project.all_tilesets.Cavernas_by_Adam_Saltsman.json ); 99 | 100 | // Types 101 | section("Types..."); 102 | CiAssert.isNotNull( ProjectNoPackage.Enum_Mobs ); 103 | CiAssert.isNotNull( ProjectNoPackage.ProjectNoPackage_EntityEnum ); 104 | CiAssert.isNotNull( ProjectNoPackage.Tileset_Cavernas_by_Adam_Saltsman ); 105 | 106 | // Levels 107 | section("Levels..."); 108 | CiAssert.isNotNull( defaultWorld.all_levels ); 109 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests ); 110 | CiAssert.isNotNull( defaultWorld.all_levels.Offset_tests ); 111 | CiAssert.isNotNull( defaultWorld.getLevel("Main_tests") ); 112 | CiAssert.equals( defaultWorld.getLevel("Main_tests"), defaultWorld.all_levels.Main_tests ); 113 | CiAssert.equals( defaultWorld.getLevel(0), defaultWorld.all_levels.Main_tests ); 114 | CiAssert.isTrue( defaultWorld.levels.length>0 ); 115 | CiAssert.isNotNull( defaultWorld.levels[0].l_IntGridTest ); 116 | CiAssert.equals( defaultWorld.levels[1].worldX, 512 ); 117 | CiAssert.equals( defaultWorld.levels[1].worldY, 256 ); 118 | CiAssert.equals( defaultWorld.levels[0].bgColor_hex, "#271E27" ); 119 | CiAssert.equals( defaultWorld.levels[0].bgColor_int, 0x271E27 ); 120 | CiAssert.equals( defaultWorld.levels[0].neighbours.length, 2 ); 121 | CiAssert.equals( defaultWorld.levels[0].neighbours[0].dir, ldtk.Level.NeighbourDir.East ); 122 | CiAssert.equals( defaultWorld.getLevelAt(10,10), defaultWorld.all_levels.Main_tests ); 123 | CiAssert.equals( defaultWorld.getLevelAt(600,400), defaultWorld.all_levels.Offset_tests ); 124 | 125 | // Layer misc 126 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_IntGridTest.visible, true ); 127 | 128 | // Layer JSONs 129 | var layer = defaultWorld.all_levels.Main_tests.l_EntityTest; 130 | CiAssert.isNotNull(layer.json); 131 | CiAssert.isNotNull(layer.json.entityInstances); 132 | CiAssert.isNotNull(layer.defJson); 133 | CiAssert.equals(layer.json.layerDefUid, layer.defJson.uid); 134 | CiAssert.equals(layer.defJson.identifier, "EntityTest"); 135 | 136 | 137 | // Layer offsets 138 | CiAssert.equals( defaultWorld.all_levels.Offset_tests.l_IntGrid8.pxTotalOffsetX, 4 ); 139 | CiAssert.equals( defaultWorld.all_levels.Offset_tests.l_IntGrid8.pxTotalOffsetY, 4 ); 140 | CiAssert.equals( defaultWorld.all_levels.Offset_tests.l_IntGridTest.pxTotalOffsetX, 8 ); 141 | CiAssert.equals( defaultWorld.all_levels.Offset_tests.l_IntGridTest.pxTotalOffsetY, 8 ); 142 | CiAssert.equals( defaultWorld.all_levels.Offset_tests.l_EntityTest.all_OffsetTest[0].pixelX, 0 ); 143 | CiAssert.equals( defaultWorld.all_levels.Offset_tests.l_EntityTest.all_OffsetTest[0].pixelY, 0 ); 144 | 145 | 146 | // IntGrid layer 147 | section("IntGrid..."); 148 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_IntGridTest ); 149 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_IntGridTest.type, ldtk.Json.LayerType.IntGrid ); 150 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGridTest.type==IntGrid ); 151 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGridTest.getInt(0,0)==1 ); 152 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGridTest.hasValue(0,0) ); 153 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGridTest.getName(0,0)=="a" ); 154 | 155 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGridTest.getInt(1,0)==2 ); 156 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGridTest.getInt(2,0)==3 ); 157 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGridTest.getInt(3,0)==4 ); 158 | 159 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_IntGridTest.hasValue(0,1), false ); 160 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_IntGridTest.hasValue(3,0, 4), true ); 161 | 162 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_IntGridTest.isCoordValid(0,0), true ); 163 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_IntGridTest.isCoordValid(-1,0), false ); 164 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_IntGridTest.isCoordValid(999,0), false ); 165 | 166 | // Entity layer 167 | section("Entity..."); 168 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_EntityTest); 169 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_EntityTest.type, ldtk.Json.LayerType.Entities ); 170 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_EntityTest.type==Entities ); 171 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_EntityTest.all_Hero.length!=0 ); 172 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_EntityTest.all_Mob.length!=0 ); 173 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_EntityTest.all_AllFields.length!=0 ); 174 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_EntityTest.all_Unused.length, 0 ); 175 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_EntityTest.all_Mob[0].tileInfos ); 176 | 177 | // Entity layer tags 178 | var level = defaultWorld.all_levels.Main_tests; 179 | CiAssert.isNotNull( level.l_EntityWithTag ); 180 | CiAssert.isNotNull( level.l_EntityWithTag.all_Tagged ); 181 | CiAssert.equals( level.l_EntityWithTag.all_Tagged.length, 3 ); 182 | CiAssert.equals( level.l_EntityWithTag.getAllUntyped().length, 3 ); 183 | 184 | // Entities 185 | var hero = defaultWorld.all_levels.Main_tests.l_EntityTest.all_Hero[0]; 186 | var mob = defaultWorld.all_levels.Main_tests.l_EntityTest.all_Mob[0]; 187 | var allFieldsTest = defaultWorld.all_levels.Main_tests.l_EntityTest.all_AllFields[0]; 188 | var fileEnt = defaultWorld.all_levels.Main_tests.l_EntityTest.all_File[0]; 189 | CiAssert.isNotNull( hero ); 190 | CiAssert.isNotNull( mob ); 191 | CiAssert.isNotNull( allFieldsTest ); 192 | CiAssert.isNotNull( fileEnt ); 193 | CiAssert.equals( mob.f_scale, 0.5 ); 194 | CiAssert.equals( hero.width, 16 ); 195 | CiAssert.equals( hero.height, 24 ); 196 | CiAssert.equals( allFieldsTest.width, 32 ); 197 | CiAssert.equals( allFieldsTest.height, 32 ); 198 | CiAssert.equals( allFieldsTest.iid, "f2f3f740-66b0-11ec-91ab-910cd77ba401" ); 199 | CiAssert.equals( allFieldsTest.f_entityRefs.length, 2 ); 200 | CiAssert.equals( allFieldsTest.f_entityRefs[0].entityIid, "57c51ab0-66b0-11ec-8446-f3a61ee63449" ); 201 | CiAssert.equals( allFieldsTest.f_entityRefs[1].entityIid, "58f66ec0-66b0-11ec-8446-9b40d7be219b" ); 202 | 203 | // Entity JSONs 204 | CiAssert.isNotNull(hero.json); 205 | CiAssert.isNotNull(hero.json.fieldInstances); 206 | CiAssert.isNotNull(hero.defJson); 207 | CiAssert.isNotNull(hero.defJson.fieldDefs); 208 | CiAssert.equals(hero.json.defUid, hero.defJson.uid); 209 | CiAssert.equals(hero.defJson.identifier, "Hero"); 210 | 211 | // Extern enums 212 | var extEnt = defaultWorld.all_levels.Main_tests.l_EntityTest.all_ExternEnums[0]; 213 | CiAssert.isNotNull(extEnt); 214 | CiAssert.isNotNull(extEnt.f_cdb); 215 | CiAssert.isNotNull(extEnt.f_haxe); 216 | CiAssert.equals(extEnt.f_cdb, CdbA); 217 | CiAssert.equals(extEnt.f_haxe, SomeEnum.Pouet); 218 | CiAssert.isTrue( 219 | switch extEnt.f_cdb { 220 | case CdbA: true; 221 | case CdbB: false; 222 | case CdbC: false; 223 | } 224 | ); 225 | CiAssert.isTrue(extEnt.f_cdb==ExternCastleDbTest.CdbEnumTestKind.CdbA); 226 | 227 | // Entity tiles 228 | var eTiles = defaultWorld.all_levels.Main_tests.l_EntityTest.all_EntityTiles; 229 | CiAssert.isNotNull( eTiles ); 230 | CiAssert.isTrue( eTiles.length>=2 ); 231 | CiAssert.isNotNull( eTiles[0].tileInfos ); 232 | CiAssert.equals( eTiles[0].tileInfos.tilesetUid, 14 ); 233 | CiAssert.equals( eTiles[0].tileInfos.x, 32 ); 234 | CiAssert.equals( eTiles[0].tileInfos.y, 32 ); 235 | CiAssert.equals( eTiles[1].tileInfos.x, 64 ); 236 | CiAssert.equals( eTiles[1].tileInfos.y, 0 ); 237 | 238 | // Sym ref 1 239 | var fromSymRef = defaultWorld.all_levels.Main_tests.l_EntityTest.all_SymRef[0]; 240 | var toSymRef = defaultWorld.all_levels.Target_level_ref.l_EntityTest.all_SymRef[0]; 241 | CiAssert.equals( fromSymRef.f_ref.entityIid, toSymRef.iid ); 242 | CiAssert.equals( fromSymRef.f_ref.levelIid, defaultWorld.all_levels.Target_level_ref.iid ); 243 | CiAssert.equals( toSymRef.f_ref.entityIid, fromSymRef.iid ); 244 | CiAssert.equals( toSymRef.f_ref.levelIid, defaultWorld.all_levels.Main_tests.iid ); 245 | 246 | // Sym ref 2 247 | var fromSymRef = defaultWorld.all_levels.Main_tests.l_EntityTest.all_SymRef[1]; 248 | var toSymRef = defaultWorld.all_levels.Main_tests.l_EntityTest.all_SymRef[2]; 249 | CiAssert.equals( fromSymRef.f_ref.entityIid, toSymRef.iid ); 250 | CiAssert.equals( fromSymRef.f_ref.levelIid, defaultWorld.all_levels.Main_tests.iid ); 251 | CiAssert.equals( toSymRef.f_ref.entityIid, fromSymRef.iid ); 252 | CiAssert.equals( toSymRef.f_ref.levelIid, defaultWorld.all_levels.Main_tests.iid ); 253 | 254 | // Regions 255 | var r = defaultWorld.all_levels.Main_tests.l_EntityTest.all_Region[0]; 256 | CiAssert.isNotNull(r); 257 | CiAssert.equals(r.width, 64); 258 | CiAssert.equals(r.height, 48); 259 | CiAssert.equals(r.f_flag, true); 260 | 261 | // Enums 262 | section("Enums..."); 263 | CiAssert.isNotNull( Enum_Weapons ); 264 | CiAssert.isNotNull( Enum_lowercase_enum ); 265 | CiAssert.equals( Enum_Weapons.getConstructors()[0], "LongBow" ); 266 | CiAssert.equals( Enum_Weapons.getConstructors()[1], "Torch" ); 267 | CiAssert.equals( hero.f_startWeapon, LongBow ); 268 | CiAssert.equals( mob.f_type, Trash ); 269 | CiAssert.equals( mob.entityType, Mob ); 270 | CiAssert.equals( mob.f_lootDrops[0], ExternEnumTest.DroppedItemType.Ammo ); 271 | CiAssert.equals( mob.f_lootDrops[1], ExternEnumTest.DroppedItemType.Food ); 272 | CiAssert.equals( mob.f_lootDrops[2], ExternEnumTest.DroppedItemType.Gold ); 273 | CiAssert.equals( mob.f_lootDrops[3], ExternEnumTest.DroppedItemType.Key ); 274 | 275 | // Arrays 276 | CiAssert.isNotNull( allFieldsTest.f_ints ); 277 | CiAssert.equals( allFieldsTest.f_ints.length, 3 ); 278 | CiAssert.equals( allFieldsTest.f_ints[0], 0 ); 279 | CiAssert.equals( allFieldsTest.f_ints[1], 1 ); 280 | CiAssert.equals( allFieldsTest.f_ints[2], 2 ); 281 | CiAssert.equals( allFieldsTest.f_strings[0], "a" ); 282 | CiAssert.equals( allFieldsTest.f_floats[1], 0.5 ); 283 | CiAssert.equals( allFieldsTest.f_bools[0], false ); 284 | CiAssert.equals( allFieldsTest.f_bools[2], true ); 285 | CiAssert.equals( allFieldsTest.f_colors_hex[0],"#FF0000" ); 286 | CiAssert.equals( allFieldsTest.f_colors_int[0], 0xff0000 ); 287 | CiAssert.isTrue( allFieldsTest.f_localEnums.length>0 ); 288 | CiAssert.equals( allFieldsTest.f_localEnums[0], FireBall ); 289 | CiAssert.isTrue( allFieldsTest.f_externEnums.length>0 ); 290 | CiAssert.equals( allFieldsTest.f_externEnums[0], Gold ); 291 | CiAssert.equals( allFieldsTest.f_externEnums[1], null ); 292 | CiAssert.equals( allFieldsTest.f_lowercaseEnum[0], Lc_a ); 293 | CiAssert.equals( allFieldsTest.f_lowercaseEnum[1], Lc_b ); 294 | CiAssert.equals( allFieldsTest.f_lowercaseEnum[2], null ); 295 | 296 | // FilePath entity field & loading 297 | CiAssert.isNotNull( fileEnt.f_filePath ); 298 | CiAssert.isNotNull( project.getAsset(fileEnt.f_filePath) ); 299 | CiAssert.isNotNull( fileEnt.f_filePath_bytes ); 300 | CiAssert.isTrue( fileEnt.f_filePath_bytes.length>0 ); 301 | 302 | // Points / paths 303 | section("Points/paths..."); 304 | CiAssert.isTrue( allFieldsTest.f_point.cx==19 ); 305 | CiAssert.isTrue( mob.f_path!=null ); 306 | CiAssert.isTrue( mob.f_path.length>0 ); 307 | CiAssert.isTrue( mob.f_path[0].cy == mob.cy ); 308 | 309 | // Worlds untyped access 310 | for(w in project.worlds) 311 | CiAssert.isTrue( Reflect.hasField(project.all_worlds, w.identifier) ); 312 | CiAssert.isNotNull( project.getWorld(project.all_worlds.World1.iid) ); 313 | CiAssert.isNotNull( project.getWorld(project.all_worlds.World2.iid) ); 314 | CiAssert.equals( project.getWorld(project.all_worlds.World1.iid), project.all_worlds.World1 ); 315 | CiAssert.equals( project.getWorld(project.all_worlds.World2.iid), project.all_worlds.World2 ); 316 | CiAssert.equals( project.worlds[0].layout, ldtk.Json.WorldLayout.GridVania ); 317 | CiAssert.equals( project.worlds[1].layout, ldtk.Json.WorldLayout.Free ); 318 | 319 | // Enum switch check 320 | section("Switch..."); 321 | CiAssert.isTrue( switch defaultWorld.all_levels.Main_tests.l_EntityTest.all_Mob[0].f_lootDrops[0] { 322 | case null: false; 323 | case Ammo: true; 324 | case Food: false; 325 | case Gold: false; 326 | case Key: false; 327 | }); 328 | switch defaultWorld.all_levels.Main_tests.l_EntityTest.all_Mob[0].f_type { 329 | case Trash: 330 | case Shooter: 331 | case Shielder: 332 | } 333 | 334 | // Level custom fields 335 | CiAssert.equals( defaultWorld.all_levels.Main_tests.f_level_int, 1 ); 336 | CiAssert.equals( defaultWorld.all_levels.Main_tests.f_level_string, "my string value" ); 337 | CiAssert.equals( defaultWorld.all_levels.Main_tests.f_level_reward, Ammo ); 338 | CiAssert.equals( defaultWorld.all_levels.Offset_tests.f_level_int, 2 ); 339 | CiAssert.equals( defaultWorld.all_levels.Offset_tests.f_level_reward, Key ); 340 | CiAssert.equals( defaultWorld.all_levels.Main_tests.f_lowercase_enum[0], Lc_a ); 341 | CiAssert.equals( defaultWorld.all_levels.Main_tests.f_lowercase_enum[1], Lc_b ); 342 | CiAssert.equals( defaultWorld.all_levels.Main_tests.f_lowercase_enum.length, 2 ); 343 | CiAssert.equals( defaultWorld.all_levels.Main_tests.f_lowercase_enum[2], null ); 344 | 345 | // Tile layer 346 | section("Tile layer..."); 347 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_TileTest ); 348 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_TileTest.type, ldtk.Json.LayerType.Tiles ); 349 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.resolveLayer("TileTest") ); 350 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.identifier=="TileTest" ); 351 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.type==Tiles ); 352 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.hasAnyTileAt(4,0) ); 353 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_TileTest.getTileStackAt(4,0)[0].tileId, 0 ); 354 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.hasAnyTileAt(5,0) ); 355 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_TileTest.getTileStackAt(5,0)[0].tileId, 1 ); 356 | 357 | 358 | // Tilesets 359 | section("Tilesets..."); 360 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_TileTest.tileset ); 361 | // CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.atlasBytes ); 362 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.getTileStackAt(1,4)[0].tileId>=0 ); 363 | var gridSize = defaultWorld.all_levels.Main_tests.l_TileTest.tileset.tileGridSize; 364 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.getAtlasX(1)==gridSize ); 365 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.getAtlasY(1)==0 ); 366 | 367 | // Tilesets enum tags 368 | CiAssert.isNotNull( project.all_tilesets.Minecraft_texture_pack ); 369 | CiAssert.isNotNull( project.all_tilesets.Minecraft_texture_pack.hasTag ); 370 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_TileTest.tileset ); 371 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.hasTag ); 372 | CiAssert.isTrue( project.all_tilesets.Minecraft_texture_pack.hasTag(0,Grass) ); 373 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.hasTag(0,Grass) ); 374 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.hasTag(1,Stone) ); 375 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.hasTag(3,Grass) ); 376 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.hasTag(3,Dirt) ); 377 | CiAssert.isFalse( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.hasTag(1,Grass) ); 378 | CiAssert.isFalse( defaultWorld.all_levels.Main_tests.l_TileTest.tileset.hasTag(4,Grass) ); 379 | 380 | CiAssert.isNotNull( project.all_tilesets.Cavernas_by_Adam_Saltsman ); 381 | CiAssert.isNotNull( project.all_tilesets.Cavernas_by_Adam_Saltsman.hasTag ); 382 | CiAssert.isTrue( project.all_tilesets.Cavernas_by_Adam_Saltsman.hasTag(0,Lc_a) ); 383 | CiAssert.isTrue( project.all_tilesets.Cavernas_by_Adam_Saltsman.hasTag(1,Lc_b) ); 384 | CiAssert.isTrue( project.all_tilesets.Cavernas_by_Adam_Saltsman.hasTag(2,Lc_c) ); 385 | CiAssert.isTrue( project.all_tilesets.Cavernas_by_Adam_Saltsman.hasTag(3,Lc_d) ); 386 | CiAssert.isFalse( project.all_tilesets.Cavernas_by_Adam_Saltsman.hasTag(1,Lc_a) ); 387 | CiAssert.isFalse( project.all_tilesets.Cavernas_by_Adam_Saltsman.hasTag(4,Lc_a) ); 388 | 389 | 390 | // Auto-layer (IntGrid) 391 | section("Auto-Layer (IntGrid)..."); 392 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_IntGrid_AutoLayer ); 393 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_IntGrid_AutoLayer.tileset ); 394 | // CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_IntGrid_AutoLayer.tileset.atlasBytes ); 395 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGrid_AutoLayer.autoTiles.length>100 ); 396 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_IntGrid_AutoLayer.autoTiles[0] ); 397 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_IntGrid_AutoLayer.autoTiles[0].renderX!=0 ); 398 | 399 | // Auto-layer (pure) 400 | section("Auto-Layer (pure)..."); 401 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_Pure_AutoLayer); 402 | // CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_Pure_AutoLayer.tileset.atlasBytes ); 403 | CiAssert.equals( defaultWorld.all_levels.Main_tests.l_Pure_AutoLayer.type, ldtk.Json.LayerType.AutoLayer ); 404 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_Pure_AutoLayer.tileset ); 405 | 406 | // Project references 407 | section("Project refs..."); 408 | var level = defaultWorld.all_levels.Main_tests; 409 | @:privateAccess CiAssert.equals( level.untypedProject, project ); 410 | @:privateAccess CiAssert.equals( level.l_EntityTest.untypedProject, project ); 411 | @:privateAccess CiAssert.equals( level.l_IntGrid_AutoLayer.tileset.untypedProject, project ); 412 | 413 | 414 | // Level background image 415 | CiAssert.isTrue( defaultWorld.all_levels.Offset_tests.bgImageInfos==null ); 416 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.bgImageInfos ); 417 | CiAssert.equals( defaultWorld.all_levels.Main_tests.bgImageInfos.topLeftX, 0 ); 418 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.bgImageInfos.cropRect ); 419 | 420 | 421 | // Project in a package 422 | section("PROJECT (WITH PACKAGE)..."); 423 | 424 | var project = new packageTest.ProjectPackage(); 425 | CiAssert.isNotNull( project ); 426 | CiAssert.isNotNull( packageTest.ProjectPackage.Enum_Mobs ); 427 | CiAssert.isNotNull( packageTest.ProjectPackage.ProjectPackage_EntityEnum ); 428 | CiAssert.isNotNull( packageTest.ProjectPackage.Enum_Weapons ); 429 | CiAssert.isNotNull( packageTest.ProjectPackage.Tileset_Cavernas_by_Adam_Saltsman ); 430 | CiAssert.isNotNull( defaultWorld.all_levels ); 431 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.load() ); 432 | CiAssert.isTrue( defaultWorld.all_levels.Offset_tests.load() ); 433 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests ); 434 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_EntityTest.all_Mob.length>0 ); 435 | CiAssert.isNotNull( defaultWorld.all_levels.Main_tests.l_EntityTest.all_Mob[0].f_lootDrops ); 436 | CiAssert.isTrue( defaultWorld.all_levels.Main_tests.l_EntityTest.all_Hero[0].f_startWeapon == Enum_Weapons.LongBow ); 437 | 438 | // Table of content 439 | CiAssert.isNotNull( project.toc ); 440 | CiAssert.isNotNull( project.toc.Hero ); 441 | CiAssert.isTrue( project.toc.Hero.length>0 ); 442 | CiAssert.equals( project.toc.Hero[0].iids.entityIid, "f2f3d032-66b0-11ec-91ab-159ce9d99f47" ); 443 | CiAssert.isNotNull( project.toc.Hero[0].fields ); 444 | CiAssert.isNotNull( project.toc.Hero[0].fields.startWeapon ); 445 | CiAssert.equals( project.toc.Hero[0].fields.startWeapon, "LongBow" ); 446 | CiAssert.isNotNull( project.toc.Mob ); 447 | CiAssert.isTrue( project.toc.Mob.length>0 ); 448 | 449 | 450 | var world = project.all_worlds.World1; 451 | 452 | // 1.4.0 453 | var l = world.all_levels.v1_4_0; 454 | CiAssert.isNotNull(l); 455 | var e = l.l_EntityTest.all_Hero[0]; 456 | CiAssert.isNotNull(e); 457 | CiAssert.equals(e.pixelX, 40); 458 | CiAssert.equals(e.pixelY, 96); 459 | CiAssert.equals(e.worldPixelX, l.worldX+e.pixelX); 460 | CiAssert.equals(e.worldPixelY, l.worldY+e.pixelY); 461 | CiAssert.equals(l.neighbours.length, 1); 462 | CiAssert.equals(l.neighbours[0].dir, ldtk.Level.NeighbourDir.DepthBelow); 463 | } 464 | catch( e:Dynamic ) { 465 | // Unknown errors 466 | print("Exception: "+e); 467 | print(""); 468 | exit(1); 469 | return; 470 | } 471 | 472 | if( CiAssert.VERBOSE ) 473 | print(""); 474 | print("Success."); 475 | exit(0); 476 | } 477 | } 478 | 479 | -------------------------------------------------------------------------------- /tests/_base.hxml: -------------------------------------------------------------------------------- 1 | -cp tests 2 | -cp samples/_srcCommon 3 | -cp src 4 | 5 | -lib castle 6 | -D ldtkCastle=ExternCastleDbTest 7 | 8 | -lib deepnightLibs 9 | -lib heaps 10 | -D resourcesPath=samples/_assets 11 | 12 | # -D ldtk_times 13 | # -D dump=pretty 14 | --dce full 15 | -debug 16 | 17 | -main Tests 18 | -------------------------------------------------------------------------------- /tests/hl.hxml: -------------------------------------------------------------------------------- 1 | tests/_base.hxml 2 | -hl tests/bin/test.hl 3 | --cmd hl tests/bin/test.hl -v -------------------------------------------------------------------------------- /tests/js.hxml: -------------------------------------------------------------------------------- 1 | tests/_base.hxml 2 | -js tests/bin/test.js 3 | -lib hxnodejs 4 | --cmd node tests/bin/test.js -v -------------------------------------------------------------------------------- /tests/lab/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/settings.json -------------------------------------------------------------------------------- /tests/lab/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "HL debug", 9 | "request": "launch", 10 | "type": "hl", 11 | "hxml": "hl.hxml", 12 | "cwd": "${workspaceRoot}", 13 | "preLaunchTask": "HL debug" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /tests/lab/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "HL debug", 8 | "type": "hxml", 9 | "file": "hl.hxml", 10 | "presentation": { 11 | "reveal": "never", 12 | "panel": "dedicated", 13 | "clear": true 14 | }, 15 | "problemMatcher": ["$haxe"], 16 | "group": { 17 | "kind": "build", 18 | "isDefault": true 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /tests/lab/README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | This project is meant to test latest LDtk features in a minimal Heaps environment. -------------------------------------------------------------------------------- /tests/lab/hl.hxml: -------------------------------------------------------------------------------- 1 | -cp src 2 | -main Boot 3 | -dce full 4 | -debug 5 | 6 | -lib heaps 7 | -lib hldx 8 | -lib deepnightLibs 9 | -lib ldtk-haxe-api 10 | 11 | -D windowSize=1024x768 12 | -hl bin/client.hl -------------------------------------------------------------------------------- /tests/lab/res/Cavernas_by_Adam_Saltsman-Extended.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepnight/ldtk-haxe-api/22d7ee209b7a9f5775d53407253ec9432fc588db/tests/lab/res/Cavernas_by_Adam_Saltsman-Extended.png -------------------------------------------------------------------------------- /tests/lab/src/Boot.hx: -------------------------------------------------------------------------------- 1 | class Boot extends hxd.App { 2 | public static var ME : Boot; 3 | 4 | // Boot 5 | static function main() new Boot(); 6 | 7 | // Engine ready 8 | override function init() { 9 | ME = this; 10 | 11 | hxd.Res.initEmbed(); 12 | 13 | #if deepnightLibs 14 | new Main(); 15 | #end 16 | } 17 | 18 | override function onResize() { 19 | super.onResize(); 20 | 21 | #if deepnightLibs 22 | dn.Process.resizeAll(); 23 | #end 24 | } 25 | 26 | override function update(deltaTime:Float) { 27 | super.update(deltaTime); 28 | #if deepnightLibs 29 | dn.Process.updateAll(hxd.Timer.tmod); 30 | #end 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /tests/lab/src/LdtkProject.hx: -------------------------------------------------------------------------------- 1 | private typedef _Tmp = 2 | haxe.macro.MacroType<[ ldtk.Project.build("res/apiLab.ldtk") ]>; -------------------------------------------------------------------------------- /tests/lab/src/Main.hx: -------------------------------------------------------------------------------- 1 | import dn.*; 2 | import LdtkProject; 3 | 4 | class Main extends dn.Process { 5 | var bmp : h2d.Bitmap; 6 | var p : LdtkProject; 7 | var level : LdtkProject_Level; 8 | 9 | public function new() { 10 | super(); 11 | 12 | createRoot(Boot.ME.s2d); 13 | 14 | p = new LdtkProject(); 15 | level = p.all_levels.World_Level_0; 16 | 17 | // Render 18 | root.addChild( level.l_Collisions.render() ); 19 | 20 | // Level tile field 21 | var t = level.f_levelTile_getTile(); 22 | if( t!=null ) 23 | new h2d.Bitmap(t, root); 24 | 25 | // Entity tiles 26 | for(e in level.l_Entities.all_TilesTest) { 27 | var bmp = new h2d.Bitmap(e.getTile(), root); 28 | bmp.setPosition( e.pixelX, e.pixelY ); 29 | } 30 | 31 | // Refs 32 | for(e in level.l_Entities.all_RefSource) 33 | trace(e.f_name+" => "+(e.f_target!=null ? e.f_target.entityIid : null)); 34 | 35 | Process.resizeAll(); 36 | } 37 | 38 | override function onResize() { 39 | super.onResize(); 40 | 41 | root.setScale( dn.heaps.Scaler.bestFit_i(level.pxWid, level.pxHei) ); 42 | } 43 | 44 | override function update() { 45 | super.update(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/packageTest/ProjectPackage.hx: -------------------------------------------------------------------------------- 1 | package packageTest; 2 | 3 | private typedef _Tmp = haxe.macro.MacroType<[ 4 | ldtk.Project.build("samples/_assets/unitTest.ldtk") 5 | ]>; -------------------------------------------------------------------------------- /tidy.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo Samples... 4 | del samples\index.html /s 2>nul 5 | del samples\build.hxml /s 2>nul 6 | del samples\*.hl /s 2>nul 7 | del samples\*.js /s 2>nul 8 | del samples\buildAll.hxml 2>nul 9 | 10 | echo Dump... 11 | rmdir /Q/S dump 2>nul 12 | 13 | echo Done. 14 | echo. 15 | pause --------------------------------------------------------------------------------