ข้ามไปยังเนื้อหา

แนะนำโครงสร้างพื้นฐาน

ส่วนนี้สรุปโครงสร้างพื้นฐานของการผสานรวม LightScript ครอบคลุมข้อกำหนดทางเทคนิคที่สำคัญ ตัวอย่างจากการใช้งานจริง หลักการตั้งชื่อ และเคล็ดลับด้านประสิทธิภาพ โดยอธิบายลูป update พฤติกรรมของมิเตอร์ ตรรกะการเรียกใช้เอฟเฟกต์ และชี้ให้เห็นข้อผิดพลาดที่พบบ่อย ไม่ว่าคุณจะกำลังดีบัก สร้างใหม่ตั้งแต่ต้น หรือดูแลรักษาโค้ดของผู้อื่น คู่มือนี้เน้นความชัดเจน ความเสถียร และประสิทธิภาพ ซึ่งเป็นมาตรฐานหลักของการผสานรวมคุณภาพสูง

ส่วนนี้ให้ภาพรวมโดยย่อของการตั้งค่า LightScript จากมุมมองของการดูแลรักษา โดยเน้นที่จุดที่มักเกิดปัญหาและวิธีสังเกตและแก้ไขบั๊ก เราจะเริ่มด้วยการอธิบายโครงสร้าง LightScript ในอุดมคติโดยย่อเพื่อให้คุณคุ้นเคยกับโค้ด จากนั้นจะครอบคลุมการแก้ไขปัญหา และปิดท้ายด้วยคำถามที่พบบ่อย

โครงสร้างพื้นฐานต้องมี <head>, <body> และ <script> การประกาศมิเตอร์และตัวควบคุมของผู้ใช้ทั้งหมดต้องอยู่ภายใน <head> การประกาศ canvas ทั้งหมดต้องอยู่ใน <body> ส่วนสิ่งอื่น ๆ ทั้งหมดควรวางไว้ในส่วน <script>

<head> เป็นหนึ่งในส่วนที่สำคัญและซับซ้อนที่สุดของ LightScript ทุกตัว ตัวควบคุมของผู้ใช้หรือมิเตอร์ที่ผิดพลาดในส่วนนี้อาจทำให้เกิดการแครชวนซ้ำ หรือทำให้ตัวมันเองและมิเตอร์ใด ๆ ที่ประกาศหลังจากนั้นไม่ทำงาน

เมื่อสร้างมิเตอร์ คุณต้องตรวจสอบให้แน่ใจว่า:

  • ไวยากรณ์ถูกต้องสมบูรณ์ (เพื่อหลีกเลี่ยงการแครชและมิเตอร์ที่เสีย)
  • ไม่มีชื่อมิเตอร์ซ้ำกัน (ชื่อที่ซ้ำจะถูกเขียนทับ)
  • ไม่มีมิเตอร์ที่ยื่นเกินขอบเขตหน้าจอ (ทำให้เกิดการแครชและข้อผิดพลาด)
  • ไม่มีตัวเลือกในมิเตอร์ที่ขาดหายไปหรือเกินมา (ทำให้เกิดการแครช)
  • มิเตอร์ทั้งหมดมีการปรับแต่งตามความละเอียด (เพื่อให้ทำงานได้สม่ำเสมอ)

สำหรับความละเอียด อัตราส่วนภาพที่พบบ่อยที่สุด ได้แก่:

  • 16:9 (3840x2160, 2560x1440, 1920x1080, 1600x900, 1366x768, 1360x768, 1280x720)
  • 16:10 (2560x1600, 1920x1200, 1680x1050, 1440x900, 1280x800)
  • 21:9 (5120x2160, 3440x1440)

โดยค่าเริ่มต้น เราใช้ความละเอียด 2560x1440

