กับดักหนูใน SDL


12

ฉันจะดักจับเมาส์ของผู้ใช้ในเกมได้อย่างไร มันไม่ใช่เกมแบบเต็มหน้าจอ แต่ฉันต้องการมันเพื่อที่ผู้ใช้จะไม่สามารถลากเมาส์ไปด้านนอกหน้าจอ

ฉันต้องตรวจสอบพิกัดของเมาส์และ SDL_WarpCursor เพื่อให้พูดในหน้าต่าง (ด้วยตนเอง) หรือมีวิธีอัตโนมัติหรือไม่?

ขอบคุณ.


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

คำตอบ:


24

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

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

วิธีที่ถูกต้องในการวางเม้าส์ภายใต้ SDL คือ:

SDL_WM_GrabInput( SDL_GRAB_ON );

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

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

อัปเดตสำหรับ SDL2 - 9 ธันวาคม 2556

อินเทอร์เฟซนี้มีการเปลี่ยนแปลงสำหรับ SDL2 หากคุณใช้ SDL1.2 คำตอบข้างต้นยังคงถูกต้อง อย่างไรก็ตามภายใต้ SDL2 SDL_WM_GrabInput(SDL_GrabMode)ฟังก์ชันจะไม่สามารถใช้งานได้อีกต่อไป วิธีใหม่ในการจับเมาส์ของ SDL2 คือ:

SDL_SetRelativeMouseMode(SDL_TRUE);

มิฉะนั้นสิ่งนี้จะเหมือนกับฟังก์ชั่นก่อนหน้านี้ - ในโหมดนี้คุณจะยังคงรับSDL_MOUSEMOTIONเหตุการณ์ต่อไปราวกับว่าเมาส์ไม่ได้ถูก จำกัด อยู่ภายในหน้าต่าง


1
Caveat: ฉันสังเกตเห็นว่าในบางแพลตฟอร์มฉันได้รับเหตุการณ์ MouseMotion ปลอมด้วยการเคลื่อนไหวที่ใหญ่มากทันทีหลังจากเปิดเม้าส์โลภ เพื่อจัดการกับสิ่งนั้นฉันขอรหัสของฉันไม่สนใจเหตุการณ์การเคลื่อนไหวของเมาส์ครั้งแรกที่ได้รับหลังจากเปิดโหมดนี้
เทรเวอร์พาวเวลล์

มันทำงานได้อย่างสมบูรณ์และง่ายกว่าวิธีแบบแมนนวล ขอบคุณ!
David Gomes

3

ในขณะที่คำตอบที่อัปเดตของเทรเวอร์ไม่สะท้อนให้เห็นถึงสถานะปัจจุบันของ SDL2 คุณยังสามารถดักจับเมาส์โดยการสร้างของคุณSDL_WindowกับSDL_WINDOW_INPUT_GRABBEDชุด ระวังให้ดีว่าฉันเจอปัญหาแปลก ๆ บน Linux (น่าจะเป็นเพราะ X windowing quirk) ที่คุณไม่สามารถออกจากหน้าต่างได้เว้นแต่ว่ามีการเรียก SDL_QUIT (แม้ว่าจะมีเหตุการณ์ OS อื่นขโมยโฟกัสไป)


ขอบคุณ SDL_WINDOW_INPUT_GRABBED ทำงานได้อย่างสมบูรณ์ในรหัส SDL2 ของฉัน
Adrian Maire


2

คุณสามารถใช้SDL Motion Eventเพื่อตรวจจับเมื่อเมาส์เคลื่อนย้าย จากนั้นคุณสามารถเรียก WarpCursor ภายในนั้นได้แม้กระทั่งหลังจากการยิงเหตุการณ์เพื่อไพพ์ค่า relX และ relY คุณสามารถซ่อนเคอร์เซอร์ระบบปฏิบัติการของคุณและวาดเส้นเล็งหรือสิ่งที่คล้ายกันในกึ่งกลางของหน้าจอ สิ่งนี้ทำให้มั่นใจได้ว่าเมาส์นั้นจะอยู่ตรงกลางเสมอสำหรับผู้ใช้และคุณยังสามารถรับค่าของการเคลื่อนไหวและสิ่งที่คล้ายกันได้

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