diff --git a/main.py b/main.py
index 443890b..cfa19ac 100644
--- a/main.py
+++ b/main.py
@@ -1,25 +1,33 @@
import pygame
-from map import preparedMap
+import pytmx
+from map import *
from agent import trashmaster
class WalleGame():
def __init__(self):
- self.SCREEN_SIZE = [512, 512]
- self.BACKGROUND_COLOR = '#ffffff'
+ self.SCREEN_SIZE = [1000, 1000]
+ #self.BACKGROUND_COLOR = '#ffffff'
pygame.init()
pygame.display.set_caption('Wall-e')
self.screen = pygame.display.set_mode(self.SCREEN_SIZE)
- self.screen.fill(pygame.Color(self.BACKGROUND_COLOR))
+ #self.screen.fill(pygame.Color(self.BACKGROUND_COLOR))
# krata
- self.map = preparedMap(self.SCREEN_SIZE)
- self.screen.blit(self.map, (0,0))
+ #self.map = preparedMap(self.SCREEN_SIZE)
+ #self.screen.blit(self.map, (0,0))
+
+ self.map = TiledMap("resources/textures/map/roads.tmx")
+ self.map_img = self.map.make_map()
+ self.map_rect = self.map_img.get_rect()
+ self.screen.blit(self.map_img, (0,0))
+
+
def update_window(self):
pygame.display.update()
@@ -34,7 +42,7 @@ def main():
game = WalleGame()
game.update_window()
- smieciara_object = trashmaster(16,16,"resources/textures/trashmaster_blu.png",16)
+ smieciara_object = trashmaster(86,52,"resources/textures/garbagetruck/trashmaster_blu.png",16)
game.draw_trashmaster(smieciara_object)
game.update_window()
diff --git a/map.py b/map.py
index bbede27..ef58fb7 100644
--- a/map.py
+++ b/map.py
@@ -1,13 +1,40 @@
-import pygame
+import pygame as pg
+import pytmx
+
+
# config
-TILE_SIZE = 16
+# TILE_SIZE = 16
-def preparedMap(screenSize):
- tileImage = pygame.image.load('tile1.png')
- surface = pygame.Surface(screenSize)
+# def preparedMap(screenSize):
+# tileImage = pg.image.load('tile1.png')
+# surface = pg.Surface(screenSize)
- for x in range(0, screenSize[0], TILE_SIZE):
- for y in range(0, screenSize[1], TILE_SIZE):
- surface.blit(tileImage, (x, y))
- return surface
\ No newline at end of file
+# for x in range(0, screenSize[0], TILE_SIZE):
+# for y in range(0, screenSize[1], TILE_SIZE):
+# surface.blit(tileImage, (x, y))
+# return surface
+
+class TiledMap:
+ #loading file
+ def __init__(self, filename):
+ tm = pytmx.load_pygame(filename, pixelalpha=True)
+ self.width = tm.width * tm.tilewidth
+ self.height = tm.height * tm.tileheight
+ self.tmxdata = tm
+
+
+ #rendering map
+ def render(self, surface):
+ ti = self.tmxdata.get_tile_image_by_gid
+ for layer in self.tmxdata.visible_layers:
+ if isinstance(layer, pytmx.TiledTileLayer):
+ for x, y, gid, in layer:
+ tile = ti(gid)
+ if tile:
+ surface.blit(tile, (x * self.tmxdata.tilewidth, y * self.tmxdata.tilewidth))
+
+ def make_map(self):
+ temp_surface = pg.Surface((self.width, self.height))
+ self.render(temp_surface)
+ return temp_surface
\ No newline at end of file
diff --git a/resources/Tankgame.py b/resources/Tankgame.py
new file mode 100644
index 0000000..462ee0b
--- /dev/null
+++ b/resources/Tankgame.py
@@ -0,0 +1,622 @@
+import os
+import tmx
+import math
+import pygame
+from pygame import Rect
+from pygame.math import Vector2
+
+os.environ['SDL_VIDEO_CENTERED'] = '1'
+
+###############################################################################
+# Game State #
+###############################################################################
+
+class GameItem():
+ def __init__(self,state,position,tile):
+ self.state = state
+ self.status = "alive"
+ self.position = position
+ self.tile = tile
+ self.orientation = 0
+
+class Unit(GameItem):
+ def __init__(self,state,position,tile):
+ super().__init__(state,position,tile)
+ self.weaponTarget = Vector2(0,0)
+ self.lastBulletEpoch = -100
+
+class Bullet(GameItem):
+ def __init__(self,state,unit):
+ super().__init__(state,unit.position,Vector2(2,1))
+ self.unit = unit
+ self.startPosition = unit.position
+ self.endPosition = unit.weaponTarget
+
+class GameState():
+ def __init__(self):
+ self.epoch = 0
+ self.worldSize = Vector2(16,10)
+ self.ground = [ [ Vector2(5,1) ] * 16 ] * 10
+ self.walls = [ [ None ] * 16 ] * 10
+ self.units = [ Unit(self,Vector2(8,9),Vector2(1,0)) ]
+ self.bullets = [ ]
+ self.bulletSpeed = 0.1
+ self.bulletRange = 4
+ self.bulletDelay = 5
+ self.observers = [ ]
+
+ @property
+ def worldWidth(self):
+ """
+ Returns the world width as an integer
+ """
+ return int(self.worldSize.x)
+
+ @property
+ def worldHeight(self):
+ """
+ Returns the world height as an integer
+ """
+ return int(self.worldSize.y)
+
+ def isInside(self,position):
+ """
+ Returns true is position is inside the world
+ """
+ return position.x >= 0 and position.x < self.worldWidth \
+ and position.y >= 0 and position.y < self.worldHeight
+
+ def findUnit(self,position):
+ """
+ Returns the index of the first unit at position, otherwise None.
+ """
+ for unit in self.units:
+ if int(unit.position.x) == int(position.x) \
+ and int(unit.position.y) == int(position.y):
+ return unit
+ return None
+
+ def findLiveUnit(self,position):
+ """
+ Returns the index of the first live unit at position, otherwise None.
+ """
+ unit = self.findUnit(position)
+ if unit is None or unit.status != "alive":
+ return None
+ return unit
+
+ def addObserver(self,observer):
+ """
+ Add a game state observer.
+ All observer is notified when something happens (see GameStateObserver class)
+ """
+ self.observers.append(observer)
+
+ def notifyUnitDestroyed(self,unit):
+ for observer in self.observers:
+ observer.unitDestroyed(unit)
+
+class GameStateObserver():
+ def unitDestroyed(self,unit):
+ pass
+
+###############################################################################
+# Commands #
+###############################################################################
+
+class Command():
+ def run(self):
+ raise NotImplementedError()
+
+class MoveCommand(Command):
+ """
+ This command moves a unit in a given direction
+ """
+ def __init__(self,state,unit,moveVector):
+ self.state = state
+ self.unit = unit
+ self.moveVector = moveVector
+ def run(self):
+ unit = self.unit
+
+ # Destroyed units can't move
+ if unit.status != "alive":
+ return
+
+ # Update unit orientation
+ if self.moveVector.x < 0:
+ unit.orientation = 90
+ elif self.moveVector.x > 0:
+ unit.orientation = -90
+ if self.moveVector.y < 0:
+ unit.orientation = 0
+ elif self.moveVector.y > 0:
+ unit.orientation = 180
+
+ # Compute new tank position
+ newPos = unit.position + self.moveVector
+
+ # Don't allow positions outside the world
+ if not self.state.isInside(newPos):
+ return
+
+ # Don't allow wall positions
+ if not self.state.walls[int(newPos.y)][int(newPos.x)] is None:
+ return
+
+ # Don't allow other unit positions
+ unitIndex = self.state.findUnit(newPos)
+ if not unitIndex is None:
+ return
+
+ unit.position = newPos
+
+class TargetCommand(Command):
+ def __init__(self,state,unit,target):
+ self.state = state
+ self.unit = unit
+ self.target = target
+ def run(self):
+ self.unit.weaponTarget = self.target
+
+class ShootCommand(Command):
+ def __init__(self,state,unit):
+ self.state = state
+ self.unit = unit
+ def run(self):
+ if self.unit.status != "alive":
+ return
+ if self.state.epoch-self.unit.lastBulletEpoch < self.state.bulletDelay:
+ return
+ self.unit.lastBulletEpoch = self.state.epoch
+ self.state.bullets.append(Bullet(self.state,self.unit))
+
+class MoveBulletCommand(Command):
+ def __init__(self,state,bullet):
+ self.state = state
+ self.bullet = bullet
+ def run(self):
+ direction = (self.bullet.endPosition - self.bullet.startPosition).normalize()
+ newPos = self.bullet.position + self.state.bulletSpeed * direction
+ newCenterPos = newPos + Vector2(0.5,0.5)
+ # If the bullet goes outside the world, destroy it
+ if not self.state.isInside(newPos):
+ self.bullet.status = "destroyed"
+ return
+ # If the bullet goes towards the target cell, destroy it
+ if ((direction.x >= 0 and newPos.x >= self.bullet.endPosition.x) \
+ or (direction.x < 0 and newPos.x <= self.bullet.endPosition.x)) \
+ and ((direction.y >= 0 and newPos.y >= self.bullet.endPosition.y) \
+ or (direction.y < 0 and newPos.y <= self.bullet.endPosition.y)):
+ self.bullet.status = "destroyed"
+ return
+ # If the bullet is outside the allowed range, destroy it
+ if newPos.distance_to(self.bullet.startPosition) >= self.state.bulletRange:
+ self.bullet.status = "destroyed"
+ return
+ # If the bullet hits a unit, destroy the bullet and the unit
+ unit = self.state.findLiveUnit(newCenterPos)
+ if not unit is None and unit != self.bullet.unit:
+ self.bullet.status = "destroyed"
+ unit.status = "destroyed"
+ self.state.notifyUnitDestroyed(unit)
+ return
+ # Nothing happends, continue bullet trajectory
+ self.bullet.position = newPos
+
+class DeleteDestroyedCommand(Command) :
+ def __init__(self,itemList):
+ self.itemList = itemList
+ def run(self):
+ newList = [ item for item in self.itemList if item.status == "alive" ]
+ self.itemList[:] = newList
+
+
+class LoadLevelCommand(Command) :
+ def __init__(self,ui,fileName):
+ self.ui = ui
+ self.fileName = fileName
+
+ def decodeLayer(self,tileMap,layer):
+ """
+ Decode layer and check layer properties
+
+ Returns the corresponding tileset
+ """
+ if not isinstance(layer,tmx.Layer):
+ raise RuntimeError("Error in {}: invalid layer type".format(self.fileName))
+ if len(layer.tiles) != tileMap.width * tileMap.height:
+ raise RuntimeError("Error in {}: invalid tiles count".format(self.fileName))
+
+ # Guess which tileset is used by this layer
+ gid = None
+ for tile in layer.tiles:
+ if tile.gid != 0:
+ gid = tile.gid
+ break
+ if gid is None:
+ if len(tileMap.tilesets) == 0:
+ raise RuntimeError("Error in {}: no tilesets".format(self.fileName))
+ tileset = tileMap.tilesets[0]
+ else:
+ tileset = None
+ for t in tileMap.tilesets:
+ if gid >= t.firstgid and gid < t.firstgid+t.tilecount:
+ tileset = t
+ break
+ if tileset is None:
+ raise RuntimeError("Error in {}: no corresponding tileset".format(self.fileName))
+
+ # Check the tileset
+ if tileset.columns <= 0:
+ raise RuntimeError("Error in {}: invalid columns count".format(self.fileName))
+ if tileset.image.data is not None:
+ raise RuntimeError("Error in {}: embedded tileset image is not supported".format(self.fileName))
+
+ return tileset
+
+ def decodeArrayLayer(self,tileMap,layer):
+ """
+ Create an array from a tileMap layer
+ """
+ tileset = self.decodeLayer(tileMap,layer)
+
+ array = [ None ] * tileMap.height
+ for y in range(tileMap.height):
+ array[y] = [ None ] * tileMap.width
+ for x in range(tileMap.width):
+ tile = layer.tiles[x + y*tileMap.width]
+ if tile.gid == 0:
+ continue
+ lid = tile.gid - tileset.firstgid
+ if lid < 0 or lid >= tileset.tilecount:
+ raise RuntimeError("Error in {}: invalid tile id".format(self.fileName))
+ tileX = lid % tileset.columns
+ tileY = lid // tileset.columns
+ array[y][x] = Vector2(tileX,tileY)
+
+ return tileset, array
+
+ def decodeUnitsLayer(self,state,tileMap,layer):
+ """
+ Create a list from a tileMap layer
+ """
+ tileset = self.decodeLayer(tileMap,layer)
+
+ units = []
+ for y in range(tileMap.height):
+ for x in range(tileMap.width):
+ tile = layer.tiles[x + y*tileMap.width]
+ if tile.gid == 0:
+ continue
+ lid = tile.gid - tileset.firstgid
+ if lid < 0 or lid >= tileset.tilecount:
+ raise RuntimeError("Error in {}: invalid tile id".format(self.fileName))
+ tileX = lid % tileset.columns
+ tileY = lid // tileset.columns
+ unit = Unit(state,Vector2(x,y),Vector2(tileX,tileY))
+ units.append(unit)
+
+ return tileset, units
+
+
+ def run(self):
+ # Load map
+ if not os.path.exists(self.fileName):
+ raise RuntimeError("No file {}".format(self.fileName))
+ tileMap = tmx.TileMap.load(self.fileName)
+
+ # Check main properties
+ if tileMap.orientation != "orthogonal":
+ raise RuntimeError("Error in {}: invalid orientation".format(self.fileName))
+
+ if len(tileMap.layers) != 5:
+ raise RuntimeError("Error in {}: 5 layers are expected".format(self.fileName))
+
+ # World size
+ state = self.ui.gameState
+ state.worldSize = Vector2(tileMap.width,tileMap.height)
+
+ # Ground layer
+ tileset, array = self.decodeArrayLayer(tileMap,tileMap.layers[0])
+ cellSize = Vector2(tileset.tilewidth,tileset.tileheight)
+ state.ground[:] = array
+ imageFile = tileset.image.source
+ self.ui.layers[0].setTileset(cellSize,imageFile)
+
+ # Walls layer
+ tileset, array = self.decodeArrayLayer(tileMap,tileMap.layers[1])
+ if tileset.tilewidth != cellSize.x or tileset.tileheight != cellSize.y:
+ raise RuntimeError("Error in {}: tile sizes must be the same in all layers".format(self.fileName))
+ state.walls[:] = array
+ imageFile = tileset.image.source
+ self.ui.layers[1].setTileset(cellSize,imageFile)
+
+ # Units layer
+ tanksTileset, tanks = self.decodeUnitsLayer(state,tileMap,tileMap.layers[2])
+ towersTileset, towers = self.decodeUnitsLayer(state,tileMap,tileMap.layers[3])
+ if tanksTileset != towersTileset:
+ raise RuntimeError("Error in {}: tanks and towers tilesets must be the same".format(self.fileName))
+ if tanksTileset.tilewidth != cellSize.x or tanksTileset.tileheight != cellSize.y:
+ raise RuntimeError("Error in {}: tile sizes must be the same in all layers".format(self.fileName))
+ state.units[:] = tanks + towers
+ cellSize = Vector2(tanksTileset.tilewidth,tanksTileset.tileheight)
+ imageFile = tanksTileset.image.source
+ self.ui.layers[2].setTileset(cellSize,imageFile)
+
+ # Player units
+ self.ui.playerUnit = tanks[0]
+
+ # Explosions layers
+ tileset, array = self.decodeArrayLayer(tileMap,tileMap.layers[4])
+ if tileset.tilewidth != cellSize.x or tileset.tileheight != cellSize.y:
+ raise RuntimeError("Error in {}: tile sizes must be the same in all layers".format(self.fileName))
+ state.bullets.clear()
+ imageFile = tileset.image.source
+ self.ui.layers[3].setTileset(cellSize,imageFile)
+
+ # Window
+ windowSize = state.worldSize.elementwise() * cellSize
+ self.ui.window = pygame.display.set_mode((int(windowSize.x),int(windowSize.y)))
+
+###############################################################################
+# Rendering #
+###############################################################################
+
+class Layer(GameStateObserver):
+ def __init__(self,cellSize,imageFile):
+ self.cellSize = cellSize
+ self.texture = pygame.image.load(imageFile)
+
+ def setTileset(self,cellSize,imageFile):
+ self.cellSize = cellSize
+ self.texture = pygame.image.load(imageFile)
+
+ @property
+ def cellWidth(self):
+ return int(self.cellSize.x)
+
+ @property
+ def cellHeight(self):
+ return int(self.cellSize.y)
+
+ def unitDestroyed(self,unit):
+ pass
+
+ def renderTile(self,surface,position,tile,angle=None):
+ # Location on screen
+ spritePoint = position.elementwise()*self.cellSize
+
+ # Texture
+ texturePoint = tile.elementwise()*self.cellSize
+ textureRect = Rect(int(texturePoint.x), int(texturePoint.y), self.cellWidth, self.cellHeight)
+
+ # Draw
+ if angle is None:
+ surface.blit(self.texture,spritePoint,textureRect)
+ else:
+ # Extract the tile in a surface
+ textureTile = pygame.Surface((self.cellWidth,self.cellHeight),pygame.SRCALPHA)
+ textureTile.blit(self.texture,(0,0),textureRect)
+ # Rotate the surface with the tile
+ rotatedTile = pygame.transform.rotate(textureTile,angle)
+ # Compute the new coordinate on the screen, knowing that we rotate around the center of the tile
+ spritePoint.x -= (rotatedTile.get_width() - textureTile.get_width()) // 2
+ spritePoint.y -= (rotatedTile.get_height() - textureTile.get_height()) // 2
+ # Render the rotatedTile
+ surface.blit(rotatedTile,spritePoint)
+
+ def render(self,surface):
+ raise NotImplementedError()
+
+class ArrayLayer(Layer):
+ def __init__(self,ui,imageFile,gameState,array,surfaceFlags=pygame.SRCALPHA):
+ super().__init__(ui,imageFile)
+ self.gameState = gameState
+ self.array = array
+ self.surface = None
+ self.surfaceFlags = surfaceFlags
+
+ def setTileset(self,cellSize,imageFile):
+ super().setTileset(cellSize,imageFile)
+ self.surface = None
+
+ def render(self,surface):
+ if self.surface is None:
+ self.surface = pygame.Surface(surface.get_size(),flags=self.surfaceFlags)
+ for y in range(self.gameState.worldHeight):
+ for x in range(self.gameState.worldWidth):
+ tile = self.array[y][x]
+ if not tile is None:
+ self.renderTile(self.surface,Vector2(x,y),tile)
+ surface.blit(self.surface,(0,0))
+
+class UnitsLayer(Layer):
+ def __init__(self,ui,imageFile,gameState,units):
+ super().__init__(ui,imageFile)
+ self.gameState = gameState
+ self.units = units
+
+ def render(self,surface):
+ for unit in self.units:
+ self.renderTile(surface,unit.position,unit.tile,unit.orientation)
+ if unit.status == "alive":
+ size = unit.weaponTarget - unit.position
+ angle = math.atan2(-size.x,-size.y) * 180 / math.pi
+ self.renderTile(surface,unit.position,Vector2(0,6),angle)
+
+class BulletsLayer(Layer):
+ def __init__(self,ui,imageFile,gameState,bullets):
+ super().__init__(ui,imageFile)
+ self.gameState = gameState
+ self.bullets = bullets
+
+ def render(self,surface):
+ for bullet in self.bullets:
+ if bullet.status == "alive":
+ self.renderTile(surface,bullet.position,bullet.tile,bullet.orientation)
+
+class ExplosionsLayer(Layer):
+ def __init__(self,ui,imageFile):
+ super().__init__(ui,imageFile)
+ self.explosions = []
+ self.maxFrameIndex = 27
+
+ def add(self,position):
+ self.explosions.append({
+ 'position': position,
+ 'frameIndex': 0
+ })
+
+ def unitDestroyed(self,unit):
+ self.add(unit.position)
+
+ def render(self,surface):
+ for explosion in self.explosions:
+ frameIndex = math.floor(explosion['frameIndex'])
+ self.renderTile(surface,explosion['position'],Vector2(frameIndex,4))
+ explosion['frameIndex'] += 0.5
+ self.explosions = [ explosion for explosion in self.explosions if explosion['frameIndex'] < self.maxFrameIndex ]
+
+
+
+###############################################################################
+# User Interface #
+###############################################################################
+
+class UserInterface():
+ def __init__(self):
+ pygame.init()
+
+ # Game state
+ self.gameState = GameState()
+
+ # Rendering properties
+ self.cellSize = Vector2(64,64)
+
+ # Window
+ windowSize = self.gameState.worldSize.elementwise() * self.cellSize
+ self.window = pygame.display.set_mode((int(windowSize.x),int(windowSize.y)))
+ pygame.display.set_caption("Discover Python & Patterns - https://www.patternsgameprog.com")
+ pygame.display.set_icon(pygame.image.load("icon.png"))
+
+ # Layers
+ self.layers = [
+ ArrayLayer(self.cellSize,"ground.png",self.gameState,self.gameState.ground,0),
+ ArrayLayer(self.cellSize,"walls.png",self.gameState,self.gameState.walls),
+ UnitsLayer(self.cellSize,"units.png",self.gameState,self.gameState.units),
+ BulletsLayer(self.cellSize,"explosions.png",self.gameState,self.gameState.bullets),
+ ExplosionsLayer(self.cellSize,"explosions.png")
+ ]
+
+ # All layers listen to game state events
+ for layer in self.layers:
+ self.gameState.addObserver(layer)
+
+ # Controls
+ self.playerUnit = self.gameState.units[0]
+ self.commands = [
+ LoadLevelCommand(self,"level2.tmx")
+ ]
+
+ # Loop properties
+ self.clock = pygame.time.Clock()
+ self.running = True
+
+ @property
+ def cellWidth(self):
+ return int(self.cellSize.x)
+
+ @property
+ def cellHeight(self):
+ return int(self.cellSize.y)
+
+ def processInput(self):
+ # Pygame events (close, keyboard and mouse click)
+ moveVector = Vector2()
+ mouseClicked = False
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT:
+ self.running = False
+ break
+ elif event.type == pygame.KEYDOWN:
+ if event.key == pygame.K_ESCAPE:
+ self.running = False
+ break
+ elif event.key == pygame.K_RIGHT:
+ moveVector.x = 1
+ elif event.key == pygame.K_LEFT:
+ moveVector.x = -1
+ elif event.key == pygame.K_DOWN:
+ moveVector.y = 1
+ elif event.key == pygame.K_UP:
+ moveVector.y = -1
+ elif event.type == pygame.MOUSEBUTTONDOWN:
+ mouseClicked = True
+
+ # Keyboard controls the moves of the player's unit
+ if moveVector.x != 0 or moveVector.y != 0:
+ self.commands.append(
+ MoveCommand(self.gameState,self.playerUnit,moveVector)
+ )
+
+ # Mouse controls the target of the player's unit
+ mousePos = pygame.mouse.get_pos()
+ targetCell = Vector2()
+ targetCell.x = mousePos[0] / self.cellWidth - 0.5
+ targetCell.y = mousePos[1] / self.cellHeight - 0.5
+ command = TargetCommand(self.gameState,self.playerUnit,targetCell)
+ self.commands.append(command)
+
+ # Shoot if left mouse was clicked
+ if mouseClicked:
+ self.commands.append(
+ ShootCommand(self.gameState,self.playerUnit)
+ )
+
+ # Other units always target the player's unit and shoot if close enough
+ for unit in self.gameState.units:
+ if unit != self.playerUnit:
+ self.commands.append(
+ TargetCommand(self.gameState,unit,self.playerUnit.position)
+ )
+ if unit.position.distance_to(self.playerUnit.position) <= self.gameState.bulletRange:
+ self.commands.append(
+ ShootCommand(self.gameState,unit)
+ )
+
+ # Bullets automatic movement
+ for bullet in self.gameState.bullets:
+ self.commands.append(
+ MoveBulletCommand(self.gameState,bullet)
+ )
+
+ # Delete any destroyed bullet
+ self.commands.append(
+ DeleteDestroyedCommand(self.gameState.bullets)
+ )
+
+ def update(self):
+ for command in self.commands:
+ command.run()
+ self.commands.clear()
+ self.gameState.epoch += 1
+
+ def render(self):
+ for layer in self.layers:
+ layer.render(self.window)
+
+ pygame.display.update()
+
+ def run(self):
+ while self.running:
+ self.processInput()
+ self.update()
+ self.render()
+ self.clock.tick(60)
+
+userInterface = UserInterface()
+userInterface.run()
+
+pygame.quit()
+
\ No newline at end of file
diff --git a/resources/textures/Ground.tsx b/resources/textures/Ground.tsx
new file mode 100644
index 0000000..338e07b
--- /dev/null
+++ b/resources/textures/Ground.tsx
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/textures/Roads.tsx b/resources/textures/Roads.tsx
new file mode 100644
index 0000000..9406774
--- /dev/null
+++ b/resources/textures/Roads.tsx
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/textures/Trash.tsx b/resources/textures/Trash.tsx
new file mode 100644
index 0000000..1d0eead
--- /dev/null
+++ b/resources/textures/Trash.tsx
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/textures/Walls.tsx b/resources/textures/Walls.tsx
new file mode 100644
index 0000000..2fd21ae
--- /dev/null
+++ b/resources/textures/Walls.tsx
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/textures/map/map1.tmx b/resources/textures/map/map1.tmx
new file mode 100644
index 0000000..e0c4ee0
--- /dev/null
+++ b/resources/textures/map/map1.tmx
@@ -0,0 +1,143 @@
+
+
diff --git a/resources/textures/map/roads.tmx b/resources/textures/map/roads.tmx
new file mode 100644
index 0000000..d38457e
--- /dev/null
+++ b/resources/textures/map/roads.tmx
@@ -0,0 +1,143 @@
+
+
diff --git a/resources/textures/player.tsx b/resources/textures/player.tsx
new file mode 100644
index 0000000..80f5d22
--- /dev/null
+++ b/resources/textures/player.tsx
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+