Blame

3aab9f lisa 2026-08-11 23:24:06
Add C06 skill-code study pages, linked from the SD hub Eleven pages ported from the applied-computing-au C06-Reference-Godot standard: home page with the 34-code lookup, per-topic pages with labelled GDScript examples, evidence standards, and Check Your Understanding fold blocks. Generated mirror — repo copy is canonical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1
<!-- Generated from applied-computing-au vic/unit3-4/sat/C06-2026/C06-Reference-Godot — do not hand-edit; re-run the port. -->
2
# OOP Concepts — GDScript
3
4
5
**Skill codes on this page**
6
7
| Code | Level | Skill |
8
|---|---|---|
9
| C643 | 7–8 | access modifiers |
10
| C651 | 9–10 | classes |
11
| C652 | 9–10 | objects |
12
| C653 | 9–10 | abstraction |
13
| C654 | 9–10 | encapsulation |
14
| C655 | 9–10 | generalisation |
15
| C656 | 9–10 | inheritance |
16
17
**Definition.** *Object-oriented programming (OOP):* programming based on objects that contain data in the form of fields or attributes, and code in the form of methods.
18
19
Level 9–10 asks for classes and objects **plus all relevant OOP principles** — one class on its own does not reach the top band.
20
21
## C651 — Classes and C652 — Objects
22
23
**Definitions.** *Class:* a program code template for creating objects. *Object:* any instantiated class that a program can inspect and/or change. *Instantiation:* the process by which an object is created from a class.
24
25
```gdscript
26
# MykiCard.gd
27
class_name MykiCard # C651 — class: the template for every card
28
extends RefCounted
29
30
var _balance: float = 20.00
31
32
func top_up(amount: float) -> void:
33
_balance += amount
34
```
35
36
```gdscript
37
# C652 — objects: two cards from one template, separate balances
38
var my_card: MykiCard = MykiCard.new()
39
var your_card: MykiCard = MykiCard.new()
40
my_card.top_up(10.0)
41
```
42
43
**Earns the tick:** C651 — a class *you wrote* (`class_name`, fields, methods). C652 — `.new()` creating an object your program then uses. Two objects holding different state is the cleanest demo.
44
45
**In tile-matching-game:** `card.gd` opens with `class_name Card` — fields (`pair_id`, `is_face_up`) plus methods (`flip_up()`, `mark_matched()`) in one template (C651). The game then holds two of them:
46
47
```gdscript
48
# tile-matching-game — game.gd
49
var first_card: Card = null # C652 — two objects from one class,
50
var second_card: Card = null # each with its own state
51
```
52
53
(The board creates them with `card_scene.instantiate()` — instancing the card *scene* constructs a `Card` object, because the scene's root node runs `card.gd`.)
54
55
**In club-ladder** — the direct `.new()` case:
56
57
```gdscript
58
# club-ladder — app.gd
59
season.teams.append(Team.new(team_name)) # C652 — object created and used
60
```
61
62
`season.gd` builds them four arguments at a time from the XML — `Team.new(team_name, wins, draws, losses)` — and `Team._init` gives every parameter a default, so both calls work.
63
64
## C653 — Abstraction
65
66
**Definition.** An OOP principle that allows programmers to manage complexity by hiding implementation details and exposing only the essential features of an object.
67
68
**How it works in GDScript:**
69
70
- Base class defines structure meant for inheritance
71
- Methods can have default implementations or error messages
72
- Convention-based — not meant to be used directly
73
- `assert(false)` is one way to indicate override needed
74
- Focus on inheritance structure rather than enforcement
75
76
```gdscript
77
# C653 — abstraction: base class with common structure
78
class_name Animal
79
extends RefCounted
80
81
var name: String
82
83
func _init(p_name: String):
84
name = p_name
85
86
func make_sound():
87
print("Some animal sound")
88
89
func move():
90
print(name + " is moving")
91
```
92
93
Myki version:
94
95
```gdscript
96
# C653 — abstraction: callers use get_cost() and never see the fare rules
97
class_name Journey
98
extends RefCounted
99
100
var fare: float
101
102
func get_cost() -> float:
103
return fare
104
```
105
106
**Earns the tick:** a base class used through its simple interface while the details stay inside. "The HUD calls `get_cost()` and doesn't care how the cost is worked out" is the sentence to say.
107
108
**In tile-matching-game:** `card.gd`'s own header comment makes the abstraction argument — a card "does NOT decide whether two cards match — that is the Game's job. The card only reports being clicked." The game calls `flip_up()` and `mark_matched()`; how a card draws itself stays hidden inside the card.
109
110
## C654 — Encapsulation
111
112
**Definition.** An OOP principle that involves bundling the data, and the methods that operate on that data, into a single unit or class.
113
114
**How it works in GDScript:**
115
116
- Single underscore `_` indicates private by convention only
117
- No enforcement mechanism — purely documentation
118
- All class members are technically public
119
- Relies entirely on developer discipline
120
- IDE may highlight convention violations
121
122
```gdscript
123
class_name BankAccount
124
extends RefCounted
125
126
var _balance: float = 0.0 # C654 — private by convention
127
128
func get_balance() -> float:
129
return _balance
130
131
func deposit(amount: float):
132
if amount > 0:
133
_balance += amount
134
print("Deposited $" + str(amount))
135
else:
136
print("Invalid amount")
137
```
138
139
Myki version:
140
141
```gdscript
142
class_name MykiCard
143
extends RefCounted
144
145
var _balance: float = 20.00 # C654 — private, cannot be changed directly
146
147
func _is_valid(amount: float) -> bool: # C654 — private helper, used only inside this class
148
return amount > 0
149
150
func top_up(amount: float) -> void: # C654 — the only door to _balance
151
if _is_valid(amount):
152
_balance += amount
153
```
154
155
**Earns the tick:** data behind `_`, changed only through methods that validate. In validation: show `top_up(-50)` being rejected.
156
157
**In tile-matching-game:** `Card` bundles its state (`pair_id`, `is_face_up`, `is_matched`) with the methods that change it — outside code never *sets* those fields, it calls `flip_up()`, `flip_down()`, `mark_matched()`. (The game reads them directly; underscore-prefixing the fields and adding getters would push this to full-marks encapsulation.)
158
159
### C643 — Access modifiers
160
161
GDScript has no `private` / `public` keywords — the `_` prefix **is** the access modifier, applied by convention:
162
163
```gdscript
164
var _balance: float = 20.00 # C643 — "private": underscore convention
165
func get_balance() -> float: # C643 — public getter is the only way in
166
return _balance
167
```
168
169
**Earns the tick:** the convention applied consistently *and named* — "the underscore marks it private by convention; other code must go through the getter."
170
171
**In connect-go-dots:** `_open()` and `_on_back_pressed()` carry the underscore as internal helpers no other script should call. (`_ready()` also starts with `_`, but that is Godot's callback naming, not privacy.)
172
173
**In tile-matching-game:** `Card` shows the split in one class — public `flip_up()` / `mark_matched()` for other scripts, private `_on_pressed()` for itself.
174
175
## C655 — Generalisation
176
177
**Definition.** The process of defining a general class (superclass) that encapsulates common attributes and behaviours of more specific classes (subclasses).
178
179
**How it works in GDScript:**
180
181
- `class_name` makes class globally accessible
182
- `extends RefCounted` for automatic memory management
183
- Constructor `_init` sets up shared data
184
- Base class defines common interface for all subclasses
185
186
```gdscript
187
# C655 — generalisation: common functionality in base class
188
class_name Vehicle
189
extends RefCounted
190
191
var brand: String
192
var model: String
193
var is_running: bool = false
194
195
func _init(p_brand: String, p_model: String):
196
brand = p_brand
197
model = p_model
198
199
func start_engine():
200
is_running = true
201
print(brand + " " + model + " started")
202
203
func stop_engine():
204
is_running = false
205
print(brand + " stopped")
206
```
207
208
Myki version:
209
210
```gdscript
211
# C655 — generalisation: what every journey shares lives in the parent
212
class_name Journey
213
extends RefCounted
214
215
var zone: int
216
var fare: float
217
218
func _init(p_zone: int, p_fare: float):
219
zone = p_zone
220
fare = p_fare
221
222
func get_cost() -> float:
223
return fare
224
```
225
226
**Earns the tick:** shared fields and methods pulled *up* into one parent instead of repeated in each child — point at the duplication you avoided.
227
228
## C656 — Inheritance
229
230
**Definition.** A method of basing an object or class on another object or class, taking on its attributes and methods and potentially extending upon them.
231
232
**How it works in GDScript:**
233
234
- `extends` establishes parent-child relationship
235
- `super()` calls parent constructor with parameters
236
- Override by redefining method with same name
237
- Single inheritance model (one parent)
238
- Parent methods available unless explicitly overridden
239
240
```gdscript
241
# C656 — inheritance: Car is a Vehicle with extras
242
class_name Car
243
extends Vehicle
244
245
var doors: int
246
247
func _init(p_brand: String, p_model: String, p_doors: int):
248
super(p_brand, p_model)
249
doors = p_doors
250
251
func honk():
252
print("Beep beep!")
253
254
# C656 — override parent method
255
func start_engine():
256
super.start_engine()
257
print("Car is ready to drive")
258
```
259
260
Myki version:
261
262
```gdscript
263
# C656 — inheritance: a ConcessionJourney is a Journey with one changed rule
264
class_name ConcessionJourney
265
extends Journey
266
267
func get_cost() -> float: # override
268
return fare * 0.5
269
```
270
271
**Earns the tick:** `extends` *your own* class, `super` used, at least one method overridden — and both parent and child actually used by the running program.
272
273
**Not enough:** every script in connect-go-dots has `extends Control` or `extends Node` — inheriting from an *engine* class. Necessary in Godot, but C656 wants `extends` on a class of your own.
274
275
**Worth seeing anyway:** in tile-matching-game, `Card extends Button` shows what inheriting *buys* — the card never defines `pressed` or `disabled`, yet uses both, because they come from `Button`. That is inheritance working; it just is not *your* parent class, so on its own it does not earn C656.
276
277
## Check Your Understanding
278
279
1. Why does `extends Control` not earn C656?
280
281
>| ### Answer
282
>| It inherits from an *engine* class — the tick needs `extends` on a class you wrote.
283
284
2. What is GDScript's access modifier, and which code is it?
285
286
>| ### Answer
287
>| The `_` underscore prefix, applied by convention — C643.
288
289
3. List the minimum ingredients of full C656 evidence.
290
291
>| ### Answer
292
>| Your own parent class, `extends` on the child, `super` used, at least one override — and both classes used by the running program.