วันอังคารที่ 23 กุมภาพันธ์ พ.ศ. 2559

construct 2 : Random ไม่ซ้ำ


บทความนี้จะขอนำเสนอวิธีการสุ่มตัวเลข หรือ random แบบไม่ให้ตัวเลขที่ได้ซ้ำกัน โดยอาศัยคุณสมบัติของ array ซึ่งวิธีการนี้รับรองผลได้ 100% ว่าข้อมูลที่ได้ไม่มีทางที่จะซ้ำกันอย่างแน่นอน
กรณีตัวอย่างของปัญหา สมมุติว่า ต้องการสุ่มตัวเลขตั้งแต่ 1 - 100 ที่ไม่ซ้ำกัน จำนวน 10 ตัวเลข
วิธีการ 
1. สร้าง array แบบ 1 มิติ ที่มีขนาด width = 10 เพื่อให้เก็บข้อมูลที่ได้จากการสุ่ม
2. วนซ้ำจำนวน 10 รอบ
2.1 สุ่มตัวเลขมา 1 ตัวเลข ตรวจสอบว่า ตัวเลขที่สุ่มได้ อยู่ใน array หรือไม่
2.2  ถ้าตัวเลขอยู่ใน array แล้ว ย้อนกลับไปทำข้อ 2.1
2.3 ถ้าตัวเลข ไม่อยู่ใน array ให้เพิ่มตัวเลขลงใน array แล้ววนซ้ำรอบต่อไป
3. เมื่อครบ 10 รอบ แล้ว ข้อมูลตัวเลขที่อยู่ใน array  คือ ตัวเลขที่สุ่มได้ โดยไม่ซ้ำกัน

ลงมือสร้างโปรแกรม
เปิดโปรแกรม construct 2 ขึ้นมา สร้าง Project ใหม่
เพิ่มวัตถุ array เข้ามาในโปรแกรม ตั้งชื่อว่า rand_arr กำหนดค่า width = 10



เพิ่มตัวแปร Global  ชื่อ rand_num เพื่อใช้เก็บค่าตัวเลขที่ได้จากการสุ่ม
เพิ่มเหตุการณ์เพื่อให้เกิดการ random ข้อมูล ผมกำหนดให้สุ่มข้อมูลเมื่อมีการใช้งาน layout
Add event --> System --> On start of Layout
Add action --> array rand_arr --> Clear (ลบข้อมูลใน array)
Add sub event --> System --> repeat 10 time
เพิ่มการสุ่มข้อมูลมาเก็บไว้ที่ตัวแปร rand_num โดย Add action --> System --> Set value เลือกตัวแปร rand_num และกำหนดค่าเป็น floor(rand(1,100)) คือ สุ่มค่าตัวเลขจำนวนเต็ม 1- 100



เพิ่มการตรวจสอบ ให้วนสุ่มค่าตัวเลขไปเรื่อยๆ ถ้าตัวเลขที่สุ่มได้ เป็นค่าที่ซ้ำใน array
Add sub event --> System --> while
Add another condition --> array rand_arr --> contains value --> rand_num
Add action --> System --> Set value เลือกตัวแปร rand_num
โปรแกรมจะทำการสุ่มตัวเลขใหม่เรื่อยๆ จนไม่ซ้ำกับตัวเลขที่อยู่ใน array ก็จะหลุดออกมาจาก การวนซ้ำ while

ถ้าตัวเลขที่สุ่มได้ ไม่ซ้ำ กับข้อมูลใน array ให้เพิ่มข้อมูลลงใน array
Add blank sub-event
Add action --> array rand_arr --> set at x --> กำหนด x = loopindex และ value = rand_num

คำสั่งทั้งหมด เป็นดังนี้



เมื่อทดสอบการทำงานใน debug mode จะพบว่า ค่าที่ได้จากการ random ตัวเลขจำนวน 10 ตัว จะไม่ซ้ำกันเลย


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

วันศุกร์ที่ 19 กุมภาพันธ์ พ.ศ. 2559

construct 2 : Mysql to array

