2.ゲームループのコーディング

マップを作成したら次はプログラムです。このコースの残りの部分では、ゲームループの様々な要素をスクリプト化することに重点を置いています。

スクリプトの設定

バトルロイヤルは、モジュールスクリプトと通常のスクリプトを組み合わせて使用します。以下、スクリプトとその機能です。

GameManager通常のスクリプトです。GameSettingsの変数を使用して、MatchManagerの関数を実行します。ゲームのメインループはここになります。
MatchManagerモジュール スクリプトです。プレーヤーをアリーナに送り込んだり、試合の時間を追跡したりするなどの機能を実行します。
GameSettingsモジュール スクリプトです。他のスクリプトで使用される共通変数を格納します。

GameSettingsスクリプト

GameSettings という名前のモジュール スクリプトを作成して、試合や休憩時間など、他のスクリプトで使用される変数を保存します。これらの変数は、後で GameManager スクリプトによって使用されます。

  1. ServerStorageで、ModuleScripts という名前のフォルダーを作成します。そのフォルダーで、GameSettings という名前の新しいモジュールスクリプトを作成します。
  1. GameSettings を開き、スクリプトの名前と一致するようにモジュールテーブルの名前を変更します。
local GameSettings = {}

return GameSettings
  1. モジュールテーブルで、次の使用のための変数を追加します。各値について最善の推測を行います。後でテストするときにいつでも変更できます。
  • intermissionDuration: プレイヤーが試合前に待機する秒数
  • matchDuration:試合時間
  • minimumPlayers:試合開始に必要な最小プレーヤー数
  • transitionTime:試合前後の時間 (ゲームループの部分間の移行をより唐突にしないようにする)
local GameSettings = {}

-- Game Variables
GameSettings.intermissionDuration = 5
GameSettings.matchDuration = 10
GameSettings.minimumPlayers = 2
GameSettings.transitionTime = 5

return GameSettings

MatchManger スクリプト

GameManager に接続されている2つ目のスクリプトは、MatchManagerです。このスクリプトは、タイマーの開始や試合終了後のプレイヤーのリセットなどのタスクを管理します。

MatchManager 内には、 prepareGame() という名前の関数があり、プレーヤーを試合に移行してゲームを開始します。

  1. ServerStorage の ModuleScripts というフォルダに、 MatchManager という名前のモジュールスクリプトを追加します。モジュールテーブルの名前を下記の通りに変更します。
local MatchManager = {}

return MatchManager
  1. prepareGame() という名前の新しいモジュール関数を MatchManager に追加します。後でスクリプトをテストするために print 文を入れておきます。
local MatchManager = {}

function MatchManager.prepareGame()
  print("Game starting!")
end

return MatchManager

ゲームループのコーディング

ゲームループは、GameManager スクリプトの中で、先ほど作成した変数を使ってコーディングされます。ゲームループには、休憩、競技、後片付けとリセットの3つの段階があることを忘れないでください。

GameManager スクリプト

このスクリプトは通常のサーバースクリプトなので、ModuleScripts フォルダではなく、ServerScriptService にそのまま配置します。実際のゲーム ループは while true do ループになります。

  1. ServerScriptService で、GameManager という名前の新しいスクリプトを作成します。
  1. Modulescripts があるサービス「ServerStorage」の変数を追加します。次に、サービス「Players」の変数を追加します。これは、休憩中にプレイヤー数を確認するために必要です。
-- Services
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
  1. 以前に作成したモジュールを使用する場合
  • moduleScripts という名前の変数を ModuleScripts フォルダの場所に設定します。
  • matchManager および gameSettings という名前の変数を追加します。それぞれの変数に、require を使ってモジュールを読み込みます。
-- Services
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")

-- Module Scripts
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
  1. 変数の後に、while true doループを追加します。ゲームループのすべてのフェーズは、この中に入って無限に繰り返されます。
- Module Scripts
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))