LightScript ทั้งหมดต้องรองรับอัตราส่วนภาพ 16:9, 16:10 และ 21:9 แม้ว่า 4:3 จะไม่ใช่สัดส่วนที่สำคัญของฐานผู้ใช้ของเรา แต่ก็ยังควรพิจารณาเพื่อความเข้ากันได้ในอนาคต

ต่อไปนี้เป็นตัวอย่างโครงสร้างของมิเตอร์ที่มีการตั้งค่าหลายความละเอียด:

ตำแหน่งและขนาดเริ่มต้นของมิเตอร์จะใช้กับความละเอียดอื่น ๆ ทั้งหมดที่อยู่ในอัตราส่วนภาพเดียวกัน ตัวอย่างเช่น หากคุณปรับมิเตอร์ให้ทำงานกับ 1600x900 ตั้งแต่แรก มิเตอร์นั้นควรทำงานได้อย่างถูกต้องกับความละเอียด 16:9 อื่น ๆ ทั้งหมด อย่างไรก็ตาม มีข้อยกเว้นอยู่ Fortnite มีตำแหน่งมิเตอร์ที่แตกต่างกันหลายตำแหน่งแม้จะอยู่ในอัตราส่วนภาพเดียวกัน และอัตราส่วนภาพบางแบบเองก็อาจทำให้เข้าใจผิดได้ ตัวอย่างเช่น 1366x768 ซึ่งเป็นความละเอียดที่พบบ่อยทั่วโลก มักถูกระบุว่าเป็น 16:9 แต่จริง ๆ แล้วไม่ใช่อัตราส่วน 16:9 ที่แท้จริง ซึ่งไม่ใช่เรื่องแปลก ในทำนองเดียวกัน อัตราส่วนอัลตร้าไวด์อย่าง 21:9 แทบไม่เคยตรงกับขนาดตามชื่อเรียก จากประสบการณ์ในฐานะนักพัฒนาการผสานรวม เราไม่เคยพบความละเอียด 21:9 ที่ตรงเป๊ะเลย แม้จะถูกระบุเช่นนั้นก็ตาม ด้วยเหตุนี้ ความละเอียดอัลตร้าไวด์แต่ละแบบจึงต้องสร้าง ทดสอบ และกำหนดค่าแยกกัน

การปรับแต่งทั้งหมดต้องวางไว้ระหว่างแท็กเปิด <meta> และแท็กปิด </meta> มิฉะนั้นจะไม่ทำงาน หากมิเตอร์เริ่มต้นของคุณอิงตาม 16:9 และทำงานสม่ำเสมอในความละเอียดเหล่านั้น คุณไม่จำเป็นต้องเพิ่มการปรับแต่งสำหรับความละเอียด 16:9 อื่น ๆ อย่างไรก็ตาม คุณต้องเพิ่มรายการสำหรับทุกความละเอียดในอัตราส่วนภาพอื่น (เช่น 16:10 และ 21:9) แม้ว่าอัตราส่วนจะสม่ำเสมอก็ตาม

สุดท้าย มิเตอร์ทุกตัวยกเว้นมิเตอร์ OCR ต้องมีช่วง HSL เพื่อทำงาน ช่วงเหล่านี้อาจซับซ้อนขึ้นจากปัจจัยต่าง ๆ เช่น:

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

คำแนะนำพื้นฐานเกี่ยวกับ HSL และพิกัดแบบนอร์มัลไลซ์มีอยู่ในเอกสารสำหรับนักพัฒนาของเราแล้ว และจะไม่กล่าวซ้ำในที่นี้ การทดสอบมิเตอร์เหล่านี้จะกล่าวถึงในส่วน “การระบุปัญหา” แต่สิ่งสำคัญที่ต้องเน้นย้ำคือ: ปริมาณการทดสอบที่จำเป็นในการยืนยันมิเตอร์ทั้งหมดอย่างสมบูรณ์คำนวณได้จาก (จำนวนมิเตอร์) × (จำนวนการปรับแต่งตามความละเอียด) × (จำนวนโหมดเกม) × (จำนวนตัวละครที่เล่นได้) × (ระยะเวลาเฉลี่ยของเกมหนึ่งเกม) ซึ่งอาจรวมกันเป็นการตรวจสอบหลายชั่วโมงต่อเกมได้ง่าย ๆ โดยเฉพาะหากไม่มีโหมดฝึกซ้อมหรือวิธีอื่นให้ใช้

