Skip to content

Convert Learn GDScript App to Godot 4.6#1248

Open
Razoric480 wants to merge 81 commits intomainfrom
raz/learn_godot4
Open

Convert Learn GDScript App to Godot 4.6#1248
Razoric480 wants to merge 81 commits intomainfrom
raz/learn_godot4

Conversation

@Razoric480
Copy link
Copy Markdown
Collaborator

@Razoric480 Razoric480 commented Mar 20, 2026

Converts the whole of the app from the 3.6.2 custom build with GDScriptParserWrapper to a 4.6.2 custom build with a GDScriptErrorChecker. Both are uploaded to the Razoric480/custom-godot-builder repository.

Fixes #1187. Fixes #1259.

Current State

Integration tests pass

Integration Test Log Integration Test results
RUNNING INTEGRATION TEST
Time scale: 4.0x
Course path: res://course/CourseLearnGDScriptIndex.gd

Course: Learn GDScript From Zero
Total lessons: 27
Total practices: 53

[Lesson 1/27] Testing: What Code is Like
  ERROR: Scene res://course/common/inventory/DictInventory.tscn doesn't have a run() function. The Run button won't work.
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  OK - Lesson loaded successfully
  [Practice 1/1] Testing: Try Your First Code
Welcome!
["Welcome!"]
    OK - Practice completed successfully

[Lesson 2/27] Testing: Your First Error
  OK - Lesson loaded successfully
  [Practice 1/1] Testing: Fix Your First Error
    OK - Practice completed successfully

[Lesson 3/27] Testing: We Stand on the Shoulders of Giants
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Make The Character Visible
    OK - Practice completed successfully
  [Practice 2/2] Testing: Make the Robot Upright
    OK - Practice completed successfully

[Lesson 4/27] Testing: Drawing a Rectangle
  OK - Lesson loaded successfully
  [Practice 1/3] Testing: Drawing a Corner
    OK - Practice completed successfully
  [Practice 2/3] Testing: Drawing a Rectangle
    OK - Practice completed successfully
  [Practice 3/3] Testing: Drawing a Bigger Rectangle
    OK - Practice completed successfully

[Lesson 5/27] Testing: Coding Your First Function
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: A function to draw squares
    OK - Practice completed successfully
  [Practice 2/2] Testing: Drawing multiple squares
    OK - Practice completed successfully

[Lesson 6/27] Testing: Your First Function Parameter
  OK - Lesson loaded successfully
  [Practice 1/4] Testing: Drawing corners of different sizes
    OK - Practice completed successfully
  [Practice 2/4] Testing: Using multiple parameters
    OK - Practice completed successfully
  [Practice 3/4] Testing: Drawing squares of any size
    OK - Practice completed successfully
  [Practice 4/4] Testing: Drawing rectangles of any size
    OK - Practice completed successfully

[Lesson 7/27] Testing: Introduction to Member Variables
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Draw a rectangle at a precise position
    OK - Practice completed successfully
  [Practice 2/2] Testing: Draw squares at different positions
    OK - Practice completed successfully

[Lesson 8/27] Testing: Defining Your Own Variables
  OK - Lesson loaded successfully
  [Practice 1/1] Testing: Define a health variable
    OK - Practice completed successfully

[Lesson 9/27] Testing: Adding and Subtracting
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Damaging the Robot
    OK - Practice completed successfully
  [Practice 2/2] Testing: Healing the Robot
    OK - Practice completed successfully

[Lesson 10/27] Testing: The Game Loop
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Rotating a Character Continuously
    OK - Practice completed successfully
  [Practice 2/2] Testing: Creating Circular Movement
    OK - Practice completed successfully

[Lesson 11/27] Testing: Time Delta
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Rotating Using Delta
    OK - Practice completed successfully
  [Practice 2/2] Testing: Moving in a Circle Using Delta
    OK - Practice completed successfully

[Lesson 12/27] Testing: Using Variables to Make Code Easier to Read
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Clarifying Code Using Variables
    OK - Practice completed successfully
  [Practice 2/2] Testing: Fixing an Out of Scope Error
    OK - Practice completed successfully

[Lesson 13/27] Testing: Conditions
  OK - Lesson loaded successfully
  [Practice 1/3] Testing: Using Comparisons
