Güncelleme (özet)
Oldukça ayrıntılı bir cevap yazdığım için, işte bunların hepsi kaynıyor:
- Ad alanları iyidir, mantıklı olduğunda kullanın
- Kullanmak
inGameIO
ve playerIO
sınıflar muhtemelen SRP'nin ihlali anlamına gelecektir. Muhtemelen IO'yu kullanma şeklinizi uygulama mantığıyla birleştirdiğiniz anlamına gelir.
- İşleyici sınıfları tarafından kullanılan (veya bazen paylaşılan) birkaç genel IO sınıfına sahip olun. Bu işleyici sınıfları daha sonra ham girdiyi uygulama mantığınızın anlayabileceği bir biçime dönüştürür.
- Çıktı için de aynı şey geçerlidir: bu oldukça genel sınıflar tarafından yapılabilir, ancak oyun durumunu dahili oyun durumunu genel IO sınıflarının işleyebileceği bir işleyiciye dönüştüren bir işleyici / eşleştirici nesnesi aracılığıyla geçirin.
Sanırım buna yanlış bakıyorsunuz. Uygulamanın bileşenlerinin fonksiyonunda IO'yu ayırıyorsunuz, oysa - bana göre, IO'nun kaynağına ve "tipine" dayalı olarak ayrı IO sınıflarına sahip olmak daha mantıklı .
Başlamak için bazı temel / genel KeyboardIO
sınıflara MouseIO
sahip olmak ve daha sonra onlara ne zaman ve nerede ihtiyacınız olduğuna bağlı olarak, bahsedilen G / Ç'yi farklı şekilde işleyen alt sınıflara sahip olun.
Örneğin, metin girişi muhtemelen oyun içi denetimlerden farklı işlemek istediğiniz bir şeydir. Kendinizi, her kullanım durumuna bağlı olarak belirli anahtarları farklı şekilde eşlemek istediğinizde bulacaksınız, ancak bu eşleme IO'nun bir parçası değildir, bu IO'yu nasıl işlediğinizdir.
SRP'ye bağlı kaldığımda, klavye IO için kullanabileceğim birkaç dersim olurdu. Duruma bağlı olarak, muhtemelen bu sınıflarla farklı etkileşim kurmak isteyeceğim, ancak onların tek işi bana kullanıcının ne yaptığını anlatmak.
Daha sonra bu nesneleri ya uygulama mantığımın çalışabileceği bir şeye ham IO'yu eşleyecek bir işleyici nesnesine enjekte ederim (örneğin: kullanıcı "w" tuşuna basarsa , işleyici bu haritalara eşler MOVE_FORWARD
).
Bu işleyiciler, karakterleri hareket ettirmek ve ekranı buna göre çizmek için kullanılır. Brüt aşırı basitleştirme, ancak özü bu tür bir yapıdır:
[ IO.Keyboard.InGame ] // generic, if SoC and SRP are strongly adhered to, changing this component should be fairly easy to do
||
==> [ Controls.Keyboard.InGameMapper ]
[ Game.Engine ] <- Controls.Keyboard.InGameMapper
<- IO.Screen
<- ... all sorts of stuff here
InGameMapper.move() //returns MOVE_FORWARD or something
||
==> 1. Game.updateStuff();//do all the things you need to do to move the character in the given direction
2. Game.Screen.SetState(GameState); //translate the game state (inverse handler)
3. IO.Screen.draw();//generate actual output
Şimdi sahip olduğumuz şey, klavye IO'sundan ham haliyle sorumlu bir sınıf. Bu verileri oyun motorunun gerçekten anlayabileceği bir şeye dönüştüren başka bir sınıf, bu veriler daha sonra ilgili tüm bileşenlerin durumunu güncellemek için kullanılır ve son olarak, ayrı bir sınıf ekrana çıktı ile ilgilenir.
Her sınıfın tek bir işi vardır: klavye girişini işlemek, bilmediği / bakım yaptığı / işlediği girdinin ne anlama geldiğini bilmesi gereken bir sınıf tarafından yapılır. Tek yaptığı, girdinin nasıl alınacağını bilmektir (arabelleğe alınmış, arabelleğe alınmış, ...).
İşleyici bunu, uygulamanın geri kalanı için bu bilgileri anlaması için dahili bir temsile dönüştürür.
Oyun motoru çevrilen verileri alır ve bir şey olup olmadığını ilgili tüm bileşenlere bildirmek için kullanır. Bu bileşenlerin her biri, çarpışma kontrolleri veya karakter animasyonu değişiklikleri olsun, tek bir şey yapar, farketmez, bu her bir nesneye bağlıdır.
Bu nesneler daha sonra durumlarını geri aktarırlar ve bu veriler Game.Screen
özünde ters bir IO işleyicisi olan iletilir . Dahili temsili, IO.Screen
bileşenin gerçek çıktıyı oluşturmak için kullanabileceği bir şeyle eşleştirir .