รักษามิเตอร์ของคุณให้มีประสิทธิภาพ มาตรฐานของเราคือความสมบูรณ์แบบ

แท็ก <body> คือที่ที่ประกาศองค์ประกอบ canvas จริง ซึ่งควรมีลักษณะประมาณตัวอย่างต่อไปนี้เสมอ คุณสามารถเปลี่ยน id ของ canvas ได้หากต้องการ แต่ต้องแน่ใจว่าดึงมาใช้ในสคริปต์อย่างถูกต้อง

ประหยัดเวลาด้วยการคัดลอกและวางส่วนนี้

ในการผสานรวมทุกครั้ง ต้องมีสี่สิ่งเกิดขึ้นภายในแท็กนี้

  • ดึง canvas มาใช้สร้างบริบท 2D ของเรา
  • ลูป update แรกกำหนดค่ามิเตอร์ จากนั้นเรียกตัวเองซ้ำไปเรื่อย ๆ เพื่อรักษาค่าเหล่านั้น
  • ลูป update คอยอัปเดตตัวแปรของตัวควบคุมผู้ใช้
  • มิเตอร์จะเรียกใช้ฟังก์ชัน callback ของตนเมื่อเสถียร

เราได้ตั้งค่าโครงสร้างโค้ดพื้นฐานไว้แล้ว ขั้นตอนต่อไปคือการอธิบายลูปการทำงานที่เรียกใช้เอฟเฟกต์ตั้งแต่ต้นจนจบ

  1. UI ของวิดีโอเกมแสดงข้อมูลในรูปแบบแถบสี ปุ่ม กล่องข้อความ ฯลฯ SignalRGB จับข้อมูลนี้หลายครั้งต่อวินาที แต่อัตราการจับจริงขึ้นอยู่กับประสิทธิภาพของโค้ดของคุณเป็นอย่างมาก พูดให้ชัดคือ ลูปเดียวหรือตัวแปรที่ไม่ได้ประกาศเพียงตัวเดียวก็ทำให้สคริปต์ทั้งหมดของคุณเสียได้ และอาจทำให้ SignalRGB แครชด้วย ที่แย่กว่านั้นคือ การเขียนโค้ดที่ทำงานได้ในทางเทคนิคแต่ไม่มีประสิทธิภาพจนจับข้อมูลได้เพียง 1-2 FPS นั้นเกิดขึ้นได้ง่าย
  2. มิเตอร์แต่ละตัวที่ประกาศใน <head> ต้องมีขนาดเล็กและมีประสิทธิภาพที่สุดเท่าที่จะทำได้เพื่อลดภาระ คำนวณแต่เนิ่น ๆ และบ่อย ๆ มิเตอร์ที่กินพื้นที่ 25% ของหน้าจอไม่มีวันมีประสิทธิภาพ สำหรับมิเตอร์ OCR ให้จับตัวอักษรทีละตัวแทนที่จะจับทั้งคำ สำหรับแถบพลังชีวิตและมานา ให้ตรวจสอบเฉพาะส่วนที่จำเป็น รักษามิเตอร์ของคุณให้เล็กที่สุดเท่าที่จะทำได้
  3. มิเตอร์จับข้อมูลที่รีเฟรชในทุกลูป
  4. ก่อนหน้านี้ เราได้อธิบายการนิยามคลาส Meter ซึ่งเก็บข้อมูลมิเตอร์และเรียกใช้ callback เมื่ออาร์เรย์ข้อมูลเสถียร ที่ด้านบนสุดของสคริปต์ ให้ประกาศ Meter ทั้งหมดไว้ในบล็อกเดียว คุณจะจัดกลุ่มหรือเรียงตามตัวอักษรก็ได้ เพียงอย่าซ่อนไว้กระจัดกระจายในโค้ดหลายพันบรรทัด สุดท้ายคุณจะต้องปรับค่าความเสถียร และการพยายามจำว่าวางไว้ตรงไหนเป็นการเสียเวลา
  5. ภายในฟังก์ชัน update มิเตอร์เหล่านี้จะรับค่าจากตรรกะการอ่านหน้าจอในทุกลูป ตรรกะภายในจะประเมินความเสถียร และเมื่อเสถียรก็จะเรียกใช้ฟังก์ชัน callback ที่เกี่ยวข้อง
  6. ฟังก์ชัน callback เหล่านี้ควรประกาศไว้ในสคริปต์ของคุณแต่อยู่นอกฟังก์ชัน update ภายในฟังก์ชันเหล่านี้ ให้ตรวจสอบสถานะของค่า Meter (value, decreased, increased, diff) และใช้ค่าเหล่านั้นตัดสินว่าจะเล่นแอนิเมชันเอฟเฟกต์หรือไม่ การจัดโครงสร้างโค้ดแบบนี้ แทนที่จะใส่ทุกอย่างไว้ในลูป update โดยตรง ช่วยให้เราสร้างการผสานรวมที่ขยายขนาดได้

