ลำดับเหตุการณ์ใน Unity3D และการใช้ Coroutine บันทึกของฉัน กิจกรรมเกมและตัวอย่างในกิจกรรมการอัปเดตปกติของ Unity

เหตุการณ์ใน Unity3D แบ่งออกเป็นสามกลุ่มใหญ่:

เหตุการณ์ที่เกิดจากเหตุการณ์น้ำมัน (การโหลดฉาก การออกจากผู้ใช้)
เหตุการณ์กลุ่มนี้ดำเนินไปอย่างไม่ปกติ

เหตุการณ์ที่เรียกว่าเมื่อวาดเฟรม
ในกรณีนี้ สคริปต์ที่ใช้ทั้งหมดจะถูกเรียกในวงจรการวาดหน้าจอ ซึ่งหมายความว่าสคริปต์เหล่านี้จะส่งผลโดยตรงต่อ FPS (เฟรมต่อวินาที) ดังนั้นที่นี่คุณต้องทำงานอย่างระมัดระวังกับฟังก์ชันที่ต้องใช้เวลาในการประมวลผลมาก

เหตุการณ์ที่เกิดขึ้นระหว่างการคำนวณทางฟิสิกส์
และกลุ่มสุดท้าย ในการคำนวณทางฟิสิกส์ จะมีการสร้างเธรดที่แยกจากกันและเป็นอิสระ โดยจะมีการเรียกเหตุการณ์ในช่วงเวลาหนึ่ง ขนาดของช่วงเวลานี้สามารถกำหนดค่าได้ในรายการเมนู: แก้ไข -> การตั้งค่าโครงการ -> เวลา -> ขั้นเวลาคงที่

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

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

ลำดับของฟังก์ชันเหตุการณ์
ใน Unity3D มีเหตุการณ์จำนวนหนึ่งที่ดำเนินการตามลำดับเฉพาะ เราจะอธิบายขั้นตอนนี้ด้านล่าง:

ตื่น:ฟังก์ชันนี้จะถูกเรียกก่อนเริ่มฟังก์ชันใด ๆ เสมอ และทันทีหลังจากที่เตรียมใช้งานรูปแบบสำเร็จรูปแล้ว
เปิดเปิดใช้งาน:(เรียกว่าถ้าวัตถุใช้งานอยู่): ฟังก์ชันนี้จะถูกเรียกหลังจากเปิดใช้งานวัตถุแล้วเท่านั้น

ก่อนการอัพเดตเฟรมแรก

เริ่ม:เรียกว่าก่อนที่จะวาดเฟรมแรกเฉพาะเมื่อมีการกำหนดสคริปต์เท่านั้น

ในระหว่างเฟรม

บนแอปพลิเคชันหยุดชั่วคราว:เหตุการณ์นี้จะเกิดขึ้นที่ส่วนท้ายของเฟรมเมื่อมีการตรวจพบการหยุดชั่วคราว ซึ่งเกิดขึ้นอย่างมีประสิทธิภาพระหว่างการอัปเดตเฟรมปกติ หลังจาก OnApplicationPause จะมีการวาดเฟรมเพิ่มเติมหนึ่งเฟรมเพื่อแสดงหน้าต่างที่แสดงระหว่างการหยุดชั่วคราว

ขั้นตอนการอัปเดต
ในการติดตามตรรกะของเกม การโต้ตอบของวัตถุและภาพเคลื่อนไหว ตำแหน่งกล้อง ฯลฯ มีเหตุการณ์ต่างๆ มากมายที่คุณสามารถใช้ได้ กลไกทั่วไปในการทำงานส่วนใหญ่ให้สำเร็จอยู่ในฟังก์ชัน Update() แต่ก็มีฟังก์ชันอื่นๆ ด้วยเช่นกัน

แก้ไขการอัปเดต: FixedUpdate() ไม่ขึ้นอยู่กับ Update() และสามารถเรียกได้บ่อยขึ้นหรือน้อยลง (โดยปกติจะเรียกน้อยกว่าหาก FPS สูงเพียงพอ) เหตุการณ์นี้อาจเกิดขึ้นได้หลายครั้งต่อเฟรม หาก FPS ต่ำ และอาจไม่เกิดขึ้นเลยระหว่างเฟรมหาก FPS สูง การคำนวณและอัพเดตกลไกทางกายภาพทั้งหมดจะเกิดขึ้นทันทีหลังจาก FixUpdate() เมื่อใช้การคำนวณการเคลื่อนไหวภายใน FixUpdate() คุณไม่จำเป็นต้องคูณค่าของคุณด้วย Time.deltaTime นี่เป็นเพราะว่า FixUpdate() ถูกเรียกจากตัวจับเวลาอิสระที่มีอัตราเฟรม
อัปเดต: Update() ถูกเรียกหนึ่งครั้งต่อเฟรม นี่คือกิจกรรมหลักในการวาดเฟรม
อัปเดตล่าช้า: LateUpdate() จะถูกเรียกหนึ่งครั้งต่อเฟรม หลังจากที่ Update() เสร็จสิ้นแล้ว การคำนวณใดๆ ที่ดำเนินการใน Update() จะเสร็จสิ้นเมื่อมีการเรียก LateUpdate() การใช้งานหลักของ LateUpdate() คือการติดตามกล้องของบุคคลที่สาม หากคุณย้ายตัวละครของคุณในเหตุการณ์ Update() คุณสามารถย้ายกล้องและคำนวณตำแหน่งของกล้องได้ในเหตุการณ์ LateUpdate() เพื่อให้แน่ใจว่าตัวละครได้เดินไปจนสุดหน้ากล้องและรักษาตำแหน่งของเขาไว้แล้ว