["health is greater than five."]
["One is less than health."]
["health is equal to health"]
["health is not equal to seven."]
    OK - Practice completed successfully
  [Practice 2/3] Testing: Limiting Healing
    OK - Practice completed successfully
  [Practice 3/3] Testing: Preventing Health from Going Below Zero
    OK - Practice completed successfully

[Lesson 14/27] Testing: Multiplying
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Increasing maximum health exponentially
    OK - Practice completed successfully
  [Practice 2/2] Testing: Reducing damage at higher levels
    OK - Practice completed successfully

[Lesson 15/27] Testing: 2D Vectors
  ERROR: Scene res://course/lesson-16-2d-vectors/visuals/VectorVisual.tscn doesn't have a run() function. The Run button won't work.
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Increasing scale using vectors
    OK - Practice completed successfully
  [Practice 2/2] Testing: Resetting size and position using vectors
    OK - Practice completed successfully

[Lesson 16/27] Testing: Introduction to While Loops
  OK - Lesson loaded successfully
  [Practice 1/1] Testing: Moving to the end of a board
    OK - Practice completed successfully

[Lesson 17/27] Testing: Introduction to For Loops
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Using a for loop to move to the end of the board
    OK - Practice completed successfully
  [Practice 2/2] Testing: Improving code with a for loop
    OK - Practice completed successfully

[Lesson 18/27] Testing: Creating arrays
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Walking to the robot
    OK - Practice completed successfully
  [Practice 2/2] Testing: Selecting units
    OK - Practice completed successfully

[Lesson 19/27] Testing: Looping over arrays
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Move the robot along the path
    OK - Practice completed successfully
  [Practice 2/2] Testing: Back to the drawing board
    OK - Practice completed successfully

[Lesson 20/27] Testing: Strings
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Creating string variables
["Hi, Robi!"]
    OK - Practice completed successfully
  [Practice 2/2] Testing: Using an array of strings to play a combo
    OK - Practice completed successfully

[Lesson 21/27] Testing: Functions that return a value
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  ERROR: Scene  doesn't have a run() function. The Run button won't work.
  OK - Lesson loaded successfully
  [Practice 1/1] Testing: Converting coordinates from the grid to the screen
    OK - Practice completed successfully

[Lesson 22/27] Testing: Appending and popping values from arrays
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Completing orders
["completing order `tomato soup`"]
["completing order `toast`"]
["completing order `burger`"]
["completing order `cheese sandwich`"]
    OK - Practice completed successfully
  [Practice 2/2] Testing: Clearing up the crates
["popping crate 3 \'sword\'"]
["popping crate 2 \'gems\'"]
["popping crate 1 \'shield\'"]
["popping crate 0 \'healing heart\'"]
    OK - Practice completed successfully

[Lesson 23/27] Testing: Accessing values in arrays
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Using the right items
["using item 6: \"sword\""]
["using item 8: \"shield\""]
["used items: [\"sword\", \"shield\"]"]
    OK - Practice completed successfully
  [Practice 2/2] Testing: Realigning the train tracks
    OK - Practice completed successfully

[Lesson 24/27] Testing: Creating Dictionaries
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Creating an inventory using a dictionary
    OK - Practice completed successfully
  [Practice 2/2] Testing: Increasing item counts
    OK - Practice completed successfully

[Lesson 25/27] Testing: Looping over dictionaries
  ERROR: Scene res://course/common/inventory/DictInventory.tscn doesn't have a run() function. The Run button won't work.
  ERROR: Scene res://course/lesson-26-looping-over-dictionaries/GameBoard.tscn doesn't have a run() function. The Run button won't work.
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Displaying the inventory
    OK - Practice completed successfully
  [Practice 2/2] Testing: Placing units on the board
    OK - Practice completed successfully

[Lesson 26/27] Testing: Value types
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Displaying the player's health and energy
    OK - Practice completed successfully
  [Practice 2/2] Testing: Letting the player type numbers
    OK - Practice completed successfully

[Lesson 27/27] Testing: Specifying types with type hints
  OK - Lesson loaded successfully
  [Practice 1/2] Testing: Add the correct type hints to variables
    OK - Practice completed successfully
  [Practice 2/2] Testing: Fix the values to match the type hints
    OK - Practice completed successfully


