公有成员与私有成员
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 26 课,共 65 课。
封装是指对象将数据与修改这些数据的方法放在一起,并决定其他代码可以使用哪些成员。供其他代码使用的成员构成了对象的接口。
GDScript 没有 public 或 private 关键字:每个成员都可以从外部访问。Godot 风格指南规定,私有成员要在名称前加下划线:
# bank_account.gd
class_name BankAccount
extends RefCounted
var owner_name: String
var _balance: int = 0
var _history: Array[String] = []
func _init(holder: String) -> void:
owner_name = holder
func deposit(amount: int) -> void:
_balance += amount
_record("deposit %d" % amount)
func get_balance() -> int:
return _balance
func _record(entry: String) -> void:
_history.append(entry)owner_name、deposit() 和 get_balance() 是公开的,因此 main.gd 会使用它们。_balance、_history 和 _record() 是私有的:只有 bank_account.gd 内部的代码会使用它们。
# main.gd
var account := BankAccount.new("Ada")
account.deposit(50)
account.deposit(20)
print(account.owner_name) # Ada
print(account.get_balance()) # 70下划线是一种约定,不是锁:在 main.gd 中运行 account._balance = 1000000 不会出现任何错误。尽管如此,还是要遵守这个约定。当只有类会修改 _balance 时,错误的余额只能来自 bank_account.gd 中的方法,所以你只需要检查这一个文件。
GDScript 也没有 protected 级别。子类会继承所有成员,包括私有成员,因此 SavingsAccount 可以在自己的方法中使用 _balance,前提是它 extends BankAccount。
Godot 的虚方法(例如 _init() 和 _ready())也以下划线开头。Godot 会替你调用它们,所以不要给自己的私有方法起相同的名字。
挑战
简单完成 hero.gd 中的 Hero 类。它的公共成员包括 hero_name、gain_xp()、get_xp() 和 get_level()。其余成员都是私有的:
- 添加私有变量
_xp(初始值为0)和_level(初始值为1)。 - 添加私有方法
_update_level(),将_level设置为1 + _xp / 100(整除)。 gain_xp(amount)将amount加到_xp上,调用_update_level(),并在等级提升时返回true,否则返回false。get_xp()和get_level()返回对应的私有值。
提供的代码会读取英雄的名字,然后读取后续 XP 数值的个数,接着每行读取一个数值。每读取一个数值后,如果 gain_xp() 返回 true,就会打印一行 Level up!,然后打印英雄的状态。输入 Ada,以及数值 40、70 和 250 时,输出如下:
Ada: 40 XP, level 1
Level up! Ada is now level 2
Ada: 110 XP, level 2
Level up! Ada is now level 4
Ada: 360 XP, level 4你的代码应写在 hero.gd 中。main.gd 存放了提供的输入/输出代码,不能编辑。
亲手试试
extends Node
func _ready():
# 提供的输入/输出代码:保持原样
var hero := Hero.new(OS.read_string_from_stdin())
var count := int(OS.read_string_from_stdin())
for i in count:
var amount := int(OS.read_string_from_stdin())
if hero.gain_xp(amount):
print("Level up! %s is now level %d" % [hero.hero_name, hero.get_level()])
print("%s: %d XP, level %d" % [hero.hero_name, hero.get_xp(), hero.get_level()])
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器