🤖

RobloxでTycoonゲームの自動生産ライン資金回収についてEvent-DrivenとStrategyパターンで考えてみた

2023/09/01に公開

はじめに(記事の概要)

この記事では、RobloxでのTycoonゲーム開発において、ドロップアイテムの取得に関する設計とコードの流れについて解説します。特に、Event-Driven ProgrammingとStrategyパターンを活用した柔軟かつ拡張性のある設計に焦点を当てます。

コンテキスト

Robloxは多くのゲーム開発者が利用するプラットフォームであり、Tycoonゲームはその中でも人気のあるジャンルです。開発する上でドロップアイテムの取得やその後のバリデーションは、意外と頭を悩ませるポイントでした。そこで、この記事ではその課題を解決するための手法を検討してみます。

対象読者

  • Robloxでゲーム開発をしている方
  • 設計パターンやプログラミング手法に興味がある方
  • ゲーム内でのアイテム取得やバリデーションに関心がある方

今回対象のシーケンス

このシーケンス図は、ドロップアイテムが生成されてからプレイヤーの残高が更新されるまでのフローを表しています。各コンポーネントがどのように連携して動作するのかが一目瞭然です。
※CashCollector部は参考としてシーケンスのみ記載

ディレクトリ構成

Roblox Game
|-- ServerScriptService
|   |-- MainServerScript.lua
|   |-- Validation
|   |   |-- IsValidStrategy.lua
|   |   |-- BasicValidation.lua
|-- Workspace
|   |-- Tycoons
|   |   |-- Player1Tycoon
|   |   |   |-- Collectors
|   |   |   |   |-- DropItemCollector
|   |   |   |   |   |-- DropItemCollectorTrigger.lua
|-- ServerStorage
|   |-- Events
|   |   |-- ItemCollectedEvent

このディレクトリ構成によって、各スクリプトとその責任が明確に分かれています。

コードの流れ

1. DropItemCollectorTrigger.lua

  • ドロップアイテムがコレクターに触れた瞬間に動作する。
  • ItemCollectedEventを発火して、サーバーにドロップアイテムがコレクターに触れたことを通知。
  • このスクリプトは主にイベントのトリガーとして機能。

2. MainServerScript.lua

  • サーバー側で動作。
  • ItemCollectedEventをリッスンして、イベントが発火されたら動作開始。
  • IsValidStrategyを用いてドロップアイテムが有効かどうかを検証。
  • 有効な場合は、プレイヤーの残高やスコアを更新。
  • このスクリプトは主にバリデーションとデータ更新を担当。

3. IsValidStrategy.lua & BasicValidation.lua

  • IsValidStrategyは検証ロジックのインターフェース。
  • BasicValidationは具体的な検証ロジックを提供。
  • Strategyパターンを用いているため、新しい検証ロジックが必要な場合も簡単に追加や変更が可能。
  • この部分は主に柔軟なバリデーションを提供。

設計手法の活用

Event-Driven Programming

イベント駆動プログラミングとは?

イベント駆動プログラミングは、特定のイベント(ユーザー操作、外部信号など)が発生したときに特定の処理を行うプログラミング手法です。

どこでイベント駆動しているのか?

DropItemCollectorTrigger.lua

このスクリプトは、ドロップアイテムがコレクターに触れた瞬間に発火します。具体的には、ItemCollectedEvent:Fire(dropItem)ItemCollectedEventイベントを発火しています。

-- DropItemCollectorTrigger.lua
local ServerStorage = game:GetService("ServerStorage")
local ItemCollectedEvent = ServerStorage:WaitForChild("ItemCollectedEvent")

local function onDropItemCollected(dropItem)
    ItemCollectedEvent:Fire(dropItem)
end
MainServerScript.lua

このスクリプトは、ItemCollectedEventをリッスン(監視)しています。イベントが発火すると、IsValidStrategy:validate(dropItem)でドロップアイテムの有効性を検証します。

-- MainServerScript.lua
local ServerStorage = game:GetService("ServerStorage")
local ItemCollectedEvent = ServerStorage:WaitForChild("ItemCollectedEvent")
local IsValidStrategy = require(game:GetService("ServerScriptService").Validation.IsValidStrategy)

ItemCollectedEvent.Event:Connect(function(dropItem)
    if IsValidStrategy:validate(dropItem) then
        -- プレイヤーの残高を増やす処理
    end
end)

イベント駆動の有用性

  1. モジュール性: 各イベントとその処理が独立しているため、コードの再利用やテストが容易です。
  2. 拡張性: 新しいイベントや処理を追加する際も、既存のコードに影響を与えにくいです。
  3. 可読性: イベントが何を引き起こすのかが明確なため、コードの流れを理解しやすいです。

Strategyパターン

Strategyの切り替え

RobloxでのTycoonゲーム開発において、検証ロジックを柔軟に切り替えるためにStrategyパターンを活用しています。具体的には、IsValidStrategy.luaBasicValidation.luaを使っています。

1. BasicValidation.lua (Module Script)

基本的な検証ロジックをこのスクリプトで定義しています。

-- 基本的な検証ロジック
local function basicValidation(dropItem)
    -- ここで基本的な検証を行う
    -- ...
    return true  -- 一旦はtrueを返す
end

return basicValidation
2. IsValidStrategy.lua (Module Script)

Strategyパターンのインターフェースをこのスクリプトで定義しています。コンストラクタで具体的な検証ロジック(strategyImpl)を受け取り、executeメソッドでそれを実行します。

-- Strategy Pattern Interface
local IsValidStrategy = {}
IsValidStrategy.__index = IsValidStrategy

-- コンストラクタ
function IsValidStrategy.new(strategyImpl)
    local self = setmetatable({}, IsValidStrategy)
    self.strategyImpl = strategyImpl
    return self
end

-- 検証ロジックを実行
function IsValidStrategy:execute(dropItem)
    return self.strategyImpl(dropItem)
end

return IsValidStrategy
3. ServerScript

サーバーサイドのスクリプトで、IsValidStrategyBasicValidationを読み込み、Strategyをセットしています。

-- Strategyをセット
local isValid = IsValidStrategy.new(basicValidation)

local function onItemCollected(player, dropItem)
    if isValid:execute(dropItem) then
        -- 有効なDropItemの場合、何らかの処理を行う
        -- CashCollectorに通知など
    else
        warn("Invalid DropItem detected from player " .. player.Name)
    end
end

なぜこのような設計が有用なのか?

  1. 柔軟性: 検証ロジックをモジュールスクリプトとして分けることで、新しい検証ルールを追加する際も簡単に対応できます。
  2. 疎結合: IsValidStrategyを通じて検証ロジックを呼び出すため、その他の部分に影響を与えずに検証ロジックだけを変更できます。

まとめ

この記事では、Robloxゲーム開発におけるイベント駆動プログラミングとStrategyパターンの活用方法について詳しく解説しました。特に、ドロップアイテムのコレクションとそのバリデーションに焦点を当て、以下の3つの主要なスクリプトについて説明しました。

  1. DropItemCollectorTrigger.lua:ドロップアイテムがコレクターに触れた際のイベントトリガー。
  2. MainServerScript.lua:サーバー側でのイベントリスニングとデータ更新。
  3. IsValidStrategy.lua & BasicValidation.lua:柔軟なバリデーションロジックの実装。

イベント駆動プログラミングは、リアルタイムの反応性を高めるために非常に有用ですね。また、Strategyパターンを用いることで、バリデーションロジックを簡単に拡張や変更ができ、メンテナンスも容易になりそうです。

引き続き、勉強しつつ開発を進めていきたいと思います。
ありがとうございました!

Discussion