-- Main game loop
while true do

end

インターミッションのコーディング

ゲームのループは無限に続きますが、インターミッションはループを一時停止し、試合が開始できるプレイヤー数に達した場合にのみ続行する必要があります。この一時停止をコード化するには、while ループの中にインターミッションのためのネストされた繰り返しループを含めます。このネストされたループは、十分な数のプレーヤーが集まるまで繰り返し、メインループを一時停止します。十分な数のプレーヤーが集まると、ループは終了し、プレーヤーは試合に移行します。

repeat ループでは、ループ内のコードは少なくとも1回は実行されます。while ループとは異なり、ループが終了するまで条件をチェックしません。これにより、プレイヤーは試合前に必ずロビーに行くようになります。

  1. while true do ループの中で、repeat と入力して Enter を押すと、自動的に until というキーワードが出ます。
while true do
    repeat

    until
end
  1. 現在のプレイヤー数(Players.NumPlayers)が、GameSettings モジュールで先に作成した minimumPlayers 変数以上かどうかをチェックします。
while true do
   repeat

   until Players.NumPlayers >= gameSettings.minimumPlayers
end
  1. 繰り返しループの中で、インターミッションが始まるという print 文を追加します。GameSettings のintermissionDuration を使って、その秒数だけ wait() で一時停止します。
while true do
    repeat
        print("Starting intermission")
        wait(gameSettings.intermissionDuration)
    until Players.NumPlayers >= gameSettings.minimumPlayers
end
  1. プレイテストを行い、print 文「Starting intermission」が少なくとも2回表示されることを確認します。メッセージが2回表示されるのは、リピートループが十分なプレイヤーを見つけられず、再度実行されたことを証明しています。2回目のメッセージを見るには、インターミッションの長さを待つ必要があります。

トラブルシューティング

この時点で、意図したとおりにスポーンしない場合は、次のいずれかを試してください。

  • wait() は repeat ループの中に入れてください。wait がないと、スクリプトは1秒間に何度も実行され、Roblox Studio に負荷をかけ、エラーを発生させます。
  • Game Settings モジュールの変数 intermissionDuration は、1より大きくする必要があります。これより小さいと、スクリプトが頻繁に繰り返され、スローダウンの問題が発生することがあります。

インターミッションの終了

試合ができる人数が揃ったら、短い遷移時間だけ待機させます。その後に MatchManager の prepareGame() 関数を呼び出して、プレイヤー達を試合に送り込みます。この関数は一行を表示するだけですが、後でもっとコードを追加することを忘れないでください。

  1. repeat ループの最後に、「Intermission over」という print 文を追加して、コードをテストしてください。そして、GameSettingのtransitionTime変数を使ってwait() を実行します。
while true do
    repeat
        print("Starting intermission")
        wait(gameSettings.intermissionDuration)
    until Players.NumPlayers >= gameSettings.minimumPlayers
    print("Intermission over")
    wait(gameSettings.transitionTime )
end
コードは while ループの範囲内(do と end の間)に収めてください。ループの外にコードがあると、ゲームループの一部が繰り返されず、プレイヤーはインターミッションのフェーズで立ち往生するだけになるかもしれません。
  1. 待機後、MatchManager モジュールから prepareGame() を呼び出します。このコードが実行されると、出力ウィンドウにテキストが印刷されるだけです。このコードをテストするには、次のセクションまでお待ちください。
while true do
   repeat
      print("Starting intermission")
      wait(gameSettings.intermissionDuration)
   until Players.NumPlayers >= gameSettings.minimumPlayers

   print("Intermission over")
   wait(gameSettings.transitionTime)
   matchManager.prepareGame()
end
このプロジェクトの後にスクリプトを追加する場合、while true do ループ以下のコードは実行されないことに留意してください。関連するコードは while ループの中に入れるか、メインループからモジュール関数を呼び出してください。

マルチプレイヤー ゲームのテスト

