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
- Assessment
Quizzes: siswa mencari (in-game clue / resource) lalu menjawab soal.
Soal lebih sulit → poin assessment lebih besar.
- Konversi:
setiap 50 assessment points dapat ditukar 5 reward credits.
- Shop
& Crafting: reward credits dikumpulkan dan ditukar menjadi barang
/ tools untuk build mainan (toy/diecast/minifigure). Barang bisa spawnable
item atau tool.
- Garden Growth: keberhasilan siswa menanam/merawat
tanaman memengaruhi tampilan sekolah (lebih hijau, bunga, dekor).
- 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
- Role-based
Access: berikan role "Teacher" (Group rank atau attribute).
Server scripts memeriksa player:GetRankInGroup(groupId) atau attribute
IsTeacher.
- 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.
- 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.
- Moderation
Tools:
- GUI
untuk staff mem-ban/spawn item, memindahkan pemain, restore inventory.
- Audit log transaksi (server print
atau simpan ke DataStore).
- 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)
- Persiapan: buka place, pastikan gedung sekolah ada. Buat
folder Garden, SpawnLocations, ServerStorage/ShopItems.
- Buat
RemoteEvents & ModuleScripts di ReplicatedStorage sesuai struktur.
- Pasang
DataStoreManager di ServerScriptService, jalankan test lokal (Play
Solo) untuk cek save/load atribut.
- Buat
GUIs: QuizGui & ShopGui. Sambungkan tombol ke RemoteEvents via
LocalScripts.
- Implement
Quiz flow: server RequestQuiz -> server memilih soal -> client
terima & tampil GUI -> user submit -> server proses -> update
AP.
- Implement
Conversion & Shop: client convert (klik) -> server hit
RewardModule -> update RC -> client spawn item.
- Buat
Shop Items di ServerStorage/ShopItems (Tools / Models). Pastikan tool
scripts aman.
- Garden
System: buat plots di Workspace (Part per plot), klik plot opens plant
menu. Implement watering tool & growth stages.
- Teacher
Tools: special GUI untuk users with IsTeacher attribute. Uji manajemen
soal & approval.
- Test keamanan: semua perubahan ekonomi dan
inventory harus di server. Jangan update AP/RC hanya di client.
- Polishing:
tambah sounds, VFX, Tween untuk tanaman, particle untuk reward,
leaderboard.
- UAT
bersama guru: ajak beberapa guru/staff coba, minta feedback soal
difficulty balancing dan harga item.
- 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)
- Siswa
menemukan buku di library virtual (game-play clue). Klik Ambil Soal di
buku → RequestQuiz("hard") → dapat soal hard (30 AP).
- Jawab benar → server tambahkan 30 AP.
Tampilan UI update menampilkan total AP.
- Setelah
mengumpulkan 60 AP, siswa klik Convert → server convert: floor(60/50)=1
=> 5 RC, sisanya 10 AP.
- Siswa
buka Shop, membeli MiniToy seharga 10 RC (validasi server). Server kurangi
RC, tambahkan item ke Inventory lalu spawn tool ke Backpack.
- Siswa
pakai tool di area workshop untuk merakit minifigure; guru bisa
memvalidasi & beri bonus RC.
Komentar
Posting Komentar