Roblox EP2 โค้ด Luau แรก: พื้นเปลี่ยนสี พื้นลาวา และพื้นที่หายไปเมื่อยืนนาน
เขียนโค้ด Luau ครั้งแรกใน Roblox Studio รู้จัก Script, Touched, Humanoid และ debounce ผ่านตัวอย่างสามแบบที่ใช้ใน obby จริง พร้อมอธิบายทุกบรรทัด
- โค้ดใน Roblox ทำงานตาม "เหตุการณ์" เช่น Touched เกิดเมื่อมีอะไรมาแตะชิ้นส่วน แล้วฟังก์ชันที่เราผูกไว้จะทำงาน
- ต้องเช็กว่าสิ่งที่มาแตะเป็นตัวละครจริงไหม ด้วยการหา Humanoid ก่อนทำอะไรเสมอ
- Touched เกิดซ้ำหลายสิบครั้งในการเหยียบครั้งเดียว ต้องมี debounce กันโค้ดทำงานซ้ำ
EP1 เราสร้างฉากที่เดินกระโดดได้แล้ว แต่ทุกอย่างยังนิ่ง ตอนนี้จะเขียนโค้ดครั้งแรก ด้วยตัวอย่างสามแบบที่ obby ทุกเกมต้องมี ทุกบรรทัดมีคำอธิบาย ไม่ต้องเคยเขียนโปรแกรมมาก่อน
เพิ่ม Script แรก
- สร้าง Part ใหม่ ตั้ง Anchored ตั้งชื่อ
ColorPad - ใน Explorer เอาเมาส์ไปชี้ที่
ColorPadจะมีปุ่ม + ขึ้นมา กดแล้วเลือก Script - Studio เปิดหน้าเขียนโค้ด มีบรรทัดเดียวมาให้แล้ว
print("Hello world!")
- กด Play แล้วดูแผง Output จะเห็นข้อความ
Hello world!
print คือการพิมพ์ข้อความออกมาที่ Output ใช้บ่อยมากเวลาอยากรู้ว่าโค้ดทำงานถึงตรงไหนแล้ว
Script ที่อยู่ข้างใน Part จะทำงานเองตอนเกมเริ่ม ไม่ต้องสั่ง และรู้ว่าตัวเองอยู่ในอะไรผ่านคำว่า script.Parent
ตัวอย่างที่ 1: เหยียบแล้วเปลี่ยนสี
ลบบรรทัดเดิม แล้วพิมพ์ใหม่ทั้งหมด
local pad = script.Parent
pad.Touched:Connect(function(otherPart)
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
pad.BrickColor = BrickColor.random()
end
end)
ทีละบรรทัด
local pad = script.Parentสร้างตัวแปรชื่อpadเก็บ Part ที่ script นี้อยู่ข้างใน คำว่าlocalแปลว่าตัวแปรนี้ใช้ได้ในไฟล์นี้เท่านั้นpad.Touchedคือ เหตุการณ์ (event) ที่เกิดทุกครั้งที่มีอะไรมาแตะpad:Connect(function(otherPart) ... end)ผูกฟังก์ชันไว้กับเหตุการณ์ ทุกครั้งที่มีการแตะ ฟังก์ชันนี้จะทำงาน และได้รับotherPartคือชิ้นส่วนที่มาแตะotherPart.Parent:FindFirstChildWhichIsA("Humanoid")ส่วนที่มาแตะคือเท้าหรือขาของตัวละคร ตัวละครทั้งตัวคือParentของมัน และตัวละครทุกตัวมี Humanoid อยู่ข้างใน ถ้าหาเจอ แปลว่าสิ่งที่มาแตะคือตัวละครจริง ไม่ใช่ลูกบอลหรือก้อนหินที่กลิ้งมาif humanoid then ... endทำเฉพาะเมื่อหาเจอpad.BrickColor = BrickColor.random()สุ่มสีใหม่
กด Play แล้วเดินขึ้นไปเหยียบ สีจะเปลี่ยน
โค้ดใน Roblox ส่วนใหญ่มีรูปแบบเดียวกันนี้: รอเหตุการณ์ → เช็กว่าใช่สิ่งที่สนใจไหม → ทำงาน
ปัญหาแรก: Touched เกิดถี่มาก
ลองเพิ่มบรรทัดนี้ไว้บรรทัดแรกในฟังก์ชัน
print("touched by", otherPart.Name)
กด Play แล้วเดินขึ้นไปยืนนิ่ง ๆ ดู Output จะเห็นข้อความพรั่งพรูหลายสิบบรรทัด เพราะเท้าซ้าย เท้าขวา และขาแต่ละท่อน แตะพื้นแยกกัน และแตะซ้ำทุกครั้งที่ขยับนิดเดียว สีจึงเปลี่ยนรัวจนดูไม่ออก
ทางแก้เรียกว่า debounce คือมีตัวแปรบอกว่า “กำลังทำงานอยู่ ห้ามซ้ำ”
local pad = script.Parent
local cooling = false
pad.Touched:Connect(function(otherPart)
if cooling then
return
end
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if not humanoid then
return
end
cooling = true
pad.Color = Color3.fromRGB(255, 90, 90) -- แดง
task.wait(1)
pad.Color = Color3.fromRGB(90, 200, 120) -- เขียว
cooling = false
end)
coolingเริ่มเป็นfalseพอเริ่มทำงานตั้งเป็นtrueระหว่างนั้นการแตะครั้งใหม่จะเจอif cooling then return endแล้วออกทันทีreturnคือออกจากฟังก์ชันตรงนั้นเลย เขียนแบบนี้แทนการซ้อนifหลายชั้น อ่านง่ายกว่าtask.wait(1)รอหนึ่งวินาทีColor3.fromRGB(r, g, b)กำหนดสีแบบแดง เขียว น้ำเงิน ค่า 0 ถึง 255- ข้อความหลัง
--คือคอมเมนต์ โปรแกรมไม่อ่าน เขียนไว้ให้คนอ่าน
ตัวอย่างที่ 2: พื้นลาวา
obby ทุกเกมมีพื้นที่เหยียบแล้วต้องเริ่มใหม่ สร้าง Part ใหม่ชื่อ Lava ตั้ง Anchored ใน Properties ตั้ง Material เป็น Neon และ Color เป็นสีส้มแดง แล้วใส่ Script นี้
local lava = script.Parent
lava.Touched:Connect(function(otherPart)
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
humanoid.Health = 0
end
end)
humanoid.Health = 0 คือตั้งพลังชีวิตเป็นศูนย์ ตัวละครจะล้มแล้วเกิดใหม่ที่จุดเกิด ตัวนี้ไม่ต้องมี debounce เพราะตั้งพลังชีวิตเป็นศูนย์ซ้ำกี่ครั้งก็ได้ผลเหมือนเดิม
เวลาตัดสินใจว่าต้องมี debounce ไหม ให้ถามว่า “ถ้าทำซ้ำสิบครั้งติด ผลต่างจากทำครั้งเดียวไหม” ถ้าต่าง ต้องมี
ตัวอย่างที่ 3: พื้นที่หายไปเมื่อยืนนาน
พื้นที่ค่อย ๆ จางหายเมื่อเหยียบ แล้วกลับมาใหม่ บังคับให้ผู้เล่นต้องรีบ สร้าง Part ชื่อ FadePad แล้วใส่ Script นี้
local pad = script.Parent
local busy = false
pad.Touched:Connect(function(otherPart)
if busy then
return
end
if not otherPart.Parent:FindFirstChildWhichIsA("Humanoid") then
return
end
busy = true
for i = 1, 10 do
pad.Transparency = i / 10 -- จางลงทีละ 10%
task.wait(0.1)
end
pad.CanCollide = false -- ไม่มีพื้นให้ยืนแล้ว
task.wait(3)
pad.CanCollide = true
pad.Transparency = 0
busy = false
end)
for i = 1, 10 do ... endทำซ้ำ 10 รอบ โดยiมีค่า 1, 2, 3 ไปจนถึง 10Transparencyความโปร่งใส 0 คือทึบ 1 คือมองไม่เห็นเลยCanCollide = falseทำให้ชิ้นส่วนไม่มีตัวตนทางกายภาพ ตัวละครจะร่วงทะลุ- ทั้งหมดใช้เวลาจางหาย 1 วินาที หายไป 3 วินาที แล้วกลับมา
ลองปรับตัวเลขให้ยากง่ายตามใจ เช่น task.wait(0.05) จะจางเร็วขึ้นสองเท่า
อ่านข้อผิดพลาดเป็น
ลองเปลี่ยนบรรทัดที่หา Humanoid ในพื้นลาวาเป็นแบบนี้ดู
local humanoid = otherPart.Parent.Humanoid -- ไม่ใช้ FindFirstChild
พอมีอะไรที่ไม่ใช่ตัวละครมาแตะ เช่น ลูกบอลที่ไม่ได้ Anchored กลิ้งมาโดน Output จะขึ้นตัวแดงประมาณว่า Humanoid is not a valid member of ... เพราะเราสั่งให้ไปเอา Humanoid จากสิ่งที่ไม่มี Humanoid
หรือถ้าเจอ attempt to index nil with ... แปลว่ากำลังใช้งานของที่เป็น nil (ว่างเปล่า ไม่มีอยู่จริง) เหมือนพยายามเปิดลิ้นชักของตู้ที่ไม่มี
ทั้งสองแบบแก้ด้วยหลักเดียวกัน หาให้เจอก่อน แล้วเช็กว่าเจอจริง ค่อยใช้ ซึ่งก็คือ FindFirstChildWhichIsA กับ if humanoid then ที่เราเขียนมาตลอด
ลองเองใน 10 นาที
- ทำ
ColorPadแบบมี debounce แล้วลองเปลี่ยนให้กลับเป็นสีเดิมหลัง 2 วินาที - วาง
Lavaสองสามแผ่นระหว่างขั้นบันไดจาก EP1 - ทำ
FadePadเป็นสะพานข้ามลาวา แล้วกด Play ลองเล่น
ข้อผิดพลาดที่เจอบ่อย
- ไม่เช็ก Humanoid ทำให้ลูกบอลหรือชิ้นส่วนที่กลิ้งมา ทำให้โค้ดทำงานเอง
- ลืม debounce ในงานที่ทำซ้ำแล้วผลต่าง
- ลืมตั้ง
busy = falseตอนจบ ทำให้ทำงานได้แค่ครั้งเดียวตลอดเกม - ใส่ Script ผิดที่ เช่น ไว้นอก Part ทำให้
script.Parentไม่ใช่ชิ้นที่ตั้งใจ
ตอนหน้า
ตอนนี้เรามี Script หลายตัวกระจายอยู่ในแต่ละชิ้นส่วน และทุกตัวทำงานบน เซิร์ฟเวอร์ EP3 จะอธิบายว่าเกม Roblox มีสองฝั่ง คือเซิร์ฟเวอร์กับเครื่องของผู้เล่น ทำไมต้องรู้ว่าโค้ดไหนทำงานฝั่งไหน และทำไมเรื่องนี้คือหัวใจของการกันคนโกงเกม
คำถามที่พบบ่อย
ทำไมใช้ task.wait ไม่ใช้ wait
wait แบบเก่ายังใช้ได้ แต่ Roblox แนะนำ task.wait แทนแล้ว เพราะแม่นยำกว่าและเป็นส่วนหนึ่งของไลบรารี task ที่ออกแบบมาใหม่ บทความหรือคลิปเก่า ๆ ยังใช้ wait อยู่เยอะ ถ้าเจอให้เปลี่ยนเป็น task.wait ได้เลย
Output ขึ้นตัวแดง แปลว่าอะไร
แปลว่าโค้ดมีข้อผิดพลาด ข้อความบอกชื่อ script และเลขบรรทัด คลิกที่ข้อความแล้ว Studio จะพาไปที่บรรทัดนั้น ข้อผิดพลาดที่มือใหม่เจอบ่อยที่สุดคือ attempt to index nil ซึ่งอธิบายไว้ในบทความนี้
คำสั่งและค่าตั้งในบทความทดสอบบนระบบตัวอย่าง ลองบนเครื่องทดสอบก่อนใช้กับระบบจริงเสมอ