บทความนี้ ผมจะขอนำเสนอการอ่านข้อมูลจากฐานข้อมูล mysql มาเก็บไว้ที่ตัวแปรแบบ  array เพื่อนำไปใช้ประโยชน์ในการทำงานของเกมต่อไป  โดยเฉพาะการอ่านข้อมูลของผู้เล่นที่มีการบันทึกเอาไว้ในฐานข้อมูล  เมื่อมีการเข้าเล่นเกม โดยปกติจะต้องอ่านข้อมูลของผู้เล่นขึ้นมา เพื่อบอกว่าผู้เล่นมีชื่อว่าอะไร เล่นผ่านด่านอะไรแล้ว ได้คะแนนเท่าไรในแต่ละด่าน หรือการเก็บทักษะในการเล่นต่าง ๆ
การเชื่อมต่อกับฐานข้อมูล mysql ผมได้นำเสนอไว้ที่บทความ การเชื่อมต่อฐานข้อมูล  สามารถย้อนไปศึกษาเพิ่มเติมได้ ผมจะไม่ขอกล่าวย้อนอีกครั้งนะครับ ในบทความนี้ขอสมมุติว่า เข้าใจเรื่องการเชื่อมต่อฐานข้อมูลแล้ว และการอ่านฐานข้อมูลด้วย AJAX แล้วนะครับ  ฐานข้อมูลที่ผมจะใช้ในการนำเสนอวันนี้ คือ ตารางคะแนนเกม ชื่อ game สร้างตารางข้อมูล และใส่ข้อมูลเบื้องต้นไว้เล็กน้อยนะครับ มีรายละเอียดตาราง ดังนี้



สร้างไฟล์สำหรับอ่านข้อมูลจากฐานข้อมูล mysql เป็นไฟล์ชื่อ getuser.php ด้วยคำสั่ง ดังนี้
header('Access-Control-Allow-Origin: *');
header("Content-Type: text/html; charset=UTF-8");

$host = "localhost"; //database location
$user = "root"; //database username
$pass = "mypassword"; //database password
$db_name = "mydatabase"; //database name

//database connection
$link = mysql_connect($host, $user, $pass);
mysql_select_db($db_name);

// Retrieve data from database
$sql="SELECT gID,userID, level, score FROM game";
$result=mysql_query($sql);
while($rows=mysql_fetch_array($result)){
echo $rows['gID'] . "|" .$rows['userID'] . "|" . $rows['level']."|" . $rows['score']. ",";
}
mysql_close();
?>

อย่าลืมเปลี่ยนชื่อฐานข้อมูล ชื่อผู้ใช้และรหัสผ่าน เป็นของตัวเองนะครับ ขึ้นอยู่กับว่ากำหนดไว้ตอนติดตั้ง appserv เป็นอะไร แต่ละคนก็ไม่เหมือนกัน แล้วนำไปเก็บไว้ในตำแหน่งของ www ที่ได้ติดตั้งไว้แล้ว  กรณีของผม ผมสร้างไว้ใน /www/construct/  ทดสอบเรียนใช้งาน ดูว่ามีข้อมูลอะไรเขียนออกมาหรือเปล่า  ผมทดสอบโดยพิมพ์ http://localhost/construct/getuser.php ก็จะมีข้อมูลจากฐานข้อมูลแสดงออกมา



ข้อมูลแต่ละตัวจะคั่นด้วย |  และแต่ละชุดข้อมูลจะคั่นด้วย ,  ซึ่งอาจจะกำหนดเป็นอย่างอื่นได้ในไฟล์ getuser.php ตามที่ผู้เขียนเกมเห็นเหมาะสมนะครับ เพราะเราจะใช้เป็นตัวอ้างอิงในการตัดแบ่งข้อมูล

ต่อไปมาเริ่มงานที่โปรแกรม construct 2 สร้างโปรเจคใหม่ หรือจะใช้โปรแกรมเดิมก็ได้ครับ
เพิ่มวัตถุแบบ array เข้ามาที่เกมของเรา ตั้งชื่อเป็น datagame



แล้วแทรกวัตถุ AJAX เข้ามาในเกมของเรา



เพิ่มเหตุการณ์ เมื่อมีการทำงานกับ layout ใหม่
Add event --> System --> On start of layout
เพิ่มคำสั่งในการเชื่อมต่อฐานข้อมูลด้วย AJAX  ดังนี้
Add action --> AJAX --> Request URL
แล้วกำหนดค่า ดังนี้
Tag  = "getuser"   คือการกำหนดชื่อให้กับการทำงานของ AJAX
URL = "http://localhost/construct/getuser.php" คือ การอ่านข้อมูลจากไฟล์ php ที่เราได้สร้างไว้แล้ว



ขั้นต่อไป นำข้อมูลที่ได้จากการอ่านฐานข้อมูล mysql มาลงใน array ที่เราได้สร้างเอาไว้แล้ว
Add event --> AJAX --> on completed --> "getuser"
คือ เหตุการณ์ที่จะทำงานเมื่ออ่านข้อมูล AJAX จาก tag "getuser" สำเร็จแล้ว
กำหนดขนาดของ array ให้มีขนาดเท่ากับชุดข้อมูลที่อ่านมา
Add action --> Array datagame --> Set size
กำหนด width เท่ากับ จำนวนชุดข้อมูลจากการตัดข้อความด้วยเครื่องหมาย ,  ด้วยคำสั่งtokencount(AJAX.LastData,",")-1
Height เท่ากับ 4 คือ ให้มี 4 คอลัมน์ ตามข้อมูลที่มีในแต่ละชุด


