Fix credits and settings dropdowns, add high score, fps counter

This commit is contained in:
csd4ni3l
2025-06-17 15:08:24 +02:00
parent da650a5bda
commit ab11d92e3a
7 changed files with 79 additions and 26 deletions

View File

@@ -3,7 +3,8 @@ Thanks to OpenGameArt and:
TinyWorlds for the death sound effect: https://opengameart.org/content/explosion-0
The gun icons used in this project are from game-icons.net.
Licensed under the Creative Commons Attribution 3.0 International License (CC BY 3.0): https://creativecommons.org/licenses/by/3.0/
Licensed under the Creative Commons Attribution 3.0 International License (CC BY 3.0):
https://creativecommons.org/licenses/by/3.0/
Huge Thanks to Python for being the programming language used in this game.
https://www.python.org/

View File

@@ -4,7 +4,7 @@ from game.enemy import Enemy
from utils.constants import weapons, min_enemy_y, max_enemy_y
from ursina import *
from ursina.shaders import lit_with_shadows_shader
import os
import os, json
enemy_file_names = os.listdir("assets/graphics/enemy")
@@ -12,6 +12,12 @@ class Game():
def __init__(self, pypresence_client) -> None:
self.pypresence_client = pypresence_client
if os.path.exists("data.json"):
with open("data.json", "r") as file:
self.high_score = json.load(file)["high_score"]
else:
self.high_score = 0
pypresence_client.update(state='Training Aim', details=f'Hits: 0/0 Accuracy: 0%')
self.ground = Entity(model='plane', collider='box', scale=64, texture='grass', texture_scale=(4,4), shader=lit_with_shadows_shader)
@@ -23,7 +29,7 @@ class Game():
for n, weapon in enumerate(weapons):
self.inventory.append(weapons[weapon]["image"], weapon, n)
self.player = Player(self.info_label, self.inventory, pypresence_client)
self.player = Player(self.high_score, self.info_label, self.inventory, pypresence_client)
self.shootables_parent = Entity()
mouse.traverse_target = self.shootables_parent
@@ -40,6 +46,7 @@ class Game():
self.sky = Sky()
self.sky.update = self.update
def summon_enemy(self):
if not len(self.enemies) >= 50:
@@ -50,7 +57,7 @@ class Game():
if held_keys["escape"]:
self.back_to_main_menu()
elif held_keys["space"]:
elif held_keys["n"]:
self.summon_enemy()
def back_to_main_menu(self):
@@ -70,3 +77,6 @@ class Game():
for enemy in self.enemies:
destroy(enemy)
with open("data.json", "w") as file:
file.write(json.dumps({"high_score": self.player.high_score}, indent=4))

View File

@@ -7,8 +7,8 @@ from utils.preload import death_sound
import json
class Player(FirstPersonController):
def __init__(self, info_label, inventory, pypresence_client) -> None:
super().__init__(model='cube', z=16, color=color.orange, origin_y=-.5, speed=8, collider='box', gravity=False, shader=lit_with_shadows_shader)
def __init__(self, high_score, info_label, inventory, pypresence_client) -> None:
super().__init__(model='cube', z=16, color=color.orange, origin_y=-.5, speed=8, collider='box', gravity=True, shader=lit_with_shadows_shader)
self.collider = BoxCollider(self, Vec3(0,1,0), Vec3(1,2,1))
@@ -19,7 +19,7 @@ class Player(FirstPersonController):
self.info_label = info_label
self.inventory = inventory
self.pypresence_client = pypresence_client
self.high_score = high_score
self.last_presence_update = time.perf_counter()
self.shots_fired = 0
self.shots_hit = 0
@@ -40,15 +40,18 @@ class Player(FirstPersonController):
self.x = max(-16, min(self.x, 16))
self.z = max(-16, min(self.z, 16))
self.info_label.text = f"Score: {self.score} Hits: {self.shots_fired}/{self.shots_hit} Accuracy: {round(self.accuracy, 2)}%"
self.info_label.text = f"High Score: {self.high_score} Score: {self.score} Hits: {self.shots_fired}/{self.shots_hit} Accuracy: {round(self.accuracy, 2)}%"
weapon_name = self.inventory.slot_names[self.inventory.current_slot]
self.weapon_attack_speed = weapons[weapon_name]["atk_speed"]
self.weapon_dmg = weapons[weapon_name]["dmg"]
if self.score > self.high_score:
self.high_score = self.score
if time.perf_counter() - self.last_presence_update >= 3:
self.last_presence_update = time.perf_counter()
self.pypresence_client.update(state='Training Aim', details=f"Score: {self.score} Hits: {self.shots_fired}/{self.shots_hit} Accuracy: {round(self.accuracy, 2)}%")
self.pypresence_client.update(state='Training Aim', details=f"High Score: {self.high_score} Score: {self.score} Hits: {self.shots_fired}/{self.shots_hit} Accuracy: {round(self.accuracy, 2)}%")
def summon_enemy(self):
pass

View File

