6-1 モジュール スクリプトの概要

モジュール式プログラミング

例えば、宝箱からアイテムをゲット、クエスト完了でゲット、ショップでのアイテム購入。それぞれ場面は異なりますが、どれも「アイテムを取得する」という処理は同じですので、共通の関数が利用できるという発見につながるでしょう。考えてみると、各スクリプトは別々の場所に存在することになるでしょう。関数は共通に使用できるのに、それぞれのスクリプトにコピーしなくてはならないとなると面倒です。それだけではありません。もし、その関数にバグが見つかり、修正しなくてはならないとしたら全部に対して行う必要があり、それもまた時間がかかりかなり面倒になります。
このように共通で使える関数群のことをモジュールスクリプトといいます。モジュールスクリプトにすることで、メンテナンス性が向上しますので、それなりに大きなゲームを作ろうとした場合は必須になります。汎用的に使用できる関数をモジュールスクリプトで作成するとプログラムの保守と整理が容易になります。

モジュールスクリプト内で作成した関数や変数は、他のスクリプトから使用できます。こうすることで、プレイヤーが「アイテムを取得する」ときの処理にモジュールスクリプト内の関数を呼ぶだけで実現できます。

モジュールスクリプトの基本

ServerStorage に ModuleScript を作成します。

ModuleScript は、通常、サーバー側のスクリプトで使用する場合は ServerScriptService や ServerStorage に置き、クライアント側のローカルスクリプトで使用する場合は ReplicatedStorage に配置します。

サーバーとクライアント

自身のPCをクライアントと言い、インターネット上の向こう側にあるPCをサーバーと言います。Roblox はオンラインゲームになりますので、その両方でプログラムが動作している訳です。サーバープログラムで実行したものは、そのゲームに参加している全員に影響を与え、クライアントで実行したものは自分だけが影響を受けるということになります。

モジュールスクリプトの構造

モジュールスクリプトを作成すると、自動的に下記のコードが入ります。

local module = {}

return module

モジュールスクリプトは「local module = {}」で始まります。これはテーブル(配列や辞書)を作成するときの方法ですが、この中に関数や変数をすべて入れてしまうという考えになります。そして、最後に「return module」でモジュールスクリプトは完結します。モジュールスクリプトのテーブルを返すという意味になります。その理由はモジュールスクリプトを使用する際に分かると思います。

local RewardManager = {}

return RewardManager

モジュールスクリプトに名前を付けます。どのようなモジュールなのかが分かるような名称にしましょう。モジュールスクリプトは「〇〇〇〇Manager」という名称にするのが一般的です。

モジュール スクリプトへの追加

別のスクリプトから参照できる変数を作成する場合は、「TestModule.myVariable = 値」のようにします。別のスクリプトから呼ぶことができる関数を作成する場合は、「function TestModule.doTask()」のようにします。
モジュールスクリプトの関数をモジュール関数、変数をモジュール変数と呼びます。

-- モジュールスクリプトに変数を追加
TestModule.myVariable = 100

-- モジュールスクリプトに関数を追加
function TestModule.doTask(player)
    -- 何らかのプログラム
end

return TestModule

モジュールスクリプトの参照範囲

モジュール関数やモジュール変数は「local」と付けてはいけません。ローカルとはそのファイル内でしか参照できないものを意味します。

モジュール スクリプト内でしか使用しない変数等は今まで通り local と付けます。例えば以下のプログラムには、モジュール スクリプト内で使用する変数 rewardCoins と、モジュール外のスクリプトで使用できる関数getCoinReward() が含まれています。

local rewardManager = {}

-- モジュールスクリプト内でのみ使用可能
local rewardCoins = 50

-- モジュールスクリプト内でのみ使用可能
local difficultyModifier = {
    easy = 0.5,
    normal = 1,
    hard = 2
}

-- 他のスクリプトで使用可能
function rewardManager.getCoinReward(difficulty)
    local coins = difficultyModifier[difficulty] * rewardCoins
    return coins
end

return rewardManager

他のスクリプトからモジュールを使用する方法

モジュール関数は呼ばれるまで実行しません。他のスクリプトからモジュール関数を呼ぶ場合は require() を使用して、事前にロードする必要があります。require() の引数は、モジュールスクリプトがある場所を指定します。

まず、作成した変数に、require() の戻り値を代入します。require はモジュールをロードするという処理になりますので、スクリプトの上部の方で一度だけ実行します。

local myModule = require(ServerStorage.ModuleScript)

変数 myModule には、モジュールスクリプトで作成されたモジュールテーブルが含まれます。そのテーブルの関数と変数を使用するには、変数名の後にドットを入力し、モジュール関数の正確な名前を入力します 。
例: myModule.myFunction()
この例では、ServerStoreにModuleScriptという名前のモジュールスクリプト内にある myFunction() という関数が実行されるということになります。

local myModule = require(ServerStorage.ModuleScript)

myModule.myFunction()

