web analytics

Flutter Project : สร้างเกม 2048 ด้วย Flutter

cove

สวัสดีครับ บล็อกนี้จะบันทึกการทำเกม 2048 ด้วย Flutter ครับ เกมนี้สนุกนะ เล่นฆ่าเวลาได้ เกมนี้เคยฮิตกันเมื่อ 3-4 ปีที่แล้ว ตอนช่วงผมกำลังเรียนมหาวิทยาลัย ตอนนั้นชมรมคอมพิวเตอร์ที่ผมอยู่ก็จัดแข่งเกมนี้ให้กับน้องๆในงานสัปดาห์วิทยาศาสตร์ หากใครไม่รู้จักก็สามารถเล่นได้ที่ http://2048game.com/ ครับ

ก่อนหน้านี้ผมได้เขียนบันทึกเกี่ยวกับการทำเกม Tertis ไปครับ ใครสนใจตามไปอ่านได้ 

Flutter Project : ทำเกม Tertis ด้วย Flutter ตอนที่ 1

 

เริ่มต้น

พร้อมแล้วก็ New Flutter Pproject

1

 

สร้างตาราง

เกมนี้เป็นการเล่นบนตาราง 4×4 ครับ
กำหนดขนาดบล็อกให้แต่ละช่องในตาราง

 

วาดตาราง 4×4

2

 

สร้าง BlockUnit

BlockUnit คือคลาสที่เก็บค่าต่างๆในช่องของตาราง เช่น ตัวเลข สีพื้นหลัง สีตัวหนังสือ

 

ดังนั้นตารางของเกมมันก็คือ BlockUnit แบบ 2 มิติ

 

กำหนดค่าเริ่มต้นให้กับตาราง โดยผมจะขอกำหนดค่าทุกช่อง = 2 ก่อน เพื่อทดสอบ

 

ทำการเชื่อมค่าตัวแปรใน BlockUnit กับ Container Widget

 

ลองรัน

1

 

สร้าง BlockUnitManager

BlockUnit ในเกมไม่ได้มีแต่เลข 2 แต่มีเลข 4 8 16 …. 2048 ซึ่งแต่ละแบบก็มีสีไม่หมือนกัน ดังนั้น ก็เลยสร้างคลาส BlockUnitManager มาเก็บค่า BlockUnit แต่ละแบบ แล้วก็ความสามารการสุ่มบล็อก โดยผมจะลองเขียนแค่แบบ 2 ,4 ,8 ก่อน
ในส่วนของการสุ่ม เนื่องจากค่าของบล็อกมันเป็น 2^n ผมก็เลยสุ่มเลขที่ยกกำลังแทน เช่นสุ่ม 0-6 ถ้าสุ่มได้ 4 ค่าที่ได้คือ 2^4 = 16 นั่นเอง

 

 

แล้วก็กำหนด initTable() ให้สุ่มบล็อกออกมา

3

 

 

ทำปุ่มควบคุม

ต่อมาทำปุ่มให้มันเลื่อนซ้าย ขวา บนล่าง กันครับ จะได้เล่นและทดสอบง่ายๆ
เตรียมฟังก์ชัน สำหรับสร้างปุ่มควบคุม โดยผมจะใส่ไว้ด้านล่างของแอป

 

ทิศทางของการเลื่อนมี 4 แบบ ก็ประกาศค่าคงที่เอาไว้จะได้ง่ายๆ

 

สร้างปุ่มควบคุม  4 อัน และเพื่อความสวยงามเลยใส่ขอบโค้งให้ด้วย
(จริงๆอันนี้ ผม Copy มาจากเกมงู)

 

ได้ปุ่มมาแล้ว

4

 

BlockUnit เพิ่มเติม

มาเพิ่มรายละเอียด Block แบบต่างๆ โดยผมทำถึง 2^11 คือ 2048 ครับ

 

กำหนดค่าสีพื้นหลัง สีตัวหนังสือให้กับทุกอัน

 

กำหนดเลขที่ต้องการให้สุ่ม ผมสุ่ม 0-11 ก็กำหนดค่าเป็น 12

มาแล้ว

5

 

เพิ่มขนาดตัวหนังสือ

ดูเหมือนขนาดตัวหนังสือของบล็อก 1024 , 2048 มันจะใหญ่ไปเมื่อเทียบกับขนาดบล็อก ดังนั้นในเคสของเลข 4 หลัก เราควรลดขนาดตัวหนังสือลงหน่อย

