クリックした場所に弾を撃ちたいのに、位置がズレる。マウス入力を扱うと、座標の変換で、つまずきがちです。UIのボタンやシューティングの照準など、ゲームで欠かせないマウス入力は、Windowsなら、数行で取得できます。
この記事では、マウスのクリック判定、カーソル座標の取り方、座標変換、初心者がハマりやすいミスを解説します。キーボード入力を取得する方法の記事も、あわせてどうぞ。
マウス入力の基本
Windowsでは、<Windows.h> の関数を使ってマウス入力を取得します。よく使うのは次の2つです。
GetAsyncKeyState… ボタンが押されているか(左はVK_LBUTTON)GetCursorPos… カーソルの座標を取得
クリック判定を取る
左クリックされているかは、GetAsyncKeyState(VK_LBUTTON) の最上位ビットを & 0x8000 で調べます。
#include <iostream>
#include <Windows.h>
int main() {
// 左ボタンが今押されているか
if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) {
std::cout << "左クリック中\n";
}
// 右ボタンは VK_RBUTTON
if (GetAsyncKeyState(VK_RBUTTON) & 0x8000) {
std::cout << "右クリック中\n";
}
return 0;
}左クリック中
ビット演算の & 0x8000 は「そのビットが立っているか」の判定です。このあたりはキーボード入力とまったく同じ考え方です。
カーソルの座標を取る
座標は GetCursorPos で取得できますが、これは画面全体(スクリーン)の座標です。ゲームウィンドウ内の座標にするには ScreenToClient で変換します。
#include <iostream>
#include <Windows.h>
void ShowMousePos(HWND hwnd) {
POINT pt;
GetCursorPos(&pt); // スクリーン座標
ScreenToClient(hwnd, &pt); // ウィンドウ内の座標へ変換
std::cout << "マウス: (" << pt.x << ", " << pt.y << ")\n";
}マウス: (320, 240)
これで、クリックした位置に弾を撃つ、UIボタンの上にカーソルがあるか判定する、といった処理が書けます。当たり判定はAABBの当たり判定の記事と組み合わせると便利です。
【重要】私が実際にマウス入力で困った体験談
個人開発でクリック位置に弾を撃つ処理を作ったとき、GetCursorPos の座標をそのまま使ったら、画面の左上ほど大きくズレて、狙った場所に弾が飛ばないという不具合にハマりました。
原因は、GetCursorPos が返すのはスクリーン座標で、ウィンドウの位置ぶんだけズレていたこと。ScreenToClient でウィンドウ座標に変換したら、ピタッと狙った場所に飛ぶようになりました。「マウス座標は ScreenToClient で変換」と体で覚えた出来事です。
マウス入力使用時のよくある失敗例と対処法
①スクリーン座標とウィンドウ座標の混同
体験談のとおり、変換しないとズレます。ゲーム内の判定には ScreenToClient でウィンドウ座標に直しましょう。
②「押した瞬間」を取れない
& 0x8000 は「押されている間ずっと真」です。押した瞬間だけ反応させたいなら、前フレームの状態と比べて「前は押していない→今押している」で判定します。
③ビット判定を忘れて常に真になる
if (GetAsyncKeyState(VK_LBUTTON)) のように & 0x8000 を忘れると、意図しない挙動になります。必ずビットで判定しましょう。
注意点
- 座標はゲーム内で使う前に
ScreenToClientで変換する - 「押した瞬間」は前フレームとの比較で取る
- ここではWindows APIを使用。DirectXやSDLでは別の入力方法もある
まとめ
- クリックは
GetAsyncKeyState(VK_LBUTTON) & 0x8000で判定 - 座標は
GetCursorPos+ScreenToClientで取る - スクリーン座標とウィンドウ座標の変換忘れに注意
- 「押した瞬間」は前フレームと比較して判定する
座標は、GetCursorPosとScreenToClientで取ります。スクリーン座標とウィンドウ座標の変換を、忘れないでください。「押した瞬間」は、前のフレームの状態と比較して判定します。