เมื่อคุณเข้าใจแนวคิดทั่วไปแล้ว เราจะอธิบายตัวอย่างลูปจากการใช้งานจริงอย่างรวดเร็ว

  • เรากำลังเล่นเกม League of Legends ซึ่งมีไฮไลต์สีเหลืองสว่างล้อมรอบสกิลที่พร้อมใช้งาน
  • ในแต่ละลูป มิเตอร์ของสกิลนั้นจะจับสีนี้เป็นค่า “1” เนื่องจากผ่านช่วง HSL ของมิเตอร์อย่างสมบูรณ์
  • ค่า “1” นี้จะถูกส่งไปยังอินสแตนซ์ Meter ที่ผูกกับมิเตอร์อ่านหน้าจอ และใส่ลงในอาร์เรย์ข้อมูลของ Meter นั้น
  • หากค่าทุกค่าในอาร์เรย์นั้นเป็น “1” จะถือว่าเสถียร และจะเรียกใช้ฟังก์ชัน callback ของเอฟเฟกต์ที่ผูกไว้ ฟังก์ชัน callback นี้จะถูกเรียกใช้เช่นกันหากทุกค่าเป็น “0” หรือ “.1” เป็นต้น สิ่งที่ Meter สนใจมีเพียงความเสถียรเท่านั้น ข้อสังเกตสำคัญคือ ฟังก์ชัน callback จะไม่ถูกเรียกใช้ต่อเนื่องหาก Meter เสถียรอยู่ที่ค่าเดิมตลอด มีเพียงความเสถียรที่ค่าใหม่เท่านั้นที่จะเรียกใช้ callback
  • เมื่อฟังก์ชัน callback ทำงาน เราจะมาถึงการตรวจสอบเงื่อนไข ในกรณีนี้ สิ่งที่ต้องทำคือตรวจสอบว่า Meter.value เป็น “0” หรือไม่ ซึ่งบ่งบอกว่ามีการใช้สกิลแล้ว
  • เนื่องจาก Meter value เป็น “1” การตรวจสอบนี้จึงไม่ผ่าน และจะไม่เล่นเอฟเฟกต์สกิล
  • ไม่กี่วินาทีต่อมา เราใช้สกิล และไฮไลต์สีเหลืองรอบปุ่มก็หายไป
  • ค่ามิเตอร์ใหม่คือ 0 ซึ่งถูกส่งไปยังคลาส Meter ของมัน
  • เมื่อถึงความเสถียร callback จะทำงานและผ่านเงื่อนไขของเรา จึงเล่นเอฟเฟกต์สกิล ความหน่วงขึ้นอยู่กับความยาวของอาร์เรย์ Meter ทั้งหมด ซึ่งคุณกำหนดไว้ตอนประกาศ ความยาวมากขึ้นหมายถึงความหน่วงมากขึ้นและการทำงานผิดพลาดน้อยลง ดังนั้นอย่าลืมทดสอบจนกว่าจะพบจุดสมดุลที่ดี