@@ -46,14 +46,21 @@ class Main():
self.pypresence_client = FakePyPresence()
self.pypresence_client.start_time = time.time()
if os.path.exists("data.json"):
with open("data.json", "r") as file:
self.high_score = json.load(file)["high_score"]
else:
self.high_score = 0
self.pypresence_client.update(state='In Main Menu', details='In Main Menu')
button_spacing = .075 * 1.25
base_y = -2
self.menu_parent = Entity(parent=camera.ui, y=.15)
self.main_menu = Entity(parent=self.menu_parent)
self.title_label = Text("Aim Trainer", parent=self.main_menu, y=-0.25 * button_spacing, scale=3, x=-.2)
self.title_label = Text("Aim Trainer", parent=self.main_menu, y=-0.01 * button_spacing, scale=3, x=-.2)
self.high_score_label = Text(f"High Score: {self.high_score}", parent=self.main_menu, scale=1.25, y=-1 * button_spacing, x=-.12)
self.play_button = MenuButton('Play', on_click=Func(self.play), parent=self.main_menu, y=-2 * button_spacing)
self.settings_button = MenuButton('Settings', on_click=Func(self.settings), parent=self.main_menu, y=-3 * button_spacing)
self.quit_button = MenuButton('Quit', on_click=Sequence(Wait(.01), Func(application.quit)), parent=self.main_menu, y=-4 * button_spacing)

View File

@@ -1,9 +1,9 @@
from ursina import *
from ursina.prefabs.slider import ThinSlider
from ursina.prefabs.dropdown_menu import DropdownMenu, DropdownMenuButton
from ursina.prefabs.dropdown_menu import DropdownMenuButton
from ursina.prefabs.button_group import ButtonGroup
import pypresence, json, copy
from utils.utils import FakePyPresence
from utils.utils import FakePyPresence, Dropdown
from utils.constants import discord_presence_id, settings, settings_start_category
from utils.preload import music_sound
@@ -58,20 +58,29 @@ class Settings:
self.ui.append(slider)
else:
items = []
menu_buttons = []
for opt in info['options']:
b = DropdownMenuButton(opt)
b.on_click = lambda btn, n=name: self.update(n, btn.text)
items.append(b)
dm = DropdownMenu(val, buttons=tuple(items))
dm.position = (.2, y)
self.ui.append(dm)
menu_button = DropdownMenuButton(opt)
menu_buttons.append(menu_button)
dropdown_menu = Dropdown(val, buttons=tuple(menu_buttons))
for menu_button in menu_buttons:
menu_button.on_click = lambda dropdown_menu=dropdown_menu, btn=menu_button, n=name: self.dropdown_update(n, dropdown_menu, btn)
dropdown_menu.position = (.2, y)
self.ui.append(dropdown_menu)
y -= .08
self.apply_button = Button('Apply', parent=camera.ui, color=color.green, scale=(.15, .08), position=(.6, -.4), on_click=self.apply_changes)
self.ui.append(self.apply_button)
def dropdown_update(self, n, dropdown_menu, btn):
dropdown_menu.text = btn.text
self.update(n, btn.text)
def update(self, name, value):
self.edits[settings[self.category][name]['config_key']] = value
@@ -146,15 +155,15 @@ class Settings:
text = file.read()
if window.size.x >= 3840:
font_size = 2.4
font_size = 2.3
elif window.size.x >= 2560:
font_size = 1.9
font_size = 1.8
elif window.size.x >= 1920:
font_size = 1.6
font_size = 1.5
elif window.size.x >= 1440:
font_size = 1.3
font_size = 1.2
else:
font_size = 1.1
font_size = 1.0
self.credits_label = Text(text=text, parent=camera.ui, position=(0, 0), origin=(0, 0), scale=font_size, color=color.white)
self.credits_label.type = 'credits_text'

5
run.py
View File

@@ -1,7 +1,8 @@
import os, pypresence, json
import os, json
from ursina import Ursina
from menus.main import Main
from utils.utils import get_closest_resolution
from ursina import window
if os.path.exists('settings.json'):
with open('settings.json', 'r') as settings_file:
@@ -32,6 +33,8 @@ if not args["fullscreen"]:
args["size"] = list(map(int, settings['resolution'].split('x')))
app = Ursina(title="Aim Trainer", development_mode=False, **args)
window.editor_ui.enabled = True
window.fps_counter.enabled = True
if settings.get("music", True):
from utils.preload import music_sound

View File

@@ -1,4 +1,5 @@
from panda3d.core import GraphicsPipeSelection
from ursina.prefabs.dropdown_menu import DropdownMenu
def get_closest_resolution():
allowed_resolutions = [(1366, 768), (1440, 900), (1600,900), (1920,1080), (2560,1440), (3840,2160)]
@@ -24,6 +25,25 @@ def get_closest_resolution():
)
return closest_resolution
class Dropdown(DropdownMenu):
def __init__(self, text='', buttons = None, **kwargs):
super().__init__(text, buttons, **kwargs)
self.scale = (.4,.04)
def on_mouse_enter(self):
...
def input(self, key):
super().input(key)
if key == 'left mouse down' and self.hovered:
if not self.buttons[0].enabled:
self.open()
else:
self.close()
class FakePyPresence():
def __init__(self):
...