Growing School

 

Roblox: Growing School

Langkah-langkah implementasi, struktur folder, skrip (Luau) untuk server & client, serta ide tambahan untuk melibatkan guru/staff dan memperkaya lingkungan sekolah. Saya buat mudah diikuti dan siap ditempel ke tempat (place) yang sudah punya gedung sekolah.

Ringkasan fitur utama

  1. Assessment Quizzes: siswa mencari (in-game clue / resource) lalu menjawab soal. Soal lebih sulit → poin assessment lebih besar.
  2. Konversi: setiap 50 assessment points dapat ditukar 5 reward credits.
  3. Shop & Crafting: reward credits dikumpulkan dan ditukar menjadi barang / tools untuk build mainan (toy/diecast/minifigure). Barang bisa spawnable item atau tool.
  4. Garden Growth: keberhasilan siswa menanam/merawat tanaman memengaruhi tampilan sekolah (lebih hijau, bunga, dekor).
  5. Peran Guru/Staff: guru bisa membuat kuis, memvalidasi proyek, dan menjalankan workshop pembuatan barang di game.

Struktur proyek (di Roblox Studio)

Workspace

  |-- SchoolBuilding (existing)

  |-- Garden (Folder)           -- tempat plot tanaman

  |-- SpawnLocations (Folder)

ServerScriptService

  |-- GameManager (Script)

  |-- DataStoreManager (ModuleScript)

  |-- QuizManager (ModuleScript)

  |-- RewardManager (ModuleScript)

  |-- GardenManager (ModuleScript)

StarterPlayer

  StarterPlayerScripts

    |-- ClientQuizHandler (LocalScript)

StarterGui

  |-- QuizGui (ScreenGui)

  |-- ShopGui (ScreenGui)

ReplicatedStorage

  |-- RemoteEvents

        |-- RequestQuiz

        |-- SubmitAnswer

        |-- ConvertAssessment

        |-- RequestShopPurchase

        |-- SpawnItem

  |-- Modules

        |-- QuizModule

        |-- RewardModule

        |-- GardenModule

ServerStorage

  |-- ShopItems (Folder) -- template model/tool untuk item yang bisa dibeli

  |-- TeacherTools (Folder)

 


Data & ekonomi (aturan)

  • AssessmentPoints (AP): integer, diperoleh dari menjawab soal atau menyelesaikan tugas. Soal difficulty: easy=5, medium=15, hard=30 (contoh).
  • RewardCredits (RC): mata uang reward. Konversi: 50 AP -> 5 RC. (Perbandingan ini bisa diubah.)
  • Shop prices contoh: mini-toy = 10 RC, diecast part = 25 RC, minifigure kit = 40 RC.
  • Semua transaksi divalidasi server-side.

Modul penting — kode contoh (Luau)

Semua ModuleScript berada di ReplicatedStorage.Modules kecuali DataStore di ServerScriptService jika ingin privasi. Gunakan DataStoreService untuk simpanan.

1) DataStoreManager (ServerScriptService -> ModuleScript)

-- DataStoreManager

local DataStoreService = game:GetService("DataStoreService")

local Players = game:GetService("Players")

 

local DataStoreManager = {}

local playerStore = DataStoreService:GetDataStore("GrowingSchoolPlayerStore_v1")

 

local DEFAULT = {

    AssessmentPoints = 0,

    RewardCredits = 0,

    Inventory = {}, -- list of item names

    GardenPlots = {}, -- optional per-player plot states

}

 

function DataStoreManager:Load(player)

    local key = "player_" .. player.UserId

    local success, data = pcall(function() return playerStore:GetAsync(key) end)

    if success and data then

        return data

    else

        return table.clone(DEFAULT)

    end

end

 

function DataStoreManager:Save(player, data)

    local key = "player_" .. player.UserId

    pcall(function() playerStore:SetAsync(key, data) end)

end

 

function DataStoreManager:BindPlayer(player)

    local data = self:Load(player)

    player:SetAttribute("AssessmentPoints", data.AssessmentPoints or 0)

    player:SetAttribute("RewardCredits", data.RewardCredits or 0)

    player:SetAttribute("Inventory", data.Inventory or {})

    -- Save on leave

    player.AncestryChanged:Connect(function()

        if not player:IsDescendantOf(game) then

            self:Save(player, {

                AssessmentPoints = player:GetAttribute("AssessmentPoints"),

                RewardCredits = player:GetAttribute("RewardCredits"),

                Inventory = player:GetAttribute("Inventory"),

                GardenPlots = data.GardenPlots,

            })

        end

    end)

end

 

Players.PlayerAdded:Connect(function(plr)

    DataStoreManager:BindPlayer(plr)

end)

 

