GDScriptのクラス定義と継承のルール

Gobot

GDScriptのクラス定義と継承

GDScriptは、Godot Engineで使用されるオブジェクト指向プログラミング言語です。クラス定義と継承は、コードの再利用性を高め、複雑なシステムを構造化するための基本的な要素です。

クラス定義

GDScriptにおけるクラス定義は、class キーワードを使用して行われます。クラスは、データ(変数)と振る舞い(関数)をまとめたものです。

基本構文

class クラス名:
    # 変数定義
    var 変数名: 型 = 初期値

    # 関数定義
    func 関数名(引数名: 型) -> 戻り値の型:
        # 関数の処理
        pass
  • class クラス名:: クラスの定義を開始します。クラス名は通常、大文字で始まります。
  • var 変数名: 型 = 初期値: クラスのメンバ変数(プロパティ)を定義します。型アノテーション(例: : int, : String, : Vector2)は任意ですが、コードの可読性と堅牢性を高めるために推奨されます。初期値も任意で設定できます。
  • func 関数名(引数名: 型) -> 戻り値の型:: クラスのメンバ関数(メソッド)を定義します。引数名と型、そして戻り値の型を定義できます。戻り値の型がない場合は -> void または省略します。
  • pass: 何も処理を行わないことを示すプレースホルダーです。

コンストラクタ

クラスがインスタンス化される際に最初に実行される特殊な関数として、_init 関数があります。これはコンストラクタとして機能します。

class MyClass:
    var message: String

    func _init(msg: String):
        message = msg
        print("MyClass instance created with message: " + message)

この例では、MyClass のインスタンスを作成する際に、引数 msg を受け取り、それを message プロパティに格納し、コンソールにメッセージを表示します。

継承

GDScriptでは、: を使用してクラスを継承できます。これにより、親クラスのプロパティとメソッドを子クラスで再利用し、さらに子クラス独自の機能を追加したり、親クラスのメソッドをオーバーライドしたりすることが可能です。

基本構文

class 親クラス名:
    # 親クラスの定義

class 子クラス名(親クラス名):
    # 子クラス独自の変数や関数
    # 親クラスのメソッドをオーバーライドすることも可能

親クラスのメソッドの呼び出し

子クラスで親クラスのメソッドをオーバーライドした場合でも、super キーワードを使用して親クラスの元のメソッドを呼び出すことができます。

class Animal:
    var name: String

    func _init(n: String):
        name = n

    func speak():
        print("Generic animal sound.")

class Dog(Animal):
    func _init(n: String):
        # 親クラスのコンストラクタを呼び出す
        super._init(n)

    func speak():
        # 親クラスのspeak()を呼び出した後、独自の処理を追加
        super.speak()
        print("Woof!")

var my_dog = Dog("Buddy")
my_dog.speak()

この例では、Dog クラスは Animal クラスを継承しています。Dog_init メソッドでは super._init(n) を呼び出して Animal の初期化処理を実行しています。また、speak メソッドでは super.speak() を呼び出した後に、Dog 固有の「Woof!」という音を出力しています。

多重継承

GDScriptは単一継承のみをサポートしており、多重継承はできません。しかし、インターフェース(class_name を使用して定義されるもので、Godot 4以降ではより明示的なインターフェースの概念が導入されています)やコンポジション(他のオブジェクトのインスタンスをメンバ変数として持つこと)を活用することで、同様の機能を実現できます。

牛肉・豚肉・鶏肉・ジビエ情報

GDScriptのクラス定義と継承は、ゲーム内の様々な要素を表現するのに非常に役立ちます。例えば、以下のようなカテゴリ分けが考えられます。

牛肉

class Beef:
    var cut: String #部位(例: リブロース, ヒレ, モモ)
    var marbling: int #サシの入り具合(1-5など)
    var origin: String #産地(例: 和牛, 国産牛)

    func _init(c: String, m: int, o: String):
        cut = c
        marbling = m
        origin = o

    func get_description() -> String:
        return "【牛肉】部位: %s, サシ: %d, 産地: %s" % [cut, marbling, origin]

豚肉

class Pork:
    var cut: String #部位(例: 豚バラ, 豚ロース, 豚肩ロース)
    var fat_percentage: float #脂身の割合
    var breed: String #品種(例: 三元豚, 黒豚)

    func _init(c: String, fp: float, b: String):
        cut = c
        fat_percentage = fp
        breed = b

    func get_description() -> String:
        return "【豚肉】部位: %s, 脂身率: %.1f%%, 品種: %s" % [cut, fat_percentage, breed]

鶏肉

class Chicken:
    var part: String #部位(例: むね肉, もも肉, ささみ)
    var raised_method: String #飼育方法(例: 鶏舎飼育, 放し飼い)
    var age: int #月齢

    func _init(p: String, rm: String, a: int):
        part = p
        raised_method = rm
        age = a

    func get_description() -> String:
        return "【鶏肉】部位: %s, 飼育方法: %s, 月齢: %d" % [part, raised_method, age]

ジビエ

ジビエは、野生鳥獣肉のことであり、その種類は多岐にわたります。これらの情報をクラスとして表現する際には、より汎用的な構造が必要になるでしょう。

class GameMeat:
    var species: String #種(例: シカ, イノシシ, ウサギ, キジ)
    var hunting_season: String #狩猟時期
    var preparation_notes: String #下処理の注意点

    func _init(s: String, hs: String, pn: String):
        species = s
        hunting_season = hs
        preparation_notes = pn

    func get_description() -> String:
        return "【ジビエ】種: %s, 狩猟時期: %s, 注意点: %s" % [species, hunting_season, preparation_notes]

継承の応用例

これらの肉の情報を、さらに共通の基底クラス Meat を作成して継承させることで、コードの統一性を高めることができます。

class Meat:
    var cut: String #部位

    func _init(c: String):
        cut = c

    func get_base_info() -> String:
        return "部位: %s" % cut

class Beef(Meat): # Meatクラスを継承
    var marbling: int
    var origin: String

    func _init(c: String, m: int, o: String):
        super._init(c) # Meatのコンストラクタを呼び出す
        marbling = m
        origin = o

    func get_description() -> String:
        return "【牛肉】" + super.get_base_info() + ", サシ: %d, 産地: %s" % [marbling, origin]

class Pork(Meat): # Meatクラスを継承
    var fat_percentage: float
    var breed: String

    func _init(c: String, fp: float, b: String):
        super._init(c)
        fat_percentage = fp
        breed = b

    func get_description() -> String:
        return "【豚肉】" + super.get_base_info() + ", 脂身率: %.1f%%, 品種: %s" % [fat_percentage, breed]

# ... Chicken and GameMeatも同様にMeatを継承させることも可能

このように、共通のインターフェース(get_base_info など)を親クラスで定義し、子クラスでそれを拡張することで、データ構造を整理し、コードの保守性を向上させることができます。

まとめ

GDScriptにおけるクラス定義と継承は、ゲーム開発においてオブジェクト指向の設計原則を適用するための強力なツールです。class キーワードによる定義、_init によるコンストラクタ、そして :super による継承の仕組みを理解することで、再利用可能で構造化されたコードを作成し、複雑なゲームシステムを効率的に構築することが可能になります。牛肉、豚肉、鶏肉、ジビエといった具体的な情報も、これらのクラス定義と継承の原則を応用して、ゲーム内のデータやロジックとして表現することができます。