Kontrol kunci pointer dan first person shooter

John McCutchan
John McCutchan

Pengantar

Pointer Lock API membantu menerapkan kontrol first-person shooter dengan benar dalam game browser. Tanpa gerakan mouse relatif, kursor pemain dapat, misalnya, mengenai tepi kanan layar dan setiap gerakan lebih lanjut ke kanan akan ditiadakan - pandangan tidak akan terus bergeser ke kanan, dan pemain tidak akan dapat mengejar orang-orang jahat dan mengganggu mereka dengan senapan mesinnya. Pemain akan menjadi rapuh dan frustrasi. Dengan kunci pointer, perilaku yang kurang optimal ini tidak dapat terjadi.

Pointer Lock API memungkinkan aplikasi Anda melakukan hal berikut:

  • Mendapatkan akses ke data mouse mentah, termasuk gerakan mouse relatif
  • Merutekan semua peristiwa mouse ke elemen tertentu

Sebagai efek samping mengaktifkan kunci pointer, kursor mouse disembunyikan yang memungkinkan Anda memilih untuk menggambar pointer khusus aplikasi jika diinginkan, atau membiarkan pointer mouse tersembunyi sehingga pengguna dapat memindahkan frame dengan mouse. Gerakan mouse relatif adalah delta posisi pointer mouse dari frame sebelumnya, terlepas dari posisi absolutnya. Misalnya, jika pointer mouse bergerak dari (640, 480) ke (520, 490) gerakan relatifnya adalah (-120, 10). Lihat contoh interaktif di bawah ini yang menampilkan delta posisi mouse mentah.

Tutorial ini membahas dua topik: dasar-dasar pengaktifan dan pemrosesan peristiwa kunci pointer, dan menerapkan skema kontrol first-person shooter. Benar, setelah selesai membaca artikel ini, Anda akan mengetahui cara menggunakan kunci pointer dan menerapkan kontrol gaya Quake untuk game browser Anda sendiri.

Kompatibilitas browser

Dukungan Browser

  • 37
  • 13
  • 50
  • 10.1

Sumber

Mekanisme Kunci Pointer

Deteksi Fitur

Untuk menentukan apakah browser pengguna mendukung penguncian pointer, Anda harus memeriksa pointerLockElement atau versi berawalan vendor di objek dokumen. Dalam kode:

var havePointerLock = 'pointerLockElement' in document ||
    'mozPointerLockElement' in document ||
    'webkitPointerLockElement' in document;

Saat ini, kunci pointer hanya tersedia di Firefox dan Chrome. Opera dan IE belum mendukungnya.

Mengaktifkan

Mengaktifkan penguncian pointer adalah proses dua langkah. Pertama, aplikasi Anda meminta kunci pointer diaktifkan untuk elemen tertentu, dan segera setelah pengguna memberikan izin, peristiwa pointerlockchange akan diaktifkan. Pengguna dapat membatalkan kunci pointer kapan saja dengan menekan tombol escape. Aplikasi Anda juga dapat keluar secara terprogram dari kunci pointer. Saat kunci pointer dibatalkan, peristiwa pointerlockchange akan diaktifkan.

element.requestPointerLock = element.requestPointerLock ||
                 element.mozRequestPointerLock ||
                 element.webkitRequestPointerLock;
// Ask the browser to lock the pointer
element.requestPointerLock();

// Ask the browser to release the pointer
document.exitPointerLock = document.exitPointerLock ||
               document.mozExitPointerLock ||
               document.webkitExitPointerLock;
document.exitPointerLock();

Yang diperlukan hanyalah kode di atas. Saat browser mengunci pointer, balon akan pop-up yang memberi tahu pengguna bahwa aplikasi Anda telah mengunci pointer dan memerintahkan mereka bahwa mereka dapat membatalkannya dengan menekan tombol 'Esc'.

Kolom info Kunci Kursor di Chrome.
Kolom info Kunci Pointer di Chrome.

Penanganan Peristiwa

Ada dua peristiwa yang harus ditambahi pemroses oleh aplikasi Anda. Yang pertama adalah pointerlockchange, yang diaktifkan setiap kali perubahan dalam status kunci pointer terjadi. Yang kedua adalah mousemove yang aktif setiap kali mouse bergerak.

// Hook pointer lock state change events
document.addEventListener('pointerlockchange', changeCallback, false);
document.addEventListener('mozpointerlockchange', changeCallback, false);
document.addEventListener('webkitpointerlockchange', changeCallback, false);

// Hook mouse move events
document.addEventListener("mousemove", this.moveCallback, false);

Di dalam callback pointerlockchange, Anda harus memeriksa apakah pointer baru saja dikunci atau tidak terkunci. Menentukan apakah kunci pointer diaktifkan cukup mudah: periksa apakah document.pointerLockElement sama dengan elemen yang meminta kunci pointer. Jika terkunci, aplikasi Anda berhasil mengunci pointer, dan jika tidak, pointer dibuka oleh pengguna atau kode Anda sendiri.

if (document.pointerLockElement === requestedElement ||
  document.mozPointerLockElement === requestedElement ||
  document.webkitPointerLockElement === requestedElement) {
  // Pointer was just locked
  // Enable the mousemove listener
  document.addEventListener("mousemove", this.moveCallback, false);
} else {
  // Pointer was just unlocked
  // Disable the mousemove listener
  document.removeEventListener("mousemove", this.moveCallback, false);
  this.unlockHook(this.element);
}

Saat kunci pointer diaktifkan, clientX, clientY, screenX, dan screenY akan tetap konstan. movementX dan movementY diperbarui dengan jumlah piksel yang akan dipindahkan pointer sejak peristiwa terakhir dikirimkan. Dalam kode pseudo:

