如何将一个场景实例定义为子类,其中超类的
.tscn
将在所有子类之间共享?
对于纸牌战斗项目,我试图通过类使我的代码库更具可扩展性。我有一个定义类
EnemyBase
的脚本,其中有针对 EnemyTypeA
、EnemyTypeB
等的单独脚本。我想象一种情况,我只需要一个 .tscn
文件,并且我可以以某种方式将正确的类分配给获取其逻辑的场景。我希望这样,理论上我可以创建尽可能多的敌人类型,并且维护代码库也同样容易,因为公共函数只需要编写一次(在超类中)。
目前,我发现唯一有效的方法是(A)为每个子类创建一个单独的
.tscn
文件,以及(B)使用“伪”类,而不是根本有子类,通过在类中使用枚举变量def 保存各种“子类”的名称,并在所有函数中使用 match
语句来为不同的“类”定义不同的功能。我相信这些都不是解决方案,因为 (A) 本质上有许多完全独立定义的场景,而 (B) 使一个脚本非常长且难以阅读(但似乎是两者中更好的一个)。
这似乎是一个非常明显/常见的需求,所以我想有一种巧妙的方法可以做到这一点。如果除了类/子类之外还有另一种组织场景的方法,我也很想听听。谢谢。
对于未来想知道的人,我已经找到了这个问题的可接受的解决方案(在 Godot 4.+ 中工作)。
该解决方案取决于这样一个事实:场景的脚本是一个可以通过编程方式更改的参数。因此,可以使用所有子类将包含的任何节点创建“共享”场景。例如,在敌人变化的情况下,我可以让场景
baseEnemy.tscn
包含诸如包含其名称的 Label
节点、ProgressBar
健康指示器等内容。
这个场景会附加一个定义敌人实例的脚本。比如:
base
现在,我们已经准备好创建子类了。然后我们将定义许多子类,其风格如下:
# baseEnemy.gd
class_name baseEnemy
extends WhateverNodeTypeYouWantToExtend
@export var enemy_name : String = "Placeholder Enemy!"
@export var hp : int = 01
@export var hpMax : int = 01
func _ready():
$label.text = "%s" % enemy_name
$healthBar.min_value = 0
$healthBar.max_value = hpMax
$healthBar.value = hp
func generic_behavior():
# Placeholder generic behavior. Something that is shared!
# For example, a function like lower_health() might apply to every enemy type
pass
func specific_behavior():
# Placeholder specific behavior. Something that will be overridden!
# For example, a function like decide_next_action() might be different for every class
pass
但是我们仍然存在实际实例化子类的问题。
假设我们有一些场景,希望其中存在
# enemyA.gd
class_name enemyA
extends baseEnemy
enemy_name = "Enemy A!"
hpMax = 100
func _ready():
# This time, whatever paramters we want will be changed for enemies of this class.
# for example, changing the name, hp, etc.
# This next line means to call _ready as defined by its superclass, which is baseEnemy
super._ready()
func specific_behavior():
# Now we would define this function, and this code will only be run for enemies of this type!
pass
。我们会这样做:
enemyA
现在,该对象生成的名称为“Enemy A”,正确的生命值,并使用指定版本的 Specific_behavior()。