İşaretçi kilidi ve birinci şahıs nişancı kontrolleri

daha fazla içerik
John McCutchan

Giriş

Pointer Lock API, bir tarayıcı oyununda birinci şahıs nişancı denetimlerini düzgün bir şekilde uygulamaya yardımcı olur. Örneğin, göreli fare hareketi olmasaydı oyuncunun imleci ekranın sağ kenarına vurabilirdi ve sağa doğru yaptığı diğer tüm hareketler indirime tabi olur. Oyuncu dağılacak ve sinirlenecektir. İşaretçi kilidi kullanıldığında, bu ideal olmayan davranış gerçekleşemez.

Pointer Lock API, uygulamanızın aşağıdakileri yapmasına olanak tanır:

  • Göreli fare hareketleri dahil olmak üzere ham fare verilerine erişim elde edin
  • Tüm fare etkinliklerini belirli bir öğeye yönlendirme

İşaretçi kilidini etkinleştirmenin yan etkisi olarak, fare imleci gizlenerek isterseniz uygulamaya özel bir işaretçi çizmenizi seçebilir veya kullanıcının kareyi fareyle hareket edebilmesi için fare işaretçisini gizli bırakabilirsiniz. Göreli fare hareketi, mutlak konumdan bağımsız olarak fare işaretçisi konumunun önceki kareye göre deltasıdır. Örneğin, fare işaretçisi (640, 480) konumundan (520, 490) konumuna taşındıysa göreli hareket (-120, 10) olur. Ham fare konumu deltalarını gösteren etkileşimli bir örnek için aşağıya bakın.

Bu eğiticide iki konu ele alınmaktadır: İşaretçi kilidi etkinliklerini etkinleştirip işlemeye yönelik temel konular ve birinci şahıs nişancı kontrol şemasını uygulama. Bu makaleyi okumayı tamamladığınızda işaretçi kilidini nasıl kullanacağınızı ve tarayıcı oyununuz için Quake stili kontrolleri nasıl uygulayacağınızı öğrenmiş olacaksınız.

Tarayıcı uyumluluğu

Tarayıcı Desteği

  • 37
  • 13
  • 50
  • 10.1

Kaynak

İşaretçi Kilit Mekaniği

Özellik Algılama

Kullanıcının tarayıcısının işaretçi kilidini destekleyip desteklemediğini belirlemek için doküman nesnesinde pointerLockElement veya satıcı ön ekli bir sürüm olup olmadığını kontrol etmeniz gerekir. Kodda:

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

İşaretçi kilidi şu anda yalnızca Firefox ve Chrome'da kullanılabilir. Opera ve IE henüz bunu desteklememektedir.

Etkinleştiriliyor

İşaretçi kilidini iki adımda etkinleştirebilirsiniz. Uygulamanız öncelikle belirli bir öğe için işaretçi kilidinin etkinleştirilmesini ister ve kullanıcı izin verdikten hemen sonra bir pointerlockchange etkinliği tetiklenir. Kullanıcı, çıkış tuşuna basarak işaretçi kilidini istediği zaman iptal edebilir. Uygulamanız, işaretçi kilidinden programlı olarak da çıkabilir. İşaretçi kilidi iptal edildiğinde bir pointerlockchange etkinliği tetiklenir.

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();

Yukarıdaki kod yeterlidir. Tarayıcı işaretçiyi kilitlediğinde, kullanıcıya uygulamanızın işaretçiyi kilitlediğini bildiren ve "Esc" tuşuna basarak iptal edebileceklerini bildiren bir balon açılır.

Chrome'da İşaretçi Kilidi bilgi çubuğu.
Chrome'da İşaretçi Kilidi bilgi çubuğu.

Etkinlik İşleme

Uygulamanızın işleyici eklemesi gereken iki etkinlik vardır. İlki pointerlockchange ve işaretçi kilidi durumunda bir değişiklik olduğunda etkinleşir. İkincisi, fare her hareket ettiğinde tetiklenen mousemove.

// 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);

pointerlockchange geri aramanızda, işaretçinin kilitlenip kilitlenmediğini veya kilidinin yeni olup olmadığını kontrol etmeniz gerekir. İşaretçi kilidinin etkinleştirilip etkinleştirilmediğini belirlemek kolay bir işlemdir: document.pointerLockElement öğesinin, işaretçi kilidinin istenen öğeye eşit olup olmadığını kontrol edin. İşaretçi etkin durumdaysa, uygulamanız işaretçiyi başarıyla kilitlemiştir. İşaretçi etkin değilse, işaretçi kilidi kullanıcı tarafından veya kendi kodunuz tarafından açılmıştır.

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);
}