プログラム例

ModuleScript – RewardManager

  1. ServerStore に下記のモジュールスクリプトを追加します。
local rewardManager = {}

-- モジュールスクリプト内でのみ使用可能
local rewardCoins = 50

-- モジュールスクリプト内でのみ使用可能
local difficultyModifier = {
    easy = 0.5,
    normal = 1,
    hard = 2
}

-- 他のスクリプトで使用可能
function rewardManager.getCoinReward(difficulty)
    local coins = difficultyModifier[difficulty] * rewardCoins
    return coins
end

return rewardManager
Script – TreasureChestScript
  1. ServerScriptService に下記のスクリプトを追加します。
local ServerStorage = game:GetService("ServerStorage")

-- モジュールスクリプトのロード
local RewardManager = require(ServerStorage.RewardManager)

-- モジュール関数を呼び出す
local coins = RewardManager.getCoinReward("easy")
print("Should award " .. coins .. " coins")
他のスクリプトを入力するときにスペルをチェックする

別のスクリプトを使用している場合は、モジュールのスクリプト関数または変数のスペルが、そのモジュールで見つかったものとまったく同じであることを確認してください。モジュールから正確な関数または変数名をコピーして、それを使用する通常のスクリプトに貼り付けることができます。

トラブルシューティング

モジュールスクリプトを使用する際の一般的な問題を記載しておきます。

「Infinite yield possible」または「not a valid member」などのエラー メッセージが表示される
  • require() のパラメータで指定しているパスや名称を確認してください。モジュールスクリプトの正確なパスとスペルが必要です。モジュールテーブル名とモジュールスクリプト名は必ずしも同じとは限りません。
「attempt to index global」というエラー メッセージが表示される
  • モジュールスクリプトを使用するプログラムでは、関数 require() を使用して事前にロードしなくてはなりません。そうしないと、そのスクリプトはモジュール関数や変数を使用できません。

まとめ

Roblox のモジュール スクリプトは、プログラマーがコードを整理して再利用するために使用する方法です。モジュール スクリプトは、多くの場合、ServerStorage または、ReplicatedStorage に保存します。ServerStorage に入れた場合は、サーバープログラムからしか呼び出せませんが、ReplicatedStorage に入れた場合はクライアントプログラムからも呼び出すことができます。各スクリプトは、そのモジュールスクリプトに保存されている関数や変数を呼び出すことができます。

たとえば、あるゲームでは、オブジェクトを収集するプレーヤーにポイントを与えることがあります。モジュール スクリプトは、ポイントを与えるコードを処理できます。その後、さまざまなタイプのオブジェクトのスクリプトは、モジュール スクリプト関数を呼び出すだけで済みます。これにより、スクリプト間でコードを再利用する必要が減り、コードの理解と保守が容易になります。

4 thoughts on “6-1 モジュール スクリプトの概要”
  1. スイッチを押したらパーツが降ってくるプログラムを作ったのですが、実行されません。私の作ったプログラムを貼り付けましたので教えていただければ嬉しいです。
    (スイッチが押されると、 「Workspace.switch.c.dps:27: attempt to call a nil value」というエラーメッセージが出ます )
    local ps = false

    local function Dpart()
    local g = script.Parent

    if ps == false then
    for v = 0,1,0.1 do
    g.Transparency = v
    wait(0.00000001)
    end
    g.CanCollide = false
    end
    ps = true
    end

    local function TuPlayer(hit)
    wait(0.1)
    local ch = hit.Parent
    local hu = ch:FindFirstChildWhichIsA(“Humanoid”)
    if hu then
    local serverscriptservice = game:GetService(“ServerScriptService”)
    local doroppers = require(serverscriptservice.dlps)
    doroppers.Droppers()
    end
    end
    script.Parent.Touched:Connect(TuPlayer)
    script.Parent.Touched:Connect(Dpart)

    1. 何か所がおかしいところがありましたので添削させていただきました。テストしていないので
      モジュールスクリプトのロードは1回でよいのでスクリプトの上部に入れるのが基本です。

      — モジュールスクリプトのロードはここに!
      local serverscriptservice = game:GetService(“ServerScriptService”)
      local doroppers = require(serverscriptservice.dlps)

      local sw = script.Parent
      local ps = false

      local function Dpart(onoff)
      if onoff == true then
      for v = 0,1,0.1 do
      sw.Transparency = v
      wait() — 値が小さすぎると意味がないのでwait()でOK
      end
      sw.CanCollide = false
      else
      sw.Transparency = 0
      sw.CanCollide = true
      end
      end

      local function TuPlayer(hit)
      if ps == false then
      local ch = hit.Parent
      local hu = ch:FindFirstChildWhichIsA(“Humanoid”)
      if hu then
      ps = true
      Dpart(true)
      doroppers.Droppers()
      wait(1)
      Dpart(false)
      ps = false
      end
      end
      end

      sw.Touched:Connect(TuPlayer)

コメントを残す