回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

Game&Watch消防员救人游戏模拟器(Mind+ 互动编程;游戏设计大赛) 简单

头像 米菲爸爸 2024.06.21 137 0

GameWatch消防员救人游戏模拟器

简介: 这款Game&Watch消防员救人游戏模拟器利用了计算机视觉技术OpenCV,mediapipe以及简单游戏框架Pgzore,让玩家通过简单的左右手势来控制救援人员移动。玩家需要掌握正确时机和方向,成功接住从天而降的求救者,赢取积分。简单的游戏机制和直观的控制方式适合所有年龄群体。特别是70后怀旧人群。

image.png

 

首先安装必要的库,我们使用Mind+ 中的Python模式中的库管理分别输入并执行

image.png
image.png

安装好库文件后

从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写一段简单的手势识别代码.这里我们只简单的检测左手或者右手来代替按键盘的左键还是右键

 

image.png
image.png

代码
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()

附件

评论

user-avatar