กำลังเรนเดอร์ฉาก

ออนพรีคัล:เรียกว่าก่อนเกิดเหตุจะประกอบเข้ากล้อง ชุดประกอบจะกำหนดว่าวัตถุใดที่กล้องมองเห็นได้ OnPreCull จะถูกเรียกก็ต่อเมื่อฉากนั้น "ตัด" จากวัตถุที่มองไม่เห็น
OnBecameVisible / OnBecameInvisible:เรียกว่าเมื่อวัตถุปรากฏ/มองไม่เห็นด้วยกล้องใดๆ
OnWillRenderObject:เรียกหนึ่งครั้งต่อกล้องถ้าวัตถุนั้นมองเห็นได้
OnPreRender:ถูกเรียกก่อนที่กล้องจะเริ่มเรนเดอร์ฉาก
OnRenderObject:เรียกว่าเมื่อมีการวาดวัตถุทั้งหมดในฉากแล้ว คุณสามารถใช้ฟังก์ชัน GL หรือ Graphics.DrawMeshNow เพื่อสร้างภาพวาดของคุณเองบนกล้องนี้ได้
OnPostRender:เรียกว่าหลังจากฉากถูกเรนเดอร์บนกล้องแล้ว
OnRenderImage (รุ่น Pro เท่านั้น):เรียกว่าหลังจากเรนเดอร์ฉากเพื่อปรับแต่งภาพบนหน้าจอ
เปิด GUI:เรียกหลายครั้งต่อเฟรมเพื่อตอบสนองต่อเหตุการณ์อินเทอร์เฟซ เหตุการณ์การเติมตำแหน่งและสีจะถูกประมวลผลก่อน ตามด้วยเหตุการณ์การป้อนข้อมูลของแป้นพิมพ์/เมาส์
OnDrawGizmos:ใช้วาดกิสโม่บนเวที

โครูทีน
โดยทั่วไปแล้ว การเรียก Coroutine จะเกิดขึ้นหลังจากที่ฟังก์ชัน Update() กลับมา Coroutine เป็นฟังก์ชันที่สามารถหยุดการดำเนินการชั่วคราว (ผลผลิต) จนกว่าจะมีการดำเนินการ การใช้ Coroutines ในรูปแบบต่างๆ:

ผลผลิต: Coroutine จะดำเนินต่อไปหลังจากฟังก์ชัน Update() ทั้งหมดที่ถูกเรียกในเฟรมถัดไป
ให้ผลผลิต WaitForSeconds(2):ดำเนินการต่อหลังจากเวลาหน่วงที่ระบุเมื่อฟังก์ชัน Update() ทั้งหมดถูกเรียกใช้ในเฟรมแล้ว
ให้ผลผลิต WaitForFixedUpdate():ดำเนินต่อไปเมื่อมีการเรียกใช้ฟังก์ชัน FixUpdate() ทั้งหมดแล้ว
ผลผลิต WWW:ดำเนินการต่อเมื่อการโหลดเนื้อหา WWW เสร็จสมบูรณ์
ให้ผลผลิต StartCoroutine (MyFunc):การเชื่อมโยง Coroutine การเรียก Coroutine จะรอให้ฟังก์ชัน MyFunc ดำเนินการให้เสร็จสิ้น

การทำลายล้างวัตถุ

ทำลายล้าง:ฟังก์ชั่นนี้ถูกเรียกใช้ในเฟรมสุดท้ายของการดำรงอยู่ของวัตถุ (วัตถุสามารถถูกทำลายเพื่อตอบสนองต่อ Object.Destroy หรือเมื่อปิดฉาก)

เมื่อออก
ฟังก์ชันเหล่านี้ถูกเรียกใช้สำหรับวัตถุที่ใช้งานอยู่ในฉาก:

ในการสมัครออกจาก:ฟังก์ชันนี้ถูกเรียกใช้บนวัตถุในเกมทั้งหมดก่อนที่แอปพลิเคชันจะปิด ในตัวแก้ไข สิ่งนี้จะเกิดขึ้นเมื่อผู้ใช้หยุด PlayMode ใน Web Player สิ่งนี้จะเกิดขึ้นเมื่อมีการปิด Web Player
เปิดปิดการใช้งาน:ฟังก์ชันนี้จะถูกเรียกเมื่อวัตถุถูกปิดใช้งานหรือไม่ใช้งาน

ดังนั้นลำดับการดำเนินการสคริปต์ต่อไปนี้จึงเกิดขึ้น:

เหตุการณ์ตื่นทั้งหมด
กิจกรรมเริ่มต้นทั้งหมด
วนซ้ำ (โดยเพิ่มตัวแปรเวลาเดลต้า)
- ฟังก์ชั่น FixUpdate ทั้งหมด
- การพัฒนาเครื่องยนต์ฟิสิกส์
- ทริกเกอร์เหตุการณ์ OnEnter/Exit/Stay
- เหตุการณ์การชนกัน OnEnter/Exit/Stay
การเปลี่ยนแปลงของลำตัวแข็ง ตามการเปลี่ยนตำแหน่งและการหมุน
OnMouseDown/OnMouseUp เหตุการณ์อินพุตอื่นๆ
กิจกรรม Update() ทั้งหมด
แอนิเมชัน การผสมผสาน และการเปลี่ยนแปลง
กิจกรรม LateUpdate ทั้งหมด
กำลังเรนเดอร์

