Tech Kids Grand Prix 2026に「Roblox賞」が新設!応募は9/30(水)まで
CreateR Nest
ブログ一覧へ
Roblox Studio

AIにたのんで、クリアタイムと「もう一度あそぶ」ボタンを足そう

動作確認日: 2026年10月20日(Roblox Studio 0.743)

連載「AIといっしょにゲームを作ろう」の、コインあつめゲームの4回めです。前の回(ゴールを足す)を読む

前の回で、コインを5つ全部取ると、ゴールが現れるようになりました。でも、クリアしたあとは、そこで終わりです。もう一度遊ぶには、いったん停止して、プレイし直さないといけません。

今回は、コインあつめゲームの仕上げです。クリアしたあとの部分を足します。

今回作るもの

  • ゲームが始まってから、ゴールにさわるまでの時間をはかる
  • クリアしたとき、「ゴール!クリア!」の下に「クリアタイム」を出す
  • クリアしたとき、「もう一度あそぶ」ボタンを出す
  • ボタンを押すと、コインもスコアもゴールも、最初の状態にもどって、スタート地点から遊び直せる

足すものが、4つあります。ふだんなら、一度にたのみすぎですが、全部「クリアしたあとの話」なので、ひとまとめにしました。

ChatGPTにたのむ

前の回までの作品を、スタジオで開いたまま、ChatGPTに次の文を送ります。

さっき作った「コインあつめダッシュ」を、仕上げてください。
今回は、クリアしたあとの部分を足します。

【作るもの】
1. ゲームが始まってから、ゴールにさわるまでの時間をはかる。
2. クリアしたとき、「ゴール!クリア!」の下に「クリアタイム: ○○.○秒」と出す。
3. クリアしたとき、「もう一度あそぶ」ボタンを出す。
4. そのボタンを押すと、コインが全部もどって、スコアも0にもどって、ゴールも見えなくなって、スタート地点から最初からやり直せる。

【ルール】
- 今までに作った足場、コイン、スコア表示、ゴールの見た目は、変えないでください。
- 名前は分かりやすくしてください(例:ClearTimeLabel、RetryButton)。
- 小学生が読めるように、スクリプトの中に日本語のコメントをつけてください。
- 音や、新しい面は、まだ作らないでください。

【最後にお願い】
作り終わったら、次の3つを、やさしい言葉で教えてください。
- 何を足したか
- 時間をはかっているのは、どのスクリプトのどこか
- 「もう一度あそぶ」を押したとき、何をもとにもどしているか

「もとにもどすもの」を、ひとつずつ書いたのが、今回の工夫です。「最初からやり直せるように」とだけ書くと、AIは、コインだけもどして、スコアをもどし忘れる、ということがあります。

できあがりを見る

約1分で、ChatGPTから返事が来ました。

ChatGPTの返事。足したもの、時間をはかるところ、ボタンでもとにもどすものが書いてある

返事を読むと、次のことがわかります。

  • 足したもの:「ゴール!クリア!」の下に、「クリアタイム」と「もう一度あそぶ」ボタン
  • 時間をはかるところ:RoundScriptのRoundStartTimeに、始まった時こくをおぼえます。ゴールにさわると、GoalScriptが、今の時こくから引いて、何秒かかったかを計算します
  • ボタンでもとにもどすもの:コインを5つ、スコアを0、ゴールを見えない状態に。クリアの文字・タイム・ボタンを消して、プレイヤーをスタート地点にもどし、時間もはかり直します

「最後にお願い」の3つに、そのまま答えてくれています。「もう一度クリアできることも確認しました」という、AI自身が動作を確かめた報告も、ついてきました。

遊んでみる

  1. 画面の上の「▶(プレイ)」を押します
  2. 5つ全部のコインを取って、ゴールにさわります
  3. 「ゴール!クリア!」の下に、クリアタイムと、「もう一度あそぶ」ボタンが出ます

ゴールにさわった画面。「ゴール!クリア!」の下に「クリアタイム: 9.4秒」と、「もう一度あそぶ」ボタンが出ている

  1. 「もう一度あそぶ」を押します

ボタンを押したあとの画面。スタート地点にもどり、左上が「コイン: 0 / 5」になり、足場の上のコインが5つともどっている

スタート地点にもどって、左上は「コイン: 0 / 5」になり、足場の上のコインが、5つともどっています。ゴールは、また見えなくなりました。このあと、もう一度、ゴールまで遊べます。

