mirror of
https://github.com/csd4ni3l/aim-trainer.git
synced 2026-01-01 04:03:42 +01:00
Fix credits and settings dropdowns, add high score, fps counter
This commit is contained in:
3
CREDITS
3
CREDITS
@@ -3,7 +3,8 @@ Thanks to OpenGameArt and:
|
|||||||
TinyWorlds for the death sound effect: https://opengameart.org/content/explosion-0
|
TinyWorlds for the death sound effect: https://opengameart.org/content/explosion-0
|
||||||
|
|
||||||
The gun icons used in this project are from game-icons.net.
|
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.
|
Huge Thanks to Python for being the programming language used in this game.
|
||||||
https://www.python.org/
|
https://www.python.org/
|
||||||
|
|||||||
16
game/game.py
16
game/game.py
@@ -4,7 +4,7 @@ from game.enemy import Enemy
|
|||||||
from utils.constants import weapons, min_enemy_y, max_enemy_y
|
from utils.constants import weapons, min_enemy_y, max_enemy_y
|
||||||
from ursina import *
|
from ursina import *
|
||||||
from ursina.shaders import lit_with_shadows_shader
|
from ursina.shaders import lit_with_shadows_shader
|
||||||
import os
|
import os, json
|
||||||
|
|
||||||
enemy_file_names = os.listdir("assets/graphics/enemy")
|
enemy_file_names = os.listdir("assets/graphics/enemy")
|
||||||
|
|
||||||
@@ -12,6 +12,12 @@ class Game():
|
|||||||
def __init__(self, pypresence_client) -> None:
|
def __init__(self, pypresence_client) -> None:
|
||||||
self.pypresence_client = pypresence_client
|
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%')
|
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)
|
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):
|
for n, weapon in enumerate(weapons):
|
||||||
self.inventory.append(weapons[weapon]["image"], weapon, n)
|
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()
|
self.shootables_parent = Entity()
|
||||||
mouse.traverse_target = self.shootables_parent
|
mouse.traverse_target = self.shootables_parent
|
||||||
@@ -40,6 +46,7 @@ class Game():
|
|||||||
|
|
||||||
self.sky = Sky()
|
self.sky = Sky()
|
||||||
self.sky.update = self.update
|
self.sky.update = self.update
|
||||||
|
|
||||||
|
|
||||||
def summon_enemy(self):
|
def summon_enemy(self):
|
||||||
if not len(self.enemies) >= 50:
|
if not len(self.enemies) >= 50:
|
||||||
@@ -50,7 +57,7 @@ class Game():
|
|||||||
|
|
||||||
if held_keys["escape"]:
|
if held_keys["escape"]:
|
||||||
self.back_to_main_menu()
|
self.back_to_main_menu()
|
||||||
elif held_keys["space"]:
|
elif held_keys["n"]:
|
||||||
self.summon_enemy()
|
self.summon_enemy()
|
||||||
|
|
||||||
def back_to_main_menu(self):
|
def back_to_main_menu(self):
|
||||||
@@ -70,3 +77,6 @@ class Game():
|
|||||||
|
|
||||||
for enemy in self.enemies:
|
for enemy in self.enemies:
|
||||||
destroy(enemy)
|
destroy(enemy)
|
||||||
|
|
||||||
|
with open("data.json", "w") as file:
|
||||||
|
file.write(json.dumps({"high_score": self.player.high_score}, indent=4))
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from utils.preload import death_sound
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
class Player(FirstPersonController):
|
class Player(FirstPersonController):
|
||||||
def __init__(self, info_label, inventory, pypresence_client) -> None:
|
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=False, shader=lit_with_shadows_shader)
|
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))
|
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.info_label = info_label
|
||||||
self.inventory = inventory
|
self.inventory = inventory
|
||||||
self.pypresence_client = pypresence_client
|
self.pypresence_client = pypresence_client
|
||||||
|
self.high_score = high_score
|
||||||
self.last_presence_update = time.perf_counter()
|
self.last_presence_update = time.perf_counter()
|
||||||
self.shots_fired = 0
|
self.shots_fired = 0
|
||||||
self.shots_hit = 0
|
self.shots_hit = 0
|
||||||
@@ -40,15 +40,18 @@ class Player(FirstPersonController):
|
|||||||
|
|
||||||
self.x = max(-16, min(self.x, 16))
|
self.x = max(-16, min(self.x, 16))
|
||||||
self.z = max(-16, min(self.z, 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]
|
weapon_name = self.inventory.slot_names[self.inventory.current_slot]
|
||||||
self.weapon_attack_speed = weapons[weapon_name]["atk_speed"]
|
self.weapon_attack_speed = weapons[weapon_name]["atk_speed"]
|
||||||
self.weapon_dmg = weapons[weapon_name]["dmg"]
|
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:
|
if time.perf_counter() - self.last_presence_update >= 3:
|
||||||
self.last_presence_update = time.perf_counter()
|
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):
|
def summon_enemy(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -46,14 +46,21 @@ class Main():
|
|||||||
self.pypresence_client = FakePyPresence()
|
self.pypresence_client = FakePyPresence()
|
||||||
self.pypresence_client.start_time = time.time()
|
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')
|
self.pypresence_client.update(state='In Main Menu', details='In Main Menu')
|
||||||
|
|
||||||
button_spacing = .075 * 1.25
|
button_spacing = .075 * 1.25
|
||||||
base_y = -2
|
|
||||||
self.menu_parent = Entity(parent=camera.ui, y=.15)
|
self.menu_parent = Entity(parent=camera.ui, y=.15)
|
||||||
self.main_menu = Entity(parent=self.menu_parent)
|
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.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.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)
|
self.quit_button = MenuButton('Quit', on_click=Sequence(Wait(.01), Func(application.quit)), parent=self.main_menu, y=-4 * button_spacing)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from ursina import *
|
from ursina import *
|
||||||
from ursina.prefabs.slider import ThinSlider
|
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
|
from ursina.prefabs.button_group import ButtonGroup
|
||||||
import pypresence, json, copy
|
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.constants import discord_presence_id, settings, settings_start_category
|
||||||
from utils.preload import music_sound
|
from utils.preload import music_sound
|
||||||
|
|
||||||
@@ -58,20 +58,29 @@ class Settings:
|
|||||||
self.ui.append(slider)
|
self.ui.append(slider)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
items = []
|
menu_buttons = []
|
||||||
for opt in info['options']:
|
for opt in info['options']:
|
||||||
b = DropdownMenuButton(opt)
|
menu_button = DropdownMenuButton(opt)
|
||||||
b.on_click = lambda btn, n=name: self.update(n, btn.text)
|
menu_buttons.append(menu_button)
|
||||||
items.append(b)
|
|
||||||
dm = DropdownMenu(val, buttons=tuple(items))
|
dropdown_menu = Dropdown(val, buttons=tuple(menu_buttons))
|
||||||
dm.position = (.2, y)
|
|
||||||
self.ui.append(dm)
|
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
|
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.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)
|
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):
|
def update(self, name, value):
|
||||||
self.edits[settings[self.category][name]['config_key']] = value
|
self.edits[settings[self.category][name]['config_key']] = value
|
||||||
|
|
||||||
@@ -146,15 +155,15 @@ class Settings:
|
|||||||
text = file.read()
|
text = file.read()
|
||||||
|
|
||||||
if window.size.x >= 3840:
|
if window.size.x >= 3840:
|
||||||
font_size = 2.4
|
font_size = 2.3
|
||||||
elif window.size.x >= 2560:
|
elif window.size.x >= 2560:
|
||||||
font_size = 1.9
|
font_size = 1.8
|
||||||
elif window.size.x >= 1920:
|
elif window.size.x >= 1920:
|
||||||
font_size = 1.6
|
font_size = 1.5
|
||||||
elif window.size.x >= 1440:
|
elif window.size.x >= 1440:
|
||||||
font_size = 1.3
|
font_size = 1.2
|
||||||
else:
|
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 = Text(text=text, parent=camera.ui, position=(0, 0), origin=(0, 0), scale=font_size, color=color.white)
|
||||||
self.credits_label.type = 'credits_text'
|
self.credits_label.type = 'credits_text'
|
||||||
|
|||||||
5
run.py
5
run.py
@@ -1,7 +1,8 @@
|
|||||||
import os, pypresence, json
|
import os, json
|
||||||
from ursina import Ursina
|
from ursina import Ursina
|
||||||
from menus.main import Main
|
from menus.main import Main
|
||||||
from utils.utils import get_closest_resolution
|
from utils.utils import get_closest_resolution
|
||||||
|
from ursina import window
|
||||||
|
|
||||||
if os.path.exists('settings.json'):
|
if os.path.exists('settings.json'):
|
||||||
with open('settings.json', 'r') as settings_file:
|
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')))
|
args["size"] = list(map(int, settings['resolution'].split('x')))
|
||||||
|
|
||||||
app = Ursina(title="Aim Trainer", development_mode=False, **args)
|
app = Ursina(title="Aim Trainer", development_mode=False, **args)
|
||||||
|
window.editor_ui.enabled = True
|
||||||
|
window.fps_counter.enabled = True
|
||||||
|
|
||||||
if settings.get("music", True):
|
if settings.get("music", True):
|
||||||
from utils.preload import music_sound
|
from utils.preload import music_sound
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from panda3d.core import GraphicsPipeSelection
|
from panda3d.core import GraphicsPipeSelection
|
||||||
|
from ursina.prefabs.dropdown_menu import DropdownMenu
|
||||||
|
|
||||||
def get_closest_resolution():
|
def get_closest_resolution():
|
||||||
allowed_resolutions = [(1366, 768), (1440, 900), (1600,900), (1920,1080), (2560,1440), (3840,2160)]
|
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
|
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():
|
class FakePyPresence():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
...
|
...
|
||||||
|
|||||||
Reference in New Issue
Block a user