คำแนะนำ
หากคุณเรียกใช้ coroutines ใน LateUpdate พวกมันจะถูกเรียกหลังจาก LateUpdate ก่อนที่จะเรนเดอร์
Coroutines จะถูกดำเนินการหลังจากฟังก์ชัน Update() ทั้งหมด


ขอให้เป็นวันที่ดี!

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

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

ก่อนที่เราจะสร้างคลาสผู้จัดการที่จะจัดการการตั้งค่าเสียงและเพลง เราจะสร้างคลาสแบบอนุกรมที่เรียบง่าย มันจะถูกใช้เป็นแบบจำลองข้อมูลที่จะบันทึกใน JSON

การใช้ System.Collections; ใช้ System.Collections.Generic; ใช้ UnityEngine; //================================================ ============ // AudioSettingsModel // @usage model สำหรับการตั้งค่าเสียง // // พัฒนาโดย CodeBits Interactive // ​​​​https://cdbits.net/ //===== ================= ======================= AudioSettingsModel ระดับสาธารณะ ( เพลงบูลสาธารณะ = จริง; // ตั้งค่าสถานะรับผิดชอบเสียงบูลสาธารณะของเพลง = true; // ตั้งค่าสถานะรับผิดชอบเสียง)
ตอนนี้คุณสามารถเริ่มเขียนคลาสผู้จัดการได้แล้ว เราจะติดตั้งมันในขั้นตอนแรก ผู้จัดการรายนี้จะเป็นออบเจ็กต์ส่วนกลางและจะไม่ถูกลบเมื่อย้ายจากฉากหนึ่งไปอีกฉากหนึ่ง

การใช้ System.Collections; ใช้ System.Collections.Generic; ใช้ UnityEngine; ใช้ System.IO; //================================================ ============ // ตัวจัดการเสียง // @usage ทำงานร่วมกับการตั้งค่าเสียง // // พัฒนาโดย CodeBits Interactive // ​​​​https://cdbits.net/ //==== ================= ======================== AudioManager คลาสสาธารณะ: MonoBehaviour ( // สาธารณะ พารามิเตอร์ อินสแตนซ์ AudioManager คงที่สาธารณะ = null; // การตั้งค่า AudioSettingsModel คงที่สาธารณะ = null; // รูปแบบของการตั้งค่าเสียง สตริงคงที่ส่วนตัว _settings_path = ""; )( // ตั้งค่าพาธสำหรับการบันทึกการตั้งค่า _settings_path = Application.persistentDataPath + "/audioSettings.gdf" ; // ตรวจสอบว่ามีการตั้งค่าอินสแตนซ์ของผู้จัดการของเราหรือไม่หาก (อินสแตนซ์ == null)( // อินสแตนซ์ไม่ได้ตั้งค่าอินสแตนซ์ = นี่; // ตั้งค่าวัตถุปัจจุบันเป็นอินสแตนซ์ ) // ตั้งค่าพารามิเตอร์ที่ระบุ // สิ่งที่ไม่ควรลบวัตถุนี้เมื่อทำการขนถ่าย // ระดับ DontDestroyOnLoad(gameObject); // เริ่มต้นการตั้งค่าของผู้จัดการของเรา InitializeSettings (); (_ข้อมูล); // ยกเลิกการซีเรียลไลซ์ให้เป็นรุ่นปัจจุบัน) // บันทึกการตั้งค่าเสียง public void saveSettings())( string _json_data = JsonUtility.ToJson(settings); // ทำให้การตั้งค่าปัจจุบันเป็นอนุกรมจากโมเดล File.WriteAllText(_settings_path, _json_data); // บันทึกลงในไฟล์ของเรา ) // สร้างผู้รับมอบสิทธิ์สำหรับกิจกรรมของเรา ซึ่งจะถูกใช้เพื่อติดตามการเปลี่ยนแปลงในการตั้งค่าเสียง ผู้รับมอบสิทธิ์สาธารณะ ถือเป็นโมฆะ AudioSettingsChanged(); // เพิ่มเหตุการณ์สาธารณะที่ได้รับมอบสิทธิ์ใหม่ AudioSettingsChanged OnAudioSettingsChanged; // สร้างเหตุการณ์ตามนั้น // เปิด/ปิดเสียง public voidสลับเสียง(เปิดใช้งานบูล)( settings.sounds = เปิดใช้งาน; // เปลี่ยนการตั้งค่าเสียงในรุ่นปัจจุบัน saveSettings(_settings_path, settings); // บันทึกการตั้งค่าถ้า ( OnAudioSettingsChanged ! = null) OnAudioSettingsChanged(); // ทริกเกอร์เหตุการณ์ของเรา ) // เปิด/ปิดเพลงสาธารณะสลับเพลง(เปิดใช้งานบูล)( settings.music = เปิดใช้งาน; // เปลี่ยนการตั้งค่าเพลงในรูปแบบปัจจุบัน saveSettings(_settings_path, settings ); // บันทึกการตั้งค่าถ้า (OnAudioSettingsChanged != null) OnAudioSettingsChanged(); // โทรหากิจกรรมของเรา )
ตอนนี้ผู้จัดการพร้อมแล้ว คุณสามารถสร้างวัตถุว่างในฉากเริ่มต้นของคุณและตั้งชื่อเช่น "_AUDIO_MANAGER"แล้วเพิ่มผู้จัดการชั้นเรียนของเราเข้าไป ซึ่งสามารถทำได้ง่ายๆ โดยการเรียกเมนูเพิ่มส่วนประกอบบนออบเจ็กต์แล้วเลือก "ผู้จัดการเกม" => "ผู้จัดการเสียง".

