我需要一個游戲回圈中的函式,它應該只在第一次按下時回傳 true。
我不知道哪款游戲我可以舉一個目前市場上哪款游戲的例子,但我會詳細解釋這個要求(我沒有玩過/不能玩任何現代游戲,因為我是盲人)。
例如,您正在回圈中偵聽一個事件。當用戶按下S鍵時,螢屏上會出現顯示角色最后狀態的文本:耐力、能量等。這個回圈每秒可以運行數千次,因為回圈取決于硬體和代碼的速度你寫。我們只需要檢測用戶的第一次按下。按住鍵時它應該回傳 false。否則,用戶的最后狀態會在螢屏上顯示數千次。
我正在嘗試使用 win32api 提供此功能。GetAsyncKeyState似乎是這種情況下的正確選擇,但我不明白如何做到這一點。
bool IsPressed(int key) {
return GetAsyncKeyState(key) & 1 != 0;
}
我撰寫的函式就像一個 char 事件。
我怎么寫這個?
我嘗試在 StackOwerflow 上使用其他答案。但是,我找不到我提出的問題的答案。不過,這些答案幫助我解決了一些問題: 在 Win32 中確定按鍵和按住鍵的最快方法是什么?
uj5u.com熱心網友回復:
雖然GetAsyncKeyState 可以通過最低有效位指示自上次呼叫此函式以來是否已按下鍵,但不能依賴此行為。
如果設定了最高有效位,則鍵按下,如果設定了最低有效位,則在上一次呼叫 GetAsyncKeyState 后按下了鍵。但是,您不應該依賴最后一種行為......
盡管回傳值的最低有效位指示自上次查詢以來是否已按下鍵,但由于 Windows 的搶占式多任務性質,另一個應用程式可以呼叫 GetAsyncKeyState 并接收“最近按下”位而不是您的應用程式。
因此,您不能依賴 Windows API 來為您記賬。我建議將任何鍵查詢包裝在一個類中,您將用于任何按鈕按下。
class KeyInput {
public:
using key_type = int;
enum class Transition {
none,
pressed,
released,
};
struct PressResult {
bool pressed;
Transition transition;
};
PressResult state(key_type key) {
PressResult result;
result.pressed = (GetAsyncKeyState(key) < 0);
if (auto it = last_states_.find(key); it != last_states_.end()) {
if (last_states_[key] == result.pressed) {
result.transition = Transition::none;
}
else if (result.pressed) {
result.transition = Transition::pressed;
}
else {
result.transition = Transition::released;
}
}
else {
result.transition = Transition::none;
}
last_states_[key] = result.pressed;
return result;
};
private:
std::unordered_map<key_type, bool> last_states_{};
};
看到它在行動
筆記
這不會捕獲自您的程式最后一次迭代以來的轉換。為了處理這個問題,您需要您的班級在每次迭代中檢查每個按鈕按下(您關心的)。
uj5u.com熱心網友回復:
在進一步研究之后,我意識到我不能用 GetAsyncKeyState 或類似的函式來做到這一點。我使用 Windows 的回呼和事件系統撰寫了一些簡單的東西。我不關心資料競爭和其他問題。您可能需要使用互斥鎖,但這取決于您的代碼。
下面的代碼將鍵的狀態保存在一個陣列中。回呼通過函式將更改發送到陣列。
如果您在控制臺模式下編譯程式,您會看到當您按 A 時它只列印到控制臺一次。這正是我想要的。
要編譯,您可以使用:
g minimal.cpp
- 您可以按a在標準查詢鍵盤上對其進行測驗。
#include <iostream>
#include <windows.h>
#include <vector>
// We define a struct that holds the key state.
// firstPress will be updated by IsPressed.
struct keyState {
bool firstPress;
bool down;
};
// We have an Array-based collection of keys. Changes will be made by callback.
std::vector<keyState> allKeyStates(256);
void keyProcess(unsigned short key, bool down)
{
if(down) {
if(!allKeyStates[key].down) {
allKeyStates[key].down = true;
allKeyStates[key].firstPress = true;
}
return;
}
allKeyStates[key].down = false;
allKeyStates[key].firstPress = false;
}
bool IsPressed(unsigned short key)
{
if(allKeyStates[key].firstPress) {
allKeyStates[key].firstPress = false;
return true;
}
return false;
}
// forward decleration
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int main()
{
MSG msg = {0};
HWND handle;
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = "mini_windows_test";
if( !RegisterClass(&wc) )
return -1;
handle = CreateWindow(wc.lpszClassName, "Minimal Key handling application", WS_OVERLAPPEDWINDOW|WS_VISIBLE, 0,0, 640, 480, 0, 0, GetModuleHandle(NULL), NULL);
if(handle == NULL)
return -1;
while(GetMessage(&msg, NULL, 0, 0 ) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
if(IsPressed(0x41)) {
std::cout << "Key A: it will only be print on the first press. Holding the key will not run repeatedly.\n";
}
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) {
case WM_KEYDOWN:
keyProcess((unsigned short)wParam, true);
break;
case WM_KEYUP:
keyProcess((unsigned short)wParam, false);
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
為糟糕的英語和錯別字道歉。如果對您有用,您可以編輯我的問題和答案。
uj5u.com熱心網友回復:
我不了解 C ,但它在所有語言中肯定遵循相同的程序,因此您可以將該壓力方法設定為“如果”并定義一個數字,通過按下它的值,變為一,然后寫入。在“如果”中如果數字的值等于 1,就不要再這樣做了
例如,在 java 中,它說:
int x = 0;
Button back = findViewById(R.id.button);
if(x == 0){
back.setOnClickListener(v -> {
//your code to do;
x = 1;
});
}else{}
也可以在 C 中作業,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/428287.html