現在、prepareGame() を実行させるためには、repeat ループを抜ける必要があります。しかし、そのためには、プレイヤーが2人以上必要です。つまり、Playボタンを使用しても、ゲーム内のプレイヤーは自分1人だけなので、repeat ループから抜けられず、関数は実行されません(最小プレイヤー数が1人でない限り)。これをテストするには、マルチプレイヤーゲームをシミュレートする必要があります。

ローカル サーバーの起動

複数のプレイヤーを必要とするコードをテストするには、ローカルサーバーを作成します。公開されているゲームは通常Robloxサーバー上にありますが、ローカルサーバーはあなたのコンピュータ上で模擬プレイヤーによるマルチプレイヤーゲームをシミュレートするものです。

  1. ローカルサーバを起動するには、「TEST/テスト」タブの「Clients and Servers/クライアントとサーバー」セクションの GameSetting の変数 minimumPlayers にあるプレイヤーの数を設定します。このレッスンでは、「2 Players/2人のプレイヤー」を使用します。
  1. 「Start/開始」をクリックしてサーバーを開始します。
  1. サーバーがセットアップされるまで数秒待ちます。元のStudioウィンドウに加え、複数のウィンドウが開きます。ファイアウォールやその他のオンラインセキュリティソフトウェアから Roblox Studio へのアクセスを許可する必要があるかもしれません。

トラブルシューティング

この時点で、テストサーバーを見ることができない場合は、以下のいずれかをお試しください。

  • サーバーの起動に問題がある場合は、「ファイアウォールとルーターの問題」の記事を再確認してください。
  • プレーヤーの数を 2 人または 3 人などの少人数に設定します。
  • 問題が解決しない場合は、Roblox Studio を再起動するか、コンピューターを再起動してみてください。

ローカル サーバーでのテスト

サーバーが起動すると、複数のウィンドウが表示されます。それぞれが、サーバーとクライアントの関係の異なる部分を表しています。

  • 緑色の枠:サーバーの状態を表します。
  • 青色の枠:各プレーヤー(クライアント)の様子をシミュレートしています。
緑枠:サーバー
青枠:クライアント

サーバーを立ち上げた状態で、コードがうまくいったかどうかを確認することができます。

  1. 緑色の枠で囲まれた「Server/サーバー」ウィンドウを探します。MatchManager スクリプトから呼び出されたprint 文を確認します。リピートループがあるため、同じprint文が繰り返されているのがわかります。
  1. 「Cleanup/クリーンアップ」ボタンをクリックするとウィンドウが閉じテストが終了できます。

トラブルシューティング

この時点で、意図した print 文が表示されない場合は、次のいずれかを試してください。

  • prepareGame() などの関数が while true do ループのスコープ内にあることを確認します。
  • MatchManager からの print がうまくいかなかった場合は、GameManager で MatchManager スクリプトがrequired で呼び出しているか、そのモジュールのテーブルに prepareGame() が追加されているかなど、モジュールスクリプトでよくあるトラブルシューティングを確認してみてください。

完成したスクリプト

以下に、完成したスクリプトを掲載しますのでチェックしてみてください。

GameManager スクリプト

-- Services
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")

-- Module Scripts
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))

-- Main game loop
while true do
    repeat
        print("Starting intermission")
        wait(gameSettings.intermissionDuration)
    until Players.NumPlayers >= gameSettings.minimumPlayers

    print("Intermission over")
    wait(gameSettings.transitionTime)

    matchManager.prepareGame()
end

MatchManager スクリプト

local MatchManager = {}

function MatchManager.prepareGame()
    print("Game starting!")
end

return MatchManager

GameSettings スクリプト

local GameSettings = {}

-- Game Variables
GameSettings.intermissionDuration = 5
GameSettings.roundDuration = 10
GameSettings.minimumPlayers = 2
GameSettings.transitionTime = 5

return GameSettings

コメントを残す