Players.PlayerRemoving:Connect(function(plr)

    local d = {

        AssessmentPoints = plr:GetAttribute("AssessmentPoints") or 0,

        RewardCredits = plr:GetAttribute("RewardCredits") or 0,

        Inventory = plr:GetAttribute("Inventory") or {},

    }

    DataStoreManager:Save(plr, d)

end)

 

return DataStoreManager

 

2) QuizModule (ReplicatedStorage.Modules -> ModuleScript)

-- QuizModule

local QuizModule = {}

 

-- contoh bank soal (di real project simpan di Module, atau UI untuk guru menambah)

QuizModule.Questions = {

    {id=1, q="Apa itu variabel dalam pemrograman?", choices={"Tempat menyimpan data","Alat memasak","Bahasa pemrograman"}, ans=1, difficulty="easy", points=5},

    {id=2, q="Apa fungsi loop for?", choices={"Mengulang blok kode","Menambah variabel","Membuka file"}, ans=1, difficulty="medium", points=15},

    {id=3, q="Sebutkan langkah debugging yang benar.", choices={"Cek error log","Tebak saja","Jangan jalankan program"}, ans=1, difficulty="hard", points=30},

}

 

function QuizModule:GetRandomQuestionByDifficulty(diff)

    local pool = {}

    for _,v in ipairs(QuizModule.Questions) do

        if v.difficulty == diff then table.insert(pool, v) end

    end

    if #pool == 0 then return nil end

    return pool[math.random(1,#pool)]

end

 

function QuizModule:GetQuestionById(id)

    for _,v in ipairs(QuizModule.Questions) do

        if v.id == id then return v end

    end

end

 

return QuizModule

 

3) RewardModule (ReplicatedStorage.Modules -> ModuleScript)

local RewardModule = {}

 

function RewardModule:ConvertAssessmentToCredits(ap)

    -- tiap 50 AP => 5 RC; implement formula: credits = floor(ap/50) * 5

    local conversions = math.floor(ap / 50)

    return conversions * 5

end

 

function RewardModule:APLeftAfterConversion(ap)

    local used = math.floor(ap / 50) * 50

    return ap - used

end

 

return RewardModule

 

4) Server-side GameManager (ServerScriptService -> Script)

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Players = game:GetService("Players")

 

local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")

local RequestQuiz = RemoteEvents:WaitForChild("RequestQuiz")

local SubmitAnswer = RemoteEvents:WaitForChild("SubmitAnswer")

local ConvertAssessment = RemoteEvents:WaitForChild("ConvertAssessment")

local RequestShopPurchase = RemoteEvents:WaitForChild("RequestShopPurchase")

local SpawnItem = RemoteEvents:WaitForChild("SpawnItem")

 

local QuizModule = require(ReplicatedStorage.Modules.QuizModule)

local RewardModule = require(ReplicatedStorage.Modules.RewardModule)

local DataStoreManager = require(game.ServerScriptService.DataStoreManager)

 

-- helper to give AP

local function giveAssessmentPoints(player, amount)

    local current = player:GetAttribute("AssessmentPoints") or 0

    player:SetAttribute("AssessmentPoints", current + amount)

end

 

-- handle quiz requests (server picks question)

RequestQuiz.OnServerEvent:Connect(function(player, difficulty)

    -- pick question

    local q = QuizModule:GetRandomQuestionByDifficulty(difficulty or "easy")

    if q then

        -- send back question data (no answer)

        RemoteEvents:FindFirstChild("SendQuestion"):FireClient(player, {id=q.id, q=q.q, choices=q.choices, points=q.points, difficulty=q.difficulty})

    end

end)

 

-- handle answer submission

SubmitAnswer.OnServerEvent:Connect(function(player, questionId, chosenIndex)

    local q = QuizModule:GetQuestionById(questionId)

    if not q then return end

    local correct = (chosenIndex == q.ans)

    if correct then

        giveAssessmentPoints(player, q.points)

        RemoteEvents:FindFirstChild("QuizResult"):FireClient(player, true, q.points)

    else

        RemoteEvents:FindFirstChild("QuizResult"):FireClient(player, false, 0)

    end

end)

 

-- conversion AP -> RC

ConvertAssessment.OnServerEvent:Connect(function(player)

    local ap = player:GetAttribute("AssessmentPoints") or 0

    local credits = RewardModule:ConvertAssessmentToCredits(ap)

    if credits > 0 then

        local newAp = RewardModule:APLeftAfterConversion(ap)

        player:SetAttribute("AssessmentPoints", newAp)

        local rc = player:GetAttribute("RewardCredits") or 0

        player:SetAttribute("RewardCredits", rc + credits)

        RemoteEvents:FindFirstChild("ConversionResult"):FireClient(player, credits, newAp)

    else

        RemoteEvents:FindFirstChild("ConversionResult"):FireClient(player, 0, ap)

    end

end)

 

-- handle shop purchase (server validates)

