Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions autoload/LessonLoader.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Temporary adapter for loading lessons from BBCode files instead of the
# original Godot resource files. This is to migrate gradually from .tres to
# .bbcode format.
#
# TODO: Remove this when the migration to BBCode is complete.
#
# When removing this, also:
#
# - Remove the LessonLoader.gd autoload from the project
# - Update NavigationManager to load lessons directly from BBCode files
# - Delete all the lesson.tres files + course.tres from the course/ directory
# - Replace with a new GDScript index file that lists all lessons and their paths
# - Delete related resource files: ContentBlock.gd, CodeBlock.gd, Quiz*.gd,
# Practice.gd, Lesson.gd (only if they are no longer needed by the runtime)
extends Node


# Loads a lesson from either a BBCode file or falls back to the original Godot
# resources (.tres files). The tres_path should be the path to the lesson.tres
# file. Returns the Lesson resource that the UI needs to display.
#
# Set force_tres_fallback to true to force loading from .tres files even if .bbcode files exists
static func load_lesson(tres_path: String, force_tres_fallback := false) -> Lesson:
var _parser := LessonBBCodeParser.new()

if force_tres_fallback:
print("LessonLoader.gd: Loading lesson from original .tres file: ", tres_path)
return load(tres_path) as Lesson

var base_dir := tres_path.get_base_dir()
var bbcode_path := base_dir.plus_file("lesson.bbcode")
var file := File.new()
if file.file_exists(bbcode_path):
var result := _parser.parse_file(bbcode_path)

if result.errors:
push_error("LessonLoader.gd: Parse errors when loading lesson from bbcode file %s:" % bbcode_path)
for error in result.errors:
push_error(" " + error.format())
return null

if result.warnings:
print("LessonLoader.gd: Parse warnings when loading lesson from bbcode file %s:" % bbcode_path)
for warning in result.warnings:
print(" ", warning.format())
# Copy resource_path from tres to maintain compatibility with existing code
# that relies on lesson.resource_path for progress tracking, navigation, etc.

# TODO: This also needs to be adapted: navigation, progress tracking, etc. as
# well as page slugs should probably be encoded in the new TOC file,
# probably a GDScript file. For progress tracking and remembering
# scrolling position we used blocks with unique ids BUT, now I'd model
# it more like the browser: possibly have a TOC on the left generated from headings
# and use those as anchors for navigation and progress tracking. Or use
# scroll % + number of completed quizzes for tracking progress through a lesson.
#
# Practices can still have an ID separate from the lesson resource path for
# tracking practice completion.
result.lesson.resource_path = tres_path
return result.lesson
else:
print("LessonLoader.gd: No bbcode file found, loading tres: ", tres_path)
return load(tres_path) as Lesson
8 changes: 5 additions & 3 deletions autoload/NavigationManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,12 @@ func get_navigation_resource(resource_id: String) -> Resource:
var is_lesson := resource_id.ends_with("lesson.tres")

if is_lesson:
return load(resource_id) as Resource

# TODO: remove when bbcode migration is complete, this can load directly
# instead of going through LessonLoader.
# Same for other call to LessonLoader below.
return LessonLoader.load_lesson(resource_id) as Resource
var lesson_path := resource_id.get_base_dir().plus_file("lesson.tres")
var lesson_data := load(lesson_path) as Lesson
var lesson_data := LessonLoader.load_lesson(lesson_path) as Lesson

# If it's not a lesson, it's a practice. May support some other types in future.
for practice_res in lesson_data.practices:
Expand Down
160 changes: 160 additions & 0 deletions course/lesson-1-what-code-is-like/lesson.bbcode
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
[lesson title="What Code is Like"]

Learning to program can be daunting.

Yet, you want to make video games, so [b]there is no way around learning to program[/b]. [i]Every[/i] video game is a computer program.

[title]Telling the computer what to do[/title]

Programming is the process of writing precise instructions that tell a computer how to perform a task.

A game's instructions are, for example: moving a character, drawing a life bar, or playing a sound.

To do any of that, you need to learn a [b]programming language[/b]: a specialized language to tell the computer what to do.

[visual path="CodeProgrammingLanguage.tscn"]

Programming languages are different from natural ones like English or Spanish. The computer does not think. Unlike us, it can't [i]interpret[/i] what you tell it.

You can't tell it something vague like "draw a circle."

Which circle? Where? Which color should it be? How big should it be?

[title]The computer needs exact instructions[/title]

To draw a filled circle, the computer needs to know exact drawing coordinates, the radius, the thickness, and color you want.

The code to do so [i]may[/i] look like this.

[i]Click the button to run the code example and see the result.[/i]

[visual path="RunDrawCircle.tscn"]

In the following lessons, you'll learn how this code works.

