スコアボード
はじめに
前回、溶岩エリアや消えていく床をつくったので、今回はこれらを拡張して、プレイヤーごとに何秒生き残れるか確認できるスコアボードをつくっていくよ。
準備
前回つくった消えていく床を複製して、まずはプレイヤーができるだけ長く生き残れるように配置してみよう。
リーダーボード
Robloxには、プレイヤーの情報を表示するリーダーボードが組み込まれているよ。
このリーダーボードにプレイヤーの名前と生き残っている秒数をポイントとして表示していこう。
ゲーム開始時に自動で実行されるように、[ServerScriptService]に「SetupPoints」という名前でスクリプトを追加するよ。
サービス
今回プレイヤーがゲームに参加したときに、ポイントの加算をはじめたいから、ゲームに参加したときに実行されるイベントをつかっていくよ。
Robloxでは、サービスというたくさんの便利な機能が使えるようになっているんだけど、プレイヤーがゲームに参加したときに発生するイベントは[Players]サービスの[PlayerAdded]っていうイベントだ。
サービスを使うには、[game]っていうスクリプトの[GetService]っていう関数をサービス名(今回はPlayers)を指定して呼び出すルールだよ。
- [Players]サービスを「Players」っていう変数で使えるようにする。
- プレイヤーがゲームに参加したときに実行する関数の宣言だけしておこう。
- [Players]サービスの[PlayerAdded] イベントに接続。
local Players = game:GetService("Players")
local function onPlayerAdded(player)
end
Players.PlayerAdded:Connect(onPlayerAdded)
フォルダの作成
リーダーボードにプレイヤーのポイントを表示するために、[leaderstats]という名前のフォルダをつくる必要があるんだ。フォルダオブジェクトをつくるときは、Instance.new関数をつかうルールだよ。
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
end
このフォルダに [leaderstats]という 名前をつけて、関数のパラメータのプレイヤーにくっつけるよ。
local Players = game:GetService("Players")
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
end
Players.PlayerAdded:Connect(onPlayerAdded)
※ [Players]サービスは、 [leaderstats]という文字列をリーダーボードと思ってくれるので、入力ミスに注意しよう。
ポイント表示
リーダーボードの仕組みは、 [leaderstats]という名前のフォルダにあるものをすべて探し出して表示してくれるんだ。
プレイヤーのポイント表示用にIntValue(整数)オブジェクトをつくって [leaderstats] フォルダに入れるよ。
- Instance.new関数でIntValueオブジェクトをつくって、[points]という変数に格納。
- IntValueオブジェクトに[Points]という名前をつける。
- 初期値として0を設定。
- [leaderstats]フォルダを親に設定。
local Players = game:GetService("Players")
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local points = Instance.new("IntValue")
points.Name = "Points"
points.Value = 0
points.Parent = leaderstats
end
Players.PlayerAdded:Connect(onPlayerAdded)
テストしてみると、右上にプレイヤーの名前。その横にポイントが表示されていることが確認できるよ。
ポイントのカウント
各プレイヤーは生き残っている秒ごとにポイントが加算されるようにしたいから、wait関数とwhileループを使っていくよ。
- ループの条件をtrueにして無制限にループ。
- ループ内で1秒待つ。
Players.PlayerAdded:Connect(onPlayerAdded)
while true do
wait(1)
end
プレイヤーリスト
[Players]サービス のGetPlayers関数で、プレイヤーのリスト(配列)がもらえるから、リストのプレイヤー数だけポイント加算のコードを繰り返すよ。
- GetPlayers関数を呼び出して、もらったプレイヤー配列を[playerList]変数に入れる。
- forループで1からプレイヤー配列の中のプレイヤー数だけ繰り返し。※配列内の数は#変数名
while true do
wait(1)
local playerList = Players:GetPlayers()
for currentPlayer = 1, #playerList do
-- (後述:ポイント加算のコード)
end
end
ポイントの加算
各プレイヤーにポイントを加算するには、配列からプレイヤーを取り出して、そのプレイヤーのフォルダーの中のポイントオブジェクトに1を加算するんだ。
- 配列の〇番目のプレイヤーを[player]変数に保存。※配列の〇番目の要素を指定するには、変数名[〇]
- プレイヤーの[leaderstats]フォルダのポイントオブジェクトを[points]変数に保存。
- ポイントオブジェクトの値に今入っている値に+1した数を保存。
while true do
wait(1)
local playerList = Players:GetPlayers()
for currentPlayer = 1, #playerList do
local player = playerList[currentPlayer]
local points = player.leaderstats.Points
points.Value = points.Value + 1
end
end
テストしてみると1秒ごとにポイントが加算されていくよ。
ポイントのリセット
このゲームは他のプレイヤーより長く生き残こり、より多くのポイントを獲得することが目的だから、キャラクターが死亡したらポイントをリセットしないとね。
キャラクターが死亡したことを知るためには、キャラクターモデルを手に入れる必要があるんだ。
キャラクターモデルは、ゲームをスタートして、プレイヤーのキャラクターがロードされたとき、1度だけゲームに追加されるんだけど、CharacterAddedイベントでそれを手に入れることができるよ。
- キャラクターとプレイヤーの2つのパラメータを渡せる関数をonCharacterAddedっていう名前で作成。
local Players = game:GetService("Players")
local function onCharacterAdded(character, player)
-- (後述:中身のコード)
end
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
onCharacterAdded関数のパラメーターにプレーヤーも渡せるようにしたんだけど、RobloxのCharacterAddedイベントはキャラクターしか扱えないんだ。プレイヤーも扱えるようにするには無名関数っていうのを使うんだけど、ちょっとむずかしいからプレイヤーのキャラクターモデルを手に入れるには、こんなふうに書けばいいんだなってマネすればいいよ。
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local points = Instance.new("IntValue")
points.Name = "Points"
points.Value = 0
points.Parent = leaderstats
player.CharacterAdded:Connect(function(character)
onCharacterAdded(character, player)
end)
end
つづいてonCharacterAdded関数の中身の処理だけど、プレイヤーのキャラクターが死亡したとき、自動的にHumanoidオブジェクトのDiedイベントが発生するから、このタイミングでポイントをリセットするよ。
Humanoidオブジェクトはキャラクターモデルの中にあるんだけど、プレイヤーのキャラクターが死亡しているときに手に入れることができないから、ここではエラーにならないようにキャラクターが完全にロードされてスポーンするまで待ってくれるWaitForChild関数をつかうんだ。
local Players = game:GetService("Players")
local function onCharacterAdded(character, player)
local humanoid = character:WaitForChild("Humanoid")
end
つづいて、無名関数でDiedイベントに接続するよ。
さっきも無名関数がでてきたけど、無名関数は1回しか使わないような処理内容の場合、わざわざ関数として名前をつけてつくらないで、関数の作成と呼び出しをその場でやってしまう書き方なんだ。
- 無名関数でDiedイベントに接続。
- 無名関数内でパラメータのプレイヤーからフォルダの中のポイントを入手。(死亡したときのポイントが入っているはず)
- ポイントを0で上書き保存。(リセット)
local Players = game:GetService("Players")
local function onCharacterAdded(character, player)
local humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Connect(function()
local points = player.leaderstats.Points
points.Value = 0
end)
end
テストしてみると、プレイヤーのキャラクターが死亡したときにポイントがリセットされるよ。
でも、すぐにまたポイントが増えていくね。
プレイヤーの状態確認
プレイヤーのキャラクターが死んでいるあいだもポイントが増えつづける問題を修正しよう。
プレイヤーが生きているかどうかを確認するには、プレイヤーオブジェクトに属性を追加する必要があるんだ。
属性は名前と値のセットでつくって、Robloxのオブジェクトにくっつけることで独自のカスタマイズができるよ。
- onCharacterAdded関数で、プレイヤーのキャラクターがロードされるときに“IsAlive”という名前の属性の値をtrueでプレイヤーオブジェクトに設定。
- ヒューマノイドのDiedイベントの無名関数で、プレイヤーのキャラクターが死亡したら“IsAlive”属性の値をfalseでプレイヤーオブジェクトに設定。
local Players = game:GetService("Players")
local function onCharacterAdded(character, player)
player:SetAttribute("IsAlive", true)
local humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Connect(function()
local points = player.leaderstats.Points
points.Value = 0
player:SetAttribute("IsAlive", false)
end)
end
- if文で“IsAlive”属性がtrueのときだけ、ポイントを加算するコードが実行されるように修正。
while true do
wait(1)
local playerList = Players:GetPlayers()
for currentPlayer = 1, #playerList do
local player = playerList[currentPlayer]
if player:GetAttribute("IsAlive") then
local points = player.leaderstats.Points
points.Value = points.Value + 1
end
end
end
テストしてみると、プレイヤーが生きている間はポイントが増えつづけ、死亡している間はポイントが0のままになっていれば成功だよ。
友達と一緒にプレイして、だれが最高ポイントを獲得できるか競争してみよう。
今回はここまでだけど、このスクリプトはまだまだ作りはじめだよ。
ゲーム開始と同時にすべてのプレイヤーをゲームエリアの真ん中にテレポートさせたり、勝者の発表をしたり、次のラウンドに移動させたりして、ゲームを改善していった方がいいだろうね。
コメント