İşaretçi kilidi etkinleştirildiğinde clientX, clientY, screenX ve screenY sabit kalır. movementX ve movementY, son etkinlik yayınlandığından beri işaretçinin hareket ettireceği piksel sayısıyla güncellenir. Sözde kodda:

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

mousemove geri çağırmasının içindeki göreli fare hareketi verileri, etkinliğin movementX ve movementY alanlarından çıkarılabilir.

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

Hataları yakalama

İşaretçi kilidinin girilmesi veya bu kilitten çıkılmasıyla bir hata oluşursa pointerlockerror etkinliği tetiklenir. Bu etkinliğe eklenmiş veri yok.

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

Tam Ekran Gerekli mi?

İlk başta işaretçi kilidi, FullScreen API'ye bağlıydı. Diğer bir deyişle, bir öğenin işaretçinin kilitlenmesi için tam ekran modunda olması gerekir. Bu durum artık geçerli değildir ve uygulamanızdaki tam ekranda herhangi bir öğe için işaretçi kilidi kullanılabilir veya kullanılamaz.

Birinci Şahıs Nişancı Kontrolleri Örneği

İşaretçi kilidini etkinleştirdiğimize ve etkinlikleri aldığımıza göre artık uygulamalı bir örneği ele alalım. Hiç Quake'teki kontrollerin nasıl çalıştığını bilmek istediniz mi? Şimdi bunları kod yazarak açıklayacağım.

Birinci şahıs nişancı kontrolleri dört temel mekanik üzerine kuruludur:

  • Mevcut görünüm vektörü boyunca ileri ve geri gitme
  • Mevcut strafe vektör üzerinde sola ve sağa hareket etme
  • Görünüm sapmasını döndürme (sol ve sağ)
  • Manzarayı döndürme (yukarı ve aşağı)

Bu denetim düzenini uygulayan bir oyun için yalnızca üç veri parçası gerekir: kamera konumu, kamera görünümü vektörü ve sabit yukarı vektör. Yukarı vektör her zaman (0, 1, 0) olur. Yukarıdaki dört mekaniklerin dördü de kamera konumunu ve kamera görünüm vektörünü farklı şekillerde değiştirir.

Akım

İlk sırada hareket var. Aşağıdaki demoda hareket standart W, A, S ve D tuşlarıyla eşleştirilmiştir. W ve S tuşları kamerayı ileri ve geri hareket ettirir. A ve D tuşları kamerayı sola ve sağa yönlendirirken. Kamerayı ileri ve geri hareket ettirmek basittir:

// 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);

Sola ve sağa strafe için yönlendirme gerekir. Strafe yönü, çapraz çarpım kullanılarak hesaplanabilir:

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

Strafe yönünü belirledikten sonra, strafe hareketini uygulamak ileri veya geri gitmekle aynıdır.

Sonraki adım görünümü döndürmektir.

Sapma

Kamera görünümünün sapma veya yatay dönüşü, sabit yukarı vektörün etrafındaki bir dönmedir. Aşağıda, kamera görünümü vektörünü rastgele bir eksen etrafında döndürmek için genel bir kod verilmiştir. Bu modelde, axis çevresinde deltaAngle radyanın dönüşünü temsil eden bir dördünlü oluşturulur ve ardından kamera görünümü vektörünü döndürmek için bu dörtlüyü kullanır:

// 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);

Önerin

Kamera görünümünün perdesini veya dikey yönünü uygulamak benzerdir. Ancak, yukarı vektör etrafında dönme yerine strafe vektörün etrafında bir döndürme uygularsınız. İlk adım, strafe vektörünü hesaplamak ve ardından kamera görüntü vektörünü bu eksen etrafında döndürmektir.

Özet

Pointer Lock API'si, fare imlecinin kontrolünü elinize almanızı sağlar. Web oyunları oluşturuyorsanız oyuncularınız farelerini heyecanla pencerenin dışına çıkardıkları ve oyununuz fare güncellemeleri almayı durdurduğu için kaybolduklarında beğenecekler. Kullanımı basittir:

  • İşaretçi kilidinin durumunu izlemek için pointerlockchange etkinlik işleyici ekleyin
  • Belirli bir öğe için işaretçi kilidi isteme
  • Güncellemeleri almak için mousemove etkinlik işleyici ekleyin

Harici Demolar

Referanslar