วน loop เพื่อนำข้อมูลไปเก็บยัง array ที่สร้างไว้ ด้วยคำสั่ง ดังนี้


การกำหนดตำแหน่งของข้อมูลใน array กำหนดดังนี้


หลักการทำงานของคำสั่ง token
    คำสั่ง token จะใช้ในการตัดกลุ่มคำออกเป็นกลุ่มย่อยๆ ตามเงื่อนไขของตัวแบ่งที่กำหนด คำสั่งที่สำคัญที่ใช้บ่อย ๆ คือ
        tokencount  เป็น คำสั่งที่ใช้ในการนำจำนวนกลุ่มย่อยของคำที่แบ่งออกมาได้ เช่น tokencount("abxacxayxaz","x") คือนับจำนวนกลุ่มย่อยที่แบ่งด้วยตัว x  จะได้ค่า 4
        tokenat  เป็นคำสั่งที่อ้างถึงกลุ่มคำย่อยที่ถูกแบ่งด้วยตัวแบ่งคำ  เช่น tokenat("abxacxayxaz",0,"x")  คือ กลุ่มย่อยที่ 0 จากการแบ่งคำด้วยตัว x จะได้ข้อความ ab  ออกมา

หลักการคือ แบ่งชุดข้อมูลด้วยตัวอักษร ,  จะได้ชุดข้อมูลของผู้เล่นแต่ละคน  แล้วทำการวนซ้ำในแต่ละชุดข้อมูลด้วยการแยกข้อมูลจากตัวอักษร | จะได้ 4 ข้อมูล แล้วจัดเก็บลงใน array แต่ละตำแหน่ง
เมื่อทดสอบการทำงานของโปรแกรม จะพบข้อมูลใน array ตามข้อมูลที่ได้อ่านมาจากฐานข้อมูล



วันศุกร์ที่ 5 กุมภาพันธ์ พ.ศ. 2559

Delta-time and framerate independence

Framerate independent games คือ เกมที่ทำงานด้วยความเร็วที่เท่ากัน โดยไม่ยึดติดกับอัตราเร็วของเฟรม  เช่น เกมที่สร้างอาจจะมีความเร็ว 30 fps (Frames Per Second) เมื่อทำงานบนเครื่องคอมพิวเตอร์ที่ช้า และอาจมีความเร็ว 60 fps เมื่อทำงานบนเครื่องคอมพิวเตอร์ที่เร็วกว่า เป็นต้น framerate independent games จะประมวลผลให้ความเร็วของเกมเท่ากันเมื่อทำงานบนคอมพิวเตอร์ทั้งสองเครื่อง ความเร็วของวัตถุต่าง ๆ ในเกม จะเคลื่อนที่ด้วยความเร็วที่เท่ากัน หากไม่ใช้หลักการนี้ เมื่อเกมทำงานบนเครื่องที่มีความเร็วต่ำกว่า จะเหมือนกับการแสดงภาพแบบช้า (slow-motion effect) การสร้าง framerate independent games มีความสำคัญมากต่อผู้เล่น ที่จะทำให้เล่นเกมด้วยความสนุกและเล่นได้ทุกคน โดยไม่ต้องกังวลว่าจะเล่นบนคอมพิวเตอร์แบบไหนได้บ้าง เกมจะปรับเปลี่ยนความเร็วไปตามความเร็วของเครื่องคอมพิวเตอร์ที่ใช้งาน

The dt system expression
หลักสำคัญของการสร้าง framerate independence คือการใช้ตัวแปร dt ซึ่งย่อมาจาก Delta-time ซึ่งเป็นการเปลี่ยนแปลงในปริมาณที่น้อยมาก ในเสี้ยววินาที  ยกตัวอย่างเช่น ที่ความเร็ว 100 fps ค่า dt จะเป็น 0.01 (หนึ่งร้อยวินาที) และที่ความเร็ว 10 fps ค่า dt จะเป็น 0.1 (10 วินาที) ในทางปฏิบัติ ค่า dt นั้นจะเปลี่ยนไปตามช่วงเวลาที่มีการทำงานของเกม ดังนั้น ตลอดช่วงเวลาของเกม ค่า dt นั้นจะเปลี่ยนแปลงไปอยู่เสมอ

ข้อสังเกต ถ้าหากเราเพิ่มค่า dt ให้กับตัวแปรทุกรอบสัญญาณนาฬิกา คือการเพิ่มทีละ 1 ทุกวินาที เพราะว่าช่วงเวลาของสัญญาณนาฬิกาจะอยู่ในช่วง 1 วินาที สามารถศึกษาตัวอย่างของการใช้ค่า dt ได้จากไฟล์เกมต่อไปนี้ คลิกเพื่อดาวน์โหลด

