วิธีจัดการกับความแตกต่างระหว่างพิกัดหน้าจอ 2D และพิกัดคาร์ทีเซียน


23
  • ระบบพิกัดหน้าจอ / บิตแมป 2D ส่วนใหญ่มีแกน Y บวกที่ชี้ลง (โดยมีจุดเริ่มต้นที่มุมซ้ายบน)
  • นี่เป็นสิ่งที่ตรงกันข้ามกับที่คนส่วนใหญ่คิดเชิงเรขาคณิตโดยมีแกน Y บวกชี้ขึ้น (โดยมีจุดกำเนิดอยู่ตรงกลาง)

เกมส่วนใหญ่จัดการระบบพิกัด 2D สองระบบที่ต่างกันได้อย่างไร มีสองประเภทหลักของพิกัด (หน้าจอเทียบกับคาร์ทีเซียน) แต่อาจมีช่องว่างพิกัดที่แตกต่างกันมาก: พื้นที่สไปรท์พื้นที่โลกพื้นที่ดูพื้นที่หน้าจอ ฯลฯ ...

พื้นหลัง:

เดิมทีฉันสร้างพิกัดโลกในเกมของฉันให้ตรงกับแบบแผนการประสานงานหน้าจอ 2 มิติ สิ่งนี้ทำให้เป็นเรื่องธรรมดามากที่จะใช้รูทีนการวาดภาพกราฟิก แต่ปัญหาที่ละเอียดอ่อนเกิดขึ้นเมื่อใช้ฟังก์ชันตรีโกณมิติเช่น atan2 () ผลลัพธ์ของการป้อนพิกัด atan2 () หน้าจอ 2D มีความสับสนอย่างมากเนื่องจาก atan2 () สมมติว่าแกน y บวกขึ้น

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

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

ฉันรู้ว่าการแปลงจากหน้าจอเป็นพิกัดคาร์ทีเซียนนั้นเกี่ยวข้องกับการปรับขนาดค่า y ด้วย -1 ด้วยการเลือกการแปลค่าทั้งสอง (x, y) ฉันสนใจวิธีปฏิบัติที่ดีที่สุดสำหรับการออกแบบเกม:

  • เกมส่วนใหญ่ทำตามระเบียบของหน้าจอการประสานงานและเปลี่ยนความคิดของพวกเขาเกี่ยวกับวิธีการทำงานของ atan2 ()
  • การแปลงระบบพิกัดเสร็จสิ้นเมื่อใด? (ใช้เมทริกซ์, OOP abstraction เป็นต้น)
  • ที่เก็บสไปรต์ถูกจัดเก็บเป็นศูนย์กลางของสไปรต์หรือมุมใดมุมหนึ่งหรือไม่ ความสูง / ความกว้างของสไปรต์ไปในทิศทาง "ผิด" ดูเหมือนจะเป็นปัญหาทั่วไปเมื่อฉันวาด

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

คำตอบ:


8

ต้องลองทุกวิธีที่เป็นไปได้ในการทำมันฉันพบว่ามันเป็นเกม 2D ล้วนๆแค่ใช้ระบบวาดหน้าจอมันจะทำให้ชีวิตของคุณง่ายขึ้นมาก Sin, Cos และ atan2 จำเป็นต้องใช้แตกต่างกันเล็กน้อย แต่ความไม่สะดวกนี้เกิดขึ้นได้ง่ายจากความง่ายในการรู้ว่าทางใดขึ้นลงตามเข็มนาฬิกาและทวนเข็มนาฬิกา ฉันขอแนะนำให้ทำงานเป็นพิกเซลแทนที่จะเป็นเมตรสำหรับเกม 2 มิติ - มันง่ายกว่าที่จะคิดถึงระยะทางบนหน้าจอและโอกาสที่คุณต้องการเปลี่ยนขนาดทั้งหมดของเกมใกล้เคียงกับศูนย์

"เกมส่วนใหญ่จัดการระบบพิกัด 2D สองระบบที่ต่างกันได้อย่างไร"

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

"สถานที่เก็บผีสางเก็บรักษาเป็นศูนย์กลางของเทพดาหรือมุมใดมุมหนึ่งหรือไม่?"

  • หากคุณทำงานจากจุดศูนย์กลางมันจะทำให้การหมุนไปข้างหน้าตรงมากขึ้นแม้ว่าคุณจะต้องการรู้มุมเช่นกัน

"บางทีคำแนะนำบางอย่างอาจพบได้ในวิธีการของ OpenGL ... "

  • เอ็นจิ้น 3 มิติเป็นกรณีที่แตกต่างอย่างสิ้นเชิง เนื่องจากมีกล้องจริงตำแหน่งหน้าจออาจแตกต่างอย่างมากจากตำแหน่งโลก สำหรับเกมจากบนลงล่างคุณจะต้องทำงานในแกน X และ Z แทนที่จะเป็น X และ Y สำหรับสิ่งหนึ่ง

1