เพิ่มตัวแปรกำหนดขนาดตัวหนังสือให้กับ BlockUnit  กำหนด default ด้วย

 

ในเคสของ 1024,2048 กำหนดขนาดให้ตัวเล็กลง

 

ดูดีขึ้นมาอีกนิด

6

 

การเลื่อนบล็อก

มาถึงจุดสำคัญของเกม คือการเลื่อนบล็อก

ก่อนอื่นกำหนดให้ ตารางสุ่มมาแค่เลข 2 ก่อน โดยปรับให้ random สามารถรับ max มาได้

 

เราจะสุ่มแต่บล็อกว่างๆกับเลข 2 ใส่ maxPow =2
มันจะสุ่มออกมาคือ 0 กับ 1
2^0 = 1 คือบล็อกว่างๆ
2^1 = 2 คือล็อกเลข 2

7

 

ต่อมาก็เขียน method การขยับซ้าย-ขวา บอกก่อนว่าวิธีที่ผมใช้ ผมคิดเอาเอง ดังนั้นมันเลยไม่ใช่ best practise
หลักการที่ผมใช้ คือ BlockUnit เราเก็บค่าเป็น list ดังนั้นมันสามารถลบและแทรกกันได้
กรณีขยับซ้าย เราก็จะวิ่งจากซ้ายไปขวาสนใจเฉพาะช่องว่าง ถ้าเจอให้ย้ายมันไปต่อแถวหลังสุด แล้วทำจนหมด
กรณีขวาก็ทำสลับกัน

b2

จะได้ประมาณนี้

 

ทีนี้ที่ปุ่มควบคุมก็ให้ไปเรียก method

 

 

ขยับซ้ายขวาได้แล้ว

1

 

ทำให้บล็อกรวมกัน

หลังจากขยับแล้วขั้นตอนถัดไปคือ ทำให้บล็อกที่มีเลขเหมือนกันในแนวที่เราขยับ รวมค่ากัน วิธีการก็ง่ายๆอีกเช่นเคย
วิธีการมีดังนี้ สมมุติว่าขยับไปทางซ้าย เราก็ใช้วิธีเหมือนที่อธิบายไปข้างบนก่อน เพื่อให้บล็อกที่มีเลขมันขยับมาทางซ้ายให้หมด
จากนั้นก็รวมเลขที่เลขหมือนกันที่ติดกัน แล้วลบออกอันนึง พอลบออกแล้วมันจะมีช่องว่างแทรกอยู่ เราก็ทำการเลื่อนซ้ายใหม่เพื่อให้บล็อกมันชิดซ้ายให้หมด จบแล้ว

ซึ่งการรวมบล็อกมันจะมีแค่ 3 แบบ เพราะมี 4 ช่อง
คือรวม ช่องที่ 0 – 1 , 1 – 2 , 2 – 3

เช่น

b4

 

ผลลัพธ์ในตอนนี้

a2

 

กรณีเลื่อนขวาก็คล้ายกัน หลักการเดียวกันเด๊ะ

a3

 

ต่อมาก็ทำขยับลงล่างบ้าง อันนี้จะต่างจากขยับซ้ายขวาหน่อยนึง เพราะ การขยับซ้ายขวาเราสามารถลบ แทรก ผ่าน list ของ table ได้แต่ในแนวตั้ง เราทำผ่แบบนั้นไม่ได้ เพราะ list มันเก็ยค่าเป็นแบบแถว การเลื่อนในแนวตั้ง จำเป็นต้องดึงค่าจากตารางในแนวตั้งมาเก็บไว้ใน list ข้างนอกก่อน จากนั้นขยับค่าจากใน list ข้างนอกแทน เสร็จแล้วค่อยบันทึกค่าใน list ข้างนอกกลับไปที่ตาราง

แต่ภาพรวมก็ยังคงใช้หลักการเดิม คือ ย้ายลง รวมบล้อกที่ติดกัน ย้ายลงอีกครั้ง

 

เพิ่มปุ่มกดลงให้ทำงาน

a4

 

กรณีเลื่อนขึ้นก็คล้ายเลื่อนลงนั่นแหละ ทำสลับกัน

a5

 

สุ่มบล็อกใหม่เพิ่มหลังจากเลื่อน