หลังจากนี้ เราจำเป็นต้องเขียนส่วนประกอบที่เราจะแนบกับแต่ละวัตถุด้วย AudioSource

การใช้ System.Collections; ใช้ System.Collections.Generic; ใช้ UnityEngine; //================================================ ============ // Audio Muter // @usage เปิด/ปิดแหล่งกำเนิดเสียงบนวัตถุ // // พัฒนาโดย CodeBits Interactive // ​​​​https://cdbits.net/ //= ================= ============================ คลาสสาธารณะ AudioMuter: MonoBehaviour ( // พารามิเตอร์สาธารณะของบูลสาธารณะขององค์ประกอบ is_music = false; // การตั้งค่าสถานะนี้ทำให้ชั้นเรียนของเราชัดเจนไม่ว่าจะเป็นเสียงหรือเพลง // พารามิเตอร์ส่วนตัวของ AudioSource _as; // ปริมาตรพื้นฐานของ AudioSource // เตรียมใช้งานอ็อบเจ็กต์ void Start())( // รับส่วนประกอบ AudioSource และโวลุ่มเริ่มต้น _as = this.gameObject.GetComponent - // รับส่วนประกอบ _base_volume = _as.volume; // รับระดับเสียงพื้นฐาน // ที่นี่เราเพิ่มผู้ฟังที่จะดำเนินการเมธอด _audioSettingsChanged // เมื่อการตั้งค่าเพลง/เสียงมีการเปลี่ยนแปลง AudioManager.instance.OnAudioSettingsChanged += _audioSettingsChanged; // ติดตั้ง // ในตอนเริ่มต้นเราต้องตรวจสอบสถานะปัจจุบันของเสียง/เพลง _audioSettingsChanged();
) // เมื่อวัตถุถูกทำลาย void OnDestroy())( AudioManager.instance.OnAudioSettingsChanged -= _audioSettingsChanged; // Destroy the Listener ) // วิธีนี้ใช้เพื่อเปิด/ปิดระดับเสียงของ AudioSource private void _audioSettingsChanged()) ( if (is_music) _as.volume = (AudioManager.settings.music) ? _base_volume: 0F; if (!is_music) _as.volume = (AudioManager.settings.sounds) ?

วิธีนี้ทำให้เราสามารถควบคุมเสียง/เพลงในเกมได้ ตัวอย่างนี้ไม่ได้บอกวิธีการทำอย่างถูกต้อง แต่เพียงสาธิตการทำงานของระบบเหตุการณ์และผู้ฟังใน Unity3D เท่านั้น

และสุดท้ายนี้ผมอยากจะพูดถึงสิ่งที่เราใช้อยู่ตอนนี้ ในตัวอย่างด้านล่าง มีการประกาศผู้รับมอบสิทธิ์ซึ่งเป็นผู้ฟังที่ถูกสร้างขึ้น:
ผู้แทนสาธารณะถือเป็นโมฆะ AudioSettingsChanged (); เหตุการณ์สาธารณะ AudioSettingsChanged OnAudioSettingsChanged;

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

และด้วยความช่วยเหลือของผู้ร่วมประชุม คุณสามารถสร้างฟังก์ชันการโทรกลับได้ตามที่เราสร้าง Listener สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับวิธีการแบบอะซิงโครนัส (เช่น เมื่อส่งคำขอ POST แบบอะซิงโครนัส)

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

คุณสามารถช่วยเหลือและโอนเงินบางส่วนเพื่อการพัฒนาเว็บไซต์ได้

เมื่อทำงานกับเอ็นจิ้นเกม Unity3D หนึ่งในแนวคิดแรก ๆ ที่คุณต้องเรียนรู้คือลำดับการเรียกเหตุการณ์ในเกมและการประมวลผลเหตุการณ์เดียวกันเหล่านี้

แม้ว่าจะมีข้อมูลภาษารัสเซียค่อนข้างมากเกี่ยวกับเครื่องยนต์นี้ แต่ฉันไม่พบคำอธิบายเหตุการณ์ที่ถูกต้อง แต่ฉันพบบทความภาษาอังกฤษ Execution Order of Event Functions จากวิธีใช้ Unity3D

คำนำของผู้แปล

  1. เหตุการณ์ที่เรียกว่าเมื่อวาดเฟรม
    ในกรณีนี้ สคริปต์ที่ใช้ทั้งหมดจะถูกเรียกในวงจรการวาดหน้าจอ ซึ่งหมายความว่าสคริปต์เหล่านี้จะส่งผลโดยตรงต่อ FPS (เฟรมต่อวินาที) ดังนั้นที่นี่คุณต้องทำงานอย่างระมัดระวังกับฟังก์ชันที่ต้องใช้เวลาในการประมวลผลมาก
  2. เหตุการณ์ที่เกิดขึ้นระหว่างการคำนวณทางฟิสิกส์
    ในการคำนวณทางฟิสิกส์ จะมีการสร้างเธรดที่แยกจากกันและเป็นอิสระ โดยจะมีการเรียกเหตุการณ์ในช่วงเวลาหนึ่ง ขนาดของช่วงเวลานี้สามารถกำหนดค่าได้ในรายการเมนู: แก้ไข -> การตั้งค่าโครงการ -> เวลา -> ขั้นเวลาคงที่
  3. โครูทีน (Corutins)
    และกลุ่มสุดท้าย หากอยู่ในระยะไกลมากก็สามารถเปรียบเทียบได้กับกระบวนการที่แยกจากกัน แต่เนื่องจาก Unity3D ไม่อนุญาตให้สร้างเธรดแยกกัน นี่จึงเป็นการประนีประนอม ช่วยให้คุณสามารถขัดจังหวะการคำนวณ มอบทรัพยากรให้กับเธรดหลัก และจากนั้นดำเนินการส่วนถัดไปของการคำนวณต่อ ตัวอย่างที่เด่นชัดคือการคำนวณต้นทุนสินค้าที่ร้านค้าปลีกต่างๆ อย่างต่อเนื่อง มันจะทำงานด้วยตัวเอง ไม่ทำให้กระบวนการเกมช้าลง และราคาในร้านค้าจะเป็นปัจจุบันอยู่เสมอ

