Merge remote-tracking branch 'origin/passingEvents'
Before Width: | Height: | Size: 24 KiB |
BIN
data/images/entities/berry.png
Normal file
After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 64 KiB |
BIN
data/images/entities/cranberry.png
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
data/images/entities/mushroom.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 17 KiB |
BIN
data/images/entities/player.png
Normal file
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 630 B After Width: | Height: | Size: 4.2 KiB |
BIN
data/images/entities/rock.png
Normal file
After Width: | Height: | Size: 608 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 4.3 KiB |
BIN
data/images/terrain/water.png
Normal file
After Width: | Height: | Size: 61 KiB |
@ -13,11 +13,12 @@
|
|||||||
"hunger" : 20
|
"hunger" : 20
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"name" : "cranberry",
|
"name" : "cranberry",
|
||||||
"position" : {
|
"position" : {
|
||||||
"x": 7,
|
"x": 7,
|
||||||
"y": 1
|
"y": 3
|
||||||
},
|
},
|
||||||
"isPickupable" : true,
|
"isPickupable" : true,
|
||||||
"effect" : {
|
"effect" : {
|
||||||
@ -26,5 +27,52 @@
|
|||||||
"thirst" : 2,
|
"thirst" : 2,
|
||||||
"hunger" : 10
|
"hunger" : 10
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name" : "rabbit",
|
||||||
|
"position" : {
|
||||||
|
"x": 12,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"isPickupable" : true,
|
||||||
|
"effect" : {
|
||||||
|
"hp": 30,
|
||||||
|
"stamina": -5,
|
||||||
|
"thirst": -5,
|
||||||
|
"hunger": 40
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name" : "bush",
|
||||||
|
"position" : {
|
||||||
|
"x": 15,
|
||||||
|
"y": 9
|
||||||
|
},
|
||||||
|
"isPickupable" : false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "rock",
|
||||||
|
"position" : {
|
||||||
|
"x": 13,
|
||||||
|
"y": 2
|
||||||
|
},
|
||||||
|
"isPickupable" : false
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name" : "mushroom",
|
||||||
|
"position" : {
|
||||||
|
"x": 14,
|
||||||
|
"y": 3
|
||||||
|
},
|
||||||
|
"isPickupable": true,
|
||||||
|
"effect" : {
|
||||||
|
"hp": -50,
|
||||||
|
"stamina": 0,
|
||||||
|
"thirst": 0,
|
||||||
|
"hunger": 25
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -8,6 +8,7 @@ class Entity(pygame.sprite.Sprite):
|
|||||||
def __init__(self, texture, size, pos):
|
def __init__(self, texture, size, pos):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.image, self.rect = self.getTexture(texture, size)
|
self.image, self.rect = self.getTexture(texture, size)
|
||||||
|
self.image.set_colorkey((255, 255, 255))
|
||||||
self.rect.x = pos[0]
|
self.rect.x = pos[0]
|
||||||
self.rect.y = pos[1]
|
self.rect.y = pos[1]
|
||||||
self.id = self.getId()
|
self.id = self.getId()
|
||||||
|
@ -6,13 +6,21 @@ import pygame
|
|||||||
|
|
||||||
|
|
||||||
class Player(Entity):
|
class Player(Entity):
|
||||||
|
statistics: Statistics
|
||||||
|
|
||||||
def __init__(self, spawnpoint, size):
|
def __init__(self, spawnpoint, size):
|
||||||
super().__init__("player.jpg", size, (spawnpoint[0] * size, spawnpoint[1] * size))
|
super().__init__("player.png", size, (spawnpoint[0] * size, spawnpoint[1] * size))
|
||||||
# Where the player is facing, 0 - north, 1
|
# Where the player is facing, 0 - north, 1
|
||||||
self.rotation = Rotations.NORTH
|
self.rotation = Rotations.NORTH
|
||||||
|
self.statistics = Statistics(100, 100, 0, 100)
|
||||||
|
# How many steps has the player taken through its lifetime
|
||||||
|
self.movePoints = 0
|
||||||
|
|
||||||
# Move in a desired direction
|
# Move in a desired direction
|
||||||
def move(self, rotation):
|
def move(self, rotation):
|
||||||
|
self.movePoints += 1
|
||||||
|
# Player gets tired aswell!
|
||||||
|
self.applyFatigue()
|
||||||
if rotation.value == Rotations.NORTH.value:
|
if rotation.value == Rotations.NORTH.value:
|
||||||
self.rect.y -= self.rect.w
|
self.rect.y -= self.rect.w
|
||||||
elif rotation.value == Rotations.EAST.value:
|
elif rotation.value == Rotations.EAST.value:
|
||||||
@ -22,14 +30,57 @@ class Player(Entity):
|
|||||||
elif rotation.value == Rotations.WEST.value:
|
elif rotation.value == Rotations.WEST.value:
|
||||||
self.rect.x -= self.rect.w
|
self.rect.x -= self.rect.w
|
||||||
|
|
||||||
|
def applyFatigue(self):
|
||||||
|
# looses hunger every 10 steps taken
|
||||||
|
if self.movePoints % 10 == 0:
|
||||||
|
self.statistics.set_hunger(-10)
|
||||||
|
# gets more thirsty every 5 steps
|
||||||
|
if self.movePoints % 5 == 0:
|
||||||
|
self.statistics.set_thirst(10)
|
||||||
|
# gets tired every step
|
||||||
|
self.statistics.set_stamina(-2)
|
||||||
|
|
||||||
|
def getFacingCoord(self):
|
||||||
|
if self.rotation == Rotations.NORTH:
|
||||||
|
return self.rect.x, self.rect.y - (self.rect.h)
|
||||||
|
elif self.rotation == Rotations.SOUTH:
|
||||||
|
return self.rect.x, self.rect.y + (self.rect.h)
|
||||||
|
elif self.rotation == Rotations.EAST:
|
||||||
|
return self.rect.x + (self.rect.h), self.rect.y
|
||||||
|
elif self.rotation == Rotations.WEST:
|
||||||
|
return self.rect.x - (self.rect.h), self.rect.y
|
||||||
|
|
||||||
|
# Returns given statistic
|
||||||
|
def getStatistic(self, stat):
|
||||||
|
if stat.value == StatisticNames.HP:
|
||||||
|
return self.statistics.hp
|
||||||
|
elif stat.value == StatisticNames.HUNGER:
|
||||||
|
return self.statistics.hunger
|
||||||
|
elif stat.value == StatisticNames.THIRST:
|
||||||
|
return self.statistics.thirst
|
||||||
|
elif stat.value == StatisticNames.STAMINA:
|
||||||
|
return self.statistics.stamina
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getStatistics(self):
|
||||||
|
return self.statistics
|
||||||
|
|
||||||
def rotate(self, rotation):
|
def rotate(self, rotation):
|
||||||
# If the player is not facing given direction, it will not move the first time, it will only get rotated
|
# 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:
|
if self.rotation.value != rotation.value:
|
||||||
self.image = pygame.transform.rotate(self.image, ((self.rotation.value - rotation.value) * 90))
|
self.image = pygame.transform.rotate(self.image, ((self.rotation.value - rotation.value) * 90))
|
||||||
self.rotation = rotation
|
self.rotation = rotation
|
||||||
|
|
||||||
|
|
||||||
class Rotations(Enum):
|
class Rotations(Enum):
|
||||||
NORTH = 0
|
NORTH = 0
|
||||||
EAST = 1
|
EAST = 1
|
||||||
SOUTH = 2
|
SOUTH = 2
|
||||||
WEST = 3
|
WEST = 3
|
||||||
|
|
||||||
|
|
||||||
|
class StatisticNames(Enum):
|
||||||
|
HP = 0
|
||||||
|
STAMINA = 1
|
||||||
|
HUNGER = 2
|
||||||
|
THIRST = 3
|
@ -16,29 +16,29 @@ class Statistics:
|
|||||||
self.hp = 100
|
self.hp = 100
|
||||||
|
|
||||||
def set_hunger(self, hunger_diff):
|
def set_hunger(self, hunger_diff):
|
||||||
if 0 <= self.hp + hunger_diff <= 100:
|
if 0 <= self.hunger + hunger_diff <= 100:
|
||||||
self.hp = self.hp + hunger_diff
|
self.hunger = self.hunger + hunger_diff
|
||||||
else:
|
else:
|
||||||
if self.hp + hunger_diff <= 0:
|
if self.hunger + hunger_diff <= 0:
|
||||||
self.hp = 0
|
self.hunger = 0
|
||||||
else:
|
else:
|
||||||
self.hp = 100
|
self.hunger = 100
|
||||||
|
|
||||||
def set_thirst(self, thirst_diff):
|
def set_thirst(self, thirst_diff):
|
||||||
if 0 <= self.hp + thirst_diff <= 100:
|
if 0 <= self.thirst + thirst_diff <= 100:
|
||||||
self.hp = self.hp + thirst_diff
|
self.thirst = self.thirst + thirst_diff
|
||||||
else:
|
else:
|
||||||
if self.hp + thirst_diff <= 0:
|
if self.thirst + thirst_diff <= 0:
|
||||||
self.hp = 0
|
self.thirst = 0
|
||||||
else:
|
else:
|
||||||
self.hp = 100
|
self.thirst = 100
|
||||||
|
|
||||||
def set_stamina(self, stamina_diff):
|
def set_stamina(self, stamina_diff):
|
||||||
if 0 <= self.hp + stamina_diff <= 100:
|
if 0 <= self.stamina + stamina_diff <= 100:
|
||||||
self.hp = self.hp + stamina_diff
|
self.stamina = self.stamina + stamina_diff
|
||||||
else:
|
else:
|
||||||
if self.hp + stamina_diff <= 0:
|
if self.stamina + stamina_diff <= 0:
|
||||||
self.hp = 0
|
self.stamina = 0
|
||||||
else:
|
else:
|
||||||
self.hp = 100
|
self.stamina = 100
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
|
from src.entities.Pickupable import Pickupable
|
||||||
from src.entities.Player import Rotations
|
from src.entities.Player import Rotations
|
||||||
|
|
||||||
# Player can move every given milliseconds
|
# Player can move every given milliseconds
|
||||||
@ -21,19 +22,28 @@ class EventManager:
|
|||||||
def handleEvents(self):
|
def handleEvents(self):
|
||||||
pygame.event.pump()
|
pygame.event.pump()
|
||||||
|
|
||||||
|
self.game.screen.ui.timerTextView.changeText(self.game.ingameTimer.getPrettyTime())
|
||||||
|
|
||||||
keys = pygame.key.get_pressed()
|
keys = pygame.key.get_pressed()
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
self.game.running = False
|
self.game.running = False
|
||||||
|
self.game.screen.ui.updateBasedOnPygameEvent(event)
|
||||||
self.keyTimeout += self.keyTimer.tick()
|
self.keyTimeout += self.keyTimer.tick()
|
||||||
if self.keyTimeout >= TIMEOUT:
|
if self.keyTimeout >= TIMEOUT:
|
||||||
self.handlePlayerControls(keys)
|
self.handlePlayerControls(keys)
|
||||||
self.keyTimeout = 0
|
self.keyTimeout = 0
|
||||||
|
|
||||||
|
self.game.screen.ui.updateBasedOnPlayerStats(self.player.statistics)
|
||||||
|
|
||||||
def handlePlayerControls(self, keys):
|
def handlePlayerControls(self, keys):
|
||||||
# Key names are temporary
|
# Key names are temporary
|
||||||
# TODO: Load key bindings from JSON
|
# TODO: Load key bindings from JSON
|
||||||
|
if keys[pygame.K_SPACE]:
|
||||||
|
object = self.game.map.getEntityOnCoord(self.player.getFacingCoord())
|
||||||
|
if type(object) is Pickupable:
|
||||||
|
object.on_pickup(self.player)
|
||||||
|
self.game.map.removeSpriteFromMap(object)
|
||||||
if keys[pygame.K_w]:
|
if keys[pygame.K_w]:
|
||||||
self.player.rotate(Rotations.NORTH)
|
self.player.rotate(Rotations.NORTH)
|
||||||
if not self.game.map.collision(self.player.rect.x, self.player.rect.y - self.player.rect.w):
|
if not self.game.map.collision(self.player.rect.x, self.player.rect.y - self.player.rect.w):
|
||||||
|
@ -6,7 +6,11 @@ from os import path
|
|||||||
from game.EventManager import EventManager
|
from game.EventManager import EventManager
|
||||||
from game.Screen import Screen
|
from game.Screen import Screen
|
||||||
from game.Map import Map
|
from game.Map import Map
|
||||||
|
|
||||||
|
from src.entities.Pickupable import Pickupable
|
||||||
from src.entities.Player import Player
|
from src.entities.Player import Player
|
||||||
|
from src.entities.Statistics import Statistics
|
||||||
|
from src.game.Timer import Timer
|
||||||
|
|
||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
@ -37,6 +41,11 @@ class Game:
|
|||||||
print("The screen cannot be in a vertical orientation. Exiting...")
|
print("The screen cannot be in a vertical orientation. Exiting...")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
# Initialize timers
|
||||||
|
self.pgTimer = pygame.time.Clock()
|
||||||
|
self.ingameTimer = Timer()
|
||||||
|
self.ingameTimer.startClock()
|
||||||
|
|
||||||
self.screen = Screen(self, self.config["window"])
|
self.screen = Screen(self, self.config["window"])
|
||||||
print("OK")
|
print("OK")
|
||||||
|
|
||||||
@ -50,6 +59,8 @@ class Game:
|
|||||||
|
|
||||||
def mainLoop(self):
|
def mainLoop(self):
|
||||||
while self.running:
|
while self.running:
|
||||||
|
# Update ingame clock
|
||||||
|
self.ingameTimer.updateTime(self.pgTimer.tick())
|
||||||
self.eventManager.handleEvents()
|
self.eventManager.handleEvents()
|
||||||
self.spritesList.draw(self.screen.pygameScreen)
|
self.spritesList.draw(self.screen.pygameScreen)
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from game.TerrainTile import TerrainTile
|
from src.game.TerrainTile import TerrainTile
|
||||||
from game.Screen import Locations
|
from src.game.Screen import Locations
|
||||||
|
|
||||||
from src.entities.Entity import Entity
|
from src.entities.Entity import Entity
|
||||||
from src.entities.Pickupable import Pickupable
|
from src.entities.Pickupable import Pickupable
|
||||||
@ -42,7 +42,7 @@ class Map:
|
|||||||
for entity in entityListJson:
|
for entity in entityListJson:
|
||||||
try:
|
try:
|
||||||
if entity["isPickupable"]:
|
if entity["isPickupable"]:
|
||||||
actualEntities.append(Pickupable(entity["name"] + ".jpg",
|
actualEntities.append(Pickupable(entity["name"] + ".png",
|
||||||
self.tileSize,
|
self.tileSize,
|
||||||
(entity["position"]["x"] * self.tileSize, entity["position"]["y"] * self.tileSize),
|
(entity["position"]["x"] * self.tileSize, entity["position"]["y"] * self.tileSize),
|
||||||
Statistics(entity["effect"]["hp"],
|
Statistics(entity["effect"]["hp"],
|
||||||
@ -50,7 +50,7 @@ class Map:
|
|||||||
entity["effect"]["thirst"],
|
entity["effect"]["thirst"],
|
||||||
entity["effect"]["stamina"])))
|
entity["effect"]["stamina"])))
|
||||||
else:
|
else:
|
||||||
actualEntities.append(Entity(entity["name"],
|
actualEntities.append(Entity(entity["name"] + ".png",
|
||||||
self.tileSize,
|
self.tileSize,
|
||||||
(entity["position"]["x"] * self.tileSize, entity["position"]["y"] * self.tileSize)))
|
(entity["position"]["x"] * self.tileSize, entity["position"]["y"] * self.tileSize)))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -67,7 +67,7 @@ class Map:
|
|||||||
elif tile == '.':
|
elif tile == '.':
|
||||||
self.screen.draw(TerrainTile(col, row, 'grass.png', self.tileSize), Locations.MAP, 0, 0)
|
self.screen.draw(TerrainTile(col, row, 'grass.png', self.tileSize), Locations.MAP, 0, 0)
|
||||||
elif tile == 'x':
|
elif tile == 'x':
|
||||||
object = TerrainTile(col, row, 'water.jpg', self.tileSize)
|
object = TerrainTile(col, row, 'water.png', self.tileSize)
|
||||||
self.screen.draw(object, Locations.MAP, 0, 0)
|
self.screen.draw(object, Locations.MAP, 0, 0)
|
||||||
self.collidables.add(object)
|
self.collidables.add(object)
|
||||||
elif tile == 'w':
|
elif tile == 'w':
|
||||||
@ -75,6 +75,13 @@ class Map:
|
|||||||
self.screen.draw(object, Locations.MAP, 0, 0)
|
self.screen.draw(object, Locations.MAP, 0, 0)
|
||||||
self.collidables.add(object)
|
self.collidables.add(object)
|
||||||
|
|
||||||
|
def getEntityOnCoord(self, coord):
|
||||||
|
result = None
|
||||||
|
for entity in self.collidables:
|
||||||
|
if entity.rect.x == coord[0] and entity.rect.y == coord[1]:
|
||||||
|
result = entity
|
||||||
|
return result
|
||||||
|
|
||||||
def addEntity(self, entity):
|
def addEntity(self, entity):
|
||||||
self.screen.draw(entity, Locations.MAP, 0, 0)
|
self.screen.draw(entity, Locations.MAP, 0, 0)
|
||||||
self.collidables.add(entity)
|
self.collidables.add(entity)
|
||||||
|
@ -2,11 +2,19 @@ import math
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
|
from src.ui.Ui import Ui
|
||||||
|
|
||||||
# minimum UI width
|
# minimum UI width
|
||||||
MARGIN = 300
|
MARGIN = 300
|
||||||
|
|
||||||
|
|
||||||
|
# screen locations enum
|
||||||
|
class Locations(Enum):
|
||||||
|
RIGHT_UI = 1
|
||||||
|
LEFT_UI = 2
|
||||||
|
MAP = 3
|
||||||
|
|
||||||
|
|
||||||
class Screen:
|
class Screen:
|
||||||
def __init__(self, gameObject, windowConfig):
|
def __init__(self, gameObject, windowConfig):
|
||||||
self.gameObject = gameObject
|
self.gameObject = gameObject
|
||||||
@ -24,6 +32,8 @@ class Screen:
|
|||||||
# draw a white rect to resemble map
|
# draw a white rect to resemble map
|
||||||
pygame.draw.rect(self.pygameScreen, (255, 255, 255), [self.mapCoord, 0, self.mapSize, self.mapSize])
|
pygame.draw.rect(self.pygameScreen, (255, 255, 255), [self.mapCoord, 0, self.mapSize, self.mapSize])
|
||||||
|
|
||||||
|
self.__initUi__()
|
||||||
|
|
||||||
def calculateMapDimensions(self):
|
def calculateMapDimensions(self):
|
||||||
result = 0
|
result = 0
|
||||||
expectedSize = self.winY
|
expectedSize = self.winY
|
||||||
@ -49,9 +59,25 @@ class Screen:
|
|||||||
def removeSprite(self, sprite):
|
def removeSprite(self, sprite):
|
||||||
self.gameObject.spritesList.remove(sprite)
|
self.gameObject.spritesList.remove(sprite)
|
||||||
|
|
||||||
|
def getUiWidth(self, location: Locations):
|
||||||
|
if location is Locations.RIGHT_UI:
|
||||||
|
return self.winX - (self.mapCoord + self.mapSize)
|
||||||
|
elif location is Locations.LEFT_UI:
|
||||||
|
return self.mapCoord
|
||||||
|
elif location is Locations.MAP:
|
||||||
|
return self.mapSize
|
||||||
|
|
||||||
# screen locations enum
|
def __initUi__(self):
|
||||||
class Locations(Enum):
|
self.ui = Ui(self.getUiWidth(Locations.RIGHT_UI), self.getUiWidth(Locations.LEFT_UI), self.winY,
|
||||||
RIGHT_UI = 1
|
self.gameObject.ingameTimer)
|
||||||
LEFT_UI = 2
|
self.draw(self.ui.timerTextView, Locations.LEFT_UI, 0, 0)
|
||||||
MAP = 3
|
self.draw(self.ui.isDayTextView, Locations.LEFT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.console, Locations.LEFT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.healthTextView, Locations.RIGHT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.healthBar, Locations.RIGHT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.hungerTextView, Locations.RIGHT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.hungerBar, Locations.RIGHT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.staminaTextView, Locations.RIGHT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.staminaBar, Locations.RIGHT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.thirstTextView, Locations.RIGHT_UI, 0, 0)
|
||||||
|
self.draw(self.ui.thirstBar, Locations.RIGHT_UI, 0, 0)
|
||||||
|
102
src/ui/Ui.py
@ -1,3 +1,101 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from src.entities.Statistics import Statistics
|
||||||
|
from src.ui.UiBar import UiBar
|
||||||
|
from src.ui.UiConsole import UiConsole
|
||||||
|
from src.ui.UiText import UiText
|
||||||
|
|
||||||
|
|
||||||
class Ui():
|
class Ui():
|
||||||
def __init__(self):
|
def __init__(self, rightUiWidth, leftUiWidth, screenHeight, timer, font=None):
|
||||||
self.elements = []
|
self.elements = pygame.sprite.Group()
|
||||||
|
|
||||||
|
self.leftUiWidth = leftUiWidth
|
||||||
|
self.rightUiWidth = rightUiWidth
|
||||||
|
self.screenHeight = screenHeight
|
||||||
|
|
||||||
|
self.barHeight = 25
|
||||||
|
|
||||||
|
if font is None:
|
||||||
|
font = pygame.font.Font(None, self.barHeight)
|
||||||
|
self.font = font
|
||||||
|
|
||||||
|
self.timer = timer
|
||||||
|
self.timerTextView = UiText(pygame.Rect(0, 0, leftUiWidth, self.barHeight), font=self.font,
|
||||||
|
text=timer.getPrettyTime(), textColor=Colors.WHITE.value,
|
||||||
|
backgroundColor=Colors.GRAY.value)
|
||||||
|
self.isDayTextView = UiText(
|
||||||
|
pygame.Rect(0, self.timerTextView.rect.y + self.barHeight, leftUiWidth, self.barHeight), text="Day",
|
||||||
|
font=self.font, backgroundColor=Colors.GRAY.value, textColor=Colors.WHITE.value)
|
||||||
|
|
||||||
|
self.healthTextView = UiText(pygame.Rect(0, 0, rightUiWidth, self.barHeight), text="Health points",
|
||||||
|
font=self.font, textColor=Colors.WHITE.value)
|
||||||
|
self.healthBar = UiBar(
|
||||||
|
pygame.Rect(0, self.healthTextView.rect.y + self.barHeight, rightUiWidth, self.barHeight))
|
||||||
|
|
||||||
|
self.hungerTextView = UiText(
|
||||||
|
pygame.Rect(0, self.healthBar.rect.y + self.barHeight, rightUiWidth, self.barHeight),
|
||||||
|
text="Hunger", font=self.font, textColor=Colors.WHITE.value)
|
||||||
|
self.hungerBar = UiBar(
|
||||||
|
pygame.Rect(0, self.hungerTextView.rect.y + self.barHeight, rightUiWidth, self.barHeight),
|
||||||
|
initialFilledPercent=0,
|
||||||
|
filledBarColor=Colors.YELLOW.value)
|
||||||
|
|
||||||
|
self.staminaTextView = UiText(
|
||||||
|
pygame.Rect(0, self.hungerBar.rect.y + self.barHeight, rightUiWidth, self.barHeight), text="Stamina",
|
||||||
|
font=self.font, textColor=Colors.WHITE.value)
|
||||||
|
self.staminaBar = UiBar(
|
||||||
|
pygame.Rect(0, self.staminaTextView.rect.y + self.barHeight, rightUiWidth, self.barHeight),
|
||||||
|
filledBarColor=Colors.GREEN.value)
|
||||||
|
|
||||||
|
self.thirstTextView = UiText(
|
||||||
|
pygame.Rect(0, self.staminaBar.rect.y + self.barHeight, rightUiWidth, self.barHeight), text="Thirst",
|
||||||
|
font=self.font, textColor=Colors.WHITE.value)
|
||||||
|
self.thirstBar = UiBar(
|
||||||
|
pygame.Rect(0, self.thirstTextView.rect.y + self.barHeight, rightUiWidth, self.barHeight),
|
||||||
|
initialFilledPercent=0,
|
||||||
|
filledBarColor=Colors.BLUE.value)
|
||||||
|
|
||||||
|
self.console = UiConsole(pygame.Rect(0, self.timerTextView.rect.h + self.isDayTextView.rect.h, leftUiWidth,
|
||||||
|
screenHeight - self.timerTextView.rect.h - self.isDayTextView.rect.h),
|
||||||
|
font=self.font)
|
||||||
|
|
||||||
|
def updateBasedOnPlayerStats(self, statistics: Statistics):
|
||||||
|
consoleLines = []
|
||||||
|
if self.healthBar.value != statistics.hp:
|
||||||
|
self.healthBar.updateFill(statistics.hp)
|
||||||
|
consoleLines.append("Health: " + str(statistics.hp))
|
||||||
|
|
||||||
|
if self.hungerBar.value != statistics.hunger:
|
||||||
|
self.hungerBar.updateFill(statistics.hunger)
|
||||||
|
consoleLines.append("Hunger: " + str(statistics.hunger))
|
||||||
|
|
||||||
|
if self.staminaBar.value != statistics.stamina:
|
||||||
|
self.staminaBar.updateFill(statistics.stamina)
|
||||||
|
consoleLines.append("Stamina: " + str(statistics.stamina))
|
||||||
|
|
||||||
|
if self.thirstBar.value != statistics.thirst:
|
||||||
|
self.thirstBar.updateFill(statistics.thirst)
|
||||||
|
consoleLines.append("Stamina: " + str(statistics.thirst))
|
||||||
|
|
||||||
|
if len(consoleLines) > 0:
|
||||||
|
self.console.addLinesToConsoleAndScrollToDisplayThem(consoleLines)
|
||||||
|
|
||||||
|
def updateBasedOnPygameEvent(self, event: pygame.event):
|
||||||
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||||
|
console = self.console
|
||||||
|
if event.button == 4:
|
||||||
|
console.writeConsoleLines(console.topWrittenLineInd + 1)
|
||||||
|
elif event.button == 5:
|
||||||
|
console.writeConsoleLines(console.topWrittenLineInd - 1)
|
||||||
|
|
||||||
|
|
||||||
|
class Colors(Enum):
|
||||||
|
RED = (255, 0, 0)
|
||||||
|
GREEN = (0, 255, 0)
|
||||||
|
BLUE = (0, 0, 255)
|
||||||
|
YELLOW = (255, 255, 0)
|
||||||
|
WHITE = (255, 255, 255)
|
||||||
|
GRAY = (125, 125, 125)
|
||||||
|
@ -1,5 +1,32 @@
|
|||||||
import src.ui.UiElement as UiElement
|
import pygame
|
||||||
|
|
||||||
|
from src.ui.UiElement import UiElement
|
||||||
|
|
||||||
|
|
||||||
class UiBar(UiElement):
|
class UiBar(UiElement):
|
||||||
pass
|
def __init__(self, rect: pygame.Rect, initialFilledPercent=100, filledBarColor=(255, 0, 0), emptyBarColor=(0, 0, 0),
|
||||||
|
outlineColor=(75, 75, 75), outlineThickness=10):
|
||||||
|
super().__init__(rect)
|
||||||
|
self.filledPercent = initialFilledPercent / 100
|
||||||
|
self.emptyBarColor = emptyBarColor
|
||||||
|
self.barColor = filledBarColor
|
||||||
|
self.outlineColor = outlineColor
|
||||||
|
self.outlineThickness = outlineThickness
|
||||||
|
self.filledBarColor = filledBarColor
|
||||||
|
self.value = initialFilledPercent
|
||||||
|
|
||||||
|
self.__genBar__()
|
||||||
|
|
||||||
|
def __genBar__(self):
|
||||||
|
self.image = pygame.Surface((self.rect.width, self.rect.height))
|
||||||
|
filledPartRect = pygame.rect.Rect(self.outlineThickness / 2, self.outlineThickness / 2,
|
||||||
|
(self.rect.width - self.outlineThickness) * self.filledPercent,
|
||||||
|
self.rect.height - self.outlineThickness)
|
||||||
|
self.image.fill(self.filledBarColor, filledPartRect)
|
||||||
|
pygame.draw.rect(self.image, self.outlineColor, pygame.rect.Rect(0, 0, self.rect.width, self.rect.height),
|
||||||
|
self.outlineThickness)
|
||||||
|
|
||||||
|
def updateFill(self, filledPercent):
|
||||||
|
self.filledPercent = filledPercent / 100
|
||||||
|
self.value = filledPercent
|
||||||
|
self.__genBar__()
|
||||||
|
@ -1,5 +1,67 @@
|
|||||||
import src.ui.UiElement as UiElement
|
from enum import Enum
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from src.ui.UiElement import UiElement
|
||||||
|
|
||||||
|
|
||||||
class UiButton(UiElement):
|
class UiButton(UiElement):
|
||||||
pass
|
|
||||||
|
def __init__(self, rect: pygame.Rect, notClickedBtnColor=(125, 125, 125), clickedBtnColor=(255, 255, 255),
|
||||||
|
text="Click", textColor=(0, 0, 0), font=None, functionsToInvokeWhenClicked=[]):
|
||||||
|
"""
|
||||||
|
:type functionsToInvokeWhenClicked : list of tuple(function, args*), args are function arguments
|
||||||
|
"""
|
||||||
|
super().__init__(rect)
|
||||||
|
if font is None:
|
||||||
|
font = pygame.font.Font(None, 25)
|
||||||
|
self.font = font
|
||||||
|
self.textColor = textColor
|
||||||
|
self.clickedBtnColor = clickedBtnColor
|
||||||
|
self.notClickedBtnColor = notClickedBtnColor
|
||||||
|
self.text = text
|
||||||
|
self.__initBtnImages__()
|
||||||
|
|
||||||
|
self.beingClicked = False
|
||||||
|
self.image = self._images[0]
|
||||||
|
|
||||||
|
self.functionsToInvokeWhenClicked = []
|
||||||
|
|
||||||
|
self.functionsToInvokeWhenClicked.extend(functionsToInvokeWhenClicked)
|
||||||
|
|
||||||
|
def eventHandler(self, event):
|
||||||
|
# change selected color if rectangle clicked
|
||||||
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||||
|
if event.button == 1:
|
||||||
|
if self.rect.collidepoint(event.pos): # is mouse over button
|
||||||
|
self.image = self._images[ButtonImages.CLICKING_IMAGE.value]
|
||||||
|
self.beingClicked = True
|
||||||
|
for func, *args in self.functionsToInvokeWhenClicked:
|
||||||
|
func(*args)
|
||||||
|
elif event.type == pygame.MOUSEBUTTONUP and self.beingClicked:
|
||||||
|
if event.button == 1:
|
||||||
|
self.beingClicked = False
|
||||||
|
self.image = self._images[ButtonImages.DEFAULT_IMAGE.value]
|
||||||
|
|
||||||
|
def __initBtnImages__(self):
|
||||||
|
self._images = [
|
||||||
|
pygame.Surface((self.rect.width, self.rect.height)),
|
||||||
|
pygame.Surface((self.rect.width, self.rect.height)),
|
||||||
|
]
|
||||||
|
self._images[ButtonImages.DEFAULT_IMAGE.value].fill(self.notClickedBtnColor)
|
||||||
|
self._images[ButtonImages.CLICKING_IMAGE.value].fill(self.clickedBtnColor)
|
||||||
|
self.textSurface = self.font.render(self.text, False, (0, 0, 0))
|
||||||
|
self.textSurfaceDest = (self.rect.centerx - (self.textSurface.get_width() / 2),
|
||||||
|
self.rect.centery - (self.textSurface.get_height() / 2))
|
||||||
|
self._images[0].blit(self.textSurface, self.textSurfaceDest)
|
||||||
|
self._images[1].blit(self.textSurface, self.textSurfaceDest)
|
||||||
|
|
||||||
|
def addFuncToInvoke(self, tupleOfFuncAndArgs):
|
||||||
|
"""
|
||||||
|
:type tupleOfFuncAndArgs: tuple(function, *args)
|
||||||
|
"""
|
||||||
|
self.functionsToInvokeWhenClicked.append(tupleOfFuncAndArgs)
|
||||||
|
|
||||||
|
|
||||||
|
class ButtonImages(Enum):
|
||||||
|
DEFAULT_IMAGE = 0
|
||||||
|
CLICKING_IMAGE = 1
|
||||||
|
79
src/ui/UiConsole.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import pygame
|
||||||
|
|
||||||
|
from src.ui.UiElement import UiElement
|
||||||
|
|
||||||
|
|
||||||
|
class UiConsole(UiElement):
|
||||||
|
def __init__(self, rect: pygame.Rect, bgColor=(125, 125, 125), textColor=(255, 255, 255), font=None):
|
||||||
|
super().__init__(rect)
|
||||||
|
self.textColor = textColor
|
||||||
|
|
||||||
|
if font is None:
|
||||||
|
font = pygame.font.Font(None, 25)
|
||||||
|
self.font = font
|
||||||
|
self.bgColor = bgColor
|
||||||
|
|
||||||
|
self.image = pygame.Surface((rect.width, rect.height))
|
||||||
|
self.image.fill(bgColor)
|
||||||
|
|
||||||
|
self.consoleWidth = self.image.get_width()
|
||||||
|
self.linesImagesCount = 0
|
||||||
|
|
||||||
|
self.consoleLines = []
|
||||||
|
self.linesCount = 0
|
||||||
|
self.topWrittenLineInd = 0
|
||||||
|
|
||||||
|
self.linesImages = []
|
||||||
|
self.lineHeight = font.render("sampleText", False, textColor).get_height()
|
||||||
|
|
||||||
|
self.maxLines = int(self.image.get_height() / self.lineHeight)
|
||||||
|
|
||||||
|
self.addLinesToConsole(["Hello from console!"])
|
||||||
|
self.writeConsoleLines()
|
||||||
|
|
||||||
|
def writeConsoleLines(self, startingLineInd=0):
|
||||||
|
self.image.fill(self.bgColor)
|
||||||
|
if startingLineInd < 0:
|
||||||
|
startingLineInd = 0
|
||||||
|
elif startingLineInd >= self.linesImagesCount:
|
||||||
|
startingLineInd = self.linesImagesCount - 1
|
||||||
|
self.topWrittenLineInd = startingLineInd
|
||||||
|
writtenLines = 0
|
||||||
|
for i in range(startingLineInd, min(self.maxLines + startingLineInd, self.linesImagesCount)):
|
||||||
|
self.image.blit(self.linesImages[i], (0, writtenLines * self.lineHeight))
|
||||||
|
writtenLines += 1
|
||||||
|
|
||||||
|
def addLinesToConsole(self, linesToAdd):
|
||||||
|
for line in linesToAdd:
|
||||||
|
self.consoleLines.append(line)
|
||||||
|
self.linesCount += 1
|
||||||
|
|
||||||
|
row = pygame.Surface((self.consoleWidth, self.lineHeight))
|
||||||
|
row.fill(self.bgColor)
|
||||||
|
|
||||||
|
howMuchRowIsFilled = 0
|
||||||
|
words = line.split(' ')
|
||||||
|
for word in words:
|
||||||
|
wordImage = self.font.render(' ' + word, False, self.textColor)
|
||||||
|
if howMuchRowIsFilled + wordImage.get_width() <= self.consoleWidth:
|
||||||
|
row.blit(wordImage, (howMuchRowIsFilled, 0))
|
||||||
|
howMuchRowIsFilled += wordImage.get_width()
|
||||||
|
else:
|
||||||
|
self.linesImages.append(row)
|
||||||
|
self.linesImagesCount += 1
|
||||||
|
row = pygame.Surface((self.consoleWidth, self.lineHeight))
|
||||||
|
row.fill(self.bgColor)
|
||||||
|
howMuchRowIsFilled = 0
|
||||||
|
|
||||||
|
row.blit(wordImage, (howMuchRowIsFilled, 0))
|
||||||
|
howMuchRowIsFilled += wordImage.get_width()
|
||||||
|
|
||||||
|
self.linesImages.append(row)
|
||||||
|
self.linesImagesCount += 1
|
||||||
|
|
||||||
|
def addLinesToConsoleAndScrollToDisplayThem(self, linesToAdd):
|
||||||
|
self.addLinesToConsole(linesToAdd)
|
||||||
|
ind = 0
|
||||||
|
if self.linesImagesCount > self.maxLines:
|
||||||
|
ind = self.linesImagesCount - self.maxLines
|
||||||
|
self.writeConsoleLines(ind)
|
@ -1,2 +1,7 @@
|
|||||||
class UiElement:
|
import pygame
|
||||||
pass
|
|
||||||
|
|
||||||
|
class UiElement(pygame.sprite.Sprite):
|
||||||
|
def __init__(self, rect):
|
||||||
|
super().__init__()
|
||||||
|
self.rect = rect
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import src.ui.UiElement as UiElement
|
from src.ui.UiElement import UiElement
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
|
||||||
class UiImage(UiElement):
|
class UiImage(UiElement):
|
||||||
pass
|
def __init__(self, rect: pygame.Rect, image: pygame.Surface):
|
||||||
|
super().__init__(rect)
|
||||||
|
self.image = pygame.transform.scale(image, (rect.width, rect.height))
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,34 @@
|
|||||||
import src.ui.UiElement as UiElement
|
from typing import Tuple
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from src.ui.UiElement import UiElement
|
||||||
|
|
||||||
|
|
||||||
class UiText(UiElement):
|
class UiText(UiElement):
|
||||||
pass
|
def __init__(self, rect: pygame.Rect, text: str, font: pygame.font.Font = None,
|
||||||
|
textColor=(0, 0, 0), antialias: bool = False,
|
||||||
|
backgroundColor=None):
|
||||||
|
super().__init__(rect)
|
||||||
|
|
||||||
|
self.backgroundColor = backgroundColor
|
||||||
|
self.antialias = antialias
|
||||||
|
self.textColor = textColor
|
||||||
|
self.text = text
|
||||||
|
if font is None:
|
||||||
|
font = pygame.font.Font(None, 12)
|
||||||
|
self.font = font
|
||||||
|
|
||||||
|
self.image = pygame.Surface((rect.w, rect.h))
|
||||||
|
if backgroundColor is not None:
|
||||||
|
self.image.fill(backgroundColor)
|
||||||
|
wordImage = self.font.render(text, antialias, textColor)
|
||||||
|
self.image.blit(wordImage, (0, 0))
|
||||||
|
|
||||||
|
def changeText(self, newText):
|
||||||
|
self.text = newText
|
||||||
|
|
||||||
|
if self.backgroundColor is not None:
|
||||||
|
self.image.fill(self.backgroundColor)
|
||||||
|
wordImage = self.font.render(self.text, self.antialias, self.textColor)
|
||||||
|
self.image.blit(wordImage, (0, 0))
|
||||||
|