เกมนี้พอเราขยับบล็อก มันจะสุ่มบล็อกใหม่ มาใส่ในช่องที่ว่าง โดยจะสุ่มแค่บล็อก 2 -4 มาเท่านั้น
ซึ่งเราจำเป็นต้องเก็บตำแหน่งช่องที่ว่างในตาราง แล้วค่อยสุ่มเลือก

ดังนั้นสร้างคลาสสำหรับเก็บตำแหน่งในตาราง

 

สร้าง method ใน BlockUnitManager สำหรับสุ่มแค่ บล็อก 2 กับ 4

 

เขียนส่วนที่สุ่มบล็อกลงในตาราง โดยจะทำการรวบรวมช่องที่ว่างในตาราง จากนั้นก็จะเลือกช่องมาช่องนึง แล้วสุ่มบล็อกลงไป

 

กำหนดให้เรียกคำสั่งนี้หลังจากกดเลื่อนที่ปุ่มควบคุม

 

ดูผลลัพธ์

a6

 

หน่วงเวลา

พอเรากดเลื่อน มันก็สุ่มบล็อกมาใส่เลย ซึ่งไวมากๆ ไวจนเราไม่รู้ว่าอันไหนที่มันสุ่ม ดังนั้นเลยต้องหน่วงเวลานิดนึง

สร้างตัวแปรกำหนดว่า ตอนนี้กำลังหน่วงเวลาอยู่

 

เพิ่มโค้ดให้ หน่วงเวลา ผมลองแล้วประมาณ 0.2 วินาทีกำลังดี

a7

 

แก้ปัญหา

ปัญหาต่อมา คือ กรณีที่เราเลื่อนบล็อกแล้วเรากดขยับในทิศทางที่ไม่มีบล็อกไหนขยับได้ แต่เกมก็ยังสุ่มบล็อกมาเพิ่ม ซึ่งจริงๆถ้าไม่มีบล็อกไหนขยับมันจะไม่สุ่มมาเพิ่ม ไม่อย่างนั้นเกมมันจะจบยาก

a8

 

วิธีแก้คือ เราต้องเช็คว่ามีการเลื่อนบล็อกหรือการรวมกันของบล็อกเกิดขึ้นหรือไม่ ถ้าเกิดก็ค่อยสุ่ม
ซึ่งก็ต้องปรับโค้ดการเลื่อนนิดหน่อย คือ return boolean กลับมาว่ามีการเลื่อน หรือ รวมกันเกิดขึ้นมัย

ตัวอย่างของการเลื่อนซ้าย

 

ถ้า method move มัน return true กลับมาก็คือเกิดการขยับหรือรวมกันเกิดขึ้นก็ให้สุ่มอันใหม่มาได้

b1

 

ทำป้ายแสดงคะแนน

ยังขาดเมนูสำหรับแสดงคะแนนของเกม และปุ่มเริ่มเกมใหม่ครับ

ประกาศตัแปรคะแนน

 

สร้างแถบเมนูของเกม โดยผมจะวางไว้ด้านบนของจอ ใส่ปุ่มเริ่มเกมใหม่ไปด้วย

 

ใส่เมนูไว้ด้านบน

b1

 

ต่อมาก็ บวกคะแนนเพิ่ม ตอนรวมบล็อกกัน

 

ผลลัพธ์

b3

 

เริ่มเกมใหม่

ขอยุบรวม การกำหนดค่าเริ่มต้นให้เกมเป็น method initGame()

 

จากนั้น restart() ก็คือ initGame()

b2

 

Game over

ทำหน้าจอแสดงการจบเกม โดยจะใช้เป็น dialog ว่า Game Over แล้วมีปุ่ม restart เกมอีกครั้ง
ก่อนอื่นเตรียมหน้าจอของ dialog

 

เขียน method เช็คว่า Game Over หรือยัง
วิธีการคือในตารางต้องไม่มีช่องว่าง และห้ามมีเลขเหมือนกันติดกันทั้งแนวตั้งและแนวนอน
ถ้าเข้าเงื่อนไข คือ จบเกม

 

จากนั้นก็เช็คเงื่อนไข ตอนที่เรากดปุ่มเลื่อนบล็อก

b3

 

 

จบแล้ว

จบแล้วจ้า นี่ก็คือทั้งหมดของเกม 2048 แบบคร่าวๆครับเขียนด้วย Flutter แบบหยาบๆ รวมๆแล้วก็สนุกดี ไม่ซับซ้อนเท่าไหร่ครับ

โค้ดบน Github

https://github.com/benznest/2048-game-flutter