Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ jobs:
if: ${{ matrix.dependencies != 'null' }}
run: pip install ${{ matrix.dependencies }}
- name: Run Tests
run: python -m unittest tests/pytmx/test_pytmx.py
run: python -m unittest discover -s tests/pytmx -p "test_*.py"
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
PACKAGE_NAME := pytmx

.PHONY: build clean publish install lint test

build:
python3 -m build

clean:
rm -rf dist/ *.egg-info

publish: build
python3 -m twine upload dist/*

install:
pip install -e .

lint:
black $(PACKAGE_NAME)/
isort $(PACKAGE_NAME)/

test:
pytest tests/
70 changes: 43 additions & 27 deletions apps/benchmark.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
This is tested on pygame 1.9 and python 2.7 and 3.3+.
Leif Theden "bitcraft", 2012-2024
Leif Theden "bitcraft", 2012-2025

Rendering demo for the TMXLoader.

Expand All @@ -14,7 +14,9 @@
- object rotation
- terrains
"""

import logging
from pathlib import Path

import pygame
from pygame.locals import *
Expand All @@ -29,20 +31,20 @@
logger.setLevel(logging.INFO)


def init_screen(width, height):
def init_screen(width: int, height: int) -> pygame.Surface:
"""Set the screen mode
This function is used to handle window resize events
"""
return pygame.display.set_mode((width, height), pygame.RESIZABLE)


class TiledRenderer(object):
class TiledRenderer:
"""
Super simple way to render a tiled map
"""

def __init__(self, filename) -> None:
tm = load_pygame(filename)
def __init__(self, filename: Path) -> None:
tm = load_pygame(filename.as_posix())

# self.size will be the pixel size of the map
# this value is used later to render the entire map to a pygame surface
Expand All @@ -55,7 +57,7 @@ def __init__(self, filename) -> None:
print(i)
continue

def render_map(self, surface) -> None:
def render_map(self, surface: pygame.Surface) -> None:
"""Render our map to a pygame surface

Feel free to use this as a starting point for your pygame app.
Expand Down Expand Up @@ -84,7 +86,7 @@ def render_map(self, surface) -> None:
elif isinstance(layer, TiledImageLayer):
self.render_image_layer(surface, layer)

def render_tile_layer(self, surface, layer) -> None:
def render_tile_layer(self, surface: pygame.Surface, layer: TiledTileLayer) -> None:
"""Render all TiledTiles in this layer"""
# deref these heavily used references for speed
tw = self.tmx_data.tilewidth
Expand All @@ -95,7 +97,9 @@ def render_tile_layer(self, surface, layer) -> None:
for x, y, image in layer.tiles():
surface_blit(image, (x * tw, y * th))

def render_object_layer(self, surface, layer) -> None:
def render_object_layer(
self, surface: pygame.Surface, layer: TiledObjectGroup
) -> None:
"""Render all TiledObjects contained in this layer"""
# deref these heavily used references for speed
draw_rect = pygame.draw.rect
Expand Down Expand Up @@ -125,26 +129,28 @@ def render_object_layer(self, surface, layer) -> None:
else:
draw_rect(surface, rect_color, (obj.x, obj.y, obj.width, obj.height), 3)

def render_image_layer(self, surface, layer) -> None:
def render_image_layer(
self, surface: pygame.Surface, layer: TiledImageLayer
) -> None:
if layer.image:
surface.blit(layer.image, (0, 0))


class SimpleTest(object):
class SimpleTest:
"""Basic app to display a rendered Tiled map"""

def __init__(self, filename) -> None:
def __init__(self, filename: Path) -> None:
self.renderer = None
self.running = False
self.dirty = False
self.exit_status = 0
self.load_map(filename)

def load_map(self, filename) -> None:
def load_map(self, filename: Path) -> None:
"""Create a renderer, load data, and print some debug info"""
self.renderer = TiledRenderer(filename)

def draw(self, surface) -> None:
def draw(self, surface: pygame.Surface) -> None:
"""Draw our map to some surface (probably the display)"""
# first we make a temporary surface that will accommodate the entire
# size of the map.
Expand All @@ -161,7 +167,7 @@ def draw(self, surface) -> None:

# display a bit of use info on the display
f = pygame.font.Font(pygame.font.get_default_font(), 20)
i = f.render("press any key for next map or ESC to quit", 1, (180, 180, 0))
i = f.render("press any key for next map or ESC to quit", True, (180, 180, 0))
surface.blit(i, (0, 0))

def handle_input(self) -> None:
Expand All @@ -187,8 +193,13 @@ def handle_input(self) -> None:
self.exit_status = 0
self.running = False

def run(self):
"""This is our app main loop"""
def run(self) -> int:
"""
This is our app main loop

Returns:
Int: 0 means no error, 1 is an error
"""
self.dirty = True
self.running = True
self.exit_status = 1
Expand All @@ -208,8 +219,7 @@ def run(self):


if __name__ == "__main__":
import glob
import os.path
import time

import pytmx

Expand All @@ -218,22 +228,28 @@ def run(self):
screen = init_screen(600, 600)
pygame.display.set_caption("PyTMX Map Viewer")

logger.info(pytmx.__version__)
logger.info(f"PyTMX Version: {pytmx.__version__}")

# loop through a bunch of maps in the maps folder
import time
# Path to your maps folder
map_folder = Path("apps/data")
map_files = sorted(map_folder.glob("*.tmx")) # sort for consistent order

if not map_files:
logger.warning("No TMX files found in apps/data/")
else:
logger.info(f"Found {len(map_files)} TMX files.")

try:
# 6.6
start = time.time()

for i in range(500):
for filename in glob.glob(os.path.join("*.tmx")):
for filepath in map_files:
pygame.event.clear()
SimpleTest(filename)
SimpleTest(filepath).run()

end = time.time() - start
print(end)
logger.info(f"Total time: {time.time() - start:.2f} seconds")

except:
except Exception as e:
logger.exception("Unexpected error:")
pygame.quit()
raise
2 changes: 1 addition & 1 deletion apps/pygame_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def draw(self, surface) -> None:

# display a bit of use info on the display
f = pygame.font.Font(pygame.font.get_default_font(), 20)
i = f.render("press any key for next map or ESC to quit", 1, (180, 180, 0))
i = f.render("press any key for next map or ESC to quit", True, (180, 180, 0))
surface.blit(i, (0, 0))

def handle_input(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion apps/pyglet_demo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
This is tested on pyglet 1.2 and python 2.7.
Leif Theden "bitcraft", 2012-2024
Leif Theden "bitcraft", 2012-2025

Rendering demo for the TMXLoader.

Expand Down
17 changes: 11 additions & 6 deletions apps/pysdl2_demo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
This is tested on pysdl2 1.2 and python 2.7.
Leif Theden "bitcraft", 2012-2024
Leif Theden "bitcraft", 2012-2025

Rendering demo for the TMXLoader.

Expand Down Expand Up @@ -36,7 +36,7 @@
from pytmx.util_pysdl2 import load_pysdl2


class TiledRenderer(object):
class TiledRenderer:
"""
Super simple way to render a tiled map with pyglet

Expand Down Expand Up @@ -81,7 +81,7 @@ def render_map(self) -> None:
self.render_tile_layer(layer)


class SimpleTest(object):
class SimpleTest:
def __init__(self, filename, window) -> None:
self.running = False
self.dirty = False
Expand All @@ -104,8 +104,13 @@ def draw(self) -> None:
self.map_renderer.render_map()
self.sdl_renderer.present()

def run(self, window):
"""Starts an event loop without actually processing any event."""
def run(self, window) -> int:
"""
Starts an event loop without actually processing any event.

Returns:
Int: 0 means no error, 1 is an error
"""
import ctypes

event = events.SDL_Event()
Expand All @@ -126,7 +131,7 @@ def run(self, window):
return self.exit_status


def all_filenames():
def all_filenames() -> list[str]:
import glob
import os.path

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from typing import Any

project = "pytmx"
copyright = "2012-2024, Leif Theden"
copyright = "2012-2025, Leif Theden"
author = "Leif Theden"

# The full version, including alpha/beta/rc tags
Expand Down
3 changes: 2 additions & 1 deletion pytmx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Copyright (C) 2012-2024, Leif Theden <leif.theden@gmail.com>
Copyright (C) 2012-2025, Leif Theden <leif.theden@gmail.com>

This file is part of pytmx.

Expand All @@ -16,6 +16,7 @@
You should have received a copy of the GNU Lesser General Public
License along with pytmx. If not, see <http://www.gnu.org/licenses/>.
"""

import logging

from .pytmx import *
Expand Down
Loading