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


16

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

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

A. ) ขยายขอบเขตของโลกเป็น 1024x768 และปรับสเกลการชนของวัตถุทุกชิ้นตามลำดับ

B. ) "แผนที่" ตำแหน่งของเมาส์ไปสู่โลกดั้งเดิม (800x600)

โดย "map" ฉันหมายถึงเพียงแค่ปรับตำแหน่งเมาส์บนโลก 800x600 ดั้งเดิม ตัวอย่างเช่นหากตำแหน่งของเมาส์บนหน้าจอคือ (1024, 768) ดังนั้นตำแหน่งของเมาส์ในโลกคือ (800, 600)

ตอนนี้เห็นได้ชัดว่าตัวเลือก B ต้องการวิธีการคำนวณที่น้อยลงและอาจมีข้อผิดพลาดทางเรขาคณิตน้อยกว่า แต่ก็รู้สึกเหมือน "แฮ็ก" สำหรับฉันเช่นมีผลที่ไม่คาดคิดจากการใช้วิธีนี้ที่จะแก้ไขในภายหลัง

ฉันควรใช้วิธีใด: A, B หรืออย่างอื่น


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

คำตอบ:


38

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

วิธีที่ง่ายที่สุดในการบรรลุเป้าหมายนี้คือใช้กล้อง 2D ซึ่งเป็นเมทริกซ์ที่กำหนดการเปลี่ยนจากอวกาศโลก (หน่วยตามอำเภอใจของคุณ) ไปเป็นพื้นที่จอภาพ (พิกเซลบนหน้าจอ) สิ่งนี้ทำให้การจัดการกับคณิตศาสตร์เล็กน้อย

ลองดูที่ส่วนด้านล่างในการเลื่อนกล้อง XNA 2d - ทำไมต้องใช้การแปลงเมทริกซ์?

มันทำให้ง่ายต่อการแปลงระหว่างคำจำกัดความของระบบพิกัด

หากต้องการเปลี่ยนจากหน้าจอสู่อวกาศโลกเพียงใช้ Vector2.Transform โดยทั่วไปจะใช้เพื่อให้ได้ตำแหน่งของเมาส์ในโลกสำหรับการเลือกวัตถุ

Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));

หากต้องการเดินทางจากโลกหนึ่งไปยังอีกจอหนึ่ง

Vector2.Transform(mouseLocation, Camera.TransformMatrix);

ไม่มีข้อเสียในการใช้เมทริกซ์อื่นนอกจากการเรียนรู้เพียงเล็กน้อย


... และโดยทั่วไปฮาร์ดแวร์ที่ทันสมัยได้รับการออกแบบมาสำหรับการทำงานของเมทริกซ์ผ่านสถาปัตยกรรม vectorisation เช่น SSE, NEON และอื่น ๆ ดังนั้นจึงเป็นตัวเลือกที่ชาญฉลาด - คุณจะประหยัดวงจรของซีพียูด้วยวิธีที่ไม่ใช่เวกเตอร์
วิศวกร

1
ข้อจำกัดความรับผิดชอบอย่างอ่อน: XNA ถูกยกเลิกโดย microsoft แต่ Monogame ใช้ API เดียวกัน
Pharap

1
แน่นอนว่ามันฉลาดในการใช้เมทริกซ์เพื่อแปลระหว่างระบบพิกัดทั้งสอง แต่นั่นจะตอบคำถามได้อย่างไร คุณยังคงต้องตัดสินใจหากคุณต้องการแมปจากระบบ A ไปยังระบบ B หรือจาก B ถึง A และผลลัพธ์ที่ตามมาคืออะไรหากมี
mastov

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

ฉันยังตอบว่า "คุณต้องตัดสินใจเช่นกันถ้าคุณต้องการแมปจากระบบ A ไปยังระบบ B หรือจาก B ถึง A และผลลัพธ์ที่ตามมาคืออะไรหากมี" โดยบอกว่าคุณควรใช้คนที่ไม่มีข้อผูกมัดกับความละเอียดและขนาด ดังนั้น C -> A หรือ C -> B ขึ้นอยู่กับว่า A หรือ B คือความละเอียด แน่นอนคุณสามารถมี C เท่ากับความละเอียดพื้นฐานที่คุณออกแบบและปรับขนาดจากที่นั่น จุดคือคณิตศาสตร์ทั้งหมดที่เกิดขึ้นในระบบพิกัดเดียวกันและคุณปรับมาตราส่วนสำหรับการเรนเดอร์เท่านั้น
ClassicThunder

2

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

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

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


0

คำตอบของ ClassicThunder นั้นถูกต้อง แต่ฉันต้องการยกตัวอย่างของวิธีการทางเลือก / วิธีที่ง่ายกว่าในการบรรลุเอฟเฟกต์ที่ต้องการ นี่เป็นวิธีที่ง่ายกว่าสำหรับการสร้างต้นแบบอย่างรวดเร็วกรณีที่คุณไม่ได้เข้าถึงไลบรารีที่มีคุณลักษณะครบถ้วนหรือสำหรับกรณีที่คุณไม่สามารถเข้าถึง GPU (เช่นในระบบฝังตัว)

ในการทำแผนที่ดังกล่าวคุณสามารถใช้ฟังก์ชั่นต่อไปนี้ (สมมติว่ามันถูกกำหนดไว้ในคลาสคงที่Helper):

static float Map(float value, float fromLow, float fromHigh, float toLow, float toHigh)
{
    return ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)) + toLow;
}

(คุณไม่ได้ระบุภาษา แต่ฉันเห็นว่าคุณมีความรู้เกี่ยวกับ C # ดังนั้นตัวอย่างของฉันคือ C #)

จากนั้นคุณสามารถใช้ฟังก์ชันนี้ได้เช่น:

float mouseXInWorld = Helper.Map(Mouse.X, 0, Screen.Width - 1, camera.Bounds.X, camera.Bounds.X + camera.Bounds.Width - 1);
float mouseYInWorld = Helper.Map(Mouse.Y, 0, Screen.Height - 1, camera.Bounds.Y, camera.Bounds.Y + camera.Bounds.Height - 1);

camera.Boundsสี่เหลี่ยมผืนผ้าอยู่ที่ไหนในโลกที่กล้องสามารถมองเห็นได้ (เช่นบริเวณที่ถูกฉายลงบนหน้าจอ)

หากคุณมีคลาสVectorหรือPointคุณสามารถทำให้กระบวนการนี้ง่ายขึ้นด้วยการสร้างฟังก์ชันแผนที่เทียบเท่า 2D เช่น:

static Vector Map(Vector value, Rectangle fromArea, Rectangle toArea)
{
    Vector result = new Vector();
    result.X = Map(value.X, fromArea.X, fromArea.X + fromArea.Width - 1, toArea.X, toArea.X + toArea.Width - 1);
    result.Y = Map(value.Y, fromArea.Y, fromArea.Y + fromArea.Height - 1, toArea.Y, toArea.Y + toArea.Height - 1);
    return result;
}

ซึ่งจะทำให้โค้ดการแมปของคุณเป็นซับแบบง่าย ๆ :

Vector mousePosInWorld = Map(Mouse.Pos, Screen.Bounds, camera.Bounds);

-1

ตัวเลือก (C): เปลี่ยนความละเอียดหน้าจอกลับเป็น 800x600

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

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

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