はじめに
本記事では、MediaPipeを使用して手の動きを認識し、その動きでコントロールするブロック崩しゲームについて説明します
Kaijo Physics Club Advent Calendar 2024に投稿する記事です
技術スタック
- Pygame (ゲーム開発ライブラリ)
- MediaPipe (手の認識用ライブラリ)
システム概要
このゲームは以下の2つの主要な機能で構成されています:
-
ブロック崩しゲームの基本機能
- 画面上部に配置された青いブロック
- 落下する赤い球
- プレイヤーが操作する白いバー
- 衝突判定と跳ね返り処理
-
手の認識による操作
- MediaPipeによる手のランドマーク検出
- 検出された座標に基づくバーの移動
実装
1. 必要なライブラリのインポート
import pygame
import time
import cv2
import mediapipe as mp
from multiprocessing import Process, Value
import math
2. 手を検出するモデルを作成する
mp_hands = mp.solutions.hands
mp_draw = mp.solutions.drawing_utils
hands = mp_hands.Hands()
3. メインゲームループ
画面設定や、壁やブロックに当たったときの跳ね返りなどの処理を行います
動作の仕組み
基本メカニズム
- ボールは画面の端に当たると跳ね返ります
- 上部のブロックに当たると、そのブロックが消滅し、ボールが跳ね返ります
- 下部に落ちるとゲームオーバーとなります
手の認識とバーの制御
- MediaPipeが手のランドマーク(21個の特徴点)を検出
- 21個から、x座標・y座標の最小値・最大値を求め、それらの平均値の座標を計算する
- 計算された座標値でバーの位置を決定
if results.multi_hand_landmarks: # 手が検出された場合
# 検出された手を2つに絞る
hand_landmarks = results.multi_hand_landmarks[:2] # 最初の1つの手のみ処理
for hand_lms in hand_landmarks:
landmarks = []
landmark = []
for index, lm in enumerate(hand_lms.landmark):
ih, iw, _ = img.shape
x, y = int(lm.x * iw), int(lm.y * ih)
landmark.append([x, y])
landmarks.append(landmark)
x_list = []
y_list = []
for i in range(21):
x_list.append(landmarks[0][i][0])
y_list.append(landmarks[0][i][1])
most_right_x = max(x_list)
most_left_x = min(x_list)
most_up_y = max(y_list)
most_down_y = min(y_list)
color = (0, 0, 255) # 囲む線(赤)
average_x_value = (most_left_x + most_right_x) // 2
average_x.value = average_x_value
print(average_x.value)
まとめ
課題としては、複数の手が画面上にあると、検出する手が変わってしまうことが挙げられます
現状MediaPipeには同じ手を追える機能はなく、ID付与などができないので難しい状態です