เมื่อทราบรายละเอียดนี้แล้ว คุณสามารถตัดสินใจได้ว่าควรวางโค้ดใดดีกว่า

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

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

ลำดับของฟังก์ชันเหตุการณ์

ใน Unity3D มีเหตุการณ์จำนวนหนึ่งที่ดำเนินการตามลำดับเฉพาะ เราจะอธิบายขั้นตอนนี้ด้านล่าง:

กำลังโหลดฉากเป็นครั้งแรก

ฟังก์ชั่นเหล่านี้จะถูกเรียกเมื่อฉากเริ่มต้น (หนึ่งครั้งสำหรับแต่ละวัตถุในเฟรม)

  • ตื่น:ฟังก์ชันนี้จะถูกเรียกก่อนเริ่มฟังก์ชันใด ๆ เสมอ และทันทีหลังจากที่เตรียมใช้งานรูปแบบสำเร็จรูปแล้ว
  • เปิดเปิดใช้งาน:(เรียกว่าถ้าวัตถุใช้งานอยู่): ฟังก์ชันนี้จะถูกเรียกหลังจากเปิดใช้งานวัตถุแล้วเท่านั้น

ก่อนการอัพเดตเฟรมแรก

  • เริ่ม:เรียกว่าก่อนที่จะวาดเฟรมแรกเฉพาะเมื่อมีการกำหนดสคริปต์เท่านั้น

ในระหว่างเฟรม

  • บนแอปพลิเคชันหยุดชั่วคราว:เหตุการณ์นี้จะเกิดขึ้นที่ส่วนท้ายของเฟรมเมื่อมีการตรวจพบการหยุดชั่วคราว ซึ่งเกิดขึ้นอย่างมีประสิทธิภาพระหว่างการอัปเดตเฟรมปกติ หลังจาก OnApplicationPause จะมีการวาดเฟรมเพิ่มเติมหนึ่งเฟรมเพื่อแสดงหน้าต่างที่แสดงระหว่างการหยุดชั่วคราว

ขั้นตอนการอัปเดต

ในการติดตามตรรกะของเกม การโต้ตอบของวัตถุและภาพเคลื่อนไหว ตำแหน่งกล้อง ฯลฯ มีเหตุการณ์ต่างๆ มากมายที่คุณสามารถใช้ได้ กลไกทั่วไปในการทำงานส่วนใหญ่ให้สำเร็จอยู่ในฟังก์ชัน Update() แต่ก็มีฟังก์ชันอื่นๆ ด้วยเช่นกัน

  • แก้ไขการอัปเดต: FixedUpdate() ไม่ขึ้นอยู่กับ Update() และสามารถเรียกได้บ่อยขึ้นหรือน้อยลง (โดยปกติจะเรียกว่าไม่บ่อยหาก FPS สูงเพียงพอ) เหตุการณ์นี้อาจเกิดขึ้นได้หลายครั้งต่อเฟรม หาก FPS ต่ำ และอาจไม่เกิดขึ้นเลยระหว่างเฟรมหาก FPS สูง การคำนวณและอัพเดตกลไกทางกายภาพทั้งหมดจะเกิดขึ้นทันทีหลังจาก FixUpdate() เมื่อใช้การคำนวณการเคลื่อนไหวภายใน FixUpdate() คุณไม่จำเป็นต้องคูณค่าของคุณด้วย Time.deltaTime นี่เป็นเพราะว่า FixUpdate() ถูกเรียกจากตัวจับเวลาอิสระที่มีอัตราเฟรม
  • อัปเดต: Update() ถูกเรียกหนึ่งครั้งต่อเฟรม นี่คือกิจกรรมหลักในการวาดเฟรม
  • อัปเดตล่าช้า: LateUpdate() จะถูกเรียกหนึ่งครั้งต่อเฟรม หลังจากที่ Update() เสร็จสิ้นแล้ว การคำนวณใดๆ ที่ดำเนินการใน Update() จะเสร็จสิ้นเมื่อมีการเรียก LateUpdate() การใช้งานหลักของ LateUpdate() มักจะเป็นการติดตามกล้องของบุคคลที่สาม หากคุณย้ายตัวละครของคุณในเหตุการณ์ Update() คุณสามารถย้ายกล้องและคำนวณตำแหน่งของกล้องได้ในเหตุการณ์ LateUpdate() เพื่อให้แน่ใจว่าตัวละครได้เดินไปจนสุดหน้ากล้องและรักษาตำแหน่งของเขาไว้แล้ว

