Giriş
İşaretçi Kilidi API'si, tarayıcı oyunlarında birinci şahıs nişancı kontrollerini düzgün şekilde uygulamanıza yardımcı olur. Göreceli fare hareketi olmadan oyuncunun imleci örneğin ekranın sağ kenarına çarpabilir ve sağa doğru yapılan diğer hareketler dikkate alınmaz. Bu durumda görüntü sağa kaymaya devam etmez ve oyuncu kötü adamları kovalayamaz ve makineli tüfeğiyle onlara ateş edemez. Oyuncu, canı sıkılarak oyundan ayrılır. İşaretçi kilidi kullanıldığında bu en uygun olmayan davranış gerçekleşmez.
İşaretçi Kilidi API'si, uygulamanızın aşağıdakileri yapmasına olanak tanır:
- Göreli fare hareketleri dahil ham fare verilerine erişme
- Tüm fare etkinliklerini belirli bir öğeye yönlendirme
İşaretçi kilidini etkinleştirmenin bir yan etkisi olarak fare imleci gizlenir. Böylece, dilerseniz uygulamaya özel bir işaretçi çizebilir veya kullanıcının çerçeveyi fareyle hareket ettirebilmesi için fare imlecini gizli bırakabilirsiniz. Göreli fare hareketi, mutlak konumdan bağımsız olarak fare işaretçisinin önceki kareye göre delta değeridir. Örneğin, fare işaretçisi (640, 480) konumundan (520, 490) konumuna hareket ettiyse göreli hareket (-120, 10) olur. Ham fare konumu değişimlerini gösteren etkileşimli bir örnek için aşağıya bakın.
Bu eğitimde, işaretçi kilidi etkinliklerini etkinleştirme ve işleme ile birinci şahıs nişancı kontrol şemasını uygulama konuları ele alınmaktadır. Evet, bu makaleyi okuduğunuzda işaretçi kilidini nasıl kullanacağınızı ve kendi tarayıcı oyununuz için Quake tarzı kontrolleri nasıl uygulayacağınızı öğreneceksiniz.
Tarayıcı uyumluluğu
İşaretçi Kilidi Mekanizmaları
Ö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 tedarikçi ön ekiyle başlayan bir sürümü 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 bu özelliği desteklemiyor.
Etkinleştiriliyor
İşaretçi kilidini etkinleştirmek iki adımdan oluşur. Öncelikle uygulamanız, 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ı, Escape tuşuna basarak istediği zaman işaretçi kilidini iptal edebilir. Uygulamanız, işaretçi kilidinden programatik 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();
Bunun için yukarıdaki kodu kullanmanız yeterlidir. Tarayıcı işaretçiyi kilitlediğinde, kullanıcıya uygulamanızın işaretçiyi kilitlediğini ve "Esc" tuşuna basarak bu işlemi iptal edebileceğine dair talimatlar veren bir baloncuk açılır.
Olay İşleme
Uygulamanızın dinleyici eklemesi gereken iki etkinlik vardır. Bunlardan ilki pointerlockchange
'tür. İşaretçi kilidi durumunda her değişiklik olduğunda tetiklenir. İkincisi, fare 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 çağırma işlevinizde, işaretçinin kilitlenip kilitlenmediğini kontrol etmeniz gerekir. İşaretçi kilidinin etkinleştirilip etkinleştirilmediğini belirlemek kolaydır: document.pointerLockElement öğesinin, işaretçi kilidinin istendiği öğeye eşit olup olmadığını kontrol edin. Bu değer doğruysa uygulamanız işaretçiyi başarıyla kilitlemiştir. Değer yanlışsa işaretçi, kullanıcı veya kendi kodunuz tarafından kilitlenmiştir.
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 etkinliğin yayınlanmasından bu yana işaretçinin hareket edeceği piksel sayısıyla güncellenir. Sözde kodda:
event.movementX = currentCursorPositionX - previousCursorPositionX;
event.movementY = currentCursorPositionY - previousCursorPositionY;
mousemove
geri çağırma işlevi içinde, fare hareketine göre göreli veriler etkinliğin movementX
ve movementY
alanlarından ayıklanabilir.
function moveCallback(e) {
var movementX = e.movementX ||
e.mozMovementX ||
e.webkitMovementX ||
0,
movementY = e.movementY ||
e.mozMovementY ||
e.webkitMovementY ||
0;
}
Hataları yakalama
İşaretçi kilidine girildiğinde veya işaretçi kilidinden çıkıldığında 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?
İşaretçi kilidi başlangıçta FullScreen API'ye bağlıydı. Yani işaretçi bir öğeye kilitlenebilmesi için öğenin tam ekran modunda olması gerekir. Bu artık geçerli değil ve işaretçi kilidi, uygulamanızdaki herhangi bir öğe için tam ekran veya tam ekran olmayan şekilde kullanılabilir.
Birinci Şahıs Nişancı Denetimleri Örneği
İşaretçi kilidini etkinleştirip etkinlikleri almaya başladık. Şimdi pratik bir örnekle devam edelim. Quake'taki kontrollerin nasıl çalıştığını hiç merak ettiniz mi? Şimdi bunları kodla açıklamaya başlayacağım.
Birinci şahıs nişancı oyunlarının kontrolleri dört temel mekanizmaya dayanır:
- Mevcut bakış vektörü boyunca ileri ve geri hareket etme
- Mevcut yan kayma vektörü boyunca sola ve sağa hareket etme
- Görünümü yaw (sol ve sağ) yönünde döndürme
- Görünümün eğimini döndürme (yukarı ve aşağı)
Bu kontrol şemasını uygulayan bir oyunda yalnızca üç veri gerekir: kamera konumu, kamera bakış vektörü ve sabit bir yukarı vektörü. Yukarı vektörü her zaman (0, 1, 0) şeklindedir. Yukarıdaki mekanizmaların dördü de kamera konumunu ve kamera bakış vektörünü farklı şekillerde değiştirir.
Akım
İlk olarak harekete geçmeniz gerekir. Aşağıdaki demoda hareket, standart W, A, S ve D tuşlarıyla eşlenmiştir. W ve S tuşları kamerayı ileri ve geri hareket ettirir. A ve D tuşları ise kamerayı sola ve sağa hareket ettirir. Kamerayı ileri ve geri hareket ettirmek kolaydır:
// 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);
Sol ve sağa doğru hareket etmek için bir hareket yönü gerekir. Yan kayma yönü, çapraz çarpım kullanılarak hesaplanabilir:
// Strafe direction
var strafeDirection = vec3.create();
vec3.cross(cameraLookVector, cameraUpVector, strafeDirection);
Yan hareket yönünü belirledikten sonra yan hareketi uygulamak, ileri veya geri hareket etmekle aynıdır.
Ardından, görünümü döndürebilirsiniz.
Sapma açısı
Kamera görünümünün sapması veya yatay dönüşümü, sabit yukarı vektörü etrafında yapılan bir dönme hareketidir. Aşağıda, kamera bakış vektörünü rastgele bir eksen etrafında döndürmeye yönelik genel kod verilmiştir. Bu yöntem, axis
etrafında deltaAngle
radyan dönmeyi temsil eden bir quaternion oluşturarak çalışır ve ardından kamera bakış vektörünü döndürmek için quaternion'ı 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);
Teklifinizi sunun
Kamera görünümünün eğimini veya dikey dönüşünü uygulamak benzerdir ancak yukarı vektörü etrafında dönmek yerine yana kayma vektörü etrafında dönme işlemi uygularsınız. İlk adım, yan kayma vektörünü hesaplamak ve ardından kamera bakış vektörünü bu eksen etrafında döndürmektir.
Özet
İşaretçi Kilidi API'si, fare işaretçisinin kontrolünü almanıza olanak tanır. Web oyunları geliştiriyorsanız heyecanla fareyi pencereden çıkardıkları için öldürülen oyuncuların, oyununuz fare güncellemeleri almayı bıraktığında öldürülmemeye başlaması onları mutlu eder. Kullanımı basittir:
- İşaretçi kilidinin durumunu izlemek için
pointerlockchange
etkinlik işleyici ekleme - Belirli bir öğe için işaretçi kilidi isteme
- Güncelleme almak için
mousemove
etkinlik işleyici ekleme