diff --git a/.gitignore b/.gitignore index b6e4761..39decae 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,5 @@ dmypy.json # Pyre type checker .pyre/ +UrsinaAchievements/ +highscore/ diff --git a/UrsinaAchievements/__init__.py b/UrsinaAchievements/__init__.py deleted file mode 100644 index 714e900..0000000 --- a/UrsinaAchievements/__init__.py +++ /dev/null @@ -1,157 +0,0 @@ -""" -Author: TheAssasin71 or megat69 -Repo: https://github.com/megat69/UrsinaAchievements -Init file for UrsinaAchievements, a system allowing users in Ursina engine to receive achievements. -""" -from ursina import * -import json -import os -from direct.stdpy import thread - -_path = os.path.dirname(sys.argv[0]) -achievements_json = os.path.join(_path, "./UrsinaAchievements/achievements.json") - -_achievements_list = [] -try: - with open(achievements_json, "r") as save_file: - _achievements_got = json.load(save_file)["achievements_got_names"].copy() -except FileNotFoundError: - with open(achievements_json, "w") as save_file: - _achievements_got = [] - json.dump({"achievements_got_names": []}, save_file, indent=4) - - -def create_achievement(name:str, unlock_condition, icon:str=None, ringtone:str="clicking", importance:int=1): - """ - Creates a new achievement for the game. - :param name: The name of the achievement. - :param unlock_condition: A callback function representing whether the achievement should be unlocked. - Unlocks the achievement if the return value is True, passes if it is either False or None. - :param icon: The path to the image file being represented with the text, optional. - :param ringtone: The name of the ringtone to be used to signal the achievement get ; can be "clicking", - "subtle", "uplifting", or the path to a wav/ogg file. It can also be None, and thus won't produce a sound. - :param importance: The higher the number is, the longer the achievement will stay on screen. Default is 1. - """ - _achievements_list.append( - (name, unlock_condition, icon, ringtone, importance) - ) - - -def _save_achievements(): - with open(achievements_json, "w") as save_file: - json.dump({"achievements_got_names": _achievements_got.copy()}, save_file, indent=2) - - -class Achievement(Entity): - """ - Main achievement class, the popup. - """ - # The different ringtones - ringtones = { - "clicking": Audio(f"{_path}/ringtones/clicking.ogg", autoplay=False), - "subtle": Audio(f"{_path}/ringtones/subtle.ogg", autoplay=False), - "uplifting": Audio(f"{_path}/ringtones/uplifting.ogg", autoplay=False) - } - achievement_color = (64, 64, 64) - text_color = (255, 255, 255) - icon_color = (255, 255, 255) - - def __init__(self, title:str, unlock_condition, icon:str=None, ringtone:str="clicking", importance:int=1): - """ - :param title: The name of the achievement. - :param unlock_condition: A callback function representing whether the achievement should be unlocked. - Unlocks the achievement if the return value is True, passes if it is either False or None. - :param icon: The path to the image file being represented with the text, optional. - :param ringtone: The name of the ringtone to be used to signal the achievement get ; can be "clicking", - "subtle", "uplifting", or the path to a wav/ogg file. It can also be None, and thus won't produce a sound. - :param importance: The higher the number is, the longer the achievement will stay on screen. Default is 1. - """ - super().__init__( - parent=camera.ui, - model="quad", - position=((.5*window.aspect_ratio, -.5)), - origin=(.5, -.5), - scale=(.25, .15), - color=color.rgba(*Achievement.achievement_color, 185), - always_on_top=True - ) - # Adding the title - self.title = Text( - parent=self, - text=title, - position=(-.95, .9), - scale=(4, 5.5), - wordwrap=15, - color=color.rgba(*Achievement.text_color, 255) - ) - # Adding the icon if wanted - if icon is not None: - self.icon = Entity( - parent=self, - model="quad", - texture=icon, - scale=(.4, .5), - position=(-.5, .3), - color=color.rgba(*Achievement.icon_color, 255) - ) - - # Plays a ringtone if wanted - if ringtone is not None: - # Plays the ringtone if the name is in the class dictionnary - if ringtone in Achievement.ringtones.keys(): - Achievement.ringtones[ringtone].play() - # Or locates and plays the audio file if wanted - else: - Audio(ringtone) - - # Creating the animation for the entering - old_position = self.position - self.position = self.position + Vec2(0, -.2) - self.animate_position(old_position, duration=.4 * importance, curve=curve.out_back) - self.animate_color(color.rgba(*Achievement.achievement_color, 0), duration=1.5 * importance, delay=2 * importance) - self.title.animate_color(color.rgba(*Achievement.text_color, 0), duration=1.5 * importance, delay=2 * importance) - if icon is not None: - self.icon.animate_color(color.rgba(*Achievement.icon_color, 0), duration=1.5 * importance, delay=2 * importance) - - invoke(destroy, self, delay=5 * importance) - - -def _achievements_update(): - """ - Checks if the achievement condition is met at each update. - """ - pop = [] - for i, achievement in enumerate(_achievements_list): - if achievement[1]() is True and achievement[0] not in _achievements_got: - print(f"Achievement got ! {achievement[0]}") - # Shows the achievement pop-up - Achievement(*achievement) - # Adds the achievement name to the list of achievements got - _achievements_got.append(achievement[0]) - # Removes the achievement from the list of achievements to check - pop.append(i) - # Saves the achievements got list (in a new thread) - try: - thread.start_new_thread(function=_save_achievements, args='') - except Exception as e: - print('error saving the achievements', e) - - for i in range(len(pop)): - _achievements_list.pop(pop[i] - i) - -Entity(update=_achievements_update) - -if __name__ == "__main__": - app = Ursina() - Sky() - do = False - def cond(): - global do - return do - create_achievement("Bubbles.", cond, "bubbles.png", "subtle") - def setdo(): - global do - do = True - invoke(setdo, delay=2) - - app.run() \ No newline at end of file diff --git a/UrsinaAchievements/achievements.json b/UrsinaAchievements/achievements.json deleted file mode 100644 index d08e6ea..0000000 --- a/UrsinaAchievements/achievements.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "achievements_got_names": [] -} \ No newline at end of file diff --git a/UrsinaAchievements/confetti.png b/UrsinaAchievements/confetti.png deleted file mode 100644 index 1c4dbe6..0000000 Binary files a/UrsinaAchievements/confetti.png and /dev/null differ diff --git a/assets/unifont-15.0.01.otf b/assets/unifont-15.0.01.otf new file mode 100644 index 0000000..8ea8530 Binary files /dev/null and b/assets/unifont-15.0.01.otf differ diff --git a/car.py b/car.py index 5549ae1..49a75e4 100644 --- a/car.py +++ b/car.py @@ -20,7 +20,9 @@ def __init__(self, position = (0, 0, 4), rotation = (0, 0, 0), topspeed = 30, ac self.rotation_parent = Entity() # Controls - self.controls = "wasd" + self.controls = ["w", "a", "s", "d"] + self.hand_brake_control = "space" + self.respawn_control = "g" # Car's values self.speed = 0 @@ -524,10 +526,10 @@ def update(self): self.particle_time = 0 self.particles = Particles(self, self.particle_pivot.world_position - (0, 1, 0)) self.particles.destroy(1) - + # TrailRenderer / Skid Marks if self.graphics != "ultra fast": - if self.drift_speed <= self.min_drift_speed + 2 and self.start_trail: + if self.drift_speed <= self.min_drift_speed + 2 and self.start_trail: if self.pivot_rotation_distance > 60 or self.pivot_rotation_distance < -60 and self.speed > 10: for trail in self.trails: trail.start_trail() @@ -559,7 +561,7 @@ def update(self): self.camera_rotation += self.friction * 20 * time.dt # Braking - if held_keys[self.controls[2] or held_keys["down arrow"]]: + if held_keys[self.controls[2]] or held_keys["down arrow"]: self.speed -= self.braking_strenth * time.dt self.drift_speed -= 20 * time.dt self.braking = True @@ -593,7 +595,7 @@ def update(self): self.skid_sound.stop(False) # Hand Braking - if held_keys["space"]: + if held_keys[self.hand_brake_control]: if self.rotation_speed < 0: self.rotation_speed -= 3 * time.dt elif self.rotation_speed > 0: @@ -663,7 +665,7 @@ def update(self): self.rotation_speed = -self.max_rotation_speed # Respawn - if held_keys["g"]: + if held_keys[self.respawn_control]: self.reset_car() # Reset the car's position if y value is less than -100 diff --git a/highscore/highscore.json b/highscore/highscore.json deleted file mode 100644 index 27c60e2..0000000 --- a/highscore/highscore.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "race": { - "sand_track": 0.0, - "grass_track": 0.0, - "snow_track": 0.0, - "forest_track": 0.0, - "savannah_track": 0.0, - "lake_track": 0.0 - }, - "time_trial": { - "sand_track": 0, - "grass_track": 0, - "snow_track": 0, - "forest_track": 0, - "savannah_track": 0, - "lake_track": 0 - }, - "drift": { - "sand_track": 0, - "grass_track": 0, - "snow_track": 0, - "forest_track": 0, - "savannah_track": 0, - "lake_track": 0 - } -} \ No newline at end of file diff --git a/highscore/unlocked.json b/highscore/unlocked.json deleted file mode 100644 index 6763d45..0000000 --- a/highscore/unlocked.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "tracks": { - "sand_track": true, - "grass_track": false, - "snow_track": false, - "forest_track": false, - "savannah_track": false, - "lake_track": false - }, - "beat_mandaw": { - "sand_track": false, - "grass_track": false, - "snow_track": false, - "forest_track": false, - "savannah_track": false, - "lake_track": false - }, - "cars": { - "sports_car": true, - "muscle_car": false, - "limo": false, - "lorry": false, - "hatchback": false, - "rally_car": false - }, - "textures": { - "sports_car": { - "red": true, - "blue": true, - "green": false, - "orange": false, - "black": false, - "white": false - }, - "muscle_car": { - "red": false, - "blue": false, - "green": false, - "orange": true, - "black": false, - "white": false - }, - "limo": { - "red": false, - "blue": false, - "green": false, - "orange": false, - "black": true, - "white": false - }, - "lorry": { - "red": false, - "blue": false, - "green": false, - "orange": false, - "black": false, - "white": true - }, - "hatchback": { - "red": false, - "blue": false, - "green": true, - "orange": false, - "black": false, - "white": false - }, - "rally_car": { - "red": true, - "blue": false, - "green": false, - "orange": false, - "black": false, - "white": false - } - }, - "cosmetics": { - "viking_helmet": false, - "duck": false, - "banana": false, - "surfinbird": false - }, - "gamemodes": { - "drift": false - } -} \ No newline at end of file diff --git a/highscore/username.txt b/highscore/username.txt deleted file mode 100644 index ace166c..0000000 --- a/highscore/username.txt +++ /dev/null @@ -1 +0,0 @@ -Guest \ No newline at end of file diff --git a/main.py b/main.py old mode 100644 new mode 100755 index fdef27c..7b18855 --- a/main.py +++ b/main.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + from ursina import * from direct.stdpy import thread @@ -17,8 +19,9 @@ from tracks.forest_track import ForestTrack from tracks.savannah_track import SavannahTrack from tracks.lake_track import LakeTrack +from panda3d.core import InputDevice -Text.default_font = "./assets/Roboto.ttf" +Text.default_font = './assets/unifont-15.0.01.otf' Text.default_resolution = 1080 * Text.size # Window @@ -26,7 +29,7 @@ app = Ursina() window.title = "Rally" window.borderless = False -window.show_ursina_splash = True +window.show_ursina_splash = False window.cog_button.disable() window.fps_counter.disable() window.exit_button.disable() @@ -151,6 +154,61 @@ def load_assets(): # Sky Sky(texture = "sky") +base = app + +input_handler.wheel = None +input_handler.wheels = base.devices.getDevices() +if input_handler.wheels: + input_handler.wheel = input_handler.wheels[0] + + +for i, wheel in enumerate(input_handler.wheels): + wheel_name = 'wheel' + if i > 0: + wheel_name += f'_{i}' + + base.attachInputDevice(wheel, prefix=wheel_name) + buttons = { + 'trigger' : 'btn1', + 'joystick2' : 'btn2', + 'joystick3' : 'btn3', + 'joystick4' : 'btn4', + 'joystick5' : 'btn5', + 'joystick6' : 'btn6', + 'joystick7' : 'btn7', + 'joystick8' : 'btn8', + 'joystick9' : 'btn9', + 'joystick10' : 'btn10', + 'joystick11' : 'btn11', + 'joystick12' : 'btn12', + 'joystick13' : 'btn13', + 'hat_left' : 'hleft', + 'hat_right' : 'hright', + 'hat_down' : 'hdown', + 'hat_up' : 'hap', + } + + for original_name, new_name in buttons.items(): + base.accept(f'{wheel_name}-{original_name}', base.input, extraArgs=[f'{wheel_name} {new_name}']) + base.accept(f'{wheel_name}-{original_name}-up', base.input, extraArgs=[f'{wheel_name} {new_name} up']) + +def wheel_update(): + axes = { + 'roll' : 'axis1', + 'pitch' : 'axis2', + 'yaw' : 'axis3', + 'throttle' : 'axis4', + } + for i, wheels in enumerate(input_handler.wheels): + wheel_name = 'wheel' + if i > 0: + wheel_name += f'_{i}' + + for key, value in axes.items(): + held_keys[f'{wheel_name} {value}'] = wheel.findAxis(InputDevice.Axis[key]).value + +Entity(name='wheel_handler', update=wheel_update, eternal=True) # connect update() to an entity so it runs + def update(): # If multiplayer, Call the Multiplayer class if car.multiplayer: @@ -158,7 +216,7 @@ def update(): multiplayer = Multiplayer(car) car.multiplayer_update = True car.multiplayer = False - + # Update the multiplayer and check whether the client is connected if car.multiplayer_update: multiplayer.update_multiplayer() @@ -182,7 +240,7 @@ def update(): car.server.update_server() if car.server.server_update: car.server.easy.process_net_events() - + if achievements.time_spent < 10: achievements.time_spent += time.dt diff --git a/main_menu.py b/main_menu.py index b298a8e..b205789 100644 --- a/main_menu.py +++ b/main_menu.py @@ -1,42 +1,209 @@ from ursina import * from ursina import curve from server import Server +from menu import Menu import os +from enum import Enum -Text.default_resolution = 1080 * Text.size +#Text.default_resolution = 1080 * Text.size + +KeyboardConfig = Enum('KeyboardConfig', ['WASD', 'ZQSD', 'KEYBOARD', 'DEVICE']) +KeyboardInput = Enum('KeyboardInput', ['DRIVE', 'STEERING', 'BRAKING', 'HAND_BRAKE', 'RESPAWN']) class MainMenu(Entity): + def quit_menu_toggle(self, up): + for button in (element for element in self.quit_menu.children if type(element) is Button): + if self.quit_menu_button_selected != button: + self.quit_menu_button_selected.color = color.black + self.quit_menu_button_selected = button + self.quit_menu_button_selected.color = color.gray + return + self.sel_first_button_menu() + + def sel_first_button_menu(self): + if self.quit_menu_button_selected is not None: + self.quit_menu_button_selected.color = color.black + + self.quit_menu_button_selected = [element for element in self.quit_menu.children if type(element) is Button][0] + self.quit_menu_button_selected.color = color.gray + + + class MultiPlayerMenu(Menu): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def on_toggle(self): + parent = self.parent + car = parent.car + if self.enabled: + car.visible = True + car.position = (-3, -44.5, 92) + parent.grass_track.disable() + parent.snow_track.enable() + for track in parent.tracks: + for i in track.track: + i.disable() + for i in track.details: + i.disable() + for track in parent.snow_track.track: + track.enable() + if car.graphics != "ultra fast": + parent.snow_track.trees.enable() + else: + car.position = (-80, -42, 18.8) + car.rotation = (0, 90, 0) + car.visible = True + parent.grass_track.enable() + parent.snow_track.disable() + for track in parent.tracks: + for i in track.track: + i.disable() + for i in track.details: + i.disable() + for track in parent.grass_track.track: + track.enable() + if car.graphics != "ultra fast": + for detail in parent.grass_track.details: + detail.enable() + if car.graphics == "fast": + parent.grass_track.grass.disable() + + class SinglePlayerMenu(Menu): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def on_toggle(self): + parent = self.parent + car = parent.car + if self.enabled: + car.multiplayer = False + parent.grass_track.enable() + car.position = (0, 0, 4) + car.visible = False + for track in parent.tracks: + for i in track.track: + i.disable() + for i in track.details: + i.disable() + for track in parent.grass_track.track: + track.enable() + if car.graphics != "ultra fast": + for detail in parent.grass_track.details: + detail.enable() + if car.graphics == "fast": + parent.grass_track.grass.disable() + else: + car.position = (-80, -42, 18.8) + car.rotation = (0, 90, 0) + car.visible = True + parent.grass_track.enable() + if car.multiplayer_update: + car.multiplayer_update = False + for track in parent.tracks: + for i in track.track: + i.disable() + for i in track.details: + i.disable() + for track in parent.grass_track.track: + track.enable() + if car.graphics != "ultra fast": + for detail in parent.grass_track.details: + detail.enable() + if car.graphics == "fast": + parent.grass_track.grass.disable() + + class ServerMenu(Menu): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def on_toggle(self): + parent = self.parent + car = parent.car + if self.enabled: + car.visible = True + car.position = (-105, -50, -59) + parent.snow_track.disable() + parent.sand_track.enable() + for track in parent.tracks: + for i in track.track: + i.disable() + for i in track.details: + i.disable() + for track in parent.sand_track.track: + track.enable() + if car.graphics != "ultra fast": + for detail in parent.sand_track.details: + detail.enable() + else: + car.visible = True + car.position = (-3, -44.5, 92) + parent.sand_track.disable() + parent.snow_track.enable() + for track in parent.tracks: + for i in track.track: + i.disable() + for i in track.details: + i.disable() + for track in parent.snow_track.track: + track.enable() + if car.graphics != "ultra fast": + for detail in parent.snow_track.details: + detail.enable() + def __init__(self, car, ai_list, sand_track, grass_track, snow_track, forest_track, savannah_track, lake_track): super().__init__( parent = camera.ui ) + #TODO: Can we read from component? + self.input_config_mode = KeyboardConfig.WASD + self.enable_custom_input = False + self.waiting_on_input = False + self.input_mode = None + self.key_format = [] + self.input_pos = 0 + self.input_count = 0 + self.input_button = None + self.input_prefix = None # The different menus - self.start_menu = Entity(parent = self, enabled = True) - self.host_menu = Entity(parent = self, enabled = False) - self.created_server_menu = Entity(parent = self, enabled = False) - self.server_menu = Entity(parent = self, enabled = False) - self.main_menu = Entity(parent = self, enabled = False) - self.race_menu = Entity(parent = self, enabled = False) + self.start_menu = Menu(parent = self, ignore=False, enabled = True) + self.host_menu = self.MultiPlayerMenu(parent = self, enabled = False, parent_menu = self.start_menu) + self.created_server_menu = Menu(parent = self, enabled = False) + self.server_menu = self.ServerMenu(parent = self, enabled = False, parent_menu = self.host_menu) + self.singleplayer_menu = self.SinglePlayerMenu(parent = self, enabled = False, parent_menu = self.start_menu) + self.race_menu = Menu(parent = self, enabled = False, parent_menu = self.singleplayer_menu) self.maps_menu = Entity(parent = self, enabled = False) - self.settings_menu = Entity(parent = self, enabled = False) - self.video_menu = Entity(parent = self, enabled = False) - self.gameplay_menu = Entity(parent = self, enabled = False) - self.audio_menu = Entity(parent = self, enabled = False) - self.controls_menu = Entity(parent = self, enabled = False) - self.garage_menu = Entity(parent = self, enabled = False) + self.settings_menu = Menu(parent = self, enabled = False, parent_menu = self.singleplayer_menu) + self.video_menu = Menu(parent = self, enabled = False, parent_menu = self.settings_menu) + self.gameplay_menu = Menu(parent = self, enabled = False, parent_menu = self.settings_menu) + self.audio_menu = Menu(parent = self, enabled = False, parent_menu = self.settings_menu) + self.controls_menu = Menu(parent = self, enabled = False, parent_menu = self.settings_menu) + self.garage_menu = Menu(parent = self, enabled = False, parent_menu = self.singleplayer_menu) self.cars_menu = Entity(parent = self.garage_menu, enabled = False) self.colours_menu = Entity(parent = self.garage_menu, enabled = False) self.cosmetics_menu = Entity(parent = self.garage_menu, enabled = False) self.pause_menu = Entity(parent = self, enabled = False) - self.quit_menu = Entity(parent = self, enabled = False) + self.quit_menu = Menu(parent = self, enabled = False, parent_menu = self.start_menu) + self.start_menu.parent_menu = self.quit_menu self.menus = [ - self.start_menu, self.host_menu, self.created_server_menu, self.server_menu, - self.main_menu, self.race_menu, self.maps_menu, self.settings_menu, self.video_menu, self.gameplay_menu, - self.audio_menu, self.controls_menu, self.garage_menu, self.pause_menu, self.quit_menu + self.start_menu, + self.host_menu, + self.created_server_menu, + self.server_menu, + self.singleplayer_menu, + self.race_menu, + self.maps_menu, + self.settings_menu, + self.video_menu, + self.gameplay_menu, + self.audio_menu, + self.controls_menu, + self.garage_menu, + self.pause_menu, + self.quit_menu ] - + self.car = car self.sand_track = sand_track self.grass_track = grass_track @@ -54,7 +221,18 @@ def __init__(self, car, ai_list, sand_track, grass_track, snow_track, forest_tra ] # Animate the menu - for menu in (self.start_menu, self.main_menu, self.race_menu, self.maps_menu, self.settings_menu, self.video_menu, self.gameplay_menu, self.audio_menu, self.controls_menu, self.pause_menu, self.quit_menu, self.garage_menu): + for menu in (self.start_menu, + self.singleplayer_menu, + self.race_menu, + self.maps_menu, + self.settings_menu, + self.video_menu, + self.gameplay_menu, + self.audio_menu, + self.controls_menu, + self.pause_menu, + self.quit_menu, + self.garage_menu): def animate_in_menu(menu = menu): for i, e in enumerate(menu.children): e.original_scale = e.scale @@ -81,56 +259,22 @@ def animate_in_menu(menu = menu): detail.enable() def singleplayer(): - car.multiplayer = False - self.start_menu.disable() - self.main_menu.enable() - grass_track.enable() - self.car.position = (0, 0, 4) - self.car.visible = False - for track in self.tracks: - for i in track.track: - i.disable() - for i in track.details: - i.disable() - for track in self.grass_track.track: - track.enable() - if self.car.graphics != "ultra fast": - for detail in self.grass_track.details: - detail.enable() - if self.car.graphics == "fast": - self.grass_track.grass.disable() + self.singleplayer_menu.toggle() def multiplayer(): - self.start_menu.disable() - self.host_menu.enable() - self.car.visible = True - self.car.position = (-3, -44.5, 92) - grass_track.disable() - snow_track.enable() - for track in self.tracks: - for i in track.track: - i.disable() - for i in track.details: - i.disable() - for track in self.snow_track.track: - track.enable() - if self.car.graphics != "ultra fast": - self.snow_track.trees.enable() - - def quit(): - application.quit() - os._exit(0) + self.host_menu.toggle() start_title = Entity(model = "quad", scale = (0.5, 0.2, 0.2), texture = "rally-logo", parent = self.start_menu, y = 0.3) - singleplayer_button = Button(text = "Singleplayer", color = color.gray, highlight_color = color.light_gray, scale_y = 0.1, scale_x = 0.3, y = 0.05, parent = self.start_menu) - multiplayer_button = Button(text = "Multiplayer", color = color.gray, highlight_color = color.light_gray, scale_y = 0.1, scale_x = 0.3, y = -0.08, parent = self.start_menu) - + singleplayer_button = Button(text = "Singleplayer", color = color.gray, highlight_color = color.light_gray, scale_y = 0.1, scale_x = 0.3, x = -0.20, y = 0.10, parent = self.start_menu) + multiplayer_button = Button(text = "Multiplayer", color = color.gray, highlight_color = color.light_gray, scale_y = 0.1, scale_x = 0.3, x = 0.20, y = 0.10, parent = self.start_menu) + exit_button = Button(text = "Quit", color = color.gray, highlight_color = color.light_gray, scale_y = 0.1, scale_x = 0.3, y = -0.08, parent = self.start_menu) + singleplayer_button.on_click = Func(singleplayer) multiplayer_button.on_click = Func(multiplayer) + exit_button.on_click = Func(self.quit_menu.toggle) # Quit Menu - def quit(): application.quit() os._exit(0) @@ -143,8 +287,11 @@ def dont_quit(): quit_yes = Button(text = "Yes", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.05, parent = self.quit_menu) quit_no = Button(text = "No", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.07, parent = self.quit_menu) + self.quit_menu_button_selected = None + self.sel_first_button_menu() + quit_yes.on_click = Func(quit) - quit_no.on_click = Func(dont_quit) + quit_no.on_click = Func(self.quit_menu.toggle) # Host Server Menu @@ -173,54 +320,18 @@ def create_server(): detail.enable() def join_server_func(): - self.host_menu.disable() - self.server_menu.enable() - self.car.visible = True - self.car.position = (-105, -50, -59) - snow_track.disable() - sand_track.enable() - for track in self.tracks: - for i in track.track: - i.disable() - for i in track.details: - i.disable() - for track in self.sand_track.track: - track.enable() - if self.car.graphics != "ultra fast": - for detail in self.sand_track.details: - detail.enable() + self.server_menu.toggle() - def back_host(): - self.host_menu.disable() - self.start_menu.enable() - self.car.position = (-80, -42, 18.8) - self.car.rotation = (0, 90, 0) - self.car.visible = True - self.grass_track.enable() - self.snow_track.disable() - for track in self.tracks: - for i in track.track: - i.disable() - for i in track.details: - i.disable() - for track in self.grass_track.track: - track.enable() - if self.car.graphics != "ultra fast": - for detail in self.grass_track.details: - detail.enable() - if self.car.graphics == "fast": - self.grass_track.grass.disable() - self.car.host_ip = InputField(default_value = "IP", limit_content_to = "0123456789.localhost", color = color.black, alpha = 100, y = 0.1, parent = self.host_menu) self.car.host_port = InputField(default_value = "PORT", limit_content_to = "0123456789", color = color.black, alpha = 100, y = 0.02, parent = self.host_menu) create_server_button = Button(text = "Create Server", color = color.hex("F58300"), highlight_color = color.gray, scale_y = 0.1, scale_x = 0.3, y = -0.1, parent = self.host_menu) join_server_button = Button(text = "Join Server", color = color.hex("0097F5"), highlight_color = color.gray, scale_y = 0.1, scale_x = 0.3, y = -0.22, parent = self.host_menu) - back_button_host = Button(text = "<- Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.host_menu) + back_button_host = Button(text = "Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.host_menu) create_server_button.on_click = Func(create_server) join_server_button.on_click = Func(join_server_func) - back_button_host.on_click = Func(back_host) + back_button_host.on_click = Func(multiplayer) # Created Server @@ -229,7 +340,7 @@ def join_hosted_server_func(): car.port.text = car.host_port.text car.multiplayer = True self.created_server_menu.disable() - self.main_menu.enable() + self.singleplayer_menu.enable() self.car.position = (0, 0, 4) self.car.camera_offset = (20, 40, -50) camera.rotation = (35, -20, 0) @@ -267,7 +378,7 @@ def join_server(): if str(self.car.ip.text) != "IP" and str(self.car.port.text) != "PORT": car.multiplayer = True self.server_menu.disable() - self.main_menu.enable() + self.singleplayer_menu.enable() grass_track.enable() sand_track.disable() self.car.position = (0, 0, 4) @@ -289,65 +400,28 @@ def join_server(): self.grass_track.grass.disable() def back_server(): - self.host_menu.enable() - self.server_menu.disable() - self.car.visible = True - self.car.position = (-3, -44.5, 92) - sand_track.disable() - snow_track.enable() - for track in self.tracks: - for i in track.track: - i.disable() - for i in track.details: - i.disable() - for track in self.snow_track.track: - track.enable() - if self.car.graphics != "ultra fast": - for detail in self.snow_track.details: - detail.enable() + self.server_menu.toggle() car.username = InputField(default_value = car.username_text, color = color.black, alpha = 100, y = 0.18, parent = self.server_menu) car.ip = InputField(default_value = "IP", limit_content_to = "0123456789.localhost", color = color.black, alpha = 100, y = 0.1, parent = self.server_menu) car.port = InputField(default_value = "PORT", limit_content_to = "0123456789", color = color.black, alpha = 100, y = 0.02, parent = self.server_menu) join_button = Button(text = "Join Server", color = color.hex("F58300"), highlight_color = color.gray, scale_y = 0.1, scale_x = 0.3, y = -0.1, parent = self.server_menu) - back_button_server = Button(text = "<- Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.server_menu) + back_button_server = Button(text = "Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.server_menu) join_button.on_click = Func(join_server) back_button_server.on_click = Func(back_server) # Main Menu - def back_singleplayer(): - self.car.position = (-80, -42, 18.8) - self.car.rotation = (0, 90, 0) - self.car.visible = True - self.grass_track.enable() - self.start_menu.enable() - self.main_menu.disable() - if self.car.multiplayer_update: - self.car.multiplayer_update = False - for track in self.tracks: - for i in track.track: - i.disable() - for i in track.details: - i.disable() - for track in self.grass_track.track: - track.enable() - if self.car.graphics != "ultra fast": - for detail in self.grass_track.details: - detail.enable() - if self.car.graphics == "fast": - self.grass_track.grass.disable() - - title = Entity(model = "quad", scale = (0.5, 0.2, 0.2), texture = "rally-logo", parent = self.main_menu, y = 0.3) + title = Entity(model = "quad", scale = (0.5, 0.2, 0.2), texture = "rally-logo", parent = self.singleplayer_menu, y = 0.3) - back_button_singleplayer = Button(text = "Back", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.34, parent = self.main_menu) - back_button_singleplayer.on_click = Func(back_singleplayer) + back_button_singleplayer = Button(text = "Back", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.34, parent = self.singleplayer_menu) + back_button_singleplayer.on_click = Func(singleplayer) # Maps Menu def start(): - self.main_menu.disable() + self.singleplayer_menu.disable() if self.car.multiplayer_update: ai_button.disable() self.ai_slider.disable() @@ -358,10 +432,10 @@ def start(): def back(): self.maps_menu.disable() if self.car.multiplayer_update: - self.main_menu.enable() + self.singleplayer_menu.enable() else: self.race_menu.enable() - + self.car.position = (0, 0, 4) unlocked_text.disable() for track in self.tracks: @@ -397,7 +471,7 @@ def sand_track_func(): self.car.position = (-63, -30, -7) self.car.rotation = (0, 90, 0) self.car.reset_count_timer.enable() - + for track in self.tracks: track.disable() for i in track.track: @@ -497,7 +571,7 @@ def snow_track_func(): self.car.position = (-5, -35, 93) self.car.rotation = (0, 90, 0) self.car.reset_count_timer.enable() - + for track in self.tracks: track.disable() for i in track.track: @@ -556,7 +630,7 @@ def forest_track_func(): forest_track.enable() forest_track.played = True - + for f in forest_track.track: f.enable() f.alpha = 255 @@ -635,7 +709,7 @@ def savannah_track_func(): self.car.highscore.text = str(int(self.car.highscore_count)) else: unlocked_text.shake() - + def lake_track_func(): if lake_track.unlocked: self.car.visible = True @@ -774,7 +848,7 @@ def snow_track_hover(): highscore_text.text = "Highscore: " + str(round(self.car.snow_track_hs, 2)) + "\n Mandaw: 27.41" unlocked_text.disable() snow_track.alpha = 255 - + def forest_track_hover(): for track in self.tracks: track.disable() @@ -874,15 +948,15 @@ def lake_track_hover(): unlocked_text.disable() lake_track.alpha = 255 - start_button = Button(text = "Start Game", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.02, parent = self.main_menu) + start_button = Button(text = "Start Game", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.02, parent = self.singleplayer_menu) sand_track_button = Button(text = "Sand Track", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.3, x = -0.5, parent = self.maps_menu) grass_track_button = Button(text = "Grass Track", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.3, x = 0, parent = self.maps_menu) snow_track_button = Button(text = "Snow Track", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.3, x = 0.5, parent = self.maps_menu) forest_track_button = Button(text = "Forest Track", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.1, x = -0.5, parent = self.maps_menu) savannah_track_button = Button(text = "Savannah Track", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.1, x = 0, parent = self.maps_menu) lake_track_button = Button(text = "Lake Track", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.1, x = 0.5, parent = self.maps_menu) - back_button = Button(text = "<- Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.maps_menu) - + back_button = Button(text = "Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.maps_menu) + unlocked_text = Text("Get Less Than 20 seconds on Sand Track to Unlock Grass Track", scale = 1.5, color = color.orange, line_height = 2, origin = 0, y = -0.1, parent = self.maps_menu) unlocked_text.disable() @@ -896,13 +970,13 @@ def lake_track_hover(): self.leaderboard_background = Entity(model = "quad", color = color.hex("0099ff"), alpha = 100, scale = (0.4, 0.42), position = Vec2(0.6, 0.25), parent = camera.ui) self.leaderboard_title = Text("Leaderboard", color = color.gold, scale = 5, line_height = 2, origin = 0, y = 0.4, parent = self.leaderboard_background) - + self.leaderboard_01 = Text(text = "", color = color.hex("#CCCCCC"), scale = 3, line_height = 2, x = 0, origin = 0, y = 0.2, parent = self.leaderboard_background) self.leaderboard_02 = Text(text = "", color = color.hex("#CCCCCC"), scale = 3, line_height = 2, x = 0, origin = 0, y = 0.1, parent = self.leaderboard_background) self.leaderboard_03 = Text(text = "", color = color.hex("#CCCCCC"), scale = 3, line_height = 2, x = 0, origin = 0, y = 0, parent = self.leaderboard_background) self.leaderboard_04 = Text(text = "", color = color.hex("#CCCCCC"), scale = 3, line_height = 2, x = 0, origin = 0, y = -0.1, parent = self.leaderboard_background) self.leaderboard_05 = Text(text = "", color = color.hex("#CCCCCC"), scale = 3, line_height = 2, x = 0, origin = 0, y = -0.2, parent = self.leaderboard_background) - + self.leaderboard_texts = [self.leaderboard_background, self.leaderboard_title, self.leaderboard_01, self.leaderboard_02, self.leaderboard_03, self.leaderboard_04, self.leaderboard_05] self.leaderboard_background.disable() @@ -965,13 +1039,12 @@ def drift_func(): invoke(setattr, unlocked_text, "y", -0.1, delay = 1.6) def back_race(): - self.race_menu.disable() - self.main_menu.enable() + self.race_menu.toggle() race_button = Button(text = "Race", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.12, parent = self.race_menu) time_trial_button = Button(text = "Time Trial", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0, parent = self.race_menu) drift_button = Button(text = "Drift", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.12, parent = self.race_menu) - back_button_race = Button(text = "<- Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.race_menu) + back_button_race = Button(text = "Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.race_menu) race_button.on_click = Func(race_button_func) time_trial_button.on_click = Func(time_trial_func) @@ -981,31 +1054,22 @@ def back_race(): # Settings def settings(): - self.main_menu.disable() - self.settings_menu.enable() + self.settings_menu.toggle() def video(): - self.settings_menu.disable() - self.video_menu.enable() + self.video_menu.toggle() def gameplay(): - self.settings_menu.disable() - self.gameplay_menu.enable() + self.gameplay_menu.toggle() def audio(): - self.settings_menu.disable() - self.audio_menu.enable() + self.audio_menu.toggle() def controls(): - self.settings_menu.disable() - self.controls_menu.enable() + self.controls_menu.toggle() - def back_settings(): - self.settings_menu.disable() - self.main_menu.enable() + settings_button = Button(text = "Settings", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.22, parent = self.singleplayer_menu) - settings_button = Button(text = "Settings", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.22, parent = self.main_menu) - video_button = Button(text = "Video", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.24, parent = self.settings_menu) gameplay_button = Button(text = "Gameplay", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.12, parent = self.settings_menu) audio_button = Button(text = "Audio", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0, parent = self.settings_menu) @@ -1013,12 +1077,12 @@ def back_settings(): back_button_settings = Button(text = "Back", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.24, parent = self.settings_menu) - settings_button.on_click = Func(settings) + settings_button.on_click = Func(settings) video_button.on_click = Func(video) gameplay_button.on_click = Func(gameplay) audio_button.on_click = Func(audio) controls_button.on_click = Func(controls) - back_button_settings.on_click = Func(back_settings) + back_button_settings.on_click = Func(settings) # Gameplay Menu @@ -1076,8 +1140,7 @@ def camera_shake(): camera_shake_button.text = "Camera Shake: Off" def back_gameplay(): - self.gameplay_menu.disable() - self.settings_menu.enable() + self.gameplay_menu.toggle() graphics_button = Button("Graphics: Fancy", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.24, parent = self.gameplay_menu) camera_angle_button = Button("Camera Angle: Top", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.12, parent = self.gameplay_menu) @@ -1123,8 +1186,7 @@ def exit_button_func(): exit_button.text = "Exit Button: Off" def back_video(): - self.video_menu.disable() - self.settings_menu.enable() + self.video_menu.toggle() fullscreen_button = Button("Fullscreen: On", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.24, parent = self.video_menu) borderless_button = Button("Borderless: On", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.12, parent = self.video_menu) @@ -1148,14 +1210,13 @@ def audio_func(): audio_button.text = "Audio: On" self.volume.value = 1 self.car.audio = not self.car.audio - + def back_audio(): - self.audio_menu.disable() - self.settings_menu.enable() + self.audio_menu.toggle() audio_button = Button("Audio: On", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0, parent = self.audio_menu) back_button_audio = Button(text = "Back", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.12, parent = self.audio_menu) - + self.volume = Slider(min = 0, max = 1, default = 1, text = "Volume", y = 0.2, x = -0.3, scale = 1.3, parent = self.audio_menu, dynamic = True) self.volume.step = 0.1 @@ -1164,32 +1225,87 @@ def back_audio(): # Controls - def back_controls(): - self.controls_menu.disable() - self.settings_menu.enable() - - def controls_settings(): - if self.car.controls == "wasd": - self.car.controls = "zqsd" - controls_settings_button.text = "Controls: ZQSD" + def controls_settings(mode): + self.input_config_mode = mode + if mode == KeyboardConfig.ZQSD: + self.enable_custom_input = False + self.car.controls = ["z", "q", "s", "d"] drive_controls_text.text = "Drive: Z" steering_controls_text.text = "Steering: Q D" - elif self.car.controls == "zqsd": - self.car.controls = "wasd" - controls_settings_button.text = "Controls: WASD" + braking_controls_text.text = "Braking: S" + elif mode == KeyboardConfig.WASD: + self.enable_custom_input = False + self.car.controls = ["w", "a", "s", "d"] drive_controls_text.text = "Drive: W" steering_controls_text.text = "Steering: A D" - + braking_controls_text.text = "Braking: S" + drive_controls_text = Button("Drive: W", color = color.black, scale_y = 0.1, scale_x = 0.3, x = -0.5, y = 0.3, parent = self.controls_menu) steering_controls_text = Button("Steering: A D", color = color.black, scale_y = 0.1, scale_x = 0.3, x = 0, y = 0.3, parent = self.controls_menu) braking_controls_text = Button("Braking: S", color = color.black, scale_y = 0.1, scale_x = 0.3, x = 0.5, y = 0.3, parent = self.controls_menu) handbraking_controls_text = Button("Hand Brake: SPACE", color = color.black, scale_y = 0.1, scale_x = 0.3, x = -0.5, y = 0.1, parent = self.controls_menu) respawn_controls_text = Button("Respawn: G", color = color.black, scale_y = 0.1, scale_x = 0.3, x = 0, y = 0.1, parent = self.controls_menu) - controls_settings_button = Button("Controls: WASD", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.2, parent = self.controls_menu) + def enable_custom_input(mode): + self.input_config_mode = mode + self.enable_custom_input = True + button_dict = { + 'Keyboard WASD' : Func(controls_settings, KeyboardConfig.WASD), + 'Keyboard ZQSD' : Func(controls_settings, KeyboardConfig.ZQSD), + 'Custom Keyboard' : Func(enable_custom_input, KeyboardConfig.KEYBOARD), + 'Custom wheel' : Func(enable_custom_input, KeyboardConfig.DEVICE) + } + class MyButtonList(ButtonList): + def __init__(self, button_dict, **kwargs): + super().__init__(button_dict, **kwargs) + def input(self, key): + super().input(key) + self.selection_marker.enabled = True + + input_list = MyButtonList(button_dict, font='VeraMono.ttf', button_height=1.5, y = 0, parent = self.controls_menu) + back_button_controls = Button(text = "Back", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.32, parent = self.controls_menu) - back_button_controls.on_click = Func(back_controls) - controls_settings_button.on_click = Func(controls_settings) + back_button_controls.on_click = Func(controls) + + def read_input(mode): + if self.waiting_on_input or not self.enable_custom_input: + return + + self.waiting_on_input = True + self.input_mode = mode + if mode == KeyboardInput.DRIVE: + self.input_pos = 0 + self.input_count = 1 + self.input_button = drive_controls_text + self.input_prefix = "Drive: {}" + elif mode == KeyboardInput.STEERING: + self.input_pos = 1 + self.input_count = 2 + self.input_button = steering_controls_text + self.input_prefix = "Steering: {}" + elif mode == KeyboardInput.BRAKING: + self.input_pos = 2 + self.input_count = 1 + self.input_button = braking_controls_text + self.input_prefix = "Braking: {}" + elif mode == KeyboardInput.HAND_BRAKE: + self.input_pos = 0 + self.input_count = 1 + self.input_button = handbraking_controls_text + self.input_prefix = "Hand Brake: {}" + elif mode == KeyboardInput.RESPAWN: + self.input_pos = 0 + self.input_count = 1 + self.input_button = respawn_controls_text + self.input_prefix = "Respawn: {}" + self.input_button.color = color.gray + self.input_button.highlight_color = color.gray + + drive_controls_text.on_click = Func(read_input, KeyboardInput.DRIVE) + steering_controls_text.on_click = Func(read_input, KeyboardInput.STEERING) + braking_controls_text.on_click = Func(read_input, KeyboardInput.BRAKING) + handbraking_controls_text.on_click = Func(read_input, KeyboardInput.HAND_BRAKE) + respawn_controls_text.on_click = Func(read_input, KeyboardInput.RESPAWN) # Pause Menu @@ -1331,7 +1447,7 @@ def main_menu(): self.car.reset_count_timer.disable() self.car.timer_running = False self.car.anti_cheat = 1 - self.main_menu.enable() + self.singleplayer_menu.enable() self.pause_menu.disable() for track in self.tracks: track.disable() @@ -1365,7 +1481,7 @@ def main_menu(): self.car.skid_sound.stop(False) if self.car.dirt_sound.playing: self.car.dirt_sound.stop(False) - + p_resume_button = Button(text = "Resume", color = color.black, scale_y = 0.1, scale_x = 0.3, y = 0.11, parent = self.pause_menu) p_respawn_button = Button(text = "Respawn", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.01, parent = self.pause_menu) p_mainmenu_button = Button(text = "Main Menu", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.13, parent = self.pause_menu) @@ -1376,8 +1492,7 @@ def main_menu(): # Garage def back_garage(): - self.garage_menu.disable() - self.main_menu.enable() + self.garage_menu.toggle() self.car.position = (0, 0, 4) self.car.camera_offset = (20, 40, -50) camera.rotation = (35, -20, 0) @@ -1400,8 +1515,7 @@ def back_garage(): self.car.highscore_count = float(self.car.grass_track_hs) def garage_button_func(): - self.garage_menu.enable() - self.main_menu.disable() + self.garage_menu.toggle() self.cars_menu.enable() self.cosmetics_menu.disable() self.colours_menu.disable() @@ -1509,7 +1623,7 @@ def muscle_hover(): def limo_hover(): self.garage_name_text.enable() self.garage_name_text.text = "Limo" - + def lorry_hover(): self.garage_name_text.enable() self.garage_name_text.text = "Lorry" @@ -1716,17 +1830,17 @@ def duck_hover(): def banana_hover(): self.garage_name_text.enable() self.garage_name_text.text = "Banana" - + def surfinbird_hover(): self.garage_name_text.enable() self.garage_name_text.text = "Surfin Bird" self.start_spin = True - garage_button = Button(text = "Garage", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.1, parent = self.main_menu) + garage_button = Button(text = "Garage", color = color.black, scale_y = 0.1, scale_x = 0.3, y = -0.1, parent = self.singleplayer_menu) + + back_button_garage = Button(text = "Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.garage_menu) - back_button_garage = Button(text = "<- Back", color = color.gray, scale_y = 0.05, scale_x = 0.2, y = 0.45, x = -0.65, parent = self.garage_menu) - cars_menu_button = Button(text = "Cars", color = color.black, scale_y = 0.1, scale_x = 0.15, x = -0.7, y = -0.3, parent = self.garage_menu) colours_menu_button = Button(text = "Colours", color = color.black, scale_y = 0.1, scale_x = 0.15, x = -0.5, y = -0.3, parent = self.garage_menu) cosmetics_menu_button = Button(text = "Cosmetics", color = color.black, scale_y = 0.1, scale_x = 0.15, x = -0.3, y = -0.3, parent = self.garage_menu) @@ -1739,7 +1853,7 @@ def surfinbird_hover(): rally_car_button = Button(texture = "rally-icon.png", color = color.white, scale = (0.16, 0.1), y = -0.1, x = -0.3, alpha = 255, parent = self.cars_menu) red_button = Button(color = color.red, scale_y = 0.1, scale_x = 0.15, y = 0.1, x = -0.7, parent = self.colours_menu) - blue_button = Button(color = color.cyan, scale_y = 0.1, scale_x = 0.15, y = 0.1, x = -0.5, parent = self.colours_menu) + blue_button = Button(color = color.blue, scale_y = 0.1, scale_x = 0.15, y = 0.1, x = -0.5, parent = self.colours_menu) green_button = Button(color = color.lime, scale_y = 0.1, scale_x = 0.15, y = 0.1, x = -0.3, parent = self.colours_menu) orange_button = Button(color = color.orange, scale_y = 0.1, scale_x = 0.15, y = -0.1, x = -0.7, parent = self.colours_menu) black_button = Button(color = color.black, scale_y = 0.1, scale_x = 0.15, y = -0.1, x = -0.5, parent = self.colours_menu) @@ -1762,7 +1876,7 @@ def surfinbird_hover(): cosmetics_menu_button.on_click = Func(cosmetics_menu) back_button_garage.on_click = Func(back_garage) - + sports_car_button.on_click = Func(sports_car) muscle_car_button.on_click = Func(muscle_car) limo_button.on_click = Func(limo) @@ -1817,15 +1931,26 @@ def garage_locked_text(self, warning): invoke(self.garage_unlocked_text.disable, delay = 1) def update(self): - if not self.start_menu.enabled and not self.main_menu.enabled and not self.settings_menu.enabled and not self.race_menu.enabled and not self.maps_menu.enabled and not self.settings_menu.enabled and not self.garage_menu.enabled and not self.controls_menu.enabled and not self.host_menu.enabled and not self.server_menu.enabled and not self.created_server_menu.enabled and not self.video_menu.enabled and not self.gameplay_menu.enabled and not self.audio_menu.enabled and not self.quit_menu.enabled: - self.car.camera_follow = True - else: - self.car.camera_follow = False + self.car.camera_follow = (not self.start_menu.enabled and + not self.singleplayer_menu.enabled and + not self.settings_menu.enabled and + not self.race_menu.enabled and + not self.maps_menu.enabled and + not self.settings_menu.enabled and + not self.garage_menu.enabled and + not self.controls_menu.enabled and + not self.host_menu.enabled and + not self.server_menu.enabled and + not self.created_server_menu.enabled and + not self.video_menu.enabled and + not self.gameplay_menu.enabled and + not self.audio_menu.enabled and + not self.quit_menu.enabled) # AI Slider if self.car.multiplayer_update == False: if self.ai_slider.enabled: - if self.ai_slider.value == 0: + if self.ai_slider.value == 0: for ai in self.ai_list: ai.set_enabled = False elif self.ai_slider.value == 1: @@ -1842,7 +1967,11 @@ def update(self): self.ai_list[2].set_enabled = True # Set the camera's position and make the car rotate - if self.start_menu.enabled or self.host_menu.enabled or self.garage_menu.enabled or self.server_menu.enabled or self.quit_menu.enabled: + if (self.start_menu.enabled or + self.host_menu.enabled or + self.garage_menu.enabled or + self.server_menu.enabled or + self.quit_menu.enabled): if not held_keys["right mouse"]: if self.start_spin: self.car.rotation_y += 15 * time.dt @@ -1885,7 +2014,7 @@ def update(self): else: for l in self.leaderboard_texts: l.disable() - + def start_leaderboard(self): for l in self.leaderboard_texts: l.enable() @@ -1895,10 +2024,23 @@ def start_leaderboard(self): self.leaderboard_03.text = str(self.car.leaderboard_03) self.leaderboard_04.text = str(self.car.leaderboard_04) self.leaderboard_05.text = str(self.car.leaderboard_05) - + def input(self, key): # Pause menu - if not self.start_menu.enabled and not self.main_menu.enabled and not self.server_menu.enabled and not self.settings_menu.enabled and not self.race_menu.enabled and not self.maps_menu.enabled and not self.settings_menu.enabled and not self.garage_menu.enabled and not self.audio_menu.enabled and not self.controls_menu.enabled and not self.host_menu.enabled and not self.created_server_menu.enabled and not self.video_menu.enabled and not self.gameplay_menu.enabled and not self.quit_menu.enabled: + if (not self.start_menu.enabled and + not self.singleplayer_menu.enabled and + not self.server_menu.enabled and + not self.race_menu.enabled and + not self.maps_menu.enabled and + not self.settings_menu.enabled and + not self.garage_menu.enabled and + not self.audio_menu.enabled and + not self.controls_menu.enabled and + not self.host_menu.enabled and + not self.created_server_menu.enabled and + not self.video_menu.enabled and + not self.gameplay_menu.enabled and + not self.quit_menu.enabled): if key == "escape": self.pause_menu.enabled = not self.pause_menu.enabled mouse.locked = not mouse.locked @@ -1909,7 +2051,7 @@ def input(self, key): self.car.timer.enable() else: self.car.timer.disable() - + self.car.highscore.enable() if self.car.gamemode == "time trial": self.car.laps_text.enable() @@ -1934,35 +2076,71 @@ def input(self, key): if e.hovered and key == "left mouse down": self.click.volume = self.car.volume * 5 self.click.play() - + if self.audio_menu.enabled: self.car.volume = self.volume.value - # Quit Menu - if self.start_menu.enabled or self.quit_menu.enabled: - if key == "escape": - self.quit_menu.enabled = not self.quit_menu.enabled - self.start_menu.enabled = not self.start_menu.enabled - - # Settings Menu + if self.quit_menu.enabled: + if key == "enter": + self.quit_menu_button_selected.on_click() + elif key == "up arrow" or key == "tab": + self.quit_menu_toggle(True) + elif key == "down arrow": + self.quit_menu_toggle(False) + + def valid_input(key): + if key.endswith(" up"): + return False + elif self.input_config_mode == KeyboardConfig.DEVICE: + return key.startswith("wheel") + else: + return len(key) == 1 or key == 'space' + + if self.controls_menu.enabled: + if self.enable_custom_input and self.waiting_on_input and valid_input(key): + if self.input_mode == KeyboardInput.HAND_BRAKE: + self.car.hand_brake_control = key + elif self.input_mode == KeyboardInput.RESPAWN: + self.car.respawn_control = key + else: + self.car.controls[self.input_pos] = key + + def transform_key(key): + if self.input_config_mode == KeyboardConfig.DEVICE: + if key.endswith("hap"): + return '⬆' + elif key.endswith("hleft"): + return '⬅' + elif key.endswith("hright"): + return '➡' + elif key.endswith("hdown"): + return '⬇' + else: + return key.upper() + else: + return key.upper() + + self.key_format.append(transform_key(key)) + self.input_button.text = self.input_prefix.format(" ".join(self.key_format)) + self.input_count -= 1 + if self.input_count == 0: + self.input_count = 0 + self.input_pos = 0 + self.key_format = [] + self.input_mode = None + self.waiting_on_input =False + self.input_button.color = color.black + self.input_button.highlight_color = self.input_button.color.tint(.2) + self.input_button = None + self.input_prefix = None + else: + self.input_pos += 2 if key == "escape": - if self.settings_menu.enabled: - self.settings_menu.disable() - self.main_menu.enable() - elif self.video_menu.enabled: - self.video_menu.disable() - self.settings_menu.enable() - elif self.controls_menu.enabled: - self.controls_menu.disable() - self.settings_menu.enable() - elif self.gameplay_menu.enabled: - self.gameplay_menu.disable() - self.settings_menu.enable() - elif self.audio_menu.enabled: - self.audio_menu.disable() - self.settings_menu.enable() + for menu in (menu for menu in self.menus if (isinstance(menu, Menu) and menu.enabled)): + menu.toggle() + break if self.start_spin: self.car.copy_normals = False else: - self.car.copy_normals = True \ No newline at end of file + self.car.copy_normals = True diff --git a/menu.py b/menu.py new file mode 100644 index 0000000..1a20b39 --- /dev/null +++ b/menu.py @@ -0,0 +1,15 @@ +from ursina import * + +class Menu(Entity): + def __init__(self, parent_menu = None, **kwargs): + super().__init__(**kwargs) + self.parent_menu = parent_menu + + def on_toggle(self): + pass + + def toggle(self): + self.enabled = not self.enabled + self.on_toggle() + self.parent_menu.enabled = not self.parent_menu.enabled + diff --git a/rally b/rally new file mode 100755 index 0000000..4da5950 --- /dev/null +++ b/rally @@ -0,0 +1,3 @@ +#!/bin/bash + +python main.py diff --git a/requirements.txt b/requirements.txt index 6268ace..33e151f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -ursina==4.1.1 +ursina==5.0.0 ursinanetworking==2.1.4 \ No newline at end of file