diff --git a/assets/entities/player/none/0.png b/assets/entities/player/none/0.png new file mode 100644 index 0000000..b7720ab Binary files /dev/null and b/assets/entities/player/none/0.png differ diff --git a/assets/entities/player/none/1.png b/assets/entities/player/none/1.png new file mode 100644 index 0000000..38bf925 Binary files /dev/null and b/assets/entities/player/none/1.png differ diff --git a/assets/entities/player/none/2.png b/assets/entities/player/none/2.png new file mode 100644 index 0000000..0979bff Binary files /dev/null and b/assets/entities/player/none/2.png differ diff --git a/assets/tiles.png b/assets/tiles.png new file mode 100644 index 0000000..e1092fb Binary files /dev/null and b/assets/tiles.png differ diff --git a/assets/tiles.tsx b/assets/tiles.tsx new file mode 100644 index 0000000..ce65c59 --- /dev/null +++ b/assets/tiles.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/launcher.py b/launcher.py index 586f6e8..4e58a59 100644 --- a/launcher.py +++ b/launcher.py @@ -1,2 +1,3 @@ if __name__ == '__main__': import src.main + _ = src.main # Ligne ajoutée uniquement pour éviter des erreurs dans les IDE diff --git a/maps/map0.tmj b/maps/map0.tmj new file mode 100644 index 0000000..8d392cb --- /dev/null +++ b/maps/map0.tmj @@ -0,0 +1,78 @@ +{ "compressionlevel":-1, + "height":40, + "infinite":true, + "layers":[ + { + "chunks":[ + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, + 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1, + 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, + 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, + 1, 1, 1, 3, 2, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 2, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 2, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 2, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":16, + "width":16, + "x":0, + "y":0 + }, + { + "data":[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, + 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":16, + "y":0 + }], + "height":16, + "id":1, + "name":"Calque de Tuiles 1", + "opacity":1, + "startx":0, + "starty":0, + "type":"tilelayer", + "visible":true, + "width":32, + "x":0, + "y":0 + }], + "nextlayerid":2, + "nextobjectid":1, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.8.4", + "tileheight":16, + "tilesets":[ + { + "firstgid":1, + "source":"..\/..\/..\/Documents\/mapping\/6 NSI RPG\/tiles.tsx" + }], + "tilewidth":16, + "type":"map", + "version":"1.8", + "width":100 +} \ No newline at end of file diff --git a/maps/map1.tmj b/maps/map1.tmj new file mode 100644 index 0000000..8a0981d --- /dev/null +++ b/maps/map1.tmj @@ -0,0 +1,563 @@ +{ "compressionlevel":-1, + "height":20, + "infinite":true, + "layers":[ + { + "chunks":[ + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":16, + "width":16, + "x":0, + "y":0 + }, + { + "data":[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2], + "height":16, + "width":16, + "x":16, + "y":0 + }, + { + "data":[1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 3, 3, 3, 3, 3, 2, 2, 2], + "height":16, + "width":16, + "x":32, + "y":0 + }, + { + "data":[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":48, + "y":0 + }, + { + "data":[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 2, 2, 2, 2], + "height":16, + "width":16, + "x":0, + "y":16 + }, + { + "data":[2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":16, + "y":16 + }, + { + "data":[2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2], + "height":16, + "width":16, + "x":32, + "y":16 + }, + { + "data":[2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":48, + "y":16 + }, + { + "data":[2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":16, + "width":16, + "x":0, + "y":32 + }, + { + "data":[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":16, + "width":16, + "x":16, + "y":32 + }, + { + "data":[2, 2, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":16, + "width":16, + "x":32, + "y":32 + }, + { + "data":[2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2], + "height":16, + "width":16, + "x":48, + "y":32 + }, + { + "data":[2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3], + "height":16, + "width":16, + "x":0, + "y":48 + }, + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1], + "height":16, + "width":16, + "x":16, + "y":48 + }, + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 2], + "height":16, + "width":16, + "x":32, + "y":48 + }, + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":48, + "y":48 + }, + + { + "data":[2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":0, + "y":64 + }, + { + "data":[3, 3, 2, 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":16, + "y":64 + }, + { + "data":[1, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":32, + "y":64 + }, + { + "data":[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":48, + "y":64 + }, + { + "data":[2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":0, + "y":80 + }, + { + "data":[1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":16, + "y":80 + }, + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":32, + "y":80 + }, + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + "height":16, + "width":16, + "x":48, + "y":80 + }], + "height":96, + "id":1, + "name":"Calque de Tuiles 1", + "opacity":1, + "startx":0, + "starty":0, + "type":"tilelayer", + "visible":true, + "width":64, + "x":0, + "y":0 + }], + "nextlayerid":2, + "nextobjectid":1, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.10.1", + "tileheight":16, + "tilesets":[ + { + "firstgid":1, + "source":"..\/assets\/tiles.tsx" + }], + "tilewidth":16, + "type":"map", + "version":"1.10", + "width":30 +} \ No newline at end of file diff --git a/maps/map2.tmj b/maps/map2.tmj new file mode 100644 index 0000000..1862b61 --- /dev/null +++ b/maps/map2.tmj @@ -0,0 +1,128 @@ +{ "compressionlevel":-1, + "height":20, + "infinite":true, + "layers":[ + { + "chunks":[ + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 2, 2, 2, 1, 1, 3, 3, 1, 1, 1, 1, + 1, 3, 3, 1, 1, 2, 2, 2, 2, 3, 3, 3, 1, 1, 1, 1, + 1, 3, 3, 3, 2, 3, 2, 2, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 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], + "height":16, + "width":16, + "x":0, + "y":0 + }], + "height":16, + "id":1, + "name":"Calque de Tuiles 1", + "opacity":1, + "startx":0, + "starty":0, + "type":"tilelayer", + "visible":true, + "width":16, + "x":0, + "y":0 + }, + { + "chunks":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":16, + "width":16, + "x":0, + "y":0 + }], + "height":16, + "id":2, + "name":"Calque de Tuiles 2", + "opacity":1, + "startx":0, + "starty":0, + "type":"tilelayer", + "visible":true, + "width":16, + "x":0, + "y":0 + }, + { + "chunks":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":16, + "width":16, + "x":0, + "y":0 + }], + "height":16, + "id":3, + "name":"Calque de Tuiles 3", + "opacity":1, + "startx":0, + "starty":0, + "type":"tilelayer", + "visible":true, + "width":16, + "x":0, + "y":0 + }], + "nextlayerid":4, + "nextobjectid":1, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.10.1", + "tileheight":16, + "tilesets":[ + { + "firstgid":1, + "source":"..\/assets\/tiles.tsx" + }], + "tilewidth":16, + "type":"map", + "version":"1.10", + "width":30 +} \ No newline at end of file diff --git a/src/engine.py b/src/engine.py deleted file mode 100644 index 0381a80..0000000 --- a/src/engine.py +++ /dev/null @@ -1,6 +0,0 @@ -class Engine: - def __init__(self): - pass - - def loop(self): - pass diff --git a/src/engine/animation.py b/src/engine/animation.py new file mode 100644 index 0000000..17c936d --- /dev/null +++ b/src/engine/animation.py @@ -0,0 +1,66 @@ +# Classe animation adaptée depuis ESG Engine : +# https://github.com/yannis300307/ESG_Engine/blob/main/ESG_Engine/client/animation.py +import os + +import pygame + + +class Anim: + """Une animation contenant les images pygame et le temps entre chaque frames.""" + def __init__(self, change_frame_time: float): + self.frames = [] + self.change_frame_time = change_frame_time # Delay entre chaque frames + self.current_frame = 0 + self.time = 0 + + def add_frame(self, frame: pygame.Surface): + """Enregistre une nouvelle image dans la liste des frames.""" + self.frames.append(frame.convert_alpha()) + + def get_frame_nbr(self): + """Renvoie le nombre d'images enregistrées.""" + return len(self.frames) + + def get_frame(self, delta: float): + """Donne l'image courante de l'animation.""" + # Avant de retourner l'image, on met à jour le delay + self.update_current_frame(delta) + + return self.frames[self.current_frame] + + def update_current_frame(self, delta: float): + """Met à jour le delay de l'image courante avec le delta time.""" + self.time += delta + + # Si le delay entre deux images est écoulé, on incrémente le numéro de l'image et on remet le temps à 0 + if self.time >= self.change_frame_time: + self.current_frame += 1 + self.time = 0 + + # Si on sort de la liste d'images, on revient au début + if self.current_frame >= len(self.frames): + self.current_frame = 0 + + def get_specific_frame(self, base: int): + """Donne la {base} ème image apres l'image courante.""" + # Si le delay entre deux images est écoulé, on incrémente le numéro de l'image et on remet le temps à 0 + if self.time >= self.change_frame_time: + self.current_frame += 1 + self.time = 0 + + # Si on sort de la liste d'images, on revient au début + if self.current_frame >= len(self.frames): + self.current_frame = 0 + + return self.frames[(self.current_frame + base) % len(self.frames)] + + def load_animation_from_directory(self, path: str): + """Récupère toutes les images au format png dans un dossier et les enregistre comme frames de l'animation.""" + + # On récupère tous les fichiers dans le dossier donné + files = os.listdir(path) + + # Si ils sont bien en PNG, on les enregistre + for file in files: + if file.endswith(".png"): + self.add_frame(pygame.image.load(path + os.sep + file)) diff --git a/src/engine/camera.py b/src/engine/camera.py new file mode 100644 index 0000000..aa3a09a --- /dev/null +++ b/src/engine/camera.py @@ -0,0 +1,33 @@ +from src.engine.entity import Entity + + +class Camera: + def __init__(self): + self.x = 0 + self.y = 0 + self.zoom = 1. + + # Variables utilisées pour le scrolling + self.target_x = self.x + self.target_y = self.y + self.target_zoom = self.zoom + + self.smoothness = 20. + + self.followed_entity: Entity | None = None + + def update(self): + """Met à jour la caméra. Permet, par exemple, de faire le scrolling.""" + + # Si on suit une entité, on met à jour les coordonnées de suivi + if self.followed_entity is not None: + self.target_x = self.followed_entity.x + self.target_y = self.followed_entity.y + + self.x += (self.target_x - self.x) / self.smoothness + self.y += (self.target_y - self.y) / self.smoothness + self.zoom += (self.target_zoom - self.zoom) / self.smoothness + + def follow_entity(self, entity: Entity | None): + """Active le suivit de l'entité donnée. Mettre `None` pour retirer le suivit.""" + self.followed_entity = entity diff --git a/src/engine/engine.py b/src/engine/engine.py new file mode 100644 index 0000000..e6cce74 --- /dev/null +++ b/src/engine/engine.py @@ -0,0 +1,52 @@ +from src.engine.camera import Camera +from src.engine.entity_manager import EntityManager +from src.engine.event_handler import EventHandler +from src.engine.map_manager import MapManager +from src.engine.renderer import Renderer +from src.engine.enums import GameState +import pygame + + +class Engine: + """Classe principale qui regroupe tous les composants du programme (Renderer, MapManager, EventHandler, etc ...)""" + def __init__(self): + # L'initialisation de Pygame est nécessaire pour tous les modules + pygame.init() + + # Debug mode utilisé pour tricher (voir les collisions, etc...) WOW ! n'utilisez pas ça pour jouer ! + self.DEBUG_MODE = False + + # Etat courant du jeu + self.game_state = GameState.NORMAL + + self.clock = pygame.time.Clock() + + self.running = False + + # Composants du moteur de jeu + self.renderer = Renderer(self) + self.event_handler = EventHandler(self) + self.map_manager = MapManager() + self.camera = Camera() + self.entity_manager = EntityManager() + + def loop(self): + """Fonction à lancer au début du programme et qui va lancer les updates dans une boucle. + Attend jusqu'à la fin du jeu.""" + self.running = True + while self.running: + self.update() + self.clock.tick(60.) + + def update(self): + """Fonction qui regroupe toutes les updates des composants. Elle permet de mettre à jour le jeu quand on + l'appelle.""" + self.camera.update() + self.entity_manager.update(0.016666666) + self.renderer.update(0.016666666) + self.event_handler.update() + + def stop(self): + """Arrête le programme.""" + self.running = False + pygame.quit() diff --git a/src/engine/entity.py b/src/engine/entity.py new file mode 100644 index 0000000..bcfa816 --- /dev/null +++ b/src/engine/entity.py @@ -0,0 +1,117 @@ +from src.engine.map_manager import MapManager + + +class Entity: + """Classe permettant de gérer les entités. Créée automatiquement par `EntityManager.register_entity()`""" + + def __init__(self, name: str): + self.x = 8 + self.y = 8 + + self.life_points = -1 + self.max_life_points = -1 + + # Cooldown entre deux points de dégât + self.damage_cooldown = 0 + self.default_damage_cooldown = 0.5 + + self.collision_rect = [0, 0, 0, 0] # x1, y1, x2, y2 + + # Time utilisé pour les IA + self.time = 0 + + self.name = name + + self.animation_name = None + + def set_default_life(self, life: int): + """Définit le nombre de PV de l'entité. Mettre -1 pour rendre l'entité immortelle.""" + self.life_points = life + self.max_life_points = life + + def update(self, delta: float): + """Met à jour l'entité.""" + self.time += delta + + # Diminue la valeur du cooldown de dégât + self.damage_cooldown -= delta + if self.damage_cooldown < 0: + self.damage_cooldown = 0 + + def take_damages(self, damages: int): + """Inflige {damages} dégâts à l'entité.""" + + # Si life_points est égal à -1, l'entité est immortelle + if self.life_points != -1 and self.damage_cooldown == 0: + # On inflige les dégâts + self.life_points -= damages + # Remet le cooldown au maximum + self.damage_cooldown = self.default_damage_cooldown + # Si la vie passe en négatif, on la remet à 0 + if self.life_points < 0: + self.life_points = 0 + + def get_collisions(self, x: float, y: float, map_manager: MapManager): + """Calcule les collisions.""" + + # On calcule les coordonnées des points en haut à gauche et en bas à droite + top_left_corner_tile = (int((x + self.collision_rect[0]) / 16), + int((y + self.collision_rect[1]) / 16)) + + bottom_right_corner_tile = (int((x + self.collision_rect[2]-1) / 16), + int((y + self.collision_rect[3]-1) / 16)) + + collision = False + + # On itère dans toute la zone de collision + for xx in range(top_left_corner_tile[0], bottom_right_corner_tile[0]+1): + for yy in range(top_left_corner_tile[1], bottom_right_corner_tile[1]+1): + # Pour les collisions, on utilise le layer 1 (le deuxième) + # On récupère la tile aux coordonnées données + tile = map_manager.get_tile_at(xx, yy, 1) + + # Si la tile n'est pas du vide, il y a une collision. + if tile != 0: + collision = True + + return collision + + def move(self, x: float, y: float, map_manager: MapManager): + """Fait bouger l'entité en tenant compte des collisions.""" + + # On simule le mouvement. Si on ne rencontre pas de collision, on applique le mouvement + if not self.get_collisions(self.x + x, self.y, map_manager): + self.x += x + else: + # Si on a une collision, on avance pixel par pixel jusqu'à atteindre la collision + i = 0 + if x > 0: + while not self.get_collisions(self.x + i, self.y, map_manager): + i += 1 + i -= 1 + else: + while not self.get_collisions(self.x + i, self.y, map_manager): + i -= 1 + i += 1 + + self.x += i + + # On répète le procédé avec l'ordonnée + if not self.get_collisions(self.x, self.y + y, map_manager): + self.y += y + else: + i = 0 + if y > 0: + while not self.get_collisions(self.x, self.y + i, map_manager): + i += 1 + i -= 1 + else: + while not self.get_collisions(self.x, self.y + i, map_manager): + i -= 1 + i += 1 + + self.y += i + + def link_animation(self, name: str): + """Met à jour l'animation en cours de l'entité.""" + self.animation_name = name diff --git a/src/engine/entity_manager.py b/src/engine/entity_manager.py new file mode 100644 index 0000000..425897c --- /dev/null +++ b/src/engine/entity_manager.py @@ -0,0 +1,29 @@ +from src.engine.entity import Entity + + +class EntityManager: + """Classe chargée de gérer les entités.""" + def __init__(self): + self.entities: dict[str:Entity] = {} + + def register_entity(self, name: str): + """Crée une entité et l'enregistre dans un dictionnaire.""" + entity = Entity(name) + self.entities[name] = entity + return entity + + def update(self, delta: float): + """Met à jour toutes les entités enregistrées.""" + for entity_name in list(self.entities.keys()): + entity = self.entities[entity_name] + entity.update(delta) + if entity.life_points == 0: + self.entities.pop(entity_name) + + def get_all_entities(self): + """Donne la liste de toutes les entités enregistrées.""" + return list(self.entities.values()) + + def get_by_name(self, name: str): + """Donne l'entité avec le nom donné.""" + return self.entities[name] diff --git a/src/engine/enums.py b/src/engine/enums.py new file mode 100644 index 0000000..ceeddeb --- /dev/null +++ b/src/engine/enums.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class GameState(Enum): + """Enumération utilisée pour définir l'état actuel du jeu.""" + NONE = 0 + NORMAL = 1 + BOSS_FIGHT = 2 + MAIN_MENU = 3 + # AJouter si besoin, mais à utiliser de préférence avec parsimony diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py new file mode 100644 index 0000000..538fa04 --- /dev/null +++ b/src/engine/event_handler.py @@ -0,0 +1,40 @@ +from pygame import event +from pygame.locals import * + +import src.engine.engine as engine + + +class EventHandler: + """Classe utilisée pour traiter les pygame.event.get() et gérer les interactions avec le reste du programme.""" + def __init__(self, core: 'engine.Engine'): + self.engine = core + self.key_pressed = [] + + def update(self): + """Vérifie s'il y a de nouvelles interactions et les traites.""" + + # Récupère les événements + for e in event.get(): + if e.type == QUIT: + self.engine.stop() + elif e.type == KEYDOWN: + self.key_pressed.append(e.key) + elif e.type == KEYUP: + self.key_pressed.remove(e.key) + + player = self.engine.entity_manager.get_by_name("player") + if K_RIGHT in self.key_pressed: + player.move(2, 0, self.engine.map_manager) + if K_LEFT in self.key_pressed: + player.move(-2, 0, self.engine.map_manager) + if K_UP in self.key_pressed: + player.move(0, -2, self.engine.map_manager) + if K_DOWN in self.key_pressed: + player.move(0, 2, self.engine.map_manager) + if K_x in self.key_pressed: + self.engine.camera.target_zoom *= 1.01 + if K_c in self.key_pressed: + self.engine.camera.target_zoom *= 0.99 + if K_l in self.key_pressed: + player.take_damages(1) + diff --git a/src/engine/map_manager.py b/src/engine/map_manager.py new file mode 100644 index 0000000..668fc55 --- /dev/null +++ b/src/engine/map_manager.py @@ -0,0 +1,47 @@ +import json + + +class MapManager: + """Stocke les cartes du jeu.""" + def __init__(self): + # structure : [layers{chunks[x, y][data]} + self.map_layers = [] + self.chunk_width = 16 + self.chunk_height = 16 + + def load_new(self, file_path: str): + """Charge une map infinie au format tiled.""" + with open(file_path, "r") as file: + data = json.loads(file.read()) + for layer in data["layers"]: + chunks = {} + for chunk in layer["chunks"]: + chunks[(chunk["x"]//self.chunk_width, chunk["y"]//self.chunk_height)] = chunk["data"] + self.map_layers.append(chunks) + + print(self.map_layers) + + def get_tile_at(self, x: int, y: int, layer_id: int): + """Donne l'id de la tile aux coordonnées données et à la couche choisie.""" + + # On récupère la couche demandée + layer = self.map_layers[layer_id] + + # On calcule les coordonnées du chunk + coordinates = (x//self.chunk_width, y//self.chunk_height) + + # On transforme les coordonnées globales en coordonnées dans le chunk + x %= 16 + y %= 16 + + if coordinates not in layer: + return 0 + + chunk = layer[coordinates] + + # On vérifie que la tile demandée existe sinon on répond "vide" + if x >= self.chunk_width or x < 0 or y >= self.chunk_height or y < 0: + return 0 + + # On calcule l'index et on renvoie la tile + return chunk[x+y*self.chunk_width] diff --git a/src/engine/renderer.py b/src/engine/renderer.py new file mode 100644 index 0000000..7b263fb --- /dev/null +++ b/src/engine/renderer.py @@ -0,0 +1,163 @@ +import math + +from pygame import display, image, surface, transform, draw +from pygame.locals import RESIZABLE, SRCALPHA + +import src.engine.engine as engine +from src.engine.animation import Anim +from src.engine.enums import GameState + + +class Renderer: + """Classe contenant le moteur de rendu. On utilise, pour cela la bibliothèque Pygame.""" + + def __init__(self, core: 'engine.Engine'): + self.engine = core + self.window = display.set_mode((600, 600), RESIZABLE) + self.tiles = [] + self.tile_size = 0 + self.animations: dict[str: Anim] = {} + + def load_tile_set(self, file_path: str, tile_size: int): + """Charge le jeu de tuiles en utilisant le fichier donné et la taille donnée.""" + tile_set = image.load(file_path).convert_alpha() + + self.tile_size = tile_size + + # Scan tout le tile set et le découpe pour créer des tiles de {tile_size} px de hauteur et de largeur + for y in range(tile_set.get_height() // tile_size): + for x in range(tile_set.get_width() // tile_size): + tile = tile_set.subsurface((x * tile_size, y * tile_size, tile_size, tile_size)) + self.tiles.append(tile) + + def update(self, delta: float): + """Fait le rendu du jeu.""" + self.window.fill((255, 255, 255)) + + if self.engine.game_state == GameState.NORMAL: + # On crée une surface temporaire qui nous permettra de faire le rendu à l'échelle 1:1 + rendered_surface_size = (display.get_window_size()[0] / self.engine.camera.zoom, + display.get_window_size()[1] / self.engine.camera.zoom) + rendered_surface = surface.Surface(rendered_surface_size) + + # On crée une surface qui sera ajoutée à la fenêtre apres rendered_surface pour pouvoir mettre des GUI + gui_surface = surface.Surface(display.get_window_size(), SRCALPHA) + gui_surface.fill((0, 0, 0, 0)) + + self.renderer_layer(0, rendered_surface) + self.render_entities(rendered_surface, gui_surface, delta) + self.renderer_layer(1, rendered_surface) + self.renderer_layer(2, rendered_surface) + + # Enfin, on redimensionne notre surface et on la colle sur la fenêtre principale + self.window.blit( + transform.scale(rendered_surface, (math.ceil(rendered_surface_size[0] * self.engine.camera.zoom), + math.ceil(rendered_surface_size[1] * self.engine.camera.zoom))), + (0, 0)) + + self.window.blit(gui_surface, (0, 0)) + + elif self.engine.game_state == GameState.BOSS_FIGHT: + self.window.fill((255, 0, 0)) + + # Apres avoir tout rendu, on met à jour l'écran + display.update() + + def register_animation(self, animation: Anim, name: str): + """Enregistre une animation.""" + self.animations[name] = animation + + def render_entities(self, rendered_surface: surface.Surface, gui_surface: surface.Surface, delta: float): + """Rend toutes les entités.""" + # On calcule le décalage pour centrer la caméra + x_middle_offset = display.get_window_size()[0] / 2 / self.engine.camera.zoom + y_middle_offset = display.get_window_size()[1] / 2 / self.engine.camera.zoom + + for entity in self.engine.entity_manager.get_all_entities(): + # On récupère la frame courante de l'animation + anim: Anim = self.animations[entity.animation_name] + frame = anim.get_frame(delta) + + # Si l'entité n'apparait pas à l'écran, on passe son rendu + if (entity.x - self.engine.camera.x + x_middle_offset + frame.get_width() < 0 or + entity.x - self.engine.camera.x - x_middle_offset - frame.get_width() > 0 or + entity.y - self.engine.camera.y + y_middle_offset + frame.get_height() < 0 or + entity.y - self.engine.camera.y - y_middle_offset - frame.get_height() > 0): + continue + + # On calcule les coordonnées de rendu de l'entité + entity_dest = (math.floor(entity.x - self.engine.camera.x + x_middle_offset - frame.get_width() / 2), + math.floor(entity.y - self.engine.camera.y + y_middle_offset - frame.get_height() / 2)) + + # On affiche l'image + rendered_surface.blit(frame, entity_dest) + + if entity.max_life_points != -1: + # Rendu de la barre de vie des entités + life_bar_width = 50 + life_bar_height = 8 + life_bar_y_offset = 5 + life_bar_border = 2 + + life_bar_value = entity.life_points / entity.max_life_points + cooldown_value = entity.damage_cooldown / entity.default_damage_cooldown + + # On calcule où placer la barre de vei sur la surface des GUI + life_bar_dest = (math.floor((entity.x - self.engine.camera.x + x_middle_offset) * self.engine.camera.zoom - + life_bar_width / 2), + math.floor((entity.y - self.engine.camera.y + y_middle_offset - frame.get_height() / 2) * + self.engine.camera.zoom - life_bar_height - life_bar_y_offset)) + + # Contour de la barre de vie + draw.rect(gui_surface, (20, 0, 0), (life_bar_dest[0] - life_bar_border, + life_bar_dest[1] - life_bar_border, + life_bar_width + life_bar_border * 2, + life_bar_height + life_bar_border * 2)) + + # Barre de vie + draw.rect(gui_surface, (255 - 255 * life_bar_value, 255 * life_bar_value, 0), + life_bar_dest + (life_bar_width * life_bar_value, life_bar_height)) + + draw.rect(gui_surface, (200, 200, 200), + life_bar_dest + (life_bar_width * life_bar_value * cooldown_value, life_bar_height)) + + if self.engine.DEBUG_MODE: + top_let_corner_x = entity.x - self.engine.camera.x + x_middle_offset + top_let_corner_y = entity.y - self.engine.camera.y + y_middle_offset + + draw.rect(rendered_surface, (255, 0, 0), + (top_let_corner_x + entity.collision_rect[0], + top_let_corner_y + entity.collision_rect[1], + entity.collision_rect[2] - entity.collision_rect[0], + entity.collision_rect[3] - entity.collision_rect[1]), + width=1) + + def renderer_layer(self, layer_id: int, rendered_surface: surface.Surface): + """Rend la map.""" + # On calcule le nombre de tiles à mettre sur notre écran en prenant en compte le zoom + x_map_range = int(display.get_window_size()[0] / self.tile_size / self.engine.camera.zoom) + 2 + y_map_range = int(display.get_window_size()[1] / self.tile_size / self.engine.camera.zoom) + 2 + + # On calcule le décalage pour centrer la caméra + x_middle_offset = display.get_window_size()[0] / 2 / self.engine.camera.zoom + y_middle_offset = display.get_window_size()[1] / 2 / self.engine.camera.zoom + + # On calcule le décalage du début de rendu des tiles + x_map_offset = int((self.engine.camera.x - x_middle_offset) / self.tile_size) + y_map_offset = int((self.engine.camera.y - y_middle_offset) / self.tile_size) + + # On itère pour chaque couche, toutes les tiles visibles par la caméra + for x in range(x_map_offset, x_map_offset + x_map_range): + for y in range(y_map_offset, y_map_offset + y_map_range): + + # On récupère l'id de la tile à la position donnée + tile_id = self.engine.map_manager.get_tile_at(x, y, layer_id) + + # Si l'id est 0, il s'agit de vide donc on saute le rendu + if tile_id == 0: + continue + + # Puis, on cherche à quelle image elle correspond et on la colle sur notre surface + rendered_surface.blit(self.tiles[tile_id - 1], + (math.floor(x * self.tile_size - self.engine.camera.x + x_middle_offset), + math.floor(y * self.tile_size - self.engine.camera.y + y_middle_offset))) diff --git a/src/main.py b/src/main.py index 1f9775b..7e9f317 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,41 @@ -from engine import Engine +import random -engine = Engine() -engine.loop() +from src.engine.animation import Anim +from src.engine.engine import Engine + + +class Game(Engine): + def __init__(self): + super().__init__() + self.map_manager.load_new("maps/map2.tmj") + + self.renderer.load_tile_set("assets/tiles.png", 16) + + anim = Anim(0.5) + anim.load_animation_from_directory("assets/entities/player/none") + self.renderer.register_animation(anim, "player_none") + + player = self.entity_manager.register_entity("player") + player.link_animation("player_none") + player.collision_rect = [-7, -7, 7, 7] + + player.set_default_life(10) + + self.camera.follow_entity(player) + + for i in range(20): + anim = Anim(0.5) + anim.load_animation_from_directory("assets/entities/player/none") + self.renderer.register_animation(anim, f"player_none_{i}") + + test = self.entity_manager.register_entity(f"test_{i}") + test.x = random.randint(0, 200) + test.y = random.randint(0, 200) + test.link_animation(f"player_none_{i}") + test.collision_rect = [-7, -7, 7, 7] + + test.set_default_life(10) + + +game = Game() +game.loop() diff --git a/src/renderer.py b/src/renderer.py deleted file mode 100644 index 67b57c5..0000000 --- a/src/renderer.py +++ /dev/null @@ -1,6 +0,0 @@ -class Renderer: - def __init__(self): - pass - - def loop(self): - pass