Godotで放置ゲームを作る⑤:Resourceで電力→酸素→部品を連鎖させる

初心者向け実践開発

※本記事にはアフィリエイト広告(Udemy)を含みます。

前回のおさらい

前回④では、Timerを使って発電パネルが電力を自動生産する仕組みを作りました。今回は、電力だけでなく酸素・部品という新しい資源を追加し、「電力を使って酸素を作り、酸素を使って部品を作る」という連鎖構造を実装します。

今回のゴール

追加する設備は2つです。

  • 酸素生成装置:電力を消費して酸素を生産する
  • 部品工場:酸素を消費して部品を生産する

この連鎖により、「電力だけを増やせばいい」という単調な状態から、複数の資源のバランスを見ながら設備を増やしていく遊び方に変わります。

先に設計方針を1つ明示しておきます。電力や酸素が足りないときは、その回の生産を単純にスキップします。マイナスの資源になることは想定していません。

酸素生成装置を追加する

電力を消費して酸素を生産する理由

STATION OPSでは、資源の並び順そのものに意味を持たせています。電力がすべての基盤であり、電力を使うことで初めて酸素という次の資源を得られる、という構造にすることで、「まず電力から」という遊びの順序が自然に伝わるようにしています。

GameManagerに変数と購入関数を追加する

var oxygen_generator_count: int = 0
var oxygen_generator_cost: float = 25.0

const OXYGEN_GENERATOR_COST_RATE: float = 1.15
const OXYGEN_GENERATOR_POWER_COST: float = 2.0
const OXYGEN_GENERATOR_PRODUCTION: float = 1.0


func can_buy_oxygen_generator() -> bool:
    return power_panel_count >= 1


func buy_oxygen_generator() -> bool:
    if not can_buy_oxygen_generator():
        return false
    if power < oxygen_generator_cost:
        return false
    power -= oxygen_generator_cost
    oxygen_generator_count += 1
    oxygen_generator_cost *= OXYGEN_GENERATOR_COST_RATE
    resources_changed.emit()
    return true

発電パネルを1基以上持っていないと購入できないようにする

can_buy_oxygen_generator()で、発電パネルを1基も持っていない場合はfalseを返すようにしています。これは、いきなり酸素生成装置だけを購入できてしまうと、電力→酸素という連鎖の順序を学ばずに進めてしまうためです。設備には段階を踏ませることで、資源の関係性を自然に理解できるようにしています。

部品工場を追加する

考え方は酸素生成装置と同じです。酸素を消費して部品を生産します。

var parts_factory_count: int = 0
var parts_factory_cost: float = 15.0

const PARTS_FACTORY_COST_RATE: float = 1.3
const PARTS_FACTORY_OXYGEN_COST: float = 3.0
const PARTS_FACTORY_PRODUCTION: float = 1.0


func can_buy_parts_factory() -> bool:
    return oxygen_generator_count >= 1


func buy_parts_factory() -> bool:
    if not can_buy_parts_factory():
        return false
    if oxygen < parts_factory_cost:
        return false
    oxygen -= parts_factory_cost
    parts_factory_count += 1
    parts_factory_cost *= PARTS_FACTORY_COST_RATE
    resources_changed.emit()
    return true

Tick処理の順序を考える

なぜ処理の順番が重要なのか

毎秒の生産処理では、「発電パネルが電力を作る」「酸素生成装置がその電力を使って酸素を作る」「部品工場がその酸素を使って部品を作る」という3つの処理が同時に走ります。もし部品工場の処理を最初に実行してしまうと、その回に酸素生成装置が作るはずだった酸素をまだ受け取れておらず、本来使えるはずの酸素を使えないまま終わってしまいます。そのため、上流(電力)から下流(部品)に向かって順番に処理する必要があります。

_on_production_tick()を書き直す

func _on_production_tick() -> void:
    # 1. 発電パネル: 電力を生産
    if power_panel_count > 0:
        power += power_panel_count * POWER_PANEL_PRODUCTION

    # 2. 酸素生成装置: 電力を消費して酸素を生産(電力不足ならスキップ)
    if oxygen_generator_count > 0:
        var required_power: float = oxygen_generator_count * OXYGEN_GENERATOR_POWER_COST
        if power >= required_power:
            power -= required_power
            oxygen += oxygen_generator_count * OXYGEN_GENERATOR_PRODUCTION

    # 3. 部品工場: 酸素を消費して部品を生産(酸素不足ならスキップ)
    if parts_factory_count > 0:
        var required_oxygen: float = parts_factory_count * PARTS_FACTORY_OXYGEN_COST
        if oxygen >= required_oxygen:
            oxygen -= required_oxygen
            parts += parts_factory_count * PARTS_FACTORY_PRODUCTION

    resources_changed.emit()

required_powerrequired_oxygenで必要量を先に計算し、if power >= required_powerのように足りているか確認してから消費する、という書き方をすることで、資源がマイナスになることを防いでいます。

UIに酸素・部品の表示と購入行を追加する

段階に応じて表示・非表示を切り替える

②で酸素・部品のLabelを非表示にしておいたことを思い出してください。ここで、条件を満たしたときに表示する処理を書きます。

func _update_display() -> void:
    power_label.text = "電力: %d" % int(GameManager.power)

    if GameManager.oxygen_generator_count > 0 or GameManager.can_buy_oxygen_generator():
        oxygen_label.visible = true
        oxygen_label.text = "酸素: %d" % int(GameManager.oxygen)

    if GameManager.parts_factory_count > 0 or GameManager.can_buy_parts_factory():
        parts_label.visible = true
        parts_label.text = "部品: %d" % int(GameManager.parts)

    oxygen_generator_row.visible = GameManager.can_buy_oxygen_generator()
    if oxygen_generator_row.visible:
        oxygen_generator_info.text = "酸素生成装置 (%d基) - 次: %d" % [
            GameManager.oxygen_generator_count,
            int(GameManager.oxygen_generator_cost)
        ]
        oxygen_generator_buy_button.disabled = GameManager.power < GameManager.oxygen_generator_cost

    parts_factory_row.visible = GameManager.can_buy_parts_factory()
    if parts_factory_row.visible:
        parts_factory_info.text = "部品工場 (%d基) - 次: %d" % [
            GameManager.parts_factory_count,
            int(GameManager.parts_factory_cost)
        ]
        parts_factory_buy_button.disabled = GameManager.oxygen < GameManager.parts_factory_cost

酸素生成装置・部品工場それぞれの購入行についても、④で作った発電パネルの行と同じ要領でUpgradeListの中に追加してください。ボタンの接続方法も④と同様です。

動作確認

発電パネル→酸素生成装置→部品工場の順に購入してみてください。酸素生成装置を購入すると酸素の表示が現れ、部品工場を購入すると部品の表示も現れます。しばらく待つと、電力・酸素・部品が連鎖しながら増えていくことを確認できます。

次回予告

次回⑥では、中央制御システムという設備を追加し、すべての生産量を底上げする「乗算バフ」を実装します。

Godot学習におすすめのオンライン講座

複数の資源やシステムが絡み合う設計は、実際に手を動かして経験値を積むのが一番の近道です。体系立てて学びたい方はこちらもどうぞ。

Godotのコースを見る

参考リンク


コメント

タイトルとURLをコピーしました