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
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name" : "cranberry",
|
||||
"position" : {
|
||||
"x": 7,
|
||||
"y": 1
|
||||
"y": 3
|
||||
},
|
||||
"isPickupable" : true,
|
||||
"effect" : {
|
||||
@ -26,5 +27,52 @@
|
||||
"thirst" : 2,
|
||||
"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):
|
||||
super().__init__()
|
||||
self.image, self.rect = self.getTexture(texture, size)
|
||||
self.image.set_colorkey((255, 255, 255))
|
||||
self.rect.x = pos[0]
|
||||
self.rect.y = pos[1]
|
||||
self.id = self.getId()
|
||||
|
@ -6,13 +6,21 @@ import pygame
|
||||
|
||||
|
||||
class Player(Entity):
|
||||
statistics: Statistics
|
||||
|
||||
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
|
||||
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
|
||||
def move(self, rotation):
|
||||
self.movePoints += 1
|
||||
# Player gets tired aswell!
|
||||
self.applyFatigue()
|
||||
if rotation.value == Rotations.NORTH.value:
|
||||
self.rect.y -= self.rect.w
|
||||
elif rotation.value == Rotations.EAST.value:
|
||||
@ -22,14 +30,57 @@ class Player(Entity):
|
||||
elif rotation.value == Rotations.WEST.value:
|
||||
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):
|
||||
# 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.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
|
||||
WEST = 3
|
||||
|
||||
|
||||
class StatisticNames(Enum):
|
||||
HP = 0
|
||||
STAMINA = 1
|
||||
HUNGER = 2
|
||||
THIRST = 3
|
@ -16,29 +16,29 @@ class Statistics:
|
||||
self.hp = 100
|
||||
|
||||
def set_hunger(self, hunger_diff):
|
||||
if 0 <= self.hp + hunger_diff <= 100:
|
||||
self.hp = self.hp + hunger_diff
|
||||
if 0 <= self.hunger + hunger_diff <= 100:
|
||||
self.hunger = self.hunger + hunger_diff
|
||||
else:
|
||||
if self.hp + hunger_diff <= 0:
|
||||
self.hp = 0
|
||||
if self.hunger + hunger_diff <= 0:
|
||||
self.hunger = 0
|
||||
else:
|
||||
self.hp = 100
|
||||
self.hunger = 100
|
||||
|
||||
def set_thirst(self, thirst_diff):
|
||||
if 0 <= self.hp + thirst_diff <= 100:
|
||||
self.hp = self.hp + thirst_diff
|
||||
if 0 <= self.thirst + thirst_diff <= 100:
|
||||
self.thirst = self.thirst + thirst_diff
|
||||
else:
|
||||
if self.hp + thirst_diff <= 0:
|
||||
self.hp = 0
|
||||
if self.thirst + thirst_diff <= 0:
|
||||
self.thirst = 0
|
||||
else:
|
||||
self.hp = 100
|
||||
self.thirst = 100
|
||||
|
||||
def set_stamina(self, stamina_diff):
|
||||
if 0 <= self.hp + stamina_diff <= 100:
|
||||
self.hp = self.hp + stamina_diff
|
||||
if 0 <= self.stamina + stamina_diff <= 100:
|
||||
self.stamina = self.stamina + stamina_diff
|
||||
else:
|
||||
if self.hp + stamina_diff <= 0:
|
||||
self.hp = 0
|
||||
if self.stamina + stamina_diff <= 0:
|
||||
self.stamina = 0
|
||||
else:
|
||||
self.hp = 100
|
||||
self.stamina = 100
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import pygame
|
||||
|
||||
from src.entities.Pickupable import Pickupable
|
||||
from src.entities.Player import Rotations
|
||||
|
||||
# Player can move every given milliseconds
|
||||
@ -21,19 +22,28 @@ class EventManager:
|
||||
def handleEvents(self):
|
||||
pygame.event.pump()
|
||||
|
||||
self.game.screen.ui.timerTextView.changeText(self.game.ingameTimer.getPrettyTime())
|
||||
|
||||
keys = pygame.key.get_pressed()
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
self.game.running = False
|
||||
self.game.screen.ui.updateBasedOnPygameEvent(event)
|
||||
self.keyTimeout += self.keyTimer.tick()
|
||||
if self.keyTimeout >= TIMEOUT:
|
||||
self.handlePlayerControls(keys)
|
||||
self.keyTimeout = 0
|
||||
|
||||
self.game.screen.ui.updateBasedOnPlayerStats(self.player.statistics)
|
||||
|
||||
def handlePlayerControls(self, keys):
|
||||
# Key names are temporary
|
||||
# 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]:
|
||||
self.player.rotate(Rotations.NORTH)
|
||||
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.Screen import Screen
|
||||
from game.Map import Map
|
||||
|
||||
from src.entities.Pickupable import Pickupable
|
||||
from src.entities.Player import Player
|
||||
from src.entities.Statistics import Statistics
|
||||
from src.game.Timer import Timer
|
||||
|
||||
|
||||
class Game:
|
||||
@ -37,6 +41,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 +59,8 @@ 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()
|
||||
|
@ -1,8 +1,8 @@
|
||||
import json
|
||||
|
||||
import pygame
|
||||
from game.TerrainTile import TerrainTile
|
||||
from game.Screen import Locations
|
||||
from src.game.TerrainTile import TerrainTile
|
||||
from src.game.Screen import Locations
|
||||
|
||||
from src.entities.Entity import Entity
|
||||
from src.entities.Pickupable import Pickupable
|
||||
@ -42,7 +42,7 @@ class Map:
|
||||
for entity in entityListJson:
|
||||
try:
|
||||
if entity["isPickupable"]:
|
||||
actualEntities.append(Pickupable(entity["name"] + ".jpg",
|
||||
actualEntities.append(Pickupable(entity["name"] + ".png",
|
||||
self.tileSize,
|
||||
(entity["position"]["x"] * self.tileSize, entity["position"]["y"] * self.tileSize),
|
||||
Statistics(entity["effect"]["hp"],
|
||||
@ -50,7 +50,7 @@ class Map:
|
||||
entity["effect"]["thirst"],
|
||||
entity["effect"]["stamina"])))
|
||||
else:
|
||||
actualEntities.append(Entity(entity["name"],
|
||||
actualEntities.append(Entity(entity["name"] + ".png",
|
||||
self.tileSize,
|
||||
(entity["position"]["x"] * self.tileSize, entity["position"]["y"] * self.tileSize)))
|
||||
except KeyError:
|
||||
@ -67,7 +67,7 @@ class Map:
|
||||
elif tile == '.':
|
||||
self.screen.draw(TerrainTile(col, row, 'grass.png', self.tileSize), Locations.MAP, 0, 0)
|
||||
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.collidables.add(object)
|
||||
elif tile == 'w':
|
||||
@ -75,6 +75,13 @@ class Map:
|
||||
self.screen.draw(object, Locations.MAP, 0, 0)
|
||||
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):
|
||||
self.screen.draw(entity, Locations.MAP, 0, 0)
|
||||
self.collidables.add(entity)
|
||||
|
@ -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)
|
||||
|
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():
|
||||
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)
|
||||
|
||||
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):
|
||||
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):
|
||||
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:
|
||||
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,34 @@
|
||||
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))
|
||||
|
||||
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))
|
||||
|