diff --git a/.gitignore b/.gitignore index 85e7c1d..78b759b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /.idea/ +__pycache__ diff --git a/data/images/entities/player.jpg b/data/images/entities/player.jpg new file mode 100644 index 0000000..1845ca8 Binary files /dev/null and b/data/images/entities/player.jpg differ diff --git a/data/images/terrain/floor.png b/data/images/terrain/floor.png new file mode 100644 index 0000000..bab8d02 Binary files /dev/null and b/data/images/terrain/floor.png differ diff --git a/data/images/terrain/grass.png b/data/images/terrain/grass.png new file mode 100644 index 0000000..6df59c8 Binary files /dev/null and b/data/images/terrain/grass.png differ diff --git a/data/images/terrain/wall.png b/data/images/terrain/wall.png new file mode 100644 index 0000000..9db4a3a Binary files /dev/null and b/data/images/terrain/wall.png differ diff --git a/data/mapdata/map.txt b/data/mapdata/map.txt new file mode 100644 index 0000000..606c117 --- /dev/null +++ b/data/mapdata/map.txt @@ -0,0 +1,20 @@ +.................... +..wwww..w...w...ww.. +..w......w.w...w..w. +,,wwww,,,,w,,,,wwww, +..w......w.w...w..w. +..wwww..w...w..w..w. +.................... +.w...w...ww...w..ww. +.ww.ww..w..w..w..w.. +,w,w,w,,wwww,,w,,ww, +.w...w..w.....w..w.. +.w...w..w.....ww.ww. +.................... +..w...w...ww...ww... +..ww.ww..w..w.w..w.. +,,w,w,w,,wwww,wwww,, +..w...w..w..w.w..... +..w...w..w..w.w..... +.................... +.................... \ No newline at end of file diff --git a/src/Run.py b/src/Run.py index 07e0abb..a3e220a 100644 --- a/src/Run.py +++ b/src/Run.py @@ -1,3 +1,3 @@ -from src.game.Game import Game +from game.Game import Game game = Game() diff --git a/src/entities/Collidable.py b/src/entities/Collidable.py index ebe0f2f..72a7c36 100644 --- a/src/entities/Collidable.py +++ b/src/entities/Collidable.py @@ -1,5 +1,31 @@ -import src.entities.Entity as Entity +from src.entities.Entity import Entity class Collidable(Entity): - pass + + def __init__(self, texture, pos, id): + super().__init__(texture, pos, id) + + def check_for_collision(self, x_pos, y_pos): + if self.pos[0] == x_pos: + if self.pos[1] == y_pos: + return True + + return False + + +col = Collidable(1, 1, 1) + + +""" + def interact_with_hp(self, hp, Statistics): + Statistics.set_hp(hp) + + def interact_with_hunger(self, hunger, Statistics): + Statistics.set_hunger(hunger) + + def interact_with_thirst(self, thirst, Statistics): + Statistics.set_thirst(thirst) + + def interact_with_stamina(self, stamina, Statistics): + Statistics.set_stamina(stamina)""" \ No newline at end of file diff --git a/src/entities/Entity.py b/src/entities/Entity.py index b9d4d43..857f664 100644 --- a/src/entities/Entity.py +++ b/src/entities/Entity.py @@ -1,5 +1,36 @@ -class Entity: - def __init__(self): - self.texture - self.pos - self.id +from pathlib import Path +import pygame + + +class Entity(pygame.sprite.Sprite): + nextId = 1 + + def __init__(self, texture, size, pos): + super().__init__() + self.image, self.rect = self.getTexture(texture, size) + self.rect.x = pos[0] + self.rect.y = pos[1] + self.id = self.getId() + + # A method to return auto-incremented ID + def getId(self): + id = Entity.nextId + Entity.nextId += 1 + return id + + # A method that returns image and rect from a file + def getTexture(self, textureName, tileSize): + texturesFolder = "" + textureFile = "" + try: + texturesFolder = Path("../data/images/entities") + textureFile = texturesFolder / textureName + except IOError: + print("Cannot load texture from " + texturesFolder + ". Exiting...") + exit(1) + image = pygame.image.load(str(textureFile)).convert_alpha() + image = pygame.transform.scale(image, (tileSize, tileSize)) + rect = image.get_rect() + return image, rect + + diff --git a/src/entities/Interactable.py b/src/entities/Interactable.py index 7720fdf..a3f3fb9 100644 --- a/src/entities/Interactable.py +++ b/src/entities/Interactable.py @@ -1,5 +1,24 @@ -import src.entities.Entity as Entity +from src.entities.Entity import Entity class Interactable(Entity): - pass + + def __init__(self, texture, pos, id): + super().__init__(texture, pos, id) + + @staticmethod + def interact_with_hp(hp, Statistics): + Statistics.set_hp(hp) + + @staticmethod + def interact_with_hunger(hunger, Statistics): + Statistics.set_hunger(hunger) + + @staticmethod + def interact_with_thirst(thirst, Statistics): + Statistics.set_thirst(thirst) + + @staticmethod + def interact_with_stamina(stamina, Statistics): + Statistics.set_stamina(stamina) + diff --git a/src/entities/Npc.py b/src/entities/Npc.py index 45f460e..5867cac 100644 --- a/src/entities/Npc.py +++ b/src/entities/Npc.py @@ -1,7 +1,10 @@ -import src.entities.Collidable as Collidable +from src.entities.Collidable import Collidable +from src.entities.Interactable import Interactable -class Npc(Collidable): - def __init__(self): - self.path - self.speed +class Npc(Collidable, Interactable): + def __init__(self, texture, pos, id, path, speed): + Collidable.__init__(self, texture, pos, id) + Interactable.__init__(self, texture, pos, id) + self.path = path + self.speed = speed diff --git a/src/entities/Player.py b/src/entities/Player.py index 0cc7578..ed6f38a 100644 --- a/src/entities/Player.py +++ b/src/entities/Player.py @@ -1,6 +1,40 @@ -import src.entities.Entity as Entity +from enum import Enum + +from src.entities.Entity import Entity +from src.entities.Statistics import Statistics +import pygame class Player(Entity): - def __init__(self): - self.statistics + def __init__(self, spawnpoint, size): + super().__init__("player.jpg", size, spawnpoint) + # Where the player is facing, 0 - north, 1 + self.rotation = Rotations.NORTH + + # Move in a desired direction + def move(self, rotation): + # If the player is not facing given direction, it will not move the first time, it will only get rotated + if self.rotation.value != rotation.value: + self.rotate(rotation) + # Otherwise, move one tile to a given direction + else: + # TODO: Collision checks + if rotation.value == Rotations.NORTH.value: + self.rect.y -= self.rect.w + elif rotation.value == Rotations.EAST.value: + self.rect.x += self.rect.w + elif rotation.value == Rotations.SOUTH.value: + self.rect.y += self.rect.w + elif rotation.value == Rotations.WEST.value: + self.rect.x -= self.rect.w + + def rotate(self, rotation): + self.image = pygame.transform.rotate(self.image, ((self.rotation.value - rotation.value) * 90)) + self.rotation = rotation + + +class Rotations(Enum): + NORTH = 0 + EAST = 1 + SOUTH = 2 + WEST = 3 \ No newline at end of file diff --git a/src/entities/Statistics.py b/src/entities/Statistics.py index 18b4cc9..c506eee 100644 --- a/src/entities/Statistics.py +++ b/src/entities/Statistics.py @@ -1,6 +1,44 @@ class Statistics: - def __init__(self): - self.hp - self.hunger - self.thirst - self.stamina + def __init__(self, hp, hunger, thirst, stamina): + self.hp = hp + self.hunger = hunger + self.thirst = thirst + self.stamina = stamina + + # methods that don't let the values pass below 0 and over 100 during change + def set_hp(self, hp_diff): + if 0 <= self.hp + hp_diff <= 100: + self.hp = self.hp + hp_diff + else: + if self.hp + hp_diff <= 0: + self.hp = 0 + else: + self.hp = 100 + + def set_hunger(self, hunger_diff): + if 0 <= self.hp + hunger_diff <= 100: + self.hp = self.hp + hunger_diff + else: + if self.hp + hunger_diff <= 0: + self.hp = 0 + else: + self.hp = 100 + + def set_thirst(self, thirst_diff): + if 0 <= self.hp + thirst_diff <= 100: + self.hp = self.hp + thirst_diff + else: + if self.hp + thirst_diff <= 0: + self.hp = 0 + else: + self.hp = 100 + + def set_stamina(self, stamina_diff): + if 0 <= self.hp + stamina_diff <= 100: + self.hp = self.hp + stamina_diff + else: + if self.hp + stamina_diff <= 0: + self.hp = 0 + else: + self.hp = 100 + diff --git a/src/game/EventManager.py b/src/game/EventManager.py index 3cc4e99..d2a9a13 100644 --- a/src/game/EventManager.py +++ b/src/game/EventManager.py @@ -1,11 +1,44 @@ import pygame +from src.entities.Player import Rotations +# Player can move every given milliseconds +TIMEOUT = 100 class EventManager: - def __init__(self, gameObject): + keyTimeout = 0 + + def __init__(self, gameObject, player): self.game = gameObject + self.player = player + self.keyTimer = pygame.time.Clock() + # Player controls + + # TODO + def loadKeyboardSettings(self): + pass def handleEvents(self): + pygame.event.pump() + + keys = pygame.key.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: self.game.running = False + self.keyTimeout += self.keyTimer.tick() + if self.keyTimeout >= TIMEOUT: + self.handlePlayerControls(keys) + self.keyTimeout = 0 + + def handlePlayerControls(self, keys): + # Key names are temporary + # TODO: Load key bindings from JSON + + if keys[pygame.K_w]: + self.player.move(Rotations.NORTH) + if keys[pygame.K_s]: + self.player.move(Rotations.SOUTH) + if keys[pygame.K_d]: + self.player.move(Rotations.EAST) + if keys[pygame.K_a]: + self.player.move(Rotations.WEST) + diff --git a/src/game/Game.py b/src/game/Game.py index 6c208c7..6e6e8e4 100644 --- a/src/game/Game.py +++ b/src/game/Game.py @@ -1,11 +1,11 @@ import pygame import json from pathlib import Path +from os import path from game.EventManager import EventManager from game.Screen import Screen - -from src.game.Timer import Timer +from game.Map import Map class Game: @@ -28,7 +28,6 @@ class Game: pygame.init() self.spritesList = pygame.sprite.Group() print("OK") - print("Initializing screen, params: " + str(self.config["window"]) + "...", end=" ") # Vertical rotation is unsupported due to UI layout @@ -41,6 +40,11 @@ class Game: self.eventManager = EventManager(self) + # Start Map implement + self.mapDataFolder = path.dirname("../data/mapdata/") + self.map = Map(path.join(self.mapDataFolder, 'map.txt'), self.screen) + # End Map implement + self.mainLoop() def mainLoop(self): diff --git a/src/game/Map.py b/src/game/Map.py index 8a4b1c9..7daa356 100644 --- a/src/game/Map.py +++ b/src/game/Map.py @@ -1,4 +1,33 @@ +import pygame +from game.TerrainTile import TerrainTile +from game.Screen import Locations + class Map: - def __init__(self): - self.terrain - self.entites = [] + def __init__(self, filename, screen): + self.screen = screen + self.terrain = [] + self.entities = [] + with open(filename, 'rt') as f: + for line in f: + self.terrain.append(line) + + self.tileSize = int(self.screen.mapSize/20) + + self.tileWidth = len(self.terrain[0]) + self.tileHeight = len(self.terrain) + self.width = self.tileWidth * self.tileSize + self.height = self.tileHeight * self.tileSize + + self.terrainDraw() + + def terrainDraw(self): + for row, tiles in enumerate(self.terrain): + for col, tile in enumerate(tiles): + if tile == 'w': + self.screen.draw(TerrainTile('wall.png', self.tileSize), Locations.MAP, col*self.tileSize, row*self.tileSize) + elif tile == ',': + self.screen.draw(TerrainTile('floor.png', self.tileSize), Locations.MAP, col*self.tileSize, row*self.tileSize) + elif tile == '.': + self.screen.draw(TerrainTile('grass.png', self.tileSize), Locations.MAP, col*self.tileSize, row*self.tileSize) + + diff --git a/src/game/TerrainTile.py b/src/game/TerrainTile.py index ec906e5..636838b 100644 --- a/src/game/TerrainTile.py +++ b/src/game/TerrainTile.py @@ -1,3 +1,13 @@ -class TerrainTile: - def __init__(self): - self.tiles = [] +import pygame +import os +from os import path + + +class TerrainTile(pygame.sprite.Sprite): + def __init__(self, texture, tileSize): + super().__init__() + self.imagesFolder = path.dirname("../data/images/") + self.terrainFolder = path.join(self.imagesFolder, 'terrain') + self.image = pygame.image.load(os.path.join(self.terrainFolder, texture)).convert() + self.image = pygame.transform.scale(self.image, (tileSize, tileSize)) + self.rect = self.image.get_rect()