==================================================
Test Summary
==================================================
Total lessons tested: 27
Total practices tested: 53
Tests passed: 53 / 53
Failures: 0
Timeouts: 0

OK - All tests passed!
  • Currently deployed to staging gh-pages
  • Entire project has been converted to Godot 4, from the main menu up to the ending screen.
  • Large bugs have mostly been dealt with, but there are likely still some smaller ones
  • Font size and font resource overrides have been replaced with Theme Variations

Potential issues

  • Various pages had so many renames between godot 3 and 4 that the auto-converter didn't even bother. RichTextLabel adjust_height didn't get ported to fit_content so I had to find those, for example. Particle settings were only marginally converted.

Some internals to keep in mind

  • Coroutine code examples used yield() with GDScriptFunctionState to step through a function. Instead, I've split those up to have either a run() (no coroutines or stepping) or a run_coroutine(CoroutineController). yield() is replaced with await coroutine_controller.step_requested, and run_coroutine() should end with an coroutine_controller.finished.emit().
  • Web release uses no-threads to maximize compatibility.
  • Uses the gl_compat renderer to maximize compatibility and web support.
  • As a bonus, we include the GDScriptAnalyzer in the offline script verifier, allowing us to catch some errors that would crash at runtime in the godot 3 version

Conversion gotchas I ran into

  • DynamicFont were all auto-converted to FontFile and were all broken. I had to convert them all to FontVariation and re-assign the main font + fallback.
    • Font sizes is no longer part of the font variation - they are stored as a Font Size theme override. I assigned Theme Variations wherever a font size or font was requested, which required a change to the Theme Manager.
  • TileMapLayer's map_to_local() is centered, whereas TileMap's map_to_world() was top left corner
  • String manipulation: godot 3's right() function gave you the characters to the right of the index. godot 4's right() gives you X characters from the right side (which, to be fair, matches what left() does).
  • super._ready() and the like are no longer implicit and need to be called explicitly. I think I've found most of them but it's possible I've missed some.
  • Some of the RichTextLabels were copied by the auto-converter by their display text and not by their BBCode

@NathanLovato
Copy link
Copy Markdown
Contributor

Made a couple more changes, notably removed the import cache folder from git tracking and updated the signal connections and the likes + corrected errors in the revealer script.

@NathanLovato
Copy link
Copy Markdown
Contributor

One small note on something I just noticed: In the UI practice scene, there's a CodeHighlighter resource embedded. I think it's a resource we would want to share across all code editors across the application, but I couldn't find where it is in the scene to extract it as a reusable resource.

@Razoric480
Copy link
Copy Markdown
Collaborator Author

I did extract a re-usable TRES, but I must have missed that one. I'll see about tracking it down.

@Razoric480
Copy link
Copy Markdown
Collaborator Author

Razoric480 commented Mar 28, 2026

The profile was saving multiple times. Not sure why it wasn't noticeable in the godot 3 version as it happened there too. Fixed it by queueing the save so that even if save() is called multiple times, it only happens once. There's still a bit of a spike but it's a lot less egregious. Not sure if there's been a change with ResourceSaver between godot 3 and 4 that made it a bit slower.

Alternatively would be to save/load with var_to_string and save one line at a time behind await process_frame, or to compile with threads support and save behind a thread.

@NathanLovato
Copy link
Copy Markdown
Contributor

NathanLovato commented Mar 29, 2026

Thanks.

I did a bit of testing and profiling because the lag remained long for me and saving multiple times itself should not have been too slow, although it's good that this has been cleaned up.

I found that the root issue was when we change the fonts in the theme, it caused lots of notifications and re-layouts. But excessively. In the profiler, strangely enough, the time spike was reported as physics time.

I managed to reduce it from 4000 ms to 500 ms by removing many references to theme resources. That's still quite long. I think this could be improved by producing fewer individual controls, notably lesson content blocks. Hopefully at least. The app could generally use a pass later on to simplify or consolidate the UI and theme etc., but maybe I will put Yuri on that when he is available (former Godot UI and theme system maintainer).

I'll do a bit more testing before pushing. I'm also adding some logic so if you change settings that are not related to theme resources it doesn't touch the theme and doesn't cause any re-layout so the change is perceptually instant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lesson 22, Practice 1 - Persistent Freeze during Run assessment Port the app to Godot 4

2 participants