RequestShopPurchase.OnServerEvent:Connect(function(player, itemName)

    local priceLookup = {

        ["MiniToy"] = 10,

        ["DiecastPart"] = 25,

        ["MinifigureKit"] = 40,

    }

    local price = priceLookup[itemName]

    if not price then return end

    local rc = player:GetAttribute("RewardCredits") or 0

    if rc >= price then

        player:SetAttribute("RewardCredits", rc - price)

        -- add to inventory (table)

        local inv = player:GetAttribute("Inventory") or {}

        table.insert(inv, itemName)

        player:SetAttribute("Inventory", inv)

        -- optionally spawn item in front of player

        RemoteEvents.SpawnItem:FireClient(player, itemName)

    else

        RemoteEvents:FindFirstChild("PurchaseFailed"):FireClient(player, "Insufficient credits")

    end

end)

 

5) Client Quiz Handler (StarterPlayerScripts -> LocalScript)

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Players = game:GetService("Players")

local player = Players.LocalPlayer

local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")

 

local RequestQuiz = RemoteEvents:WaitForChild("RequestQuiz")

local SubmitAnswer = RemoteEvents:WaitForChild("SubmitAnswer")

local QuizGui = game.StarterGui:WaitForChild("QuizGui") -- clone to PlayerGui automatically

 

-- show question from server

RemoteEvents:WaitForChild("SendQuestion").OnClientEvent:Connect(function(data)

    -- tampilkan di GUI: data.q, data.choices

    -- Contoh sederhana: print

    print("Soal:", data.q)

    for i,choice in ipairs(data.choices) do print(i,choice) end

    -- GUI harus menangani penekanan jawaban lalu SubmitAnswer: FireServer(questionId,index)

end)

 

RemoteEvents:WaitForChild("QuizResult").OnClientEvent:Connect(function(isCorrect, points)

    if isCorrect then

        -- beri feedback, mainkan efek

        print("Benar! +"..points.." AP")

    else

        print("Salah.")

    end

end)

 

-- contoh panggil quiz tombol di GUI

-- RequestQuiz: FireServer("medium")

 

6) Spawn Item Client Handler (LocalScript dalam StarterPlayerScripts)

-- spawn item client-side (server memerintahkan)

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")

local ServerStorage = game:GetService("ServerStorage")

local player = game.Players.LocalPlayer

local backpack = player:WaitForChild("Backpack")

 

RemoteEvents.SpawnItem.OnClientEvent:Connect(function(itemName)

    local template = ServerStorage:FindFirstChild("ShopItems"):FindFirstChild(itemName)

    if template then

        local clone = template:Clone()

        clone.Parent = backpack -- menjadikan tool siap pakai

    end

end)

 


UI (QuizGui & ShopGui)

Buat GUI sederhana:

  • QuizGui: soal + 3 pilihan + label difficulty + tombol Ambil Soal (memanggil RequestQuiz).
  • ShopGui: menampilkan AP dan RC (baca dari Attributes via :GetAttributeChangedSignal), tombol Convert (panggil ConvertAssessment), list item dengan harga + tombol beli (panggil RequestShopPurchase).

Pastikan validasi transaksi hanya di server (seperti contoh).


Garden Growth System (ReplicatedStorage.Modules.GardenModule)

  • Setiap siswa bisa menanam di plot. Menjawab kuis/menyelesaikan tugas memberi AP yang bisa dipakai untuk membeli bibit.
  • Tanaman punya stages: seed -> sprout -> young -> mature -> bloom. Perawatan: water action (tool), fertilizer (item), dan waktu.
  • Progress tanaman bisa disimpan ke DataStore per pemain atau ke server global untuk taman sekolah.

Contoh sederhana:

-- GardenModule (concept)

local GardenModule = {}

GardenModule.Plots = {} -- {plotId = {owner = userId, stage = 1, lastWatered = os.time()}}

 

function GardenModule:WaterPlot(plotId, player)

    local plot = self.Plots[plotId]

    if not plot or plot.owner ~= player.UserId then return false end

    plot.lastWatered = os.time()

    plot.stage = math.min(plot.stage + 1, 5)

    return true

end

 

return GardenModule

 

Visual: gunakan TweenService untuk animasi tumbuh; ganti mesh/size/texture tiap stage.


