XBox Denetleyicisini soyutlaştırmanın doğru yolu


12

Bir uygulama için girdi olarak kullanmak istediğim bir XBox360 denetleyicim var.

Çalışamayacağım şey, bunu bir arayüz aracılığıyla ortaya çıkarmanın en iyi uygulama yoludur.

Perde arkasında, denetleyiciyi / denetleyicileri işleyen sınıf yoklama düğmesi durumuna dayanır.

Başlangıçta bir şey denedim bağlantı:

Event ButtonPressed() as ButtonEnum

nerede ButtonEnumoldu ButtonRed, ButtonStartvs ...

Bu sadece düğme basmalarını desteklemesi, tutma / desenleri (iki kez basma vb.)

Bir sonraki fikir, sadece düğme durumunu uygulamaya maruz bırakmaktı.

Property RedPressed as Boolean
Property StartPressed as Boolean
Property Thumb1XAxis as Double

Bu çok esnektir, ancak gerçekten uygulamaya çok fazla çalışma zorlar ve uygulamanın anket yapmasını gerektirir - mümkünse olayı tercih ederim.

Örneğin birden fazla etkinlik eklemeyi düşündüm

Event ButtonPressed(Button as ButtonEnum)
Event ButtonPressedTwice(Button as ButtonEnum)
Event ButtonHeldStart(Button as ButtonEnum)
Event ButtonHeldEnd(Button as ButtonEnum)

ama bu biraz hantal görünüyor ve "Bağla" ekranında gerçek bir acıydı.

Birisi beni kontrolörlerden gelen girdileri işlemenin "doğru" yoluna yönlendirebilir mi?

Not: Arabirimi uygulayan sınıfın içinde SlimDX kullanıyorum. Bu durumu çok kolay okumama izin veriyor. Sorunumu çözecek alternatifler de takdir ediliyor

Yanıtlar:


21

Size platforma özgü bir soyutlama veren tek bir mükemmel harita yoktur, çünkü 360 denetleyiciye mantıklı gelen tanımlayıcıların çoğu bir PlayStation denetleyicisi için yanlıştır (X yerine B, Circle yerine A). Ve elbette bir Wii kontrolörü tamamen başka bir şeydir.

Bununla başa çıkmanın en etkili yolu üç uygulama katmanı kullanmaktır. Alt katman tamamen platforma / denetleyiciye özgüdür ve kaç tane dijital düğme ve analog eksen bulunduğunu bilir. Donanım durumunun nasıl yoklanacağını bilen bu katman ve bir düğmenin ne zaman basıldığını veya birden fazla kene için kapalı olup olmadığını ya da basılmamış olup olmadığını bilen önceki durumu yeterince hatırlayan bu katman. . Bunun dışında aptal - tek bir denetleyiciyi temsil eden saf bir devlet sınıfı. Gerçek değer, denetleyici durumunu orta katmandan uzakta sorgulamanın azimli cesetini soyutlamaktır.

Orta katman, gerçek düğmelerden oyun kavramlarına (örneğin A -> Atla) gerçek kontrol eşlemesidir. Düğmeler yerine onlara dürtü diyoruz, çünkü artık belirli bir denetleyici türüne bağlı değiller. Bu katmanda kontrolleri yeniden oluşturabilirsiniz (geliştirme sırasında veya kullanıcının zamanında çalışma zamanında). Her platformun kontrolleri sanal dürtülerle eşlemesi vardır . Bundan kaçmaya çalışamazsınız. Her denetleyici benzersizdir ve kendi eşlemesine ihtiyaç duyar. Düğmeler birden fazla dürtü ile eşleşebilir (oyun moduna bağlı olarak) ve birden fazla düğme aynı dürtü ile eşleşebilir (örneğin A ve X'in ikisi de hızlanır, B ve Y'nin ikisi de yavaşlar). Haritalama bunların hepsini tanımlar,

