Metadata-Version: 2.4
Name: panda3d-tmx
Version: 0.0.0
Summary: Tiled TMX parser for the Panda3D game engine
License: The MIT License (MIT)
        
        Copyright (c) 2026 Digital Descent, LLC
        Copyright (c) 2025 Yonnji.
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
        
Project-URL: Homepage, https://github.com/DigitalDescent/panda3d-tmx
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Games/Entertainment
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: panda3d
Requires-Dist: panda3d-vfs
Requires-Dist: panda3d-toolbox
Requires-Dist: pytiled-parser
Dynamic: license-file

# panda3d-tmx

A lightweight [Tiled Map Editor](https://www.mapeditor.org/) integration for the [Panda3D](https://www.panda3d.org/) game engine. Load TMX and JSON map files and render them as optimized Panda3D scene graphs with minimal setup.

> panda3d-tmx is based on the [panda3d-tiled](https://github.com/kitsune-ONE-team/panda3d-tiled) project by the Kitsune One team.

## Features

- **TMX & JSON map loading** via [pytiled-parser](https://github.com/Beefy-Swain/pytiled_parser)
- **Tile layers** rendered as atlas-textured cards, flattened into a single draw call per layer
- **Image layers** displayed as full-image sprites with transparency support
- **Object layers** with points, rectangles, polygons, and ellipses extracted as data
- **Layer groups** with recursive processing and proper draw ordering via fixed cull bins
- **Object registry** — map Tiled class names to factory functions for automatic game-object instantiation
- **Per-layer configuration** for scaling, offsets, custom sprite classes, and hit-box algorithms
- **Pixel-art friendly** — nearest-neighbor filtering applied by default

## Installation

```bash
pip install panda3d-tmx
```

### Dependencies

- [panda3d](https://pypi.org/project/panda3d/)
- [panda3d-vfs](https://pypi.org/project/panda3d-vfs/)
- [panda3d-toolbox](https://pypi.org/project/panda3d-toolbox/)
- [pytiled-parser](https://pypi.org/project/pytiled-parser/)

## Quick Start

```python
from pathlib import Path

from direct.showbase.ShowBase import ShowBase
from panda3d.core import Filename, get_model_path, loadPrcFileData

# Prevent Panda3D from rescaling non-power-of-2 tile atlases
loadPrcFileData("", "textures-power-2 none")

from panda3d_tmx.tilemap import TileMap


class Game(ShowBase):
    def __init__(self):
        super().__init__()

        map_dir = Path(__file__).resolve().parent
        get_model_path().prepend_directory(
            Filename.from_os_specific(str(map_dir))
        )

        self.tile_map = TileMap(map_file=map_dir / "level.tmx", scaling=1.0)
        self.tile_map.reparent_to(self.render)


app = Game()
app.run()
```

## Object Registry

Use `ObjectRegistry` to automatically instantiate your own game objects from Tiled's **class** field:

```python
from panda3d_tmx.tilemap import TileMap
from panda3d_tmx.objects import ObjectRegistry, TiledObject


class SpawnPoint:
    def __init__(self, tiled_object: TiledObject) -> None:
        self.x, self.y = tiled_object.shape[0], tiled_object.shape[1]
        self.facing = (tiled_object.properties or {}).get("facing", "north")


registry = ObjectRegistry()
registry.register("SpawnPoint", SpawnPoint)

tile_map = TileMap(map_file="level.tmx", object_registry=registry)

# Access created instances by layer name
for layer_name, instances in tile_map.object_instances.items():
    for inst in instances:
        print(inst)
```

## Layer Options

Per-layer settings can be passed via the `layer_options` dict:

```python
tile_map = TileMap(
    map_file="level.tmx",
    layer_options={
        "Platforms": {
            "use_spatial_hash": True,
            "scaling": 2.5,
            "offset": (-128, 64),
            "custom_class": MyPlatformSprite,
            "custom_class_args": {"health": 100},
        },
    },
)
```

Available options per layer:

| Option | Type | Description |
|---|---|---|
| `scaling` | `float` | Layer-specific sprite scaling |
| `offset` | `tuple[float, float]` | X/Y position offset for the layer |
| `use_spatial_hash` | `bool` | Enable spatial hashing for faster collision checks |
| `hit_box_algorithm` | `HitBoxAlgorithm` | Hit-box algorithm for sprites in this layer |
| `custom_class` | `type` | Custom `TileSprite` subclass for all tiles in the layer |
| `custom_class_args` | `dict` | Extra keyword arguments passed to the custom class constructor |
| `object_registry` | `ObjectRegistry` | Per-layer object registry, overriding the map-level one |

## API Overview

### `TileMap`

The main entry point. Loads a Tiled map and builds the scene graph.

| Attribute | Type | Description |
|---|---|---|
| `sprite_lists` | `dict[str, NodeGroup]` | Tile layer sprites keyed by layer path |
| `object_lists` | `dict[str, list[TiledObject]]` | Object layer data keyed by layer path |
| `object_instances` | `dict[str, list]` | Factory-created game objects keyed by layer path |

| Method | Description |
|---|---|
| `reparent_to(parent)` | Attach the map's root node to a Panda3D `NodePath` |
| `get_cartesian(row, col)` | Convert tile coordinates to pixel coordinates |
| `get_tilemap_layer(path)` | Retrieve a `NodeGroup` by layer path |

### `TiledObject`

A `NamedTuple` containing data for a single Tiled object:

| Field | Type | Description |
|---|---|---|
| `shape` | `tuple[int, int, int, int]` | Bounding box `(x, y, width, height)` |
| `properties` | `Properties \| None` | Custom properties from Tiled |
| `name` | `str \| None` | Object name |
| `type` | `str \| None` | Object class/type |
| `sprite` | `TileSprite \| None` | Associated sprite for tile-based objects |

### `TileSprite`

A lightweight sprite backed by an atlas-textured card. Supports position, size, rotation, and custom properties.

### `NodeGroup`

A group of nodes that can be flattened into a single draw call via `flatten()`.

## Examples

Working examples are in the [`example/`](example/) directory:

- **[basic-01](example/basic-01/)** — Load and display a desert tilemap with camera panning and zoom
- **[objects-02](example/objects-02/)** — Use `ObjectRegistry` to auto-create game objects from Tiled class types

## Requirements

- Python >= 3.9
- Panda3D
- Orthogonal maps only (isometric/hexagonal not supported)
- Infinite maps are not supported

## License

[MIT](LICENSE) — Copyright (c) 2026 Digital Descent, LLC / Copyright (c) 2025 Yonnji.
