Compare commits
10 Commits
4deabdc16f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
058c16b685 | ||
| 52df76081e | |||
| ab42032582 | |||
| 323770b753 | |||
| bb06e3e338 | |||
|
|
adb1fd2ca4 | ||
| cd4bfff5e7 | |||
| 98e44a6cf8 | |||
| 5abf81c6cb | |||
| b576537fb5 |
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
*.dem
|
||||
__pycache__/
|
||||
venv
|
||||
venv
|
||||
.venv
|
||||
BIN
assets/fonts/Metropolis-Bold.ttf
Normal file
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
BIN
assets/images/bomb.png
Normal file
|
After Width: | Height: | Size: 377 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@@ -1,6 +1,6 @@
|
||||
|
||||
{
|
||||
"material": "maps/cs_office.png",
|
||||
"material": "assets/maps/overview/cs_office.png",
|
||||
"pos_x": -1838,
|
||||
"pos_y": 1858,
|
||||
"scale": 4.1,
|
||||
8
assets/maps/config/de_ancient.json
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
{
|
||||
"material": "assets/maps/overview/de_ancient.png",
|
||||
"pos_x": -2953,
|
||||
"pos_y": 2164,
|
||||
"scale": 5
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"material": "maps/de_anubis.png",
|
||||
"material": "assets/maps/overview/de_anubis.png",
|
||||
"pos_x": -2796.000000,
|
||||
"pos_y": 3328.000000,
|
||||
"scale": 5.220000
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
{
|
||||
"material": "maps/de_dust2.png" ,
|
||||
"material": "assets/maps/overview/de_dust2.png" ,
|
||||
"pos_x": -2476 ,
|
||||
"pos_y": 3239,
|
||||
"scale": 4.4 ,
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
{
|
||||
"material": "maps/de_inferno.png",
|
||||
"material": "assets/maps/overview/de_inferno.png",
|
||||
"pos_x": -2087 ,
|
||||
"pos_y" : 3870,
|
||||
"scale": 4.9,
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"material": "maps/de_mirage.png",
|
||||
"material": "assets/maps/overview/de_mirage.png",
|
||||
"pos_x": -3230,
|
||||
"pos_y": 1713,
|
||||
"scale": 5.00,
|
||||
8
assets/maps/config/de_overpass.json
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
{
|
||||
"material": "assets/maps/overview/de_overpass.png",
|
||||
"pos_x": -4831,
|
||||
"pos_y": 1781,
|
||||
"scale": 5.2
|
||||
|
||||
}
|
||||
|
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
@@ -1,5 +1,4 @@
|
||||
import pygame
|
||||
import copy
|
||||
|
||||
class ControlController:
|
||||
def __init__(self, control_renderer, box_top: tuple[int, int]):
|
||||
|
||||
4
main.py
@@ -22,13 +22,15 @@ def main():
|
||||
},
|
||||
"styling": {
|
||||
"font": pygame.font.Font("assets/fonts/Metropolis-Regular.ttf", 30),
|
||||
"small_font": pygame.font.Font("assets/fonts/Metropolis-Regular.ttf", 15),
|
||||
"small_font": pygame.font.Font("assets/fonts/Metropolis-Regular.ttf", 18),
|
||||
"underline_bold_font": (lambda f: (f.set_underline(True), f)[1])(pygame.font.Font("assets/fonts/Metropolis-Bold.ttf", 30)),
|
||||
"button_colour": (200, 200, 200),
|
||||
"pressed_button_colour": (150, 150, 150),
|
||||
"text_colour": (255, 255, 255),
|
||||
"background_colour": (30, 30, 30),
|
||||
"foreground_colour": (100, 100, 100),
|
||||
"player_selected_colour": (255, 255, 0),
|
||||
"bomb_image": pygame.image.load("assets/images/bomb.png"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
{
|
||||
"material": "maps/de_ancient.png",
|
||||
"pos_x": -2953,
|
||||
"pos_y": 2164,
|
||||
"scale": 5
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
{
|
||||
"material": "maps/de_overpass.png",
|
||||
"pos_x": -4831,
|
||||
"pos_y": 1781,
|
||||
"scale": 5.2
|
||||
|
||||
}
|
||||
@@ -2,11 +2,13 @@ from models.player import Player
|
||||
from models.team import Team
|
||||
|
||||
class Match:
|
||||
def __init__(self, map_name, game_info, team_1: Team, team_2: Team, tick_rate=64):
|
||||
def __init__(self, map_name, game_info, team_1: Team, team_2: Team, game_events, tick_rate=64):
|
||||
self.team_1 = team_1
|
||||
self.team_2 = team_2
|
||||
|
||||
self.map_name = map_name
|
||||
self.game_events = game_events
|
||||
self.round_start_times = list(self.game_events[0][1]["tick"])
|
||||
|
||||
self.tick = 1
|
||||
self.current_tick = game_info[game_info["tick"] == self.tick]
|
||||
@@ -17,28 +19,46 @@ class Match:
|
||||
self.game_info = game_info.sort_values(by=["tick", "player_steamid"]) # pd dataframe sorted by tick
|
||||
self.tick_rate = tick_rate
|
||||
|
||||
def _update_player_positions(self) -> None:
|
||||
# inefficient, might need to change
|
||||
|
||||
def _update_player(self, player: Player) -> None:
|
||||
player_row = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]
|
||||
|
||||
if player_row.empty:
|
||||
return
|
||||
|
||||
row = player_row.iloc[0]
|
||||
|
||||
player.x = row["X"]
|
||||
player.y = row["Y"]
|
||||
player.z = row["Z"]
|
||||
player.pitch = row["pitch"]
|
||||
player.yaw = row["yaw"]
|
||||
player.dead = row["is_alive"] == 0
|
||||
player.is_shooting = row["shots_fired"]
|
||||
player.health = int(row["health"])
|
||||
player.armour = int(row["armor_value"])
|
||||
player.current_weapon = row["active_weapon_name"]
|
||||
player.kills = int(row["kills_total"])
|
||||
player.deaths = int(row["deaths_total"])
|
||||
player.assists = int(row["assists_total"])
|
||||
player.inventory = row["inventory"]
|
||||
|
||||
if "C4 Explosive" in player.inventory:
|
||||
player.has_bomb = True
|
||||
else:
|
||||
player.has_bomb = False
|
||||
|
||||
if "Defuse Kit" in player.inventory:
|
||||
player.has_defuser = True
|
||||
else:
|
||||
player.has_defuser = False
|
||||
|
||||
def _update_players(self) -> None:
|
||||
# empty tick
|
||||
if self.current_tick.empty:
|
||||
return
|
||||
|
||||
# # check if current tick has NaN values
|
||||
# if self.current_tick.isnull().values.any():
|
||||
# return
|
||||
|
||||
|
||||
for player in self.get_players():
|
||||
player.x = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["X"].values[0]
|
||||
player.y = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["Y"].values[0]
|
||||
player.z = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["Z"].values[0]
|
||||
player.pitch = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["pitch"].values[0]
|
||||
player.yaw = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["yaw"].values[0]
|
||||
player.dead = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["is_alive"].values[0] == 0
|
||||
player.is_shooting = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["shots_fired"].values[0]
|
||||
player.health = int(self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["health"].values[0])
|
||||
player.armour = int(self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["armor_value"].values[0])
|
||||
player.current_weapon = self.current_tick[self.current_tick["player_steamid"] == player.steam_id]["active_weapon_name"].values[0]
|
||||
self._update_player(player)
|
||||
|
||||
def _update_round(self) -> None:
|
||||
if self.current_tick.empty:
|
||||
@@ -46,27 +66,34 @@ class Match:
|
||||
|
||||
self.round = self.current_tick["total_rounds_played"].values[0]
|
||||
|
||||
if self.round >= 12:
|
||||
self.team_1.set_t()
|
||||
self.team_2.set_ct()
|
||||
self.team_1.score = int(self.current_tick[self.current_tick["team_num"] == 3]["team_rounds_total"].values[0])
|
||||
self.team_2.score = int(self.current_tick[self.current_tick["team_num"] == 2]["team_rounds_total"].values[0])
|
||||
else:
|
||||
self.team_1.set_ct()
|
||||
self.team_2.set_t()
|
||||
self.team_1.score = int(self.current_tick[self.current_tick["team_num"] == 2]["team_rounds_total"].values[0])
|
||||
self.team_2.score = int(self.current_tick[self.current_tick["team_num"] == 3]["team_rounds_total"].values[0])
|
||||
self.team_1.score = int(self.current_tick[self.current_tick["team_num"] == self.team_1.id]["team_rounds_total"].values[0])
|
||||
self.team_2.score = int(self.current_tick[self.current_tick["team_num"] == self.team_2.id]["team_rounds_total"].values[0])
|
||||
|
||||
def _update_team_ids(self) -> None:
|
||||
# get random player from each team
|
||||
if self.current_tick.empty:
|
||||
return
|
||||
|
||||
for team in self.get_teams():
|
||||
random_player = team.players[0]
|
||||
player_team_id = self.current_tick[self.current_tick["player_steamid"] == random_player.steam_id]["team_num"].values[0]
|
||||
|
||||
if player_team_id == 2:
|
||||
team.set_t()
|
||||
elif player_team_id == 3:
|
||||
team.set_ct()
|
||||
|
||||
def next_tick(self) -> None:
|
||||
self.tick += 1
|
||||
self.current_tick = self.game_info[self.game_info["tick"] == self.tick]
|
||||
self._update_player_positions()
|
||||
self._update_players()
|
||||
self._update_team_ids()
|
||||
self._update_round()
|
||||
|
||||
def set_tick(self, tick: int) -> None:
|
||||
self.tick = tick
|
||||
self.current_tick = self.game_info[self.game_info["tick"] == self.tick]
|
||||
self._update_player_positions()
|
||||
self._update_players()
|
||||
self._update_round()
|
||||
|
||||
def get_players(self) -> list[Player]:
|
||||
|
||||
@@ -13,6 +13,15 @@ class Player:
|
||||
self.dead = False
|
||||
self.is_shooting = False
|
||||
self.current_weapon = None
|
||||
self.has_bomb = False
|
||||
self.is_planting = False
|
||||
self.has_defuser = False
|
||||
self.is_defusing = False
|
||||
self.inventory = []
|
||||
|
||||
self.kills = 0
|
||||
self.deaths = 0
|
||||
self.assists = 0
|
||||
|
||||
## UI-related state
|
||||
self.is_selected = False
|
||||
|
||||
@@ -7,7 +7,8 @@ class Team:
|
||||
def __init__(self):
|
||||
self.players = []
|
||||
self.score = 0
|
||||
self.set_t()
|
||||
self.id = 1
|
||||
self.set_ct()
|
||||
|
||||
def add_player(self, player: Player):
|
||||
self.players.append(player)
|
||||
@@ -16,9 +17,9 @@ class Team:
|
||||
self.players.remove(player)
|
||||
|
||||
def set_ct(self):
|
||||
self.is_ct = True
|
||||
self.id = 3
|
||||
self.colour = CT_COLOUR
|
||||
|
||||
def set_t(self):
|
||||
self.is_ct = False
|
||||
self.id = 2
|
||||
self.colour = T_COLOUR
|
||||
@@ -1,5 +1,5 @@
|
||||
import pygame
|
||||
from widgets.slider import HorizontalSlider
|
||||
from widgets.break_slider import BreakSlider
|
||||
|
||||
class ControlRenderer:
|
||||
def __init__(self, screen, match):
|
||||
@@ -8,7 +8,10 @@ class ControlRenderer:
|
||||
self.match = match
|
||||
self.colour = (255, 255, 255)
|
||||
|
||||
self.slider = HorizontalSlider(self.screen, 50, 0, self.screen.get_width()-50, 20, 1, self.match.max_tick)
|
||||
self.slider = BreakSlider(self.screen, 50, 0, self.screen.get_width()-50, 20, 1, self.match.max_tick)
|
||||
self.slider.fill = True
|
||||
self.slider.set_breakpoints(self.match.round_start_times)
|
||||
self.slider.set_fill_colour((0,0,0))
|
||||
|
||||
def _render_slider(self):
|
||||
# Update slider value
|
||||
|
||||
@@ -10,10 +10,10 @@ class GUIRenderer:
|
||||
|
||||
# Buttons
|
||||
self.settings_button = Button(self.screen.get_width()-40, 10, 30, 30, None)
|
||||
self.settings_button.set_image("assets/setting.png")
|
||||
self.settings_button.set_image("assets/images/setting.png")
|
||||
|
||||
self.back_button = Button(self.screen.get_width()-80, 10, 30, 30, None)
|
||||
self.back_button.set_image("assets/arrow.png")
|
||||
self.back_button.set_image("assets/images/arrow.png")
|
||||
|
||||
self.colour = (255, 255, 255)
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import pygame
|
||||
|
||||
class InfoRenderer:
|
||||
def __init__(self, screen, styling, match):
|
||||
self.screen = screen
|
||||
@@ -8,25 +6,45 @@ class InfoRenderer:
|
||||
self.colour = self.styling["text_colour"]
|
||||
self.font = self.styling["font"]
|
||||
self.small_font = self.styling["small_font"]
|
||||
|
||||
self.underline_bold_font = self.styling["underline_bold_font"]
|
||||
self.selected_player = None
|
||||
|
||||
self.player_info_start_y = 100
|
||||
self.match_info_start_y = 500
|
||||
|
||||
# Private methods
|
||||
def _render_player_info(self):
|
||||
"""Draws the player info on the screen."""
|
||||
if self.selected_player is None:
|
||||
return
|
||||
player_info_title = "No player selected\n"
|
||||
player_info = ""
|
||||
else:
|
||||
player_info_title = f"Player: {self.selected_player.name}\n"
|
||||
player_info = f"Active Weapon: {self.selected_player.current_weapon}\n"
|
||||
player_info += f"Inventory: \n - {"\n - ".join(self.selected_player.inventory)}\n"
|
||||
player_info += f"Health: {self.selected_player.health}\n"
|
||||
player_info += f"Armour: {self.selected_player.armour}\n"
|
||||
player_info += f"Kills: {self.selected_player.kills}\n"
|
||||
player_info += f"Deaths: {self.selected_player.deaths}\n"
|
||||
player_info += f"Assists: {self.selected_player.assists}\n"
|
||||
|
||||
player_info_title = f"{self.selected_player.name}\n"
|
||||
player_info = f"Active Weapon: {self.selected_player.current_weapon}\n"
|
||||
player_info += f"Health: {self.selected_player.health}\n"
|
||||
player_info += f"Armour: {self.selected_player.armour}\n"
|
||||
|
||||
text_surface = self.font.render(player_info_title, True, self.styling["text_colour"])
|
||||
self.screen.blit(text_surface, (10, 100))
|
||||
text_surface = self.underline_bold_font.render(player_info_title, True, self.styling["text_colour"])
|
||||
self.screen.blit(text_surface, (10, self.player_info_start_y))
|
||||
|
||||
text_surface = self.small_font.render(player_info, True, self.styling["text_colour"])
|
||||
self.screen.blit(text_surface, (10, 150))
|
||||
self.screen.blit(text_surface, (10, self.player_info_start_y + 50))
|
||||
|
||||
def _render_match_info(self):
|
||||
"""Draws the match info on the screen."""
|
||||
match_info_title = "Match Info\n"
|
||||
match_info = f"Map: {self.match.map_name}\n"
|
||||
match_info += f"Score: {self.match.team_1.score}-{self.match.team_2.score}\n"
|
||||
|
||||
text_surface = self.underline_bold_font.render(match_info_title, True, self.styling["text_colour"])
|
||||
self.screen.blit(text_surface, (10, self.match_info_start_y))
|
||||
|
||||
text_surface = self.small_font.render(match_info, True, self.styling["text_colour"])
|
||||
self.screen.blit(text_surface, (10, self.match_info_start_y + 50))
|
||||
|
||||
def _render_current_tick(self, match_tick, max_tick):
|
||||
text = self.font.render(f"Tick: {match_tick}/{max_tick}", True, self.colour)
|
||||
@@ -41,4 +59,4 @@ class InfoRenderer:
|
||||
"""Renders the info on the screen."""
|
||||
self._render_player_info()
|
||||
self._render_current_tick(self.match.tick, self.match.max_tick)
|
||||
self._render_team_scores(self.match.team_1.score, self.match.team_2.score)
|
||||
self._render_match_info()
|
||||
@@ -13,9 +13,14 @@ class PlayerRenderer:
|
||||
self.styling = styling
|
||||
self.player_font = pygame.font.Font(None, 15)
|
||||
|
||||
self.bomb_image = self.styling["bomb_image"]
|
||||
|
||||
self.player_radius = 5
|
||||
self.hovered_radius = 10
|
||||
|
||||
self.bomb_radius = 10
|
||||
self.bomb_hovered_radius = 15
|
||||
|
||||
self.health_bar_foreground = (0, 255, 0)
|
||||
self.health_bar_background = (255, 0, 0)
|
||||
|
||||
@@ -41,6 +46,10 @@ class PlayerRenderer:
|
||||
|
||||
## Private Methods
|
||||
def _render_circle(self, player: Player, team):
|
||||
if player.has_bomb:
|
||||
self._render_bomb(player)
|
||||
return
|
||||
|
||||
if player.is_hovered:
|
||||
radius = self.hovered_radius
|
||||
else:
|
||||
@@ -49,6 +58,16 @@ class PlayerRenderer:
|
||||
x, y = self.map_coord_converter.map_to_screen(player.x, player.y)
|
||||
pygame.draw.circle(self.screen, team.colour, (x, y), radius)
|
||||
|
||||
def _render_bomb(self, player: Player):
|
||||
if player.is_hovered:
|
||||
radius = self.bomb_hovered_radius
|
||||
else:
|
||||
radius = self.bomb_radius
|
||||
|
||||
x, y = self.map_coord_converter.map_to_screen(player.x, player.y)
|
||||
bomb_image = pygame.transform.scale(self.bomb_image, (radius*2, radius*2))
|
||||
self.screen.blit(bomb_image, (x-radius, y-radius))
|
||||
|
||||
def _render_text(self, player):
|
||||
if player.is_selected:
|
||||
text = self.player_font.render(player.name, True, self.styling["player_selected_colour"])
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import pygame
|
||||
from widgets.button import Button
|
||||
from widgets.switch import Switch
|
||||
|
||||
@@ -21,7 +20,7 @@ class SettingsMenuRenderer:
|
||||
self.back_button.set_colour(self.styling["button_colour"])
|
||||
self.back_button.set_font(self.styling["font"])
|
||||
self.back_button.set_pressed_colour(self.styling["pressed_button_colour"])
|
||||
self.back_button.set_image("assets/arrow.png")
|
||||
self.back_button.set_image("assets/images/arrow.png")
|
||||
|
||||
# Switches
|
||||
self.show_yaw_button = Switch(self.widget_start_x, 100, 100, self.show_yaw_text.get_rect().height, self.options["show_yaw"])
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
demoparser2==0.38.0
|
||||
numpy==2.2.4
|
||||
numpy==2.2.5
|
||||
pandas==2.2.3
|
||||
polars==1.25.2
|
||||
pyarrow==19.0.1
|
||||
pygame==2.6.1
|
||||
polars==1.29.0
|
||||
pyarrow==20.0.0
|
||||
pygame-ce==2.5.3
|
||||
pygame_gui==0.6.13
|
||||
python-dateutil==2.9.0.post0
|
||||
pytz==2025.1
|
||||
python-i18n==0.3.9
|
||||
pytz==2025.2
|
||||
six==1.17.0
|
||||
tqdm==4.67.1
|
||||
tzdata==2025.1
|
||||
pygame_gui==0.6.13
|
||||
pygame-ce==2.5.3
|
||||
pygame-pgu==0.21
|
||||
python-i18n==0.3.9
|
||||
tzdata==2025.2
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import time
|
||||
from states.game_state import GameState
|
||||
from controllers.player_controller import PlayerController
|
||||
from render.map_renderer import MapRenderer
|
||||
@@ -15,10 +16,19 @@ class Game(GameState):
|
||||
def __init__(self, switch_state_callback, context):
|
||||
super().__init__(switch_state_callback, context)
|
||||
|
||||
match_data_path = f"maps/{self.match.map_name}.json"
|
||||
match_image_path = f"maps/{self.match.map_name}.png"
|
||||
self.match_data_path = f"assets/maps/config/{self.match.map_name}.json"
|
||||
self.match_image_path = f"assets/maps/overview/{self.match.map_name}.png"
|
||||
|
||||
self.game_update_interval = 1 / self.match.tick_rate
|
||||
self.elapsed_time = 0
|
||||
self.last_time = time.perf_counter()
|
||||
|
||||
# Screen Areas
|
||||
self.__init_screen_areas()
|
||||
self.__init_utils()
|
||||
self.__init_renderers()
|
||||
self.__init_controllers()
|
||||
|
||||
def __init_screen_areas(self):
|
||||
self.info_box = pygame.Surface((350, self.screen.get_height()), pygame.SRCALPHA)
|
||||
self.info_box_top_left = (0, 0)
|
||||
|
||||
@@ -28,17 +38,17 @@ class Game(GameState):
|
||||
self.control_box = pygame.Surface((650, 120), pygame.SRCALPHA)
|
||||
self.control_box_top_left = (350, 650)
|
||||
|
||||
# Helper Classes
|
||||
self.map_coord_controller = MapCoordConverter(self.game_box.get_width(), self.game_box.get_height(), match_data_path, match_image_path)
|
||||
def __init_utils(self):
|
||||
self.map_coord_controller = MapCoordConverter(self.game_box.get_width(), self.game_box.get_height(), self.match_data_path, self.match_image_path)
|
||||
|
||||
# Renderers
|
||||
self.map_renderer = MapRenderer(self.game_box, match_data_path, match_image_path)
|
||||
def __init_renderers(self):
|
||||
self.map_renderer = MapRenderer(self.game_box, self.match_data_path, self.match_image_path)
|
||||
self.player_renderer = PlayerRenderer(self.game_box, self.match, self.map_coord_controller, self.options, self.styling)
|
||||
self.gui_render = GUIRenderer(self.screen, self.match)
|
||||
self.info_render = InfoRenderer(self.info_box, self.styling, self.match)
|
||||
self.control_render = ControlRenderer(self.control_box, self.match)
|
||||
|
||||
# Controllers
|
||||
def __init_controllers(self):
|
||||
self.player_controller = PlayerController(self.player_renderer, self.match, self.game_box_top_left)
|
||||
self.gui_controller = GUIController(self.gui_render, self.switch_state)
|
||||
self.info_controller = InfoController(self.info_render, self.player_controller)
|
||||
@@ -55,8 +65,15 @@ class Game(GameState):
|
||||
self.control_controller.update(event)
|
||||
|
||||
def update(self):
|
||||
"""Updates game objects."""
|
||||
self.match.next_tick()
|
||||
"""Fixed-timestep update decoupled from frame rate."""
|
||||
now = time.perf_counter()
|
||||
delta = now - self.last_time
|
||||
self.last_time = now
|
||||
self.elapsed_time += delta
|
||||
|
||||
while self.elapsed_time >= self.game_update_interval:
|
||||
self.match.next_tick()
|
||||
self.elapsed_time -= self.game_update_interval
|
||||
|
||||
def draw(self):
|
||||
"""Draws everything on screen."""
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
from states.game_state import GameState
|
||||
from widgets.button import Button
|
||||
from widgets.switch import Switch
|
||||
from controllers.settings_controller import SettingsController
|
||||
from render.settings_menu_renderer import SettingsMenuRenderer
|
||||
import pygame
|
||||
|
||||
class SettingsMenu(GameState):
|
||||
def __init__(self, switch_state_callback, context):
|
||||
|
||||
@@ -3,7 +3,6 @@ from widgets.button import Button
|
||||
from models.match import Match
|
||||
from models.player import Player
|
||||
from models.team import Team
|
||||
from pgu import gui
|
||||
import demoparser2
|
||||
import pygame
|
||||
import pygame_gui
|
||||
@@ -17,7 +16,7 @@ class StartMenu(GameState):
|
||||
self.default_button_width = self.screen.get_width() * 0.8
|
||||
|
||||
# logo
|
||||
self.logo = pygame.image.load("assets/logo.png").convert_alpha()
|
||||
self.logo = pygame.image.load("assets/images/logo.png").convert_alpha()
|
||||
self.logo_scale = 0.7
|
||||
self.logo = pygame.transform.smoothscale(self.logo, (self.logo.get_rect().size[0] * self.logo_scale, self.logo.get_rect().size[1] * self.logo_scale))
|
||||
|
||||
@@ -84,15 +83,19 @@ class StartMenu(GameState):
|
||||
demo_parser = demoparser2.DemoParser(demo_file)
|
||||
game_info = demo_parser.parse_ticks(["X", "Y", "Z", "pitch", "yaw", "is_alive", "team", "player_steamid",
|
||||
"team_rounds_total", "team_num", "total_rounds_played", "shots_fired",
|
||||
"kills_total", "deaths_total", "assists_total", "inventory",
|
||||
"health", "armor_value", "active_weapon_name"])
|
||||
round_changes = demo_parser.parse_events(["round_start", "is_ct_timeout"])
|
||||
header_info = demo_parser.parse_header()
|
||||
map_name = header_info['map_name']
|
||||
players = demo_parser.parse_player_info()
|
||||
|
||||
print(demo_parser.list_game_events())
|
||||
|
||||
team_1 = Team()
|
||||
team_1.set_ct()
|
||||
team_2 = Team()
|
||||
m = Match(map_name, game_info, team_1, team_2, self.options)
|
||||
team_2.set_ct()
|
||||
m = Match(map_name, game_info, team_1, team_2, round_changes)
|
||||
for index, row in players.iterrows():
|
||||
if row["team_number"] == 2:
|
||||
team_1.add_player(Player(row["name"], row["steamid"]))
|
||||
|
||||
55
widgets/break_slider.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from widgets.slider import HorizontalSlider
|
||||
import pygame
|
||||
|
||||
class BreakSlider(HorizontalSlider):
|
||||
def __init__(self, screen, x, y, width, height, min_value, max_value):
|
||||
super().__init__(screen, x, y, width, height, min_value, max_value)
|
||||
self.breakpoints = []
|
||||
|
||||
# defaults
|
||||
self.breakpoint_colour = (0, 0, 0)
|
||||
self.breakpoint_line_width = 2
|
||||
|
||||
def add_breakpoint(self, breakpoint):
|
||||
if breakpoint < self.min_value or breakpoint > self.max_value:
|
||||
raise ValueError("Breakpoint must fit between min and max values")
|
||||
|
||||
self.breakpoints.append(breakpoint)
|
||||
|
||||
def set_breakpoints(self, breakpoints):
|
||||
self.breakpoints = breakpoints
|
||||
|
||||
def _draw_breakpoints(self):
|
||||
for breakpoint in self.breakpoints:
|
||||
# create line
|
||||
break_x = self._value_to_knob(breakpoint)
|
||||
|
||||
pygame.draw.line(self.screen,
|
||||
self.breakpoint_colour,
|
||||
(break_x, self.y),
|
||||
(break_x, self.y + self.height),
|
||||
width=self.breakpoint_line_width)
|
||||
|
||||
def draw(self):
|
||||
self._draw_slider()
|
||||
self._draw_breakpoints()
|
||||
self._draw_knob()
|
||||
|
||||
if __name__ == "__main__":
|
||||
pygame.init()
|
||||
screen = pygame.display.set_mode((800, 600))
|
||||
slider = BreakSlider(screen, 50, 50, 700, 20, 0, 1000)
|
||||
slider.add_breakpoint(100)
|
||||
slider.add_breakpoint(500)
|
||||
slider.add_breakpoint(700)
|
||||
running = True
|
||||
|
||||
while running:
|
||||
screen.fill((0, 0, 0))
|
||||
slider.draw()
|
||||
pygame.display.flip()
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
slider.handle_event(event)
|
||||
@@ -41,7 +41,7 @@ class Button:
|
||||
def set_font_size(self, font_size: int) -> None:
|
||||
self.font_size = font_size
|
||||
|
||||
def set_font(self, font: pygame.Font) -> None:
|
||||
def set_font(self, font: pygame.font.Font) -> None:
|
||||
self.font = font
|
||||
|
||||
def set_text(self, text: str) -> None:
|
||||
|
||||
@@ -15,7 +15,7 @@ class HorizontalSlider:
|
||||
self.knob_colour = (255, 0, 0)
|
||||
self.rect_radius = 5
|
||||
|
||||
self.knob_radius = 10
|
||||
self.knob_radius = 5
|
||||
self.knob_x = self.x + self.knob_radius
|
||||
self.dragging = False
|
||||
|
||||
@@ -54,16 +54,23 @@ class HorizontalSlider:
|
||||
self.knob_x = event.pos[0]
|
||||
self.value = self._knob_to_value(self.knob_x)
|
||||
|
||||
def draw(self):
|
||||
"""
|
||||
Draw the slider on the screen
|
||||
"""
|
||||
def _draw_slider(self):
|
||||
if self.fill:
|
||||
pygame.draw.rect(self.screen, self.fill_colour, (self.x, self.y, self.knob_x, self.height), border_radius=self.rect_radius)
|
||||
pygame.draw.rect(self.screen, self.background_colour, (self.knob_x, self.y, self.width - (self.knob_x - self.x), self.height), border_radius=self.rect_radius)
|
||||
else:
|
||||
pygame.draw.rect(self.screen, self.background_colour, (self.x, self.y, self.width, self.height), border_radius=self.rect_radius)
|
||||
pygame.draw.circle(self.screen, self.knob_colour, (int(self.knob_x), self.y + self.height // 2), self.knob_radius)
|
||||
|
||||
def _draw_knob(self):
|
||||
pygame.draw.line(self.screen, self.knob_colour, (self.knob_x, self.y), (self.knob_x, self.y + self.height), width=self.knob_radius)
|
||||
|
||||
def draw(self):
|
||||
"""
|
||||
Draw the slider on the screen
|
||||
"""
|
||||
self._draw_slider()
|
||||
self._draw_knob()
|
||||
|
||||
|
||||
def set_value(self, value):
|
||||
"""
|
||||
@@ -89,6 +96,9 @@ class HorizontalSlider:
|
||||
def set_knob_colour(self, colour):
|
||||
self.knob_colour = colour
|
||||
|
||||
def set_fill_colour(self, colour):
|
||||
self.fill_colour = colour
|
||||
|
||||
if __name__ == "__main__":
|
||||
pygame.init()
|
||||
screen = pygame.display.set_mode((800, 600))
|
||||
|
||||