For now, we want to give you a sense of what computer code looks like. In this example, everything matters: each parenthesis, capital letter, period, and comma.

The computer always does [b]exactly[/b] what you tell it to. No more, no less. It [i]blindly[/i] follows every instruction.

[b]When you program, you're the one in charge, and you're free to do [i]anything[/i] you want.[/b]

[quiz_choice question="How do you give instructions to a computer?" multiple="false" shuffle="true"]
[option correct]Using a programming language and precise instructions[/option]
[option]Using prose in plain English[/option]
[explanation]Computers don't understand natural languages like English. To make them do anything, you need to give them precise instructions they understand, using a programming language.[/explanation]
[/quiz_choice]

[title]You'll learn to code with GDScript[/title]

In this course, you'll learn the GDScript programming language (the name stands for "Godot script").

This is a language by game developers for game developers. You can use it within the Godot game engine to create games and applications.

It's the language used by games like [ignore][url=https://store.steampowered.com/app/1637320/Dome_Keeper/]Dome Keeper[/url] and [ignore][url=https://store.steampowered.com/app/1942280/Brotato/]Brotato[/url].

Engineers at Tesla also used it for their cars' dashboards.

[visual path="ImageBrotato.tscn"]

GDScript is an excellent language to get started with programming because it's specialized. Unlike some other languages, it doesn't have an [i]overwhelming[/i] amount of features for you to learn.

[title]Most programming languages are similar[/title]

Don't be afraid of being locked in. The concepts you learn in your first programming language will apply to all the others.

Most languages have more similarities than differences. Once you learn one, it takes much less time to become productive with the next one.

Here's an example of the same code in three languages: GDScript, JavaScript, and Python.

Try to spot the similarities and differences.

[visual path="ThreeCodeExamples.tscn"]

It doesn't look [i]that[/i] different, does it?

[quiz_choice question="Are programming languages all completely different?" multiple="false" shuffle="true"]
If you learn one language and then want to learn another, will you have to start from scratch?
[option correct]No, they have many similarities[/option]
[option]Yes, they are completely different[/option]
[explanation]Most programming languages build upon the same ideas of how to program. As a result, they're mostly similar.

It's not to say all languages are the same, though. Some offer a really unique syntax and require a completely different mindset compared to GDScript.

However, languages like GDScript, Python, JavaScript, C++, C#, and many others build upon a similar programming philosophy.[/explanation]
[/quiz_choice]

[title]This is a course for beginners[/title]

If you want to learn to make games or code but don't know where to start, this course should be perfect.

[visual path="WelcomeAnimation.tscn"]

We designed it for [i]absolute beginners[/i], but if you already know another language, it can be a fun way to get started with Godot.

We will give you the coding foundations you need to start making games and applications with Godot.

Please be patient. It will take time before you can make your first complete game alone.

[title]Learning to make games takes practice[/title]

Creating games is more accessible than ever, but it still takes a lot of work and practice.

Do not expect any single course or book to turn you into a professional. [b]Programming is something you learn through practice.[/b]

If something doesn't make immediate sense, don't stress it too much! Keep learning and come back to it later.

Enjoy the process and celebrate every little success. You will never stop learning as a game developer.

[title]What and how you'll learn[/title]

In this free course, you will learn the foundations you need to start coding things like these:

[visual path="res://course/lesson-26-looping-over-dictionaries/ExampleDisplayInventory.tscn"]

[visual path="res://course/lesson-19-creating-arrays/visuals/ExamplePathfinding.tscn"]

Along the way, we'll teach you:

- Some of the mindset you need as a developer. Too many programming courses skip that essential part.
- How to write GDScript code.
- Essential programming foundations to get you started.

As you go through the course, you will have many questions. We will answer them the best we can as we go.

But there is so much to cover that we have to take a few shortcuts. We don't want to [i]overwhelm[/i] you with information. We also want to respect the pace at which our brains memorize things.

We broke down the course into short lessons and practices. If we put too much into each part, you'd learn slower.

