Merge branch 'UI' into passingEvents
# Conflicts: # src/game/Screen.py
This commit is contained in:
commit
a28fab0956
@ -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()
|
||||
|
@ -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)
|
||||
|
61
src/ui/Ui.py
61
src/ui/Ui.py
@ -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)
|
||||
|
@ -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__()
|
||||
|
@ -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
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
|
||||
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:
|
||||
pass
|
||||
import pygame
|
||||
|
||||
|
||||
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):
|
||||
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,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))
|
||||
|
Loading…
Reference in New Issue
Block a user