問題なく動きました。 今回も、直してもらう必要はありませんでした。足すものが4つあっても、「もとにもどすもの」を書いておいたので、一度で動いたのかもしれません。

どこに増えたか見てみる

「■(停止)」を押して編集の画面にもどり、右のエクスプローラーを見てみましょう。今回は、新しい場所が3か所にあります。

  • ServerStorageの中に、CoinTemplatesというフォルダがあります。中に、Coin1〜5が入っています。もどすためのコインの見本です
  • ReplicatedStorageの中に、RetryRequestがあります。ボタンの知らせを運ぶ道具です
  • StarterGuiのGoalGuiの中に、ClearTimeLabel(タイムの文字)とRetryButton(ボタン)と、RetryDisplayScriptが増えています

ServerStorageは、ゲームの中には出ない、しまっておく場所です。ReplicatedStorageは、画面の係とゲームの中身の係が、どちらも使える場所です。

スクリプトを読んでみる

今回は、新しいスクリプトが2つあり、前の回のGoalScriptも少し変わっています。流れを見てみましょう。

ボタンを押す(RetryDisplayScript)
   ↓ 「もう一度あそびたい!」と知らせる(RetryRequest)
やり直しの係(RoundScript)が、コイン・スコア・ゴール・場所・時間をもどす

1. 時間をはかる:RoundScript の前半と GoalScript

RoundScriptの前半です。

local function preparePlayer(player)
    -- ゲームに入った時こくをおぼえて、時間をはかり始めるよ。
    if player:GetAttribute("RoundStartTime") == nil then
        player:SetAttribute("RoundStartTime", workspace:GetServerTimeNow())
        player:SetAttribute("CoinCount", 0)
        player:SetAttribute("GoalCleared", false)
    end
end
Players.PlayerAdded:Connect(preparePlayer)
  • workspace:GetServerTimeNow():今の時こくです。時計のようなもので、時間がたつほど大きくなります
  • player:SetAttribute("RoundStartTime", ...):その人のスタートの時こくを、属性におぼえさせます。前の回で出てきたCoinCountと同じ、名前つきのメモです
  • Players.PlayerAdded:Connect(preparePlayer):プレイヤーがゲームに入ったときに、この準備を動かします

つまり、はかり始めるのは、ゲームに入ったときからです。最初に動いたときではありません。

次に、GoalScriptの、ゴールにさわったところです。

    -- 今の時こくから、スタートの時こくを引くと、かかった秒数になるよ。
    local started = player:GetAttribute("RoundStartTime")
    if not started then
        return
    end
    player:SetAttribute("ClearTime", math.max(0, workspace:GetServerTimeNow() - started))
    player:SetAttribute("GoalCleared", true)
  • workspace:GetServerTimeNow() - started:今の時こくから、スタートの時こくを引き算します。それが、かかった秒数です。たとえば、スタートが100秒、ゴールが109.4秒なら、109.4 - 100 = 9.4 で、9.4秒です
  • math.max(0, ...):0より小さくならないようにします
  • SetAttribute("ClearTime", ...):かかった秒数を、ClearTimeという名前でおぼえさせます。画面の係が、これを読んで、タイムを出します

2. タイムとボタンを見せる:RetryDisplayScript

StarterGuiのGoalGuiの中にある、RetryDisplayScriptです。

local function update()
    local cleared = player:GetAttribute("GoalCleared") == true
    local seconds = player:GetAttribute("ClearTime") or 0
    -- 小数点のあとを1けたにして、秒数を見せるよ。
    timeLabel.Text = string.format("クリアタイム: %.1f秒", seconds)
    timeLabel.Visible = cleared
    button.Visible = cleared
    if not cleared then
        waiting = false
    end
end
  • string.format("クリアタイム: %.1f秒", seconds):文字の中の %.1f のところに、seconds の数を、小数点のあと1けたで入れます。9.4 なら、「クリアタイム: 9.4秒」です
  • timeLabel.Visible = cleared と button.Visible = cleared:クリアしている(true)ときだけ、タイムの文字とボタンを見せます。前の回の「ゴール!クリア!」と同じしくみです

3. ボタンを押したら:「知らせ」を送る

ここが、今回のいちばん新しいところです。同じスクリプトの、ボタンの部分です。