Üst katman oyun katmanıdır. Dürtüleri alır ve nasıl üretildiklerini umursamaz. Belki bir kontrolörden ya da bir kontrolörün kaydından geliyorlardı, ya da bir yapay zekadan gelmişlerdi. Bu seviyede, umrunda değil. Önem verdiğiniz şey, yeni bir Atlama dürtüsü olması veya Hızlanma dürtüsünün devam etmesi veya Dalış dürtüsünün bu kene 0,35 değerinde olmasıdır.

Bu tür bir sistemle, her bir denetleyici için alt katmanı bir kez yazarsınız. Üst katman platformdan bağımsızdır. Orta katmanın kodunun yalnızca bir kez yazılması gerekir, ancak verilerin (yeniden eşleme) her platform / denetleyici için yeniden yapılması gerekir.


Bu çok temiz ve zarif bir yaklaşım gibi görünüyor. Teşekkür ederim!
Temel

1
Çok hoş. Benimkinden çok daha iyi: P
Jordaan Mylonas

3
Çok güzel bir soyutlama. Ancak uygularken dikkatli olun: her kullanıcı eylemi için yeni dürtü nesnesi yaratmayın ve yok etmeyin. Havuz kullanın. Çöp toplayıcı size teşekkür edecektir.
grega g

Kesinlikle. Maksimum eşzamanlı impuls sayısına göre boyutlandırılmış statik bir dizi neredeyse her zaman en iyi seçenektir; çünkü hemen hemen her zaman, her bir dürtüden sadece bir tane aynı anda aktif olmasını istersiniz. Çoğu zaman bu dizinin içinde sadece birkaç öğe vardır, bu nedenle tekrarlamak hızlıdır.
MrCranky

@grega ikinize de teşekkür ediyorum - bunu düşünmemiştim.
Temel

1

Dürüst olmak gerekirse, optimal arayüzün büyük oranda oyundaki kullanıma bağlı olacağını söyleyebilirim. Ancak, genel kullanım senaryosu için, olay tabanlı ve yoklama tabanlı yaklaşımları ayıran iki katmanlı bir mimari öneririm.

Alt katman, "yoklama tabanlı" katman olarak kabul edilebilir ve bir düğmenin geçerli durumunu gösterir. Böyle bir arabirimin sadece 2 işlevi olabilir GetAnalogState(InputIdentifier)ve GetDigitalState(InputIdentifier)nerede InputIdentifierkontrol ettiğiniz düğmeyi, tetikleyiciyi veya çubuğu temsil eden numaralandırılmış değerdir. (GetAnalogState'in bir düğme için çalıştırılması 1.0 veya 0.0 döndürür ve analog bir çubuk için GetDigitalState'in çalıştırılması önceden ayarlanmış bir eşiğin üzerindeyse true, aksi takdirde false değerini döndürür).

İkinci katman daha sonra durum değişikliği üzerine olaylar oluşturmak için alt katmanı kullanır ve öğelerin geri çağrılar için kayıt yapmasına izin verir (C # Olaylar görkemli). Bu geri aramalar basın, serbest bırakma, dokunma, uzun süre tutma vb. Olayları içerir. Analog bir çubuk için, örneğin dövüş oyunu için QCF gibi hareketler ekleyebilirsiniz. Maruz kalan olay sayısı, gönderilmesini istediğiniz bir olayın ne kadar ayrıntılı olduğuna bağlı olacaktır. Diğer ButtonStateChanged(InputIdentifier)her şeyi ayrı bir mantıkla ele almak istiyorsanız , basit bir ateş edebilirsiniz .

Dolayısıyla, bir giriş düğmesinin veya kontrol çubuğunun mevcut durumunu kontrol etmeniz gerekiyorsa, alt katmanı kontrol edin. Bir giriş olayında bir işlevi başlatmak istiyorsanız, ikinci katmandan bir geri arama için kaydolun.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.