Merge branch 'UI' into passingEvents

# Conflicts:
#	src/game/Screen.py
This commit is contained in:
Michał Czekański 2020-04-05 23:23:30 +02:00
commit a28fab0956
9 changed files with 305 additions and 17 deletions

View File

@ -37,6 +37,11 @@ class Game:
print("The screen cannot be in a vertical orientation. Exiting...")
exit(1)
# Initialize timers
self.pgTimer = pygame.time.Clock()
self.ingameTimer = Timer()
self.ingameTimer.startClock()
self.screen = Screen(self, self.config["window"])
print("OK")
@ -50,6 +55,9 @@ class Game:
def mainLoop(self):
while self.running:
# Update ingame clock
self.ingameTimer.updateTime(self.pgTimer.tick())
self.eventManager.handleEvents()
self.spritesList.draw(self.screen.pygameScreen)
pygame.display.flip()

View File

@ -2,11 +2,19 @@ import math
from enum import Enum
import pygame
from src.ui.Ui import Ui
# minimum UI width
MARGIN = 300
# screen locations enum
class Locations(Enum):
RIGHT_UI = 1
LEFT_UI = 2
MAP = 3
class Screen:
def __init__(self, gameObject, windowConfig):
self.gameObject = gameObject
@ -24,6 +32,8 @@ class Screen:
# draw a white rect to resemble map
pygame.draw.rect(self.pygameScreen, (255, 255, 255), [self.mapCoord, 0, self.mapSize, self.mapSize])
self.__initUi__()
def calculateMapDimensions(self):
result = 0
expectedSize = self.winY
@ -49,9 +59,25 @@ class Screen:
def removeSprite(self, 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
class Locations(Enum):
RIGHT_UI = 1
LEFT_UI = 2
MAP = 3
def __initUi__(self):
self.ui = Ui(self.getUiWidth(Locations.RIGHT_UI), self.getUiWidth(Locations.LEFT_UI), self.winY,
self.gameObject.ingameTimer)
self.draw(self.ui.timerTextView, Locations.LEFT_UI, 0, 0)
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)

View File

@ -1,3 +1,60 @@
from enum import Enum
import pygame
from src.ui.UiBar import UiBar
from src.ui.UiConsole import UiConsole
from src.ui.UiText import UiText
class Ui():
def __init__(self):
self.elements = []
def __init__(self, rightUiWidth, leftUiWidth, screenHeight, timer, font=None):
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)
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)

View File

@ -1,5 +1,30 @@
import src.ui.UiElement as UiElement
import pygame
from src.ui.UiElement import 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.__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.__genBar__()

View File

@ -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):
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
View 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
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)

View File

@ -1,2 +1,7 @@
class UiElement:
pass
import pygame
class UiElement(pygame.sprite.Sprite):
def __init__(self, rect):
super().__init__()
self.rect = rect

View File

@ -1,5 +1,10 @@
import src.ui.UiElement as UiElement
from src.ui.UiElement import UiElement
import pygame
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))

View File

@ -1,5 +1,26 @@
import src.ui.UiElement as UiElement
from typing import Tuple
import pygame
from src.ui.UiElement import 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))