button.Activated:Connect(function()
    -- ボタンを押したら、やり直しの係に知らせるよ。
    if waiting then
        return
    end
    waiting = true
    retry:FireServer()
end)
  • button.Activated:Connect(function():ボタンが押されたときに動きます
  • retry:FireServer():RetryRequestを使って、ゲームの中身の係(サーバー)に「もう一度あそびたい!」と知らせます。RemoteEvent(リモートイベント)という、知らせるための道具です

どうして、ボタンのスクリプトが、直接コインをもどさないのでしょうか。ボタンのスクリプトは、自分の画面だけを動かす、LocalScriptです。コインやゴールは、みんなで遊ぶゲームの中身なので、自分の画面だけでは、動かせないのです。そこで、お願いの手紙を出して、ゲームの中身の係に、やってもらいます。

4. もとにもどす:RoundScript の後半

手紙を受け取るのは、RoundScriptの後半です。

retry.OnServerEvent:Connect(function(player)
    -- クリアした人だけ、やり直せるよ。続けて押しても大丈夫だよ。
    if player:GetAttribute("GoalCleared") ~= true then
        return
    end
    -- (中略:キャラクターを調べる)
    player:SetAttribute("GoalCleared", false)
    player:SetAttribute("CoinCount", 0)
    player:SetAttribute("ClearTime", nil)

    -- スタート地点にもどして、体の動きも止めるよ。
    character:PivotTo(course.StartSpawn.CFrame + Vector3.new(0, 4, 0))
    root.AssemblyLinearVelocity = Vector3.zero
    root.AssemblyAngularVelocity = Vector3.zero

    -- とっておいたコインのコピーで、5つとも元にもどすよ。
    for i = 1, 5 do
        local oldCoin = course:FindFirstChild("Coin" .. i)
        if oldCoin then
            oldCoin:Destroy()
        end
        templates:WaitForChild("Coin" .. i):Clone().Parent = course
    end
    -- 新しいスタートの時こくに入れかえるよ。
    player:SetAttribute("RoundStartTime", workspace:GetServerTimeNow())
end)
  • retry.OnServerEvent:Connect(function(player):知らせが届いたときに、動きます。player は、ボタンを押した人です
  • 最初の if ... ~= true then return end:クリアしていない人が押しても、何もしないで終わります。ちょっとした安全のしかけです
  • SetAttribute(...) の3行:GoalClearedを false に、CoinCountを 0 に、ClearTimeを nil(なし)に、もどします。すると、スコア表示も、ゴールも、クリアの文字も、前の回までのしくみで、自動でもどります
  • character:PivotTo(...):キャラクターを、スタート地点の上に動かします。下の2行で、動いていた勢いも、止めます
  • for i = 1, 5 do ... end:1から5まで、くり返します。いま残っているコインがあれば、消して、CoinTemplatesの見本を、:Clone()(コピー)して、コースにならべ直します。コインが5つ、もどる部分です
  • 最後に、RoundStartTimeを、新しいスタートの時こくにします。時間も、はかり直しです

「もとにもどす」ためには、もとの形を、とっておく必要があります。ChatGPTは、ServerStorageにコインの見本をしまっておいて、必要なときにコピーする、というやり方を選んでくれました。

ためしに、数字を変えてみましょう

クリアタイムの小数点の数は、RetryDisplayScriptの %.1f の1で決まっています。これを2に変えてみましょう。

  1. 「■(停止)」を押して、編集の画面にもどります
  2. エクスプローラーで、StarterGuiの中のGoalGuiを開いて、RetryDisplayScriptをダブルクリックします
  3. string.format("クリアタイム: %.1f秒", seconds) の %.1f の1だけを、2に書きかえます(%.2f になります)
  4. 「▶(プレイ)」を押して、ゴールまで遊びます

「クリアタイム: 9.43秒」のように、小数点のあとが2けたで出ます。 %.0f にすると、小数点なしの整数で出ます。確かめたら、2 を 1 にもどしておきましょう。

読めれば、直せます。 AIにたのまなくても、タイムの見え方を、自分で変えられました。

もっといい、たのみ方

  • 「もとにもどすもの」を、ひとつずつ書く:コイン、スコア、ゴール、場所、時間のように、何をもとにもどしたいのかを書きます
  • 「もどす」ために、何を残すかも聞く:今回は、AIがコインの見本をしまっておく、というやり方を選びました。「何をもとにもどしているか」と聞くと、そのしくみがわかります
  • AIが確かめたことを、自分でも確かめる:「確認しました」と言われても、自分で遊んで、もう一度クリアできるかまで、見ておきましょう

つぎは

これで、コインあつめゲームが、完成しました。

足場にコインを置いて、スコアを出して、ゴールを作って、やり直せるようにする。この流れを、ChatGPTにたのみながら、1本のゲームとして作りました。次の回からは、2つめのゲームに進みます。