Melibatkan Guru & Staff — ide & implementasi

  1. Role-based Access: berikan role "Teacher" (Group rank atau attribute). Server scripts memeriksa player:GetRankInGroup(groupId) atau attribute IsTeacher.
  2. Teacher Panel:
    • GUI untuk membuat/mengunggah soal (question editor) — server menyimpan soal baru ke QuizModule (atau DataStore).
    • Panel untuk memvalidasi proyek siswa (mis. approve desain mainan) → pada approval teacher memberikan RC bonus.
    • Jadwalkan workshop in-game (mis. setiap Jumat jam 4 PM) — teacher memicu event spawn workstation.
  3. Staff-Led Events:
    • Competition: lomba garden paling rindang. Guru menilai dan memberikan hadiah RC.
    • Workshop Build: guru menempatkan blueprint/recipe, siswa gunakan material inventori untuk merakit minifigure.
    • Exhibition: ruang pamer di gedung sekolah untuk menampilkan mainan yang dibuat pemain; guru bisa memberikan label & nilai.
  4. Moderation Tools:
    • GUI untuk staff mem-ban/spawn item, memindahkan pemain, restore inventory.
    • Audit log transaksi (server print atau simpan ke DataStore).
  5. Pembelajaran Lintas Mapel:
    • Soal dapat bertema Matematika, Sains, Bahasa, dan coding. Guru mata pelajaran masing-masing menambah soal dan reward khusus.

Ide lingkungan sekolah & gameplay tambahan

  • Misi Harian & Mingguan: daily quest (jawab X soal), weekly event (kolaborasi menanam Y pohon).
  • Mini-classes: teacher memberikan mini-lesson (audio/text), setelah menonton siswa mendapat kuis khusus.
  • Marketplace Sekolah: siswa bisa jual-beli barang dengan RC (server-side matching).
  • Perbaikan Gedung: hasil garden/points bisa dipakai untuk membeli dekor gedung sekolah (lebih banyak bunga, mural).
  • Klub (Clubs): kelompok siswa membuat klub (Robotics Club) yang bisa kumpulkan AP bersama untuk membeli item klub.
  • Achievement & Badges: unlock cosmetic untuk avatar / label di profil.
  • Kegiatan Fisik Virtual: lomba scavenger hunt di area sekolah—bisa disisipkan elemen edukatif.

Tahapan implementasi (step-by-step)

  1. Persiapan: buka place, pastikan gedung sekolah ada. Buat folder Garden, SpawnLocations, ServerStorage/ShopItems.
  2. Buat RemoteEvents & ModuleScripts di ReplicatedStorage sesuai struktur.
  3. Pasang DataStoreManager di ServerScriptService, jalankan test lokal (Play Solo) untuk cek save/load atribut.
  4. Buat GUIs: QuizGui & ShopGui. Sambungkan tombol ke RemoteEvents via LocalScripts.
  5. Implement Quiz flow: server RequestQuiz -> server memilih soal -> client terima & tampil GUI -> user submit -> server proses -> update AP.
  6. Implement Conversion & Shop: client convert (klik) -> server hit RewardModule -> update RC -> client spawn item.
  7. Buat Shop Items di ServerStorage/ShopItems (Tools / Models). Pastikan tool scripts aman.
  8. Garden System: buat plots di Workspace (Part per plot), klik plot opens plant menu. Implement watering tool & growth stages.
  9. Teacher Tools: special GUI untuk users with IsTeacher attribute. Uji manajemen soal & approval.
  10. Test keamanan: semua perubahan ekonomi dan inventory harus di server. Jangan update AP/RC hanya di client.
  11. Polishing: tambah sounds, VFX, Tween untuk tanaman, particle untuk reward, leaderboard.
  12. UAT bersama guru: ajak beberapa guru/staff coba, minta feedback soal difficulty balancing dan harga item.
  13. Deploy: public/private, atur akses group jika perlu.

Tips teknis & best practices

  • Simpan soal & item config di ModuleScript agar mudah diubah. Untuk skala besar, buat admin GUI untuk teacher menambah soal (server-only).
  • DataStore throttling: jangan lakukan set/get terlalu sering. Simpan saat PlayerRemoving & berkala (contoh tiap 5 menit).
  • Validasi server-side untuk semua transaksi dan spawn item.
  • Gunakan ContextActionService untuk actions seperti watering.
  • Pertimbangkan MessagingService jika ingin notifikasi cross-server (global events).

Contoh flow lengkap (skenario)

  1. Siswa menemukan buku di library virtual (game-play clue). Klik Ambil Soal di buku → RequestQuiz("hard") → dapat soal hard (30 AP).
  2. Jawab benar → server tambahkan 30 AP. Tampilan UI update menampilkan total AP.
  3. Setelah mengumpulkan 60 AP, siswa klik Convert → server convert: floor(60/50)=1 => 5 RC, sisanya 10 AP.
  4. Siswa buka Shop, membeli MiniToy seharga 10 RC (validasi server). Server kurangi RC, tambahkan item ke Inventory lalu spawn tool ke Backpack.
  5. Siswa pakai tool di area workshop untuk merakit minifigure; guru bisa memvalidasi & beri bonus RC.

 

Komentar

Postingan populer dari blog ini

Materi Roblox Permainan Harvest

Script Roblox Studio (Character Free Falling)

Script Roblox Studio Kill Player, Lava Floor, Neon