How to use dt
โดยทั่วไป การเคลื่อนไหวจะขึ้นอยู่กับอัตราของ framerate การเคลื่อนที่ในทุกรอบของสัญญาณนาฬิกา (1 รอบต่อ 1 เฟรม)



วัตถุจะเคลื่อนที่ไปทางขวา 1 pixel ถ้ากำหนดให้ 30 fps หมายความว่า เคลื่อนที่ 30 pixel ต่อวินาที และถ้ากำหนดให้ 60 fps หมายความว่า เคลื่อนที่ 60 pixel ต่อวินาที จะเห็นว่า ความเร็วของวัตถุมีความแตกต่างกันใน 1 วินาที ความเร็วที่ต่างกันนี้ขึ้นอยู่กับอัตราเร็วของเฟรมที่กำหนด
การเคลื่อนที่แบบอิสระโดยไม่ขึ้นกับ framerate วัตถุจะเคลื่อนที่ไปทางขวา  60 pixel ต่อวินาที ในทุกอัตราเร็วของเฟรม ในการกำหนดค่า dt เป็น 1 จะถูกเพิ่มขึ้น 1 ในทุกวินาที


ถ้ากำหนด 60 * dt คือการเพิ่มขึ้น 60 ในทุกวินาที ดังนั้น ไม่ว่าจะกำหนดความเร็วของเฟรมเป็น 30 fps หรือ 60 fps วัตถุก็จะเคลื่อนที่ไปทางขวาด้วยความเร็ว 60 pixel ต่อวินาทีเท่าเดิม

ในการสั่งให้วัตถุเคลื่อนที่ด้วยความเร็วคงที่ จำเป็นต้องใช้ dt ในการกำหนดค่าความเร็วในการเคลื่อนที่ เพื่อให้วัตถุเคลื่อนที่ได้อย่างอิสระ โดยไม่ขึ้นกับอัตราเร็วของเฟรม สมมุติว่าเราสั่งให้วัตถุเคลื่อนที่ไปด้านหน้า ควรใช้คำสั่ง 60 * dt ในการเคลื่อนที่วัตถุไป 60 pixel ต่อวินาที ในมุมและทิศทางเดิม

การทำงานของค่า dt จะถูกฝังตัวอยู่ในทุกพฤติกรรมของ construct 2 ดังนั้น ผู้พัฒนาเกมสามารถเรียกใช้งานได้ โดยไม่ต้องกำหนดค่าใด ๆ เพิ่มเติม สามารถเรียกใช้งานได้ทันที ยกเว้นเพียงแค่พฤติกรรมแบบ Physics โดยปกตินั้น จะไม่สามารถเรียกใช้งาน dt ได้ทันที ด้วยเหตุที่ว่า ค่า dt จะเกิดจากการสุ่มค่าที่มีการเปลี่ยนแปลงเล็กน้อย เมื่อสั่งเกมทำงานในลักษณะของการแสดงพฤติกรรมแบบ Physics ในแต่ละครั้งจะให้ผลการทำงานที่แตกต่างกันออกไป จึงนิยมใช้การเคลื่อนที่แบบยึดติดกับอัตราเร็วของเฟรม เพื่อให้การทำงานได้ผลเช่นเดียวกันทุกครั้ง แต่หากต้องการใช้งานค่า dt สามารถทำได้โดย การกำหนดค่า Set stepping mode จาก fixed เป็น Framerate independent


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

Timescaling
คุณสมบัติที่น่าสนใจอีกอย่างหนึ่งของ construct 2 คือ timescaling คุณสมบัตินี้จะทำให้ผู้สร้างเกมสามารถเปลี่ยนอัตราของเวลาภายในเกมได้ เรียกว่า time scale การกำหนดค่าของ time scale หากกำหนดเป็น 1 จะเป็นค่าความเร็วพื้นฐาน ถ้ากำหนดเป็น 0.5 ความเร็วจะลดลงครึ่งหนึ่ง และถ้ากำหนดเป็น 2 ความเร็วจะเพิ่มขึ้นเป็นสองเท่า ถ้ากำหนดเป็น 0.1 เวลาก็จะช้าลง 10 เท่า แต่ก็ยังมีความต่อเนื่อง ซึ่งสามารถนำไปใช้กับการสร้างภาพช้า slow-motion ได้เป็นอย่างดี

การทำงานของ timescaling  จะเปลี่ยนแปลงค่าจากตัวแปร dt ดังนั้น ถ้าผู้สร้างเกมไม่ได้ใช้ค่า dt ในการคำนวณการเคลื่อนที่ จะส่งผลให้ไม่สามารถใช้คุณสมบัติของ time scale ได้ แต่ถ้าเราใช้ time scaling จะส่งผลให้เปิดใช้งานตัวแปร dt ในการเคลื่อนที่ทั้งหมด

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