dua opsi: jika kasus "input bersarang" paling banyak tiga, empat, saya hanya akan menggunakan flag. "Memegang benda? Tidak bisa menembak." Ada lagi yang overengineering itu.
Jika tidak, Anda dapat menyimpan tumpukan penanganan acara per-input-kunci.
Actions.Empty = () => { return; };
if(IsPressed(Keys.E)) {
keyEventHandlers[Keys.E].Push(Actions.Empty);
keyEventHandlers[Keys.LeftMouseButton].Push(Actions.Empty);
keyEventHandlers[Keys.Space].Push(Actions.Empty);
} else if (IsReleased(Keys.E)) {
keyEventHandlers[Keys.E].Pop();
keyEventHandlers[Keys.LeftMouseButton].Pop();
keyEventHandlers[Keys.Space].Pop();
}
while(GetNextKeyInBuffer(out key)) {
keyEventHandlers[key].Invoke(); // we invoke only last event handler
}
Atau sesuatu untuk efek ini :)
Sunting : seseorang menyebutkan konstruksi if-else yang tidak dikelola. Apakah kita akan menggunakan data-driven penuh untuk kegiatan penanganan event input? Anda pasti bisa, tetapi mengapa?
Pokoknya, untuk itu:
void BuildOnKeyPressedEventHandlerTable() {
onKeyPressedHandlers[Key.E] = () => {
keyEventHandlers[Keys.E].Push(Actions.Empty);
keyEventHandlers[Keys.LeftMouseButton].Push(Actions.Empty);
keyEventHandlers[Keys.Space].Push(Actions.Empty);
};
}
void BuildOnKeyReleasedEventHandlerTable() {
onKeyReleasedHandlers[Key.E] = () => {
keyEventHandlers[Keys.E].Pop();
keyEventHandlers[Keys.LeftMouseButton].Pop();
keyEventHandlers[Keys.Space].Pop();
};
}
/* get released keys */
foreach(var releasedKey in releasedKeys)
onKeyReleasedHandlers[releasedKey].Invoke();
/* get pressed keys */
foreach(var pressedKey in pressedKeys)
onKeyPressedHandlers[pressedKey].Invoke();
keyEventHandlers[key].Invoke(); // we invoke only last event handler
Edit 2
Kylotan menyebutkan pemetaan kunci, yang merupakan fitur dasar yang harus dimiliki setiap game (pikirkan tentang aksesibilitas juga). Termasuk keymapping adalah cerita yang berbeda.
Mengubah perilaku tergantung pada kombinasi tombol tekan atau urutan terbatas. Saya mengabaikan bagian itu.
Perilaku terkait dengan logika game dan bukan input. Yang cukup jelas, kalau dipikir-pikir itu.
Karena itu, saya mengusulkan solusi berikut:
// //>
void Init() {
// from config file / UI
// -something events should be set automatically
// quake 1 ftw.
// name family key keystate
"+forward" "movement" Keys.UpArrow Pressed
"-forward" Keys.UpArrow Released
"+shoot" "action" Keys.LMB Pressed
"-shoot" Keys.LMB Released
"jump" "movement" Keys.Space Pressed
"+lstrafe" "movement" Keys.A Pressed
"-lstrafe" Keys.A Released
"cast" "action" Keys.RMB Pressed
"picknose" "action" Keys.X Pressed
"lockpick" "action" Keys.G Pressed
"+crouch" "movement" Keys.LShift Pressed
"-crouch" Keys.LShift Released
"chat" "user" Keys.T Pressed
}
void ProcessInput() {
var pk = GetPressedKeys();
var rk = GetReleasedKeys();
var actions = TranslateToActions(pk, rk);
PerformActions(actions);
}
void TranslateToActions(pk, rk) {
// use what I posted above to switch actions depending
// on which keys have been pressed
// it's all about pushing and popping the right action
// depending on the "context" (it becomes a contextual action then)
}
actionHandlers["movement"] = (action, actionFamily) => {
if(player.isCasting)
InterruptCast();
};
actionHandlers["cast"] = (action, actionFamily) => {
if(player.isSilenced) {
Message("Cannot do that when silenced.");
}
};
actionHandlers["picknose"] = (action, actionFamily) => {
if(!player.canPickNose) {
Message("Your avatar does not agree.");
}
};
actionHandlers["chat"] = (action, actionFamily) => {
if(player.isSilenced) {
Message("Cannot chat when silenced!");
}
};
actionHandlers["jump"] = (action, actionFamily) => {
if(player.canJump && !player.isJumping)
player.PerformJump();
if(player.isJumping) {
if(player.CanDoubleJump())
player.PerformDoubleJump();
}
player.canPickNose = false; // it's dangerous while jumping
};
void PerformActions(IList<ActionEntry> actions) {
foreach(var action in actions) {
// we pass both action name and family
// if we find no action handler, we look for an "action family" handler
// otherwise call an empty delegate
actionHandlers[action.Name, action.Family]();
}
}
// //<
Ini bisa ditingkatkan dalam banyak hal oleh orang-orang yang lebih pintar dari saya, tetapi saya percaya itu juga merupakan titik awal yang baik.
Kami menggunakan sistem negara, seperti yang Anda sebutkan sebelumnya.
Kami akan membuat peta yang akan berisi semua kunci untuk negara tertentu dengan bendera yang memungkinkan melewati kunci yang sebelumnya dipetakan atau tidak. Ketika kami mengubah status, peta baru akan didorong atau peta sebelumnya akan muncul.
Contoh sederhana cepat dari status input adalah Default, In-Menu dan Magic-Mode. Default adalah tempat Anda berlarian dan bermain game. Dalam-Menu akan ketika Anda berada di menu mulai, atau ketika Anda telah membuka menu toko, menu jeda, layar opsi. In-Menu akan berisi flag no pass through karena ketika Anda menavigasi menu Anda tidak ingin karakter Anda bergerak. Di sisi lain, sangat mirip dengan contoh Anda dengan membawa item, Magic-Mode hanya akan memetakan kembali tombol tindakan / item untuk bukannya melemparkan mantra (kami juga akan mengikat itu untuk efek suara dan partikel tapi itu sedikit di luar pertanyaanmu).
Apa yang menyebabkan peta didorong dan muncul terserah Anda, dan saya juga akan dengan jujur mengatakan bahwa kami memiliki acara 'jelas' untuk memastikan tumpukan peta tetap bersih, pemuatan tingkat menjadi waktu yang paling jelas (Cutscenes juga di waktu).
Semoga ini membantu.
TL; DR - Gunakan status dan peta input yang dapat Anda tekan dan / atau pop. Sertakan bendera untuk mengatakan apakah peta menghapus input sebelumnya atau tidak.
sumber
Ini terlihat seperti kasus di mana warisan dapat menyelesaikan masalah Anda. Anda bisa memiliki kelas dasar dengan banyak metode yang menerapkan perilaku default. Anda kemudian dapat memperluas kelas ini dan mengganti beberapa metode. Beralih mode kemudian hanya masalah beralih dari implementasi saat ini.
Berikut ini beberapa kode semu
Ini mirip dengan apa yang diusulkan James.
sumber
Saya tidak menulis kode persis dalam bahasa tertentu. Aku memberimu ide.
1) Petakan tindakan utama Anda ke acara Anda.
(Keys.LeftMouseButton, left_click_event), (Keys.E, e_key_event), (Keys.Space, space_key_event)
2) Tetapkan / Ubah acara Anda seperti yang diberikan di bawah ini
Biarkan aksi lompatan Anda tetap dipisahkan dengan peristiwa lain seperti lompat dan tembak.
Hindari if..else .. cek bersyarat di sini karena akan menyebabkan kode tidak terkelola.
sumber
secret cloak
akan membutuhkan hal-hal seperti api, lari, berjalan, dan mengganti senjata agar tidak terdaftar, dan tidak terdaftar untuk didaftarkan.Alih-alih membatalkan pendaftaran, buat saja status lalu daftarkan kembali.
Tentu saja, memperluas ide sederhana ini adalah bahwa Anda mungkin memiliki status terpisah untuk bergerak, dan semacamnya, dan alih-alih mendikte "Yah, inilah semua hal yang tidak dapat saya lakukan saat dalam Mode Jubah Rahasia, inilah semua yang saya bisa lakukan lakukan dalam Mode Jubah Rahasia. "
sumber