ฉันอาจกำลังใช้สิ่งต่าง ๆ เกินความจริงที่นี่ แต่ความชอบของฉันก็คือการมีระบบย่อย 2D / UI ใด ๆ จัดการอย่างเคร่งครัดในสิ่งที่คุณขนานนามพิกัด "หน้าจอ" คุณจะมีสองเมทริกซ์: ScreenToCartesianTransform และ CartesianToScreenTransform เมื่อได้รับเหตุการณ์การป้อนข้อมูลด้วยเมาส์พิกัดของเมาส์จะถูกแปลงโดยใช้ CartesianToScreenTransform ก่อนที่จะถูกส่งผ่านไปยังตัวจัดการอินพุตของระบบ 2D / UI จากจุดนั้นระบบ UI จะทำการทดสอบ Hit โดยใช้ระบบพิกัดหน้าจอและจัดการ (หรือไม่จัดการ) เหตุการณ์ตามลำดับ หากเหตุการณ์การป้อนข้อมูลเมาส์ไม่สามารถจัดการได้โดย 2D / UI เหตุการณ์นั้นอาจถูกส่งผ่านไปยังระบบ 3D (หากมีอยู่) โดยใช้พิกัดดั้งเดิมที่ไม่ได้เปลี่ยนรูปแบบ

เนื่องจากระบบ 2D / UI จะจัดการในพิกัด "หน้าจอ" เท่านั้นจึงจำเป็นต้องเปลี่ยนรูปทรงเรขาคณิตของมันผ่าน ScreenToCartesianTransform ก่อนประมวลผลโดยเอ็นจิ้นการแสดงผล


ในความเป็นจริงแล้วขึ้นอยู่กับชุดเครื่องมือที่คุณใช้งานเหตุการณ์การป้อนข้อมูลด้วยเมาส์อาจอยู่ในพิกัดหน้าจอแล้ว ในกรณีนี้คุณจะไม่แปลงมันสำหรับระบบ 2D / UI แต่คุณจะใช้กับระบบ 3D (ถ้ามี)
Mike Strobel

0

ฉันชอบที่จะใช้โครงสร้างการแสดงผลเหมือนใน Flash ฉันจะมีรูทโหนด (มุมมองเกม) ซึ่งมีลูกสำหรับโลก (โหนดโลก) และอีกโหนดหนึ่งสำหรับฮัด ภายในโหนดโลกจะเป็นโหนดสำหรับวัตถุในโลกของเกม

จากนั้นฉันก็เปลี่ยนโหนดโลก นอกเหนือจากการแปล (การแพนกล้อง) และการปรับสัดส่วน (การซูมกล้อง) ฉันยังใช้การแปลงสองแบบ:

  • มาตราส่วน -1 y เพื่อพลิกระบบพิกัด
  • มาตราส่วนสำหรับแปลงหน่วยโลก (เมตร) เป็นหน่วยหน้าจอ (พิกเซล)

จากนั้นฉันก็ใช้พิกัด y-up / world ในรหัสรูปวาดวัตถุของเกมและพิกัด y-down / หน้าจอในรหัสรูปวาด HUD ซึ่งทั้งคู่รู้สึกเป็นธรรมชาติมาก

เพื่อตอบคำถามเช่น "ฉันกำลังคลิกวัตถุอะไร" ฉันใช้วิธีการแสดงโหนดเพื่อแปลงพิกัดระหว่างระบบพิกัด (เช่นglobalToLocalและสิ่งที่ตรงกันข้ามใน Flash)

โดยวิธีการที่atanไม่ทำงานแตกต่างกันจริงๆเมื่อ y ลงคุณก็ต้องคิดว่าทุกมุมเป็นไปตามเข็มนาฬิกาแทนทวนเข็มนาฬิกา


0

OpenGL เช่น DirectX มีแกน X และ Z ตามแนวระนาบแนวนอนและ Y หันขึ้นด้านบน
ฉันไม่เคยมีปัญหาใด ๆ กับพิกัดหน้าจอและฉันคิดว่าวิธีที่ง่ายที่สุดก็คือการจัดการกับมันว่ามันเป็นอย่างไร: ถ้ามีอะไรบางอย่างเช่น atan2 ไม่ชอบมันแล้วเปลี่ยนพารามิเตอร์ที่ถูกเลี้ยง

หากคุณใช้พิกัดแบบสัมพันธ์หรือในท้องถิ่นเช่นกราฟฉากฟังก์ชั่นง่าย ๆ เช่น ToGlobalCoords () นั้นดี ในความเป็นจริงถ้าคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการวางตำแหน่งเชิงพื้นที่กราฟฉากและ localToGlobal ตัวแยกฟรีจาก Game Engine Architecture นั้นเกี่ยวกับสิ่งนั้น

สไปรต์ถูกดึงมาจากมุมซ้ายด้านบนหรือ (0,0) ต้นกำเนิด สาเหตุที่เป็นเพราะต้นกำเนิดด้านบนซ้ายของหน้าต่าง

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.