diff --git a/.env b/.env index de6d935..50018bc 100644 --- a/.env +++ b/.env @@ -2,10 +2,10 @@ # Godot -GODOT_VERSION=4.2.1 +GODOT_VERSION=4.2.1-stable # Game GAME_NAME=Marble -GAME_VERSION=1.4.5 +GAME_VERSION=1.4.6 GAME_ITCHIO_KEY=marble diff --git a/.github/renovate.json b/.github/renovate.json index 720f78c..9d107f8 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,35 +1,35 @@ { - "regexManagers": [ - { - "fileMatch": ["^plug\\.gd$"], - "matchStrings": [ - "\\s+plug\\(\"(?.*?)\",\\ \\{\\s*\"commit\":\\ \"(?)(?.*?)\"" - ], - "depNameTemplate": "{{{gitUrl}}}", - "packageNameTemplate": "https://github.com/{{{gitUrl}}}", - "versioningTemplate": "git", - "datasourceTemplate": "git-refs" - }, - { - "fileMatch": ["^plug\\.gd$"], - "matchStrings": [ - "\\s+plug\\(\"(?.*?)\",\\ \\{\\s*\"tag\":\\ \"(?)(?.*?)\"" - ], - "depNameTemplate": "{{{gitUrl}}}", - "packageNameTemplate": "https://github.com/{{{gitUrl}}}", - "versioningTemplate": "git", - "datasourceTemplate": "git-tags" - }, - { - "fileMatch": ["^.env$"], - "matchStrings": [ - "GODOT_VERSION=(?.*?)\\n" - ], - "depNameTemplate": "godotengine/godot", - "packageNameTemplate": "https://github.com/godotengine/godot", - "versioningTemplate": "loose", - "extractVersionTemplate": "^(?.*)-stable$", - "datasourceTemplate": "git-tags" - } - ] + "regexManagers": [ + { + "fileMatch": ["^plug\\.gd$"], + "matchStrings": [ + "\\s+plug\\(\"(?.*?)\",\\ \\{\\s*\"commit\":\\ \"(?)(?.*)\"" + ], + "depNameTemplate": "{{{gitUrl}}}", + "packageNameTemplate": "https://github.com/{{{gitUrl}}}", + "versioningTemplate": "git", + "datasourceTemplate": "git-refs" + }, + { + "fileMatch": ["^plug\\.gd$"], + "matchStrings": [ + "\\s+plug\\(\"(?.*?)\",\\ \\{\\s*\"tag\":\\ \"(?.*)\"" + ], + "depNameTemplate": "{{{gitUrl}}}", + "packageNameTemplate": "https://github.com/{{{gitUrl}}}", + "versioningTemplate": "git", + "datasourceTemplate": "git-tags" + }, + { + "fileMatch": ["^.env$"], + "matchStrings": [ + "GODOT_VERSION=(?.*?)\\n" + ], + "depNameTemplate": "godotengine/godot", + "packageNameTemplate": "https://github.com/godotengine/godot", + "versioningTemplate": "loose", + "extractVersionTemplate": "^(?.*)$", + "datasourceTemplate": "git-tags" + } + ] } diff --git a/.github/workflows/release-packaging.yml b/.github/workflows/release-packaging.yml index 13bd7b1..2d67383 100644 --- a/.github/workflows/release-packaging.yml +++ b/.github/workflows/release-packaging.yml @@ -19,13 +19,8 @@ jobs: - name: Load dotenv run: just ci-load-dotenv - # Retry multiple times, sometimes in CI, gdlint raise "file exists" - name: Check - uses: nick-fields/retry@v2 - with: - timeout_minutes: 1 - max_attempts: 3 - command: just fmt + run: just fmt - name: Ensure version is equal to tag if: startsWith(github.ref, 'refs/tags/') @@ -44,6 +39,14 @@ jobs: - name: Load dotenv run: just ci-load-dotenv + - name: Cache Godot + uses: actions/cache@v3 + with: + path: | + ~/.mkflower/bin + ~/.local/share/godot/export_templates + key: ${{ env.godot_version }} + - name: Export run: just export @@ -65,6 +68,14 @@ jobs: - uses: actions/checkout@v4 - uses: extractions/setup-just@v1 + - name: Cache Godot + uses: actions/cache@v3 + with: + path: | + ~/.mkflower/bin + ~/.local/share/godot/export_templates + key: ${{ env.godot_version }} + - name: Load dotenv run: just ci-load-dotenv @@ -106,7 +117,7 @@ jobs: skip_unpack: false - name: Publish - run: just publish + run: just ci-publish env: BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 288dad0..22be8cd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,6 +21,13 @@ repos: rev: v2.2.5 hooks: - id: codespell +- repo: https://github.com/Scony/godot-gdscript-toolkit + rev: 4.2.2 + hooks: + - id: gdformat + exclude: '^addons/gd-plug/' + - id: gdlint + exclude: '^addons/gd-plug/' - repo: local hooks: - id: lower-case-only @@ -30,26 +37,18 @@ repos: files: '[^a-z0-9._/-]' exclude: | (?x)^( + .godot/| .reuse/| - LICENSES/| - public/| - Justfile| - CONTRIBUTING.md| + addons/| CHANGELOG.md| + CONTRIBUTING.md| CREDITS.md| + Justfile| LICENSE.md| + LICENSES/| + public/| README.md ) - - id: check-gdscript - name: check gdscript - entry: gdformat - language: system - files: \.gd$ - exclude: | - (?x)^( - addons/| - plug.gd - ) - id: check-shaders name: check shaders entry: clang-format @@ -60,13 +59,3 @@ repos: language: system files: \.gdshader$ exclude: ^addons/ - - id: lint-gdscript - name: lint gdscript - entry: gdlint - language: system - files: \.gd$ - exclude: | - (?x)^( - addons/| - plug.gd - ) diff --git a/Justfile b/Justfile index c8a6ced..f4548b9 100644 --- a/Justfile +++ b/Justfile @@ -1,8 +1,9 @@ #!/usr/bin/env -S just --justfile +# === Settings === + set dotenv-load := true -export PIP_REQUIRE_VIRTUALENV := "true" # === Aliases === @@ -42,10 +43,11 @@ godot_platform := if arch() == "x86" { } } } -godot_filename := "Godot_v" + godot_version + "-stable_" + godot_platform -godot_template := "Godot_v" + godot_version + "-stable_export_templates.tpz" +godot_filename := "Godot_v" + godot_version + "_" + godot_platform +godot_template := "Godot_v" + godot_version + "_export_templates.tpz" godot_bin := bin_dir / godot_filename -godot_editor_data_dir := "~/.local/share/godot/" +godot_editor_data_dir := "~/.local/share/godot" +godot_templates_dir := godot_editor_data_dir / "export_templates" / replace_regex(godot_version, "([^-]+)-([^-]+)", "$1.$2") # Game variables game_name := env_var('GAME_NAME') @@ -77,46 +79,104 @@ butler_platform := if arch() == "x86" { "linux-386" } else { if arch() == "x86_6 @makedirs: mkdir -p {{ cache_dir }} {{ bin_dir }} {{ build_dir }} {{ dist_dir }} +# === Installer === +# +# Recipes that check and/or install some binaries like Godot, Bulter ... +# This means the user doesn't have to worry about installation, +# and can be sure that the same code is running in CI and locally. + +# Download Godot +[private] +install-godot: makedirs + curl -L --silent -X GET "https://github.com/godotengine/godot-builds/releases/download/{{ godot_version }}/{{ godot_filename }}.zip" --output {{ cache_dir }}/{{ godot_filename }}.zip + unzip -o {{ cache_dir }}/{{ godot_filename }}.zip -d {{ cache_dir }} + cp {{ cache_dir }}/{{ godot_filename }} {{ godot_bin }} + +# Download Godot if not already done +[private] +@check-godot: + [ ! -e {{ godot_bin }} ] && just install-godot || true + +# Download Godot export templates +[private] +install-templates: makedirs + curl -L --silent -X GET "https://github.com/godotengine/godot-builds/releases/download/{{ godot_version }}/{{ godot_template }}" --output {{ cache_dir }}/{{ godot_template }} + unzip -o {{ cache_dir }}/{{ godot_template }} -d {{ cache_dir }} + mkdir -p {{ godot_templates_dir }} + cp {{ cache_dir }}/templates/* {{ godot_templates_dir }} + +# Download Godot export templates if not already done +[private] +@check-templates: + [ ! -d {{ godot_templates_dir }} ] && just install-templates || true + +# Download Butler +[private] +install-butler: makedirs + curl -L --silent -X GET "https://broth.itch.ovh/butler/{{ butler_platform }}/LATEST/archive/default" --output {{ cache_dir }}/butler.zip + unzip -o {{ cache_dir }}/butler.zip -d {{ cache_dir }} + mv {{ cache_dir }}/butler {{ butler_bin }} + chmod +x {{ butler_bin }} + +# Download Butler if not already done +[private] +@check-butler: + [ ! -e {{ butler_bin }} ] && just install-butler || true + +# === Python === +# +# Recipes that use python or python packages. +# This ensures that all python packages are installed in a virtual environment. + +export PIP_REQUIRE_VIRTUALENV := "true" + # Python virtualenv wrapper [private] @venv *ARGS: [ ! -d {{ venv_dir }} ] && python3 -m venv {{ venv_dir }} || true . {{ venv_dir }}/bin/activate && {{ ARGS }} -# Download Godot -[private] -install-godot: - #!/usr/bin/env sh - if [ ! -e {{ godot_bin }} ] - then - curl -X GET "https://downloads.tuxfamily.org/godotengine/{{ godot_version }}/{{ godot_filename }}.zip" --output {{ cache_dir }}/{{ godot_filename }}.zip - unzip {{ cache_dir }}/{{ godot_filename }}.zip -d {{ cache_dir }} - cp {{ cache_dir }}/{{ godot_filename }} {{ godot_bin }} - fi +# Run files formatters +fmt: + just venv pip install pre-commit==3.* + just venv pre-commit run -a -# Download Godot export templates -[private] -install-templates: - #!/usr/bin/env sh - if [ ! -d {{ godot_editor_data_dir }}/export_templates/{{ godot_version }}.stable ] - then - curl -X GET "https://downloads.tuxfamily.org/godotengine/{{ godot_version }}/{{ godot_template }}" --output {{ cache_dir }}/{{ godot_template }} - unzip {{ cache_dir }}/{{ godot_template }} -d {{ cache_dir }} - mkdir -p {{ godot_editor_data_dir }}/export_templates/{{ godot_version }}.stable - cp {{ cache_dir }}/templates/* {{ godot_editor_data_dir }}/export_templates/{{ godot_version }}.stable - fi +# Generate the CREDTIS.md file +credits: + just venv python ./generate_credits.py + +# === Godot === +# +# Recipes around the Godot binary. +# This simplifies some recurring tasks, such as installing addons. + +# Godot binary wrapper +godot *ARGS: check-godot check-templates + {{ godot_bin }} {{ ARGS }} # Download game plugins -install-addons: - [ -f plug.gd ] && just godot --headless --script plug.gd install || true +@install-addons: + [ -f plug.gd ] && just godot --headless --script plug.gd install force || true # Workaround from https://github.com/godotengine/godot/pull/68461 # Import game resources -import-resources: +@import-resources: just godot --headless --export-pack null /dev/null # timeout 60 just godot --editor || true # just godot --headless --quit --editor +# Open the Godot editor +@editor: + just godot --editor + +# === Butler === + +# Bulter wrapper +butler *ARGS: check-butler + {{ butler_bin }} {{ ARGS }} + +# === Export === + # Updates the game version for export @bump-version: echo "Update version in the presets.cfg" @@ -125,78 +185,69 @@ import-resources: sed -i "s,application/version=.*$,application/version=\"{{ game_version }}\",g" ./export_presets.cfg sed -i "s,application/short_version=.*$,application/short_version=\"{{ short_version }}\",g" ./export_presets.cfg - echo "Update version in public/packaging" - sed -i "s,version:\ '.*'$,version:\ '{{ game_version }}',g" ./public/packaging/snap/snapcraft.yaml - sed -i "s,archive/refs/tags/.*\.tar\.gz$,archive/refs/tags/{{ game_version }}\.tar\.gz,g" ./public/packaging/snap/snapcraft.yaml - sed -i "s,releases/download/.*/Marble-linux-v.*\.zip$,releases/download/{{ game_version }}/Marble-linux-v{{ game_version }}\.zip,g" ./public/packaging/snap/snapcraft.yaml - sed -i "s,Version=.*$,Version={{ game_version }},g" ./public/packaging/org.mechanicalflower.Marble.desktop + echo "Update version in the project.godot" + sed -i "s,config/version=.*$,config/version=\"{{ game_version }}\",g" ./project.godot echo "Create the override.cfg" touch override.cfg echo -e '[build_info]\npackage/version="{{ game_version }}"\npackage/build_date="{{ build_date }}"\nsource/commit="{{ commit_hash }}"' > override.cfg -# Godot binary wrapper -@godot *ARGS: makedirs install-godot install-templates - {{ godot_bin }} {{ ARGS }} - -# Open the Godot editor -editor: - just godot --editor - -# Run files formatters -fmt: - just venv pip install pre-commit==3.3.3 reuse==2.1.0 gdtoolkit==4.* - just venv pre-commit run -a +[private] +pre-export: clean-addons makedirs bump-version install-addons import-resources # Export game on Windows -export-windows: bump-version install-addons import-resources +export-windows: pre-export mkdir -p {{ build_dir }}/windows - just godot --export-release '"Windows Desktop"' --headless {{ build_dir }}/windows/{{ game_name }}.exe + just godot --headless --export-release '"Windows Desktop"' {{ build_dir }}/windows/{{ game_name }}.exe (cd {{ build_dir }}/windows && zip {{ game_name }}-windows-v{{ game_version }}.zip -r .) mv {{ build_dir }}/windows/{{ game_name }}-windows-v{{ game_version }}.zip {{ dist_dir }}/{{ game_name }}-windows-v{{ game_version }}.zip rm -rf {{ build_dir }}/windows # Export game on MacOS -export-mac: bump-version install-addons import-resources - just godot --export-release "macOS" --headless {{ dist_dir }}/{{ game_name }}-mac-v{{ game_version }}.zip +export-mac: pre-export + just godot --headless --export-release "macOS" {{ dist_dir }}/{{ game_name }}-mac-v{{ game_version }}.zip # Export game on Linux -export-linux: bump-version install-addons import-resources +export-linux: pre-export mkdir -p {{ build_dir }}/linux - just godot --export-release "Linux/X11" --headless {{ build_dir }}/linux/{{ game_name }}.x86_64 + just godot --headless --export-release "Linux/X11" {{ build_dir }}/linux/{{ game_name }}.x86_64 (cd {{ build_dir }}/linux && zip {{ game_name }}-linux-v{{ game_version }}.zip -r .) mv {{ build_dir }}/linux/{{ game_name }}-linux-v{{ game_version }}.zip {{ dist_dir }}/{{ game_name }}-linux-v{{ game_version }}.zip rm -rf {{ build_dir }}/linux # Export game for the web -export-web: bump-version install-addons import-resources +export-web: pre-export mkdir -p {{ build_dir }}/web - just godot --export-release "Web" --headless {{ build_dir }}/web/index.html + just godot --headless --export-release "Web" {{ build_dir }}/web/index.html # Export on all platform export: export-windows export-mac export-linux -# Remove cache and binaries created by this Justfile -[private] -clean-mkflower: - rm -rf {{ main_dir }} - rm -rf {{ venv_dir }} +# === Clean === +# +# Recipes that clean up the project, deleting +# files and folders created by this Justfile. -# Remove files created during the export -clean-export: - rm -rf {{ build_dir }} {{ dist_dir }} +# Remove game plugins +clean-addons: + rm -rf .plugged + [ -f plug.gd ] && find addons/ -type d -not -name 'addons' -not -name 'gd-plug' -exec rm -rf {} \; || true # Remove files created by Godot clean-resources: rm -rf .godot -# Remove game plugins -clean-addons: - rm -rf .plugged - [ -f plug.gd ] && find addons/ -type d -not -name 'addons' -not -name 'gd-plug' -exec rm -rf {} \; || true +# Remove files created during the export +clean-export: + rm -rf {{ build_dir }} {{ dist_dir }} # Remove any unnecessary files -clean: clean-export clean-resources clean-addons +clean: clean-addons clean-resources clean-export + +# === CI === +# +# Recipes launched by CI steps. +# They can be run locally, but requires the setup of some environment variables. # Add some variables to Github env ci-load-dotenv: @@ -204,24 +255,8 @@ ci-load-dotenv: echo "game_name={{ game_name }}" >> $GITHUB_ENV echo "game_version={{ game_version }}" >> $GITHUB_ENV -# Download Butler -[private] -install-butler: makedirs - #!/usr/bin/env sh - if [ ! -e {{ butler_bin }} ] - then - curl -L -X GET "https://broth.itch.ovh/butler/{{ butler_platform }}/LATEST/archive/default" --output {{ cache_dir }}/butler.zip - unzip {{ cache_dir }}/butler.zip -d {{ cache_dir }} - mv {{ cache_dir }}/butler {{ butler_bin }} - chmod +x {{ butler_bin }} - fi - -# Bulter wrapper -@butler *ARGS: install-butler - {{ butler_bin }} {{ ARGS }} - # Upload the game on Github and Itch.io -publish: +ci-publish: gh release create "{{ game_version }}" --title="v{{ game_version }}" --generate-notes {{ dist_dir }}/* just butler push {{ dist_dir }}/{{ game_name }}-windows-v{{ game_version }}.zip mechanical-flower/{{ game_itchio_key }}:windows --userversion {{ game_version }} just butler push {{ dist_dir }}/{{ game_name }}-mac-v{{ game_version }}.zip mechanical-flower/{{ game_itchio_key }}:mac --userversion {{ game_version }} diff --git a/export_presets.cfg b/export_presets.cfg index 0319560..255b069 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -35,8 +35,8 @@ application/modify_resources=true application/icon="" application/console_wrapper_icon="" application/icon_interpolation=4 -application/file_version="1.4.5.20231230" -application/product_version="1.4.5.20231230" +application/file_version="1.4.6.20240114" +application/product_version="1.4.6.20240114" application/company_name="Mechanical Flower" application/product_name="Marble" application/file_description="" @@ -131,7 +131,7 @@ application/bundle_identifier="io.itch.MechanicalFlower" application/signature="" application/app_category="Games" application/short_version="1.4" -application/version="1.4.5" +application/version="1.4.6" application/copyright="2023-present Mechanical Flower" application/copyright_localized={} application/min_macos_version="10.12" diff --git a/generate_credits.py b/generate_credits.py new file mode 100755 index 0000000..04dd34c --- /dev/null +++ b/generate_credits.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +import os +from string import Template + + +def main(): + template = Template(( + '- "[$files]($source)" by **$author** licensed' + ' under [$license](./LICENSES/$license.txt)\n' + )) + + deps = {} + section = None + + with open(".reuse/dep5", "r") as file: + for line in file: + if line.startswith('# '): + section = line[len("# "): -1].lower() + + if section is None: + continue + + if line.startswith("Files: "): + if section not in deps: + deps[section] = [] + + deps[section].append({"files": line[len("Files: "):-1]}) + + elif line.startswith("Copyright: "): + if section not in deps: + deps[section] = [] + + date_author = line[len("Copyright: "):-1].split(" ") + date_author.pop(0) + deps[section][-1]["author"] = " ".join(date_author) + + elif line.startswith("License: "): + if section not in deps: + deps[section] = [] + + deps[section][-1]["license"] = line[len("License: "):-1] + + elif line.startswith("Source: "): + if section not in deps: + deps[section] = [] + + deps[section][-1]["source"] = line[len("Source: "):-1] + + if deps: + with open("CREDITS.md", "w") as file: + file.writelines("# Credits\n\n") + + for key, value in deps.items(): + file.writelines(f"## {key.title()}\n") + for dep in value: + file.writelines(template.substitute(**dep)) + else: + if os.path.exists("CREDITS.md"): + os.remove("CREDITS.md") + + +if __name__ == "__main__": + main() diff --git a/plug.gd b/plug.gd index 651d628..0fefd45 100644 --- a/plug.gd +++ b/plug.gd @@ -2,6 +2,9 @@ extends "res://addons/gd-plug/plug.gd" func _plugging(): - plug("godot-extended-libraries/godot-debug-menu", {"commit": "9d36ea23661d095198ff7fcfff2715172f73c983"}) + plug( + "godot-extended-libraries/godot-debug-menu", + {"commit": "9d36ea23661d095198ff7fcfff2715172f73c983"} + ) plug("KoBeWi/Godot-Universal-Fade", {"commit": "f091514bba652880f81c5bc8809e0ee4498988ea"}) plug("nisovin/godot-coi-serviceworker", {"commit": "de1be2989eda4c7d77a08b8c56cd94c769181c4e"}) diff --git a/project.godot b/project.godot index b5666ea..08685e5 100644 --- a/project.godot +++ b/project.godot @@ -15,6 +15,7 @@ universal_fade/patterns_directory="res://addons/UniversalFade/Patterns" [application] config/name="Marble" +config/version="1.4.6" run/main_scene="res://scenes/main.tscn" config/project_settings_override="override.cfg" config/features=PackedStringArray("4.2") diff --git a/scenes/blocks/start_line.tscn b/scenes/blocks/start_line.tscn index 16aabe2..f868f2e 100644 --- a/scenes/blocks/start_line.tscn +++ b/scenes/blocks/start_line.tscn @@ -102,7 +102,6 @@ shape = SubResource("2") [node name="TubeVerticalToHorizontal" parent="." instance=ExtResource("4")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -7.6, 0) -collision_mask = 0 [node name="Positions" type="Node3D" parent="."] diff --git a/scenes/camera/cinematic_camera.tscn b/scenes/camera/cinematic_camera.tscn index 3004a18..4861af0 100644 --- a/scenes/camera/cinematic_camera.tscn +++ b/scenes/camera/cinematic_camera.tscn @@ -3,6 +3,7 @@ [ext_resource type="Script" path="res://scripts/camera/cinematic_camera.gd" id="1"] [node name="MarbleCamera" type="Node3D"] +process_mode = 3 script = ExtResource("1") [node name="Camera" type="Camera3D" parent="."] diff --git a/scenes/camera/rotation_camera.tscn b/scenes/camera/rotation_camera.tscn index 33a15ee..85cb44a 100644 --- a/scenes/camera/rotation_camera.tscn +++ b/scenes/camera/rotation_camera.tscn @@ -3,8 +3,8 @@ [ext_resource type="Script" path="res://scripts/camera/rotation_camera.gd" id="1"] [node name="RotationCamera" type="Node3D"] +process_mode = 3 script = ExtResource("1") -rotation_speed = 0.25 [node name="Camera" type="Camera3D" parent="."] unique_name_in_owner = true diff --git a/scenes/gui/countdown.tscn b/scenes/gui/countdown.tscn index 9660e30..eb4a88b 100644 --- a/scenes/gui/countdown.tscn +++ b/scenes/gui/countdown.tscn @@ -10,6 +10,7 @@ font = ExtResource("2_5qytn") font_size = 50 [node name="Countdown" type="Control"] +process_mode = 3 layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -41,3 +42,6 @@ volume_db = -20.0 [node name="Countdown2" type="AudioStreamPlayer" parent="."] stream = ExtResource("3") volume_db = -20.0 + +[node name="Timer" type="Timer" parent="."] +unique_name_in_owner = true diff --git a/scenes/race.tscn b/scenes/race.tscn index 955c68b..32ef2b9 100644 --- a/scenes/race.tscn +++ b/scenes/race.tscn @@ -2,10 +2,10 @@ [ext_resource type="Script" path="res://scripts/race.gd" id="1"] -[sub_resource type="Curve3D" id="Curve3D_em3nq"] +[sub_resource type="Curve3D" id="Curve3D_f15n6"] [node name="Race" type="Node3D"] script = ExtResource("1") [node name="Path" type="Path3D" parent="."] -curve = SubResource("Curve3D_em3nq") +curve = SubResource("Curve3D_f15n6") diff --git a/scripts/camera/rotation_camera.gd b/scripts/camera/rotation_camera.gd index db80ad1..a171335 100644 --- a/scripts/camera/rotation_camera.gd +++ b/scripts/camera/rotation_camera.gd @@ -2,9 +2,11 @@ class_name RotationCamera extends Node3D -const RADIUS := 50.0 - -@export var rotation_speed := 0.5 +@export var rotation_speed := 0.25 +@export var target := Vector3.ZERO +@export var y_pos := 5.0 +@export var move_y_pos := true +@export var distance_to_target := 50.0 var _current_angle := 0.0 @@ -13,7 +15,14 @@ var _current_angle := 0.0 func _process(delta: float) -> void: _current_angle = fmod(_current_angle + delta * rotation_speed, 180) - _camera.transform.origin = Vector3( - RADIUS * cos(_current_angle), 15.0, RADIUS * sin(_current_angle) - ) - _camera.look_at(Vector3.ZERO, Vector3.UP) + + var center = to_local(target) + var x := distance_to_target * cos(_current_angle) + var y := y_pos + var z := distance_to_target * sin(_current_angle) + + if move_y_pos: + y = sin(_current_angle) * 2.0 + + _camera.position = Vector3(x, y, z) + center + _camera.look_at(center, Vector3.UP) diff --git a/scripts/gui/countdown.gd b/scripts/gui/countdown.gd index f1f25a2..471e483 100644 --- a/scripts/gui/countdown.gd +++ b/scripts/gui/countdown.gd @@ -1,28 +1,35 @@ extends Control +signal countdown_finished + +var _count := 4 + +@onready var _timer: Timer = get_node(^"%Timer") @onready var _label_timer = get_node(^"%LabelTimer") @onready var _countdown_1 = get_node(^"Countdown1") @onready var _countdown_2 = get_node(^"Countdown2") -func start(): - show() +func _ready(): + _timer.connect("timeout", _decrement_and_play) - _countdown_1.play() - _label_timer.set_text("3") - await get_tree().create_timer(1.0).timeout - _countdown_1.play() - _label_timer.set_text("2") +func _decrement_and_play(): + _count -= 1 + if _count == 0: + _countdown_2.play() + _label_timer.set_text("start") + _count = 4 - await get_tree().create_timer(1.0).timeout - _countdown_1.play() - _label_timer.set_text("1") + _timer.stop() + hide() + emit_signal("countdown_finished") + else: + _countdown_1.play() + _label_timer.set_text(str(_count)) - await get_tree().create_timer(1.0).timeout - _countdown_2.play() - _label_timer.set_text("start") - await get_tree().create_timer(1.0).timeout - - hide() +func start(): + show() + _decrement_and_play() + _timer.start() diff --git a/scripts/main.gd b/scripts/main.gd index 44d66dd..e3cde86 100644 --- a/scripts/main.gd +++ b/scripts/main.gd @@ -41,9 +41,7 @@ var _positions := [] func _ready() -> void: _rotation_camera = RotationCamera.instantiate() _cinematic_camera = CinematicCamera.instantiate() - reset_position() - set_mode(_mode) @@ -174,6 +172,16 @@ func replace_camera(new_camera, old_cameras) -> void: add_child(new_camera) +func _on_timer_timeout(): + # Release SceneTree + get_tree().set_pause(false) + _timer.start() + _race_has_started = true + + # Put the camera at the right place for the start + replace_camera(_cinematic_camera, [_rotation_camera]) + + # Set the game mode func set_mode(mode): var start_a_new_race = false @@ -214,6 +222,10 @@ func set_mode(mode): # Put the camera at the right place for the start replace_camera(_rotation_camera, [_cinematic_camera]) + # Focus the rotation camera on the marble start line + _rotation_camera.target = get_highest_piece().global_position + Vector3.UP * 5 + _rotation_camera.distance_to_target = 10.0 + var names = _pause_menu.get_names() if len(names) > 0: # Stop SceneTree, to make all the marbles leave at the same time @@ -229,15 +241,8 @@ func set_mode(mode): _cinematic_camera.set_target(marble) await Fade.fade_in(1, Color.BLACK, "Diamond", false, false).finished - await _countdown.start() - - # Release SceneTree - get_tree().set_pause(false) - _timer.start() - _race_has_started = true - - # Put the camera at the right place for the start - replace_camera(_cinematic_camera, [_rotation_camera]) + _countdown.connect("countdown_finished", _on_timer_timeout, CONNECT_ONE_SHOT) + _countdown.start() else: _overlay.show() @@ -248,10 +253,16 @@ func set_mode(mode): _overlay.hide() _pause_menu.open_start_menu() replace_camera(_rotation_camera, [_cinematic_camera]) + # Focus the rotation camera on race + _rotation_camera.target = Vector3.ZERO + _rotation_camera.distance_to_target = 50.0 elif _mode == State.MODE_PAUSE: _pause_menu.open_pause_menu() replace_camera(_rotation_camera, [_cinematic_camera]) + # Focus the rotation camera on race + _rotation_camera.target = Vector3.ZERO + _rotation_camera.distance_to_target = 50.0 # Remove a node from the scene tree @@ -264,7 +275,9 @@ func _process(delta): if _time > TIME_PERIOD: if _mode == State.MODE_START: + # Regenerate race _race.call_deferred(&"generate_race", true) + # Reset timer _time = 0 diff --git a/scripts/marble.gd b/scripts/marble.gd index e782362..af1e656 100644 --- a/scripts/marble.gd +++ b/scripts/marble.gd @@ -24,9 +24,7 @@ func _ready() -> void: # Set material color var color = Color(randf(), randf(), randf()) - var x_ray_material: StandardMaterial3D = ( - _ball_mesh.get_active_material(0) - ) + var x_ray_material: StandardMaterial3D = _ball_mesh.get_active_material(0) x_ray_material.set_albedo(color) var toon_material: StandardMaterial3D = x_ray_material.get_next_pass() toon_material.set_albedo(color)