มิเตอร์อ่านหน้าจอ ควรมีชื่อที่เรียบง่าย ชัดเจน และสื่อความหมาย โดยขึ้นต้นด้วยตัวพิมพ์เล็กเสมอ การตั้งชื่อมิเตอร์แถบพลังชีวิตว่า “healthBar” นั้นยอดเยี่ยม การตั้งชื่อมิเตอร์สองตัวว่า “healthBarRed” และ “healthBarGreen” เมื่อติดตามสีต่างกันในพื้นที่เดียวกันก็ดีมากเช่นกัน แต่การตั้งชื่อมิเตอร์เล็ก ๆ ที่ปรากฏเฉพาะระหว่างเอฟเฟกต์ท่าไม้ตายของฮีโร่ตัวหนึ่งว่า “hrO21_yes” จะสร้างแต่ความเจ็บปวดให้กับใครก็ตามที่พยายามแก้ไขโค้ดของคุณ การหาว่ามิเตอร์เล็ก ๆ ที่ตั้งชื่อไม่ดีกำลังติดตามอะไรอยู่อาจต้องใช้เวลาจ้องพิกเซลทีละจุดเป็นชั่วโมงหากโชคไม่ดี ดังนั้นอย่าทำแบบนี้

อินสแตนซ์ของคลาส Meter ควรขึ้นต้นด้วยตัวพิมพ์ใหญ่และลงท้ายด้วยคำว่า Meter ตัวอย่างเช่น “Q_Meter”, “TookDamageMeter” และ “TowerDestroyedMeter” ล้วนใช้ได้ดี ชื่อเหล่านี้ควรแยกแยะได้ชัดเจนจากมิเตอร์ที่ประกาศในส่วน <head>

ฟังก์ชันเอฟเฟกต์ ก็ควรตั้งชื่อให้เรียบง่ายและสื่อความหมายมากที่สุดเท่าที่จะทำได้เช่นกัน บางเกมมีฟังก์ชันเหล่านี้หลายร้อยตัว บางเกมอาจมีไม่ถึงสิบตัว หากฮีโร่หลายตัวมีสกิลเฉพาะ ให้ใส่ชื่อฮีโร่เป็นคำนำหน้า เช่น “SonaQ”, “ChamberE” หรือ “AshUlt” ตัวอย่างเช่น ใน League of Legends มีฟังก์ชันอย่าง “DragonEffect”, “TowerEffect” และ “Q_Effects” ซึ่งมีเงื่อนไขหลายข้อและถูกใช้โดยมิเตอร์หลายตัว ดังนั้นการตั้งชื่อแบบนี้จึงช่วยในการปรับให้รองรับการขยายขนาดได้ด้วย

อย่าสะกดคำผิด หากไม่แน่ใจว่าสะกดอย่างไร ให้ค้นหาดู ชื่อต้องชัดเจนและอ่านง่าย ไม่ว่าใครจะเป็นผู้ทำงานกับโค้ด หรือเวลาจะผ่านไปนานเท่าใด การจัดเรียงชื่อตามตัวอักษรช่วยให้ค้นหาได้รวดเร็ว โดยเฉพาะหากคุณต้องแก้ไขส่วนนั้นบ่อย ๆ แม้การจัดระเบียบระดับนี้ไม่จำเป็นต่อการทำงานของโค้ด แต่ก็สร้างความแตกต่างอย่างมากให้กับนักพัฒนาฝ่ายดูแลรักษาของเรา