event.movementX = currentCursorPositionX - previousCursorPositionX;
event.movementY = currentCursorPositionY - previousCursorPositionY;

Di dalam callback mousemove, data gerakan mouse relatif dapat diekstrak dari kolom movementX dan movementY peristiwa.

function moveCallback(e) {
  var movementX = e.movementX ||
      e.mozMovementX          ||
      e.webkitMovementX       ||
      0,
  movementY = e.movementY ||
      e.mozMovementY      ||
      e.webkitMovementY   ||
      0;
}

Menangkap error

Jika error muncul dengan penguncian pointer masuk atau keluar, peristiwa pointerlockerror akan diaktifkan. Tidak ada data yang dilampirkan ke peristiwa ini.

document.addEventListener('pointerlockerror', errorCallback, false);
document.addEventListener('mozpointerlockerror', errorCallback, false);
document.addEventListener('webkitpointerlockerror', errorCallback, false);

Perlu Layar Penuh?

Kunci pointer awalnya dikaitkan dengan FullScreen API. Artinya, suatu elemen harus berada dalam mode layar penuh sebelum pointer dapat dikunci. Itu tidak lagi benar dan kunci pointer dapat digunakan untuk elemen apa pun dalam layar penuh aplikasi Anda atau tidak.

Contoh Kontrol First-Person Shooter

Sekarang setelah kita mengaktifkan kunci pointer dan menerima peristiwa, sekarang saatnya untuk melihat contoh praktis. Pernahkah Anda ingin tahu cara kerja kontrol di Quake? Bersiaplah karena saya akan menjelaskannya dengan kode!

Kontrol first-person shooter dibangun dengan empat mekanisme inti:

  • Bergerak maju dan mundur di sepanjang vektor tampilan saat ini
  • Bergerak ke kiri dan kanan di sepanjang vektor strafe saat ini
  • Memutar yaw tampilan (kiri dan kanan)
  • Memutar pitch tampilan (ke atas dan ke bawah)

Game yang menerapkan skema kontrol ini hanya memerlukan tiga bagian data: posisi kamera, vektor tampilan kamera, dan vektor ke atas konstan. Vektor naik selalu (0, 1, 0). Keempat mekanisme di atas hanya memanipulasi posisi kamera dan vektor tampilan kamera dengan cara yang berbeda.

Gerakan

Pertama, presentasi adalah gerakan. Pada demo di bawah ini, pergerakan dipetakan ke kunci standar W, A, S, dan D. Tombol W dan S menggerakkan kamera maju dan mundur. Sementara tombol A dan D menggerakkan kamera ke kiri dan kanan. Gerakkan kamera maju dan mundur mudah:

// Forward direction
var forwardDirection = vec3.create(cameraLookVector);
// Speed
var forwardSpeed = dt * cameraSpeed;
// Forward or backward depending on keys held
var forwardScale = 0.0;
forwardScale += keyState.W ? 1.0 : 0.0;
forwardScale -= keyState.S ? 1.0 : 0.0;
// Scale movement
vec3.scale(forwardDirection, forwardScale * forwardSpeed);
// Add scaled movement to camera position
vec3.add(cameraPosition, forwardDirection);

strafing ke kiri dan kanan memerlukan arah strafe. Arah strafe dapat dihitung menggunakan perkalian silang:

// Strafe direction
var strafeDirection = vec3.create();
vec3.cross(cameraLookVector, cameraUpVector, strafeDirection);

Setelah Anda memiliki arah strafe, menerapkan gerakan strafe sama dengan bergerak maju atau mundur.

Selanjutnya adalah memutar tampilan.

Mentah

Yaw atau rotasi horizontal tampilan kamera hanyalah rotasi di sekitar vektor ke atas yang konstan. Di bawah ini adalah kode umum untuk memutar vektor tampilan kamera di sekitar sumbu arbitrer. Fungsi ini bekerja dengan membuat kuaternion yang mewakili rotasi radian deltaAngle di sekitar axis, lalu menggunakan kuaternion untuk memutar vektor tampilan kamera:

// Extract camera look vector
var frontDirection = vec3.create();
vec3.subtract(this.lookAtPoint, this.eyePoint, frontDirection);
vec3.normalize(frontDirection);
var q = quat4.create();
// Construct quaternion
quat4.fromAngleAxis(deltaAngle, axis, q);
// Rotate camera look vector
quat4.multiplyVec3(q, frontDirection);
// Update camera look vector
this.lookAtPoint = vec3.create(this.eyePoint);
vec3.add(this.lookAtPoint, frontDirection);

Sarankan

Menerapkan pitch atau rotasi vertikal tampilan kamera mirip, tetapi alih-alih rotasi di sekitar vektor atas, Anda menerapkan rotasi di sekitar vektor strafe. Langkah pertama adalah menghitung vektor strafe, lalu memutar vektor tampilan kamera mengitari sumbu tersebut.

Ringkasan

Pointer Lock API memungkinkan Anda mengontrol kursor mouse. Jika Anda membuat game web, pemain akan menyukainya saat mereka tidak lagi rapuh karena mereka dengan bersemangat menggerakkan mouse keluar jendela dan game Anda berhenti mendapatkan pembaruan mouse. Penggunaannya sederhana:

  • Menambahkan pemroses peristiwa pointerlockchange untuk melacak status kunci pointer
  • Meminta kunci pointer untuk elemen tertentu
  • Menambahkan pemroses peristiwa mousemove untuk mendapatkan update

Demo Eksternal

Referensi