GameWatch消防员救人游戏模拟器
简介: 这款Game&Watch消防员救人游戏模拟器利用了计算机视觉技术OpenCV,mediapipe以及简单游戏框架Pgzore,让玩家通过简单的左右手势来控制救援人员移动。玩家需要掌握正确时机和方向,成功接住从天而降的求救者,赢取积分。简单的游戏机制和直观的控制方式适合所有年龄群体。特别是70后怀旧人群。
首先安装必要的库,我们使用Mind+ 中的Python模式中的库管理分别输入并执行
安装好库文件后
从github上下载游戏模拟器部分
https://github.com/Wireframe-Magazine/Wireframe-63/tree/main/source-code-game-and-watch
(如无法下载也没有关系,可以从我这里获得没有加入opencv前的游戏代码体验复古游戏的乐趣)
代码
#!pip install pgzero
import pgzrun
# 初始化一些基本的状态和值
count = catcherPos = moveCatcher = gameState = score = 0
catchers = []
jumpers = []
jumperPositions = [(130,220),(190,260),(210,320),(220,360),(240,410),(260,360),
(270,320),(290,250),(320,220),(340,250),(360,300),(380,360),
(390,410),(420,360),(430,300),(470,250),(500,300),(520,360),
(538,410),(580,360),(600,320),(620,350)]
# 初始化人物Actor,这里有3个人物,坐在雪橇上,位置在屏幕底部中央
for c in range(3):
catchers.append(Actor('catcher'+str(c), center=(240+(c*150), 425)))
# 画图函数,每运行一次就更新一帧
def draw():
# 首先画上背景
screen.blit("background",(0,0))
# 用循环把人物draw出来
for c in range(3):
if catcherPos == c: catchers[c].draw()
# 循环检查每一个跳跃者的状态,并根据状态把跳跃者画出来
for j in jumpers:
if j.state == 0: j.draw()
if j.state == -1 and count%2 == 0: j.draw()
# 画出积分,积分在屏幕上方的右侧,颜色是黑色,字体大小是25
screen.draw.text("SAVED: "+str(score), topleft = (580, 120), color=(0,0,0) , fontsize=25)
# 更新函数,每运行一次就更新一次状态
def update():
global count
count += 1
if(count%30 == 0) : doUpdate() # 每30帧更新一次doUpdate
if(count%2000 == 0) : makeJumper() # 每2000帧创建一个新的跳跃者
# 这个函数根据用户的操作或者游戏规则更新跳跃者和人物的状态
def doUpdate():
global catcherPos, moveCatcher, gameState, score
if gameState == 0:
catcherPos = limit(catcherPos+moveCatcher, 0, 2)
moveCatcher = 0
for j in jumpers:
if (j.frame < 21 and j.state == 0):
j.frame += 1
j.image = "jumper"+str(j.frame)
j.pos = jumperPositions[j.frame]
else:
if j.state == 0:
j.state = 1
score += 1
makeJumper()
if (j.frame == 4 and catcherPos != 0) or (j.frame == 12 and catcherPos != 1) or (j.frame == 18 and catcherPos != 2):
j.state = -1
j.image = "jumperdropped"
j.y += 50
gameState = 1
# 这个函数用来接收用户的按键操作
def on_key_down(key):
global moveCatcher
# 如果用户按了左键,就向左移动雪橇
if key.name == "LEFT":
moveCatcher = -1
# 如果用户按了右键,就向右移动雪橇
if key.name == "RIGHT":
moveCatcher = 1
# 这个函数用来创建新的跳跃者
def makeJumper():
if len(jumpers)%5 == 4:
jumpers.append(Actor('jumper0', center=(130, 270)))
jumpers[len(jumpers)-1].frame = 1
else:
jumpers.append(Actor('jumper0', center=(130, 220)))
jumpers[len(jumpers)-1].frame = 0
jumpers[len(jumpers)-1].state = 0
# 此函数用来限制雪橇的移动范围,防止它移动出屏幕
def limit(n, minn, maxn):
return max(min(maxn, n), minn)
# 创建第一名跳跃者
makeJumper()
# 运行游戏
pgzrun.go()
然后使用opencv写一段简单的手势识别代码.这里我们只简单的检测左手或者右手来代替按键盘的左键还是右键
代码
import cv2
import numpy as np
import mediapipe as mp
import time
# 初始化
mp_hands = mp.solutions.hands
hands = mp_hands.Hands()
capture = cv2.VideoCapture(0)
last_hand_detected = None
last_detection_time = 0
DETECTION_INTERVAL_SECONDS = 2
while capture.isOpened():
success, frame = capture.read()
if not success:
break
results = hands.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
landmarks = hand_landmarks.landmark
current_hand = "Left" if landmarks[mp_hands.HandLandmark.THUMB_TIP].x < landmarks[mp_hands.HandLandmark.PINKY_TIP].x else "Right"
if current_hand != last_hand_detected or time.time() - last_detection_time > DETECTION_INTERVAL_SECONDS:
print(f"Detected: {current_hand}")
last_hand_detected = current_hand
last_detection_time = time.time()
mp.solutions.drawing_utils.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
cv2.imshow('Frame', frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
capture.release()
现在我们把两个代码有机的结合在一起,点击运行就可以玩复古游戏了.
附件里提供了游戏的背景图片和资源包,需放在程序的images目录下
代码
import cv2
import numpy as np
import mediapipe as mp
import time
#!pip install pgzero
import pgzrun
# 初始化
mp_hands = mp.solutions.hands
hands = mp_hands.Hands()
capture = cv2.VideoCapture(0)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 240)
last_hand_detected = None
last_detection_time = 0
DETECTION_INTERVAL_SECONDS = 0.5
count = catcherPos = moveCatcher = gameState = score = 0
catchers = []
jumpers = []
jumperPositions = [(130,220),(190,260),(210,320),(220,360),(240,410),(260,360),
(270,320),(290,250),(320,220),(340,250),(360,300),(380,360),
(390,410),(420,360),(430,300),(470,250),(500,300),(520,360),
(538,410),(580,360),(600,320),(620,350)]
for c in range(3):
catchers.append(Actor('catcher'+str(c), center=(240+(c*150), 425)))
def process_gestures() :
global moveCatcher, last_hand_detected, last_detection_time
if capture.isOpened() and time.time() - last_detection_time > DETECTION_INTERVAL_SECONDS:
success, frame = capture.read()
if not success:
print("NOT success")
return
results = hands.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
landmarks = hand_landmarks.landmark
current_hand = "Left" if landmarks[mp_hands.HandLandmark.THUMB_TIP].x < landmarks[mp_hands.HandLandmark.PINKY_TIP].x else "Right"
print(f"Detected: {current_hand}")
if current_hand == "Left":
moveCatcher = -1
if current_hand == "Right":
moveCatcher = 1
last_hand_detected = current_hand
last_detection_time = time.time()
mp.solutions.drawing_utils.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
cv2.imshow('Frame', frame)
def draw():
screen.blit("background",(0,0))
for c in range(3):
if catcherPos == c: catchers[c].draw()
for j in jumpers:
if j.state == 0: j.draw()
if j.state == -1 and count%2 == 0: j.draw()
screen.draw.text("SAVED: "+str(score), topleft = (580, 120), color=(0,0,0) , fontsize=25)
def update():
global count
count += 1
process_gestures()
if(count%30 == 0) : doUpdate()
if(count%2000 == 0) : makeJumper()
def doUpdate():
global catcherPos, moveCatcher, gameState, score
if gameState == 0:
print("moveCatcher", moveCatcher)
catcherPos = limit(catcherPos+moveCatcher, 0, 2)
moveCatcher = 0
for j in jumpers:
if (j.frame < 21 and j.state == 0):
j.frame += 1
j.image = "jumper"+str(j.frame)
j.pos = jumperPositions[j.frame]
else:
if j.state == 0:
j.state = 1
score += 1
makeJumper()
if (j.frame == 4 and catcherPos != 0) or (j.frame == 12 and catcherPos != 1) or (j.frame == 18 and catcherPos != 2):
j.state = -1
j.image = "jumperdropped"
j.y += 50
gameState = 1
def on_key_down(key):
global moveCatcher
if key.name == "LEFT":
moveCatcher = -1
if key.name == "RIGHT":
moveCatcher = 1
def makeJumper():
if len(jumpers)%5 == 4:
jumpers.append(Actor('jumper0', center=(130, 270)))
jumpers[len(jumpers)-1].frame = 1
else:
jumpers.append(Actor('jumper0', center=(130, 220)))
jumpers[len(jumpers)-1].frame = 0
jumpers[len(jumpers)-1].state = 0
def limit(n, minn, maxn):
return max(min(maxn, n), minn)
makeJumper()
pgzrun.go()
cv2.destroyAllWindows()
capture.release()
附件
评论