กำลังเรนเดอร์ฉาก

  • ออนพรีคัล:เรียกว่าก่อนเกิดเหตุจะประกอบเข้ากล้อง ชุดประกอบจะกำหนดว่าวัตถุใดที่กล้องมองเห็นได้ OnPreCull จะถูกเรียกก็ต่อเมื่อฉากนั้น "ตัด" จากวัตถุที่มองไม่เห็น
  • OnBecameVisible / OnBecameInvisible:เรียกว่าเมื่อวัตถุปรากฏ/มองไม่เห็นด้วยกล้องใดๆ
  • OnWillRenderObject:เรียกหนึ่งครั้งต่อกล้องถ้าวัตถุนั้นมองเห็นได้
  • OnPreRender:ถูกเรียกก่อนที่กล้องจะเริ่มเรนเดอร์ฉาก
  • OnRenderObject:เรียกว่าเมื่อมีการวาดวัตถุทั้งหมดในฉากแล้ว คุณสามารถใช้ฟังก์ชัน GL หรือ Graphics.DrawMeshNow เพื่อสร้างภาพวาดของคุณเองบนกล้องนี้ได้
  • OnPostRender:เรียกว่าหลังจากฉากถูกเรนเดอร์บนกล้องแล้ว
  • OnRenderImage(รุ่น Pro เท่านั้น): เรียกหลังจากฉากถูกเรนเดอร์แล้ว เพื่อปรับแต่งภาพบนหน้าจอ
  • เปิด GUI:เรียกหลายครั้งต่อเฟรมเพื่อตอบสนองต่อเหตุการณ์อินเทอร์เฟซ เหตุการณ์การเติมตำแหน่งและสีจะถูกประมวลผลก่อน ตามด้วยเหตุการณ์การป้อนข้อมูลของแป้นพิมพ์/เมาส์
  • OnDrawGizmos:ใช้วาดกิสโม่บนเวที

โครูทีน

โดยทั่วไปแล้ว การเรียก Coroutine จะเกิดขึ้นหลังจากที่ฟังก์ชัน Update() กลับมา Coroutine เป็นฟังก์ชันที่สามารถหยุดการดำเนินการชั่วคราว (ผลผลิต) จนกว่าจะมีการดำเนินการ การใช้ Coroutines ในรูปแบบต่างๆ:

  • ผลผลิต: Coroutine จะดำเนินต่อไปหลังจากฟังก์ชัน Update() ทั้งหมดที่ถูกเรียกในเฟรมถัดไป
  • ให้ผลผลิต WaitForSeconds(2):ดำเนินการต่อหลังจากเวลาหน่วงที่ระบุเมื่อฟังก์ชัน Update() ทั้งหมดถูกเรียกใช้ในเฟรมแล้ว
  • ให้ผลผลิต WaitForFixedUpdate():ดำเนินต่อไปเมื่อมีการเรียกใช้ฟังก์ชัน FixUpdate() ทั้งหมดแล้ว
  • ให้ผลผลิต StartCoroutine (MyFunc):การเชื่อมโยง Coroutine การเรียก Coroutine จะรอให้ฟังก์ชัน MyFunc ดำเนินการให้เสร็จสิ้น

การทำลายล้างวัตถุ

  • ทำลายล้าง:ฟังก์ชั่นนี้ถูกเรียกใช้ในเฟรมสุดท้ายของการดำรงอยู่ของวัตถุ (วัตถุสามารถถูกทำลายเพื่อตอบสนองต่อ Object.Destroy หรือเมื่อปิดฉาก)

เมื่อออก

ฟังก์ชันเหล่านี้ถูกเรียกใช้สำหรับวัตถุที่ทำงานอยู่ทั้งหมดในฉาก:

  • ในการสมัครออกจาก:ฟังก์ชันนี้ถูกเรียกใช้บนวัตถุในเกมทั้งหมดก่อนที่แอปพลิเคชันจะปิด ในตัวแก้ไข สิ่งนี้จะเกิดขึ้นเมื่อผู้ใช้หยุด PlayMode ใน Web Player สิ่งนี้จะเกิดขึ้นเมื่อมีการปิด Web Player
  • เปิดปิดการใช้งาน:ฟังก์ชันนี้จะถูกเรียกเมื่อวัตถุถูกปิดใช้งานหรือไม่ใช้งาน

ดังนั้น เมื่อเสร็จสิ้นแล้ว เหตุการณ์ต่างๆ จะถูกเรียกตามลำดับต่อไปนี้:

  • เหตุการณ์ตื่นทั้งหมด
  • กิจกรรมเริ่มต้นทั้งหมด
  • วนซ้ำ (โดยเพิ่มตัวแปรเวลาเดลต้า)
    • คุณสมบัติ FixUpdate ทั้งหมด
    • ทดสอบเครื่องยนต์ฟิสิกส์
    • ทริกเกอร์เหตุการณ์ OnEnter/Exit/Stay
    • เหตุการณ์การชนกันของ OnEnter/Exit/Stay
  • การเปลี่ยนแปลงของลำตัวแข็ง ตามการเปลี่ยนตำแหน่งและการหมุน
  • OnMouseDown/OnMouseUp เหตุการณ์อินพุตอื่นๆ
  • กิจกรรม Update() ทั้งหมด
  • แอนิเมชัน การผสมผสาน และการเปลี่ยนแปลง
  • กิจกรรม LateUpdate ทั้งหมด
  • กำลังเรนเดอร์

หากคุณเรียกใช้ coroutines ใน LateUpdate พวกมันจะถูกเรียกหลังจาก LateUpdate ก่อนที่จะเรนเดอร์

Coroutines จะถูกดำเนินการหลังจากฟังก์ชัน Update() ทั้งหมด

ป.ล. นอกจากนี้จากผู้ใช้ Leopotam

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

ตัวอย่างเช่น:

