Game Development with Godot & GDScript Module 2
GDScript fundamentals through game data interview questions
Interview questions on GDScript fundamentals through game data: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is delta in _process(delta), and why multiply speeds by it?
-
Fresher
What is the difference between var hp = 100, var hp: int = 100 and var hp := 100?
-
Fresher
What is the difference between String and StringName, and when would you write &"…"?
Answered in the lesson Strings, StringName and text formatting
-
Fresher
How do you remove items from an array while looping over it in GDScript?
-
Fresher
How do you get the name of an enum value in GDScript?
-
Fresher
What is a variadic function in GDScript, and how do you call one with values that are in an array?
Answered in the lesson Functions, scope and variadic arguments
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
Players with 144 Hz monitors say a spinning saw trap turns more than twice as fast as in the trailer, and on a weak laptop it crawls. Its script adds 3 degrees to rotation_degrees in _process(). Explain the numbers, fix the script, and say how you would show the fix works without those machines.
- What it tests
- Seeing that a step per frame ties speed to the frame rate, rewriting it as a speed per second times delta, and testing it at several frame rates with --fixed-fps.
- First step
- Work out the speed at each frame rate: 3 degrees a frame is 180 degrees a second at 60 frames a second, probably the rate of the trailer, 432 at 144 and 90 at 30. Then fix the intended speed per second, 180, and multiply it by delta.
- Follow-ups
-
- The saw becomes a physics body that pushes the player. What changes?
- How would you check the fix automatically on every build?
- The laptop drops to 5 frames a second for a moment. What does the saw do?
From the lesson Your first script and the game loop
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A build machine runs a headless GDScript check after every push. Some nights the job sits until its one-hour timeout, and on other nights broken scripts pass. What do you look at, and how do you make the check end quickly and fail when it should?
- What it tests
- Knowing that a --script run ends only at quit(), that an error stops the function before it, that Godot's exit status stays 0 on script errors, and how to guard such a check.
- First step
- Run the same command on your machine with --quit-after and read the output. A run that never ends has not reached quit(), most often because a script error stopped the function first, and that error is in the output, with its file and line.
- Follow-ups
-
- How does a failing check make the job fail?
- Which flags would you put on every command, and why?
- How do you stop one broken test from hiding the others?
From the lesson Your first script and the game loop
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A design sheet says a critical hit deals 1.5 times the damage left after armour. Testers report that 11 damage crits for 16 instead of 17, and that crits against heavy armour heal the enemy. The code is crit = (base - armor) * 3 / 2. Find both bugs, fix them, and say which rounding you chose and why.
- What it tests
- Integer division and where it drops fractions, rounding rules for negative numbers, keeping a formula inside its range, and choosing and writing down a rounding rule.
- First step
- Work through 11: 11 * 3 is 33, and 33 / 2 divides two ints, so the half is dropped and 16.5 becomes 16. Then put the armour above the base: left is negative, the crit is negative, and subtracting it from health adds health.
- Follow-ups
-
- Why not floori(), ceili() or int() instead of roundi()?
- How do you stop the formula from changing by accident later?
- What changes if damage is kept as a float until it is shown?
From the lesson Variables, types and operators
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A 2D exploration game puts its last region 20 million pixels from the origin. There, the player's sprite shakes while standing still and slow walking looks jerky; near the start everything is smooth. Explain the cause with numbers, and compare the fixes you would consider.
- What it tests
- Knowing that Vector2 stores 32-bit floats, working out the gap between neighbouring positions at a distance, and weighing smaller regions, origin shifting and a double-precision build.
- First step
- Work out the gap between neighbouring 32-bit floats there. Between 16,777,216 (2 to the 24) and 33,554,432 every step is 2 pixels, so a position can only change in 2-pixel steps, and a walk of 1 pixel a frame rounds away.
- Follow-ups
-
- How far from the origin can the game go before steps grow past a tenth of a pixel?
- What does origin shifting involve, and what can it break?
- Would a double-precision build of Godot stop the sprite from shaking?
From the lesson Variables, types and operators
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A racing game's HUD formats lap times with "%02d:%05.2f" % [int(t) / 60, fmod(t, 60.0)]. A tester's screenshot shows a lap of 00:60.00, and the results screen, written by someone else, shows the same lap as 01:00.00. Explain both, and design one way to format times for the whole game.
- What it tests
- Seeing that rounding inside one field can carry past its limit, rounding once to the unit shown before splitting it, and keeping a single formatting function for every screen.
- First step
- Take the lap time 59.999. int(t) / 60 is 0 and fmod() gives 59.999, which %05.2f rounds to 60.00 inside the seconds field. The results screen most likely rounded the whole time first and only then split it into minutes and seconds.
- Follow-ups
-
- Should a race timer round the last digit or cut it?
- Where would you put the function so that every screen uses it?
- How would you test it?
From the lesson Strings, StringName and text formatting
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Player names must fit a 16-character name plate, and the online leaderboard accepts at most 32 bytes. The server rejects some names that look short, and one name came back cut in the middle of a letter. Explain with GDScript's own numbers, and say how you check and shorten names.
- What it tests
- Characters against UTF-8 bytes, combining characters, checking input on the client and on the server, and shortening text by whole characters.
- First step
- Measure a rejected name both ways: length() for the name plate and to_utf8_buffer().size() for the server. An accented letter takes 2 bytes and an emoji 4, so 16 characters can need up to 64 bytes, twice the server's limit.
- Follow-ups
-
- Why did one name break in the middle of a letter?
- Which limit do you check where, on the client, the server or both?
- Two names look identical, but the server says they differ. Why?
From the lesson Strings, StringName and text formatting
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
At the end of each frame, a loop over the coins array erases every coin that has been collected. Testers see a coin stay on screen after the player touched it, but only when two coins next to each other in the array were collected in the same frame. Explain why, and rewrite the clean-up so it cannot skip one.
- What it tests
- Seeing that erasing from the array a loop reads skips the next item, reproducing it with neighbouring items, and choosing between a copy, a new array and a loop that runs backwards.
- First step
- Write the array as positions and collect two neighbours: erasing the first moves the second into the position the loop has just read, so it is never looked at. One coin alone, or two coins apart, work, which is why it needs two neighbours in one frame.
- Follow-ups
-
- Which fix would you choose, and why?
- Would a loop that runs backwards over the indices work?
- How do you test it so the bug cannot come back?
From the lesson Conditions and loops
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A game freezes, with no error, the first time an enemy spawns on a small map. The spawn code picks a random spot and then loops while is_blocked(spot): spot = random_spot(). On large maps it never happens. What is going on, and how do you make sure the game can never hang there?
- What it tests
- Recognising a while loop whose end depends on luck or on a state that may never come, bounding such loops, and choosing what to do when no answer exists.
- First step
- Ask when the loop can end: only when random_spot() returns a free spot. On a small, crowded map every spot may be blocked, so the test stays true for ever and the frame never finishes. Count the tries to confirm it.
- Follow-ups
-
- How many tries would you allow, and what happens after the last one?
- How could you avoid random retries altogether?
- How do you find a hang like this in a build players run?
From the lesson Conditions and loops
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
Saves store a player's class as an int from enum Class { WARRIOR, ROGUE, MAGE }. A new release adds RANGER between WARRIOR and ROGUE, and players who load old saves find their mages turned into rogues. Explain why, repair the existing saves, and say how you would store enum values from now on.
- What it tests
- How enum values are numbered, seeing that inserting a name renumbers the names after it, and choosing a save format that survives such a change, with a migration for old files.
- First step
- Write the values out before and after the change: WARRIOR 0, ROGUE 1, MAGE 2 became WARRIOR 0, RANGER 1, ROGUE 2, MAGE 3. A save that holds 2 meant MAGE and now means ROGUE.
- Follow-ups
-
- How do you tell old saves from new ones when a file is loaded?
- Would explicit values such as MAGE = 2 have prevented this?
- What would you write into the save instead of the int?
From the lesson match statements, patterns and enums
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An enemy's _physics_process() is a 60-line if/elif chain on a String state, "idle", "chase", "attack" or "flee", with tests such as state == "chase" and distance < 40. Bugs keep appearing when a state is misspelled. How would you restructure it with an enum and match, and what can still go wrong?
- What it tests
- Replacing string states with an enum, writing one match branch per state with conditions inside, keeping a wildcard for unexpected values, and knowing what match does not check.
- First step
- Replace the strings with enum State { IDLE, CHASE, ATTACK, FLEE } and type the variable as State, so a misspelled name such as State.CHSE becomes a parse error. Then write one match branch per state.
- Follow-ups
-
- Do the distance tests belong in guards, or in if statements inside each branch?
- A new state is added and no branch handles it. What happens?
- When is match the wrong tool for an enemy's logic?
From the lesson match statements, patterns and enums
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A level editor's fill tool colours connected tiles with a recursive fill(x, y) that calls itself for the four neighbours. It works in small rooms, but filling an open 64 by 64 area prints "Stack overflow" and leaves some tiles uncoloured. Explain the limit with numbers, and rewrite the fill so it works on any map.
- What it tests
- How recursion depth grows with the data, Godot's recursion limit, and turning a recursion into a loop over a list of work that still has to be done.
- First step
- Work out how deep the calls go: each call waits for its neighbour's call, so on an open area the chain of waiting calls can grow towards the number of tiles, 4,096, while Godot 4.7.2 stopped a recursion at depth 2,047.
- Follow-ups
-
- Why were only some tiles left uncoloured, and not all of them?
- Should the loop version use a stack or a queue?
- How would you test the tool so the bug cannot come back?
From the lesson Functions, scope and variadic arguments
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A script has var speed := 200.0 and func boost(speed: float) -> void: speed *= 1.5. After boost(speed) the player is no faster, and no error appears. Explain what happens, fix it, and say which project settings would have flagged it.
- What it tests
- The lookup order of names, a parameter shadowing a member, the lifetime of parameters, and turning the shadowing warnings into errors for a project.
- First step
- Ask which speed the line speed *= 1.5 changes. Names are looked up locally first, so it is the parameter, a copy that disappears when the call returns; the member speed is never touched.
- Follow-ups
-
- Why is passing the member in as an argument not enough?
- What are two good ways to write boost()?
- Which warnings would you turn into errors for the whole team?
From the lesson Functions, scope and variadic arguments
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
All Game Development with Godot & GDScript interview questions · The Game Development with Godot & GDScript track