If at any time you're left with burning questions, you're more than welcome to join [url=https://discord.gg/87NNb3Z]our Discord community[/url].

[note title="Is this for Godot 4?"]
What you'll learn in this free course is fully compatible with Godot 4. While we initially designed this series for Godot 3, the foundations of GDScript are still the same in Godot 4.
[/note]

[title]Programming is a skill[/title]

Programming is a skill, so to get good at it, you must practice. It is why we built this app.

Each lesson is followed by an interactive practice to use what you learned.

Speaking of which, it's time to look at the practice screen!

To continue, click the [i]Practice[/i] button below. It will give you a short run through how practices work.

[practice id="res://course/lesson-1-what-code-is-like/practice-55916.tres" title="Try Your First Code"]
[description]Run your first bit of code and see the result.[/description]
[goal]
We prepared a code sample for you. For this practice, you don't need to change anything.

To test the code, click the [i]Run[/i] button below the code editor.
[/goal]
[starting_code]
func _ready():
print("Welcome!")
[/starting_code]
[cursor line="0" column="0"]
[validator path="first_practice/TestsWhatCodeIsLike.gd"]
[script_slice path="first_practice/WelcomeToTheApp.gd" name="welcome_to_app"]
[hint]Click the [i]Run[/i] button.[/hint]
[/practice]
[/lesson]
102 changes: 102 additions & 0 deletions course/lesson-10-the-game-loop/lesson.bbcode
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
[lesson title="The Game Loop"]

As we've seen, Godot has functions that do certain actions. For example, the [code]show()[/code] and [code]hide()[/code] functions change the visibility of things.

We can also create our own functions to make custom effects like adding or removing health to a character.

Godot also has special functions we can customize or add to.

Take the [code]_process()[/code] function.

[visual path="visuals/ExampleProcessFunction.tscn"]

The [code]_process()[/code] function gets its name because it does calculations or continuous actions.

It's like a juice factory that [b]processes[/b] juice bottles: the bottles are always moving along a conveyor belt, while different machines operate on them.

It's similar in Godot, but this function can run [b]hundreds of times a second[/b].

[quiz_choice question="How many parameters does this function take?" multiple="false" shuffle="true"]
[code]
func _process(delta):
[/code]
[option correct]1[/option]
[option]2[/option]
[explanation]The [code]_process()[/code] function takes one parameter: [code]delta[/code].

We'll look at what [code]delta[/code] is in the next lesson, as well as show how to use it.[/explanation]
[/quiz_choice]

The [code]_process()[/code] function won't do anything until we add something to it.

You might notice the underscore [code]_[/code] in front of the function name. This is a convention programmers use to coordinate work, and it'll only make sense once you have experience coding in Godot.

For now, all you need to know is that if the function exists in your code, and it is called precisely [code]_process[/code], then Godot will automatically run it every [i]frame[/i].

When Godot draws on the screen, we call that a frame.

[note title="Is this the same for other engines?"]
Other game engines might use different names like [code]_update()[/code].
[/note]

[title]Why is the _process() function useful?[/title]

It's perhaps better to see the [code]_process()[/code] function in action.

Take the following example.

[visual path="visuals/ExampleRotatingSprite.tscn"]

When you click the button [code]set_process(true)[/code], you activate processing on the robot.

From there, every frame, Godot runs the [code]_process()[/code] function.

Since we wrote a [code]rotate()[/code] instruction, Godot is rotating the character by [code]0.05[/code] radians [b]many[/b] times a second.

[quiz_choice question="How often does the _process() function run?" multiple="false" shuffle="true"]
[option]Once a second.[/option]
[option correct]Multiple times a second.[/option]
[explanation]The faster your computer, the more times [code]_process()[/code] will run.

Godot will try and run [code]_process()[/code] as quickly as it can. This makes sure any movement or animations look smooth and fluid.[/explanation]
[/quiz_choice]

In the practice, you'll learn how to use the process function to rotate and move a character yourself.

[practice id="res://course/lesson-10-the-game-loop/practice-tKRHJMQ2.tres" title="Rotating a Character Continuously"]
[goal]
Make the robot rotate slowly by adding to the [code]_process()[/code] function.

A rotation speed of about [code]0.05[/code] each frame should do.
[/goal]
[starting_code]
func _process(delta):

[/starting_code]
[cursor line="0" column="0"]
[validator path="rotating-sprite/TestsRotating.gd"]
[script_slice path="rotating-sprite/RotatingSprite.gd" name="move_and_rotate"]
[hint]Call the [code]rotate()[/code] function[/hint]
[hint]The [code]rotate()[/code] function takes one parameter[/hint]
[docs]rotate[/docs]
[/practice]

[practice id="res://course/lesson-10-the-game-loop/practice-QiGjB7tK.tres" title="Creating Circular Movement"]
[goal]
Make the robot move in a large circle slowly by rotating it and simultaneously moving it along its x direction.

To do this, add the [code]rotate()[/code] and [code]move_local_x()[/code] functions to [code]_process()[/code].

Use a rotation speed of [code]0.05[/code] radians per frame, and move the robot [code]5[/code] pixels per frame.
[/goal]
[starting_code]
func _process(delta):

[/starting_code]
[cursor line="0" column="0"]
[validator path="rotating-and-moving/TestsRotatingAndMoving.gd"]
[script_slice path="rotating-and-moving/RotateAndMoveSprite.gd" name="move_and_rotate"]
[hint]Call the [code]rotate()[/code] and [code]move_local_x()[/code] functions[/hint]
[docs]rotate,move_local_x[/docs]
[/practice]
[/lesson]
Loading