IEnumerator FindBozons() ( var isFound = false ; var colliderSectionID = 0 ; var colliderSectionCount = 10 ; ในขณะที่ (! isFound) ( // ประมวลผลครั้งละหนึ่งส่วนเท่านั้นเพื่อลดภาระ isFound = ProcessDataFromSection(colliderSectionID); colliderSectionID = (colliderSectionID ++ ) % colliderSectionCount; ผลตอบแทนผลตอบแทนเป็นโมฆะ;-

กลไก Coroutine จะช่วยให้มั่นใจได้ถึงการบันทึกสถานะของบริบทการดำเนินการฟังก์ชันโดยอัตโนมัติและกลับสู่จุดหยุดชะงัก (ผลผลิต)

การเขียนสคริปต์ใน Unity ไม่เหมือนกับแนวคิดดั้งเดิมของโปรแกรมที่โค้ดจะทำงานอย่างต่อเนื่องในวงวนจนกว่างานจะเสร็จสิ้น แต่ Unity จะถ่ายโอนการควบคุมไปยังสคริปต์เป็นระยะเมื่อมีการเรียกใช้ฟังก์ชันบางอย่างที่ประกาศไว้ เมื่อฟังก์ชันดำเนินการเสร็จสิ้น การควบคุมจะกลับสู่ Unity ฟังก์ชันเหล่านี้เรียกว่าฟังก์ชันเหตุการณ์เพราะว่า พวกมันถูกเปิดใช้งานโดย Unity เพื่อตอบสนองต่อเหตุการณ์ที่เกิดขึ้นระหว่างเกม Unity ใช้รูปแบบการตั้งชื่อเพื่อกำหนดฟังก์ชันที่จะเรียกใช้เหตุการณ์เฉพาะ ตัวอย่างเช่น คุณเคยเห็นฟังก์ชัน Update (ถูกเรียกก่อนการเปลี่ยนแปลงเฟรม) และฟังก์ชัน Start (ถูกเรียกก่อนเฟรมแรกของออบเจ็กต์) แล้ว มีฟังก์ชันเหตุการณ์อีกมากมายใน Unity; รายการทั้งหมดพร้อมข้อมูลเพิ่มเติมเกี่ยวกับการใช้งานสามารถดูได้ที่หน้าเอกสารประกอบของคลาส MonoBehaviour ต่อไปนี้คือเหตุการณ์สำคัญและเกิดขึ้นบ่อยครั้งบางส่วน

กิจกรรมอัพเดทปกติ

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

การอัปเดตเป็นโมฆะ() ( ระยะทางลอย = ความเร็ว * Time.deltaTime * Input.GetAxis("แนวนอน"); แปลง.แปล(Vector3.right * ระยะทาง); )

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

เป็นโมฆะ FixUpdate() ( Vector3 force = Transformer.forward * driveForce * Input.GetAxis("Vertical"); Rigidbody.AddForce(force); )

บางครั้งก็มีประโยชน์เช่นกันที่สามารถทำการเปลี่ยนแปลงเพิ่มเติมได้ในเวลาที่ฟังก์ชัน Update และ FixUpdate ทำงานได้กับวัตถุทั้งหมดในฉากและภาพเคลื่อนไหวทั้งหมดได้รับการคำนวณแล้ว ตามตัวอย่าง กล้องควรยังคงล็อคอยู่กับวัตถุเป้าหมาย ต้องทำการปรับการวางแนวกล้องหลังจากที่วัตถุเป้าหมายเคลื่อนที่แล้ว อีกตัวอย่างหนึ่งคือเมื่อโค้ดสคริปต์จำเป็นต้องแทนที่เอฟเฟกต์ของแอนิเมชั่น (เช่น ทำให้หัวของตัวละครหันไปทางวัตถุเป้าหมายในฉาก) ในสถานการณ์ประเภทนี้ คุณสามารถใช้ฟังก์ชัน LateUpdate ได้

โมฆะ LateUpdate() ( Camera.main.transform.LookAt(target.transform); )

เหตุการณ์การเริ่มต้น

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

เหตุการณ์ GUI

Unity มีระบบสำหรับการเรนเดอร์การควบคุม GUI เหนือทุกสิ่งที่เกิดขึ้นในฉากและตอบสนองต่อการคลิกองค์ประกอบเหล่านั้น รหัสนี้ได้รับการจัดการแตกต่างจากการอัปเดตเฟรมปกติเล็กน้อย ดังนั้นจึงต้องวางไว้ในฟังก์ชัน OnGUI ที่จะมีการเรียกเป็นระยะๆ

เป็นโมฆะ OnGUI() ( GUI.Label(labelRect, "Game Over"); )

คุณยังสามารถกำหนดเหตุการณ์เมาส์ที่เริ่มทำงานบน GameObject ที่อยู่ในฉากได้ สามารถใช้เล็งปืนหรือแสดงข้อมูลตัวละครใต้เคอร์เซอร์ของเมาส์ มีชุดฟังก์ชันเหตุการณ์ OnMouseXXX (เช่น OnMouseOver, OnMouseDown) ที่อนุญาตให้สคริปต์ตอบสนองต่อการกระทำของเมาส์ของผู้ใช้ ตัวอย่างเช่น หากกดปุ่มเมาส์ในขณะที่เคอร์เซอร์ของเมาส์อยู่เหนือวัตถุใดวัตถุหนึ่ง ถ้ามีฟังก์ชัน OnMouseDown ในสคริปต์ของวัตถุนี้ ฟังก์ชันนั้นจะถูกเรียก

เหตุการณ์ฟิสิกส์

เอ็นจิ้นฟิสิกส์จะรายงานการชนกับวัตถุโดยการเรียกใช้ฟังก์ชันเหตุการณ์ในสคริปต์ของวัตถุนั้น ฟังก์ชั่น

สวัสดีทุกคน. วันนี้ฉันต้องการพูดคุยเกี่ยวกับวิธีที่คุณสามารถใช้กิจกรรมเกมนำเสนอและวิธีสร้างระบบกิจกรรมเกมที่ยอมรับได้อย่างสมบูรณ์ใน Unity ด้วยการคลิกสองครั้งโดยไม่ต้องใช้ UnityActions ที่แตกต่างกัน

บันทึก: บทความนี้ไม่ใช่ความจริงของความจริง นี่เป็นเพียงความคิดและประสบการณ์ของฉัน

ฉันไม่มีเวลาถ่ายรูปบทความ แต่ฉันต้องทำ! นั่นเป็นเหตุผลว่าทำไมภาพนี้จึงมาจาก Google!

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

  1. เชิงเส้น ตัวเลือกนี้หมายความว่ามีการดำเนินการเหตุการณ์จำนวน N จำนวนหลังจากเหตุการณ์ถัดไป
  2. ขนาน. ปลุกมากกว่าหนึ่งเหตุการณ์ในตัวจัดการหนึ่งคน
  3. ผสม นี่เป็นส่วนผสมของตัวเลือกแรกและตัวที่สอง

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

เพื่อให้คุณเข้าใจสิ่งที่ฉันหมายถึงโดยตัวจัดการ นี่คือตัวอย่าง: ทริกเกอร์, ปุ่มกด (แป้นคีย์บอร์ด), รังสี (Raycast) ฯลฯ
ภายใต้สิ่งกระตุ้น: การเล่นเสียง วัตถุที่กำลังเคลื่อนที่ ฯลฯ

โดยสรุป ฉันสร้างสถาปัตยกรรมต่อไปนี้:

ดูเหมือนค่อนข้างง่ายใช่ไหม? แม้ในแง่ซอฟต์แวร์ก็ไม่จำเป็นต้องโหลดการโน้มน้าวใจ (แม้ว่าฉันจะใช้งานได้ยากก็ตาม)

นี่คือลักษณะของคลาสพื้นฐานของกิจกรรมทั้งหมด:

การใช้ UnityEngine; // System.Collections.Generics; CoreEvent คลาสนามธรรมสาธารณะ: MonoBehaviour ( CoreEvent สาธารณะ nextEvent; // กิจกรรมถัดไป // รายการสาธารณะ รายการกิจกรรม;

การกระทำโมฆะนามธรรมสาธารณะ (); -

ในความคิดเห็น ฉันได้ระบุรายการเหตุการณ์ที่สามารถ/ควรกระตุ้นได้ ตัวอย่างเล็กๆ น้อยๆ:

การใช้ UnityEngine; LookEvent คลาสสาธารณะ: CoreEvent ( แทนที่สาธารณะ void Action() ( //if(nextEvent != null) nextEvent.Action(); //else print("Look"); ) )
ในตัวอย่างนี้ ฉันเพียงแต่ยกเหตุการณ์ต่อไปนี้ สำหรับรายการ/อาร์เรย์ให้ใช้การวนซ้ำ หากมีเหตุการณ์หนึ่งเกิดขึ้น

เราไม่ได้ระบุสิ่งใดในฟิลด์ nextEvent และนั่นก็เป็นเช่นนั้นเพราะว่า ในการใช้งาน เราได้ดูแลการประมวลผลค่า Null แล้ว
เงื่อนไขสำหรับค่า null อยู่ในเหตุการณ์ใดเหตุการณ์หนึ่ง นั่นคือ เงื่อนไขดังกล่าวถูกสร้างขึ้นสำหรับแต่ละเหตุการณ์ จริงๆ แล้ว สิ่งนี้ไม่จำเป็นหากคุณไม่ได้ใช้การประมวลผลแบบขนานในขั้นต้น คลาสนั้นไม่ใช่นามธรรมและ วิธีการ Action() เป็นเสมือน
ซึ่งทำให้สามารถ check ใน base class ได้ด้วยการเขียนเพียงครั้งเดียว แล้วจึงทำดังนี้

Public ovveride void Action() ( base.Action(); //บางฟังก์ชัน)

อย่างไรก็ตามที่นี่จะสะดวกกว่าสำหรับทุกคน ฉันตัดสินใจที่จะทำให้มันเป็นนามธรรมเพราะมันลดจำนวนโค้ดในคลาสเหตุการณ์พื้นฐาน + สิ่งนี้ลงอย่างมาก
จากมุมมองของการเขียนโปรแกรม จะเหมาะสมกว่าหากคุณทราบคำจำกัดความของคีย์เวิร์ด abstract

HandlerEvents ระดับสาธารณะ: MonoBehaviour (รายการสาธารณะ เหตุการณ์; // ระบุคลาสพื้นฐาน< events.Count; countEvent++) { if (events != null) events.Action(); // Вызываем только те события, которые указаны в листе (не null). } } } public enum TriggerType { Enter, Stay, Exit } public class TriggerHandler: HandlerEvents { public TriggerType triggerType; private void OnTriggerEnter2D(Collider2D other) { if (triggerType == TriggerType.Enter && other.GetComponentการเปิดตัวโมฆะเสมือนสาธารณะ () ( สำหรับ (byte countEvent = 0; countEvent ()) ปล่อย(); ) โมฆะส่วนตัว OnTriggerExit2D (Collider2D อื่น ๆ ) ( ถ้า (triggerType == TriggerType.Exit && other.GetComponent ()) ปล่อย(); ) โมฆะส่วนตัว OnTriggerStay2D (Collider2D อื่น ๆ ) ( ถ้า (triggerType == TriggerType.Stay && other.GetComponent

()) ปล่อย(); -

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

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