话不多说,来围观效果。
一、选题背景
非常高兴能和一众大咖们一起同台竞技,参与Mind+ 互动编程&游戏设计大赛,能力和精力所限,一直徘徊如何选题,直到米菲爸爸发布了他的作品,我的作品雏形渐渐形成,使用Mind+的python模式做一款简单又好玩的小游戏,能把大家带回童年的时光,回味,升华。就是它
不用按键盘和手柄,空中伸出手就可以玩滑雪游戏。
选择做滑雪小游戏的原因有以下三点:
1.游戏目标简单
滑雪小游戏的目标是让玩家控制角色在雪地上滑行,尽可能地躲避障碍物并收集道具,以获得最高的分数或滑行更远的距离。
2.游戏玩法通俗易懂
角色控制:玩家通过键盘按键来控制滑雪者的移动方向,包括左右移动等,以避开障碍物和陷阱。
道具收集:在滑行过程中,玩家可以收集各种道具,如硬币、宝石、加速器等,这些道具可以增加分数、延长游戏时间或增强角色的能力。
障碍物躲避:游戏中会设置各种障碍物,如树木、岩石、其他滑雪者等,玩家需要灵活应对,避免碰撞到这些障碍物,否则游戏可能会结束。
3.加入智能识别程序时,不至于程序复杂影响编程的进度和效率。
二、工欲善其事 必先利其器
使用mind+作为编程的利器,他不仅支持各种硬件和传感器,还加入了Python模式,不用安装python程序就可以编程了。界面如下
右上角中实时模式、上传模式、python模式选择python模式。
左上角模块和代码要选择代码,模块指的是图形化编程 的模块。
不仅如此它还具有如下特点:
1. 图形化编程:Mind+提供图形化积木编程功能,用户只需拖动图形化程序块即可完成编程,大大降低了编程的入门门槛,让青少年能够轻松跨入编程世界的大门。
2. 支持多种编程语言:除了图形化编程外,Mind+还支持Python/C/C++等高级编程语言,用户可以根据需要选择适合的编程语言进行编程学习。
3. 集成多种硬件:Mind+集成了各种主流主控板及上百种开源硬件,支持人工智能(AI)与物联网(IoT)功能,让用户能够轻松实现硬件编程与控制。
4. 自动转换代码:在图形化编程时,Mind+可以自动将图形化积木编程转换为Python或C代码,方便用户对照学习,同时也可以手动编辑代码,满足进阶编程需求。
5. 丰富的扩展功能:Mind+拥有强大的硬件扩展功能库,可以直接对上百种硬件模块进行编程控制,包括各种传感器、执行器、通讯模块、显示器、功能模块等。同时,Mind+还开放了扩展库,给用户提供了丰富的扩展空间进行无限的创造。
三、项目制作步骤
步骤1 收集素材,制作图片库
搜集或者制作游戏主人公的各种动作。
搜集和制作游戏中的旗帜和障碍物的图片。
并放置到同一个文件夹下,命名为img
步骤2 使用Pygame库编写滑雪小游戏
虽然是小游戏,还是考验码农的逻辑能力,如果太费神就可以从github、gitee或者通过大语言模型来获取滑雪小游戏的模版来改写。
本人搜的的代码如下
import pygame, sys, random
skier_images = [
'img/skier_down.png',
'img/skier_right1.png',
'img/skier_right2.png',
'img/skier_left2.png',
'img/skier_left1.png',
]
class SkierClass(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('img/skier_down.png')
self.rect = self.image.get_rect()
self.rect.center = [320, 100]
self.angle = 0
def turn(self, direction):
self.angle = self.angle + direction
if self.angle < -2:
self.angle = -2
if self.angle > 2:
self.angle = 2
center = self.rect.center
self.image = pygame.image.load(skier_images[self.angle])
self.rect = self.image.get_rect()
self.rect.center = center
speed = [self.angle, 6 - abs(self.angle) * 2]
return speed
def move(self, speed):
self.rect.centerx = self.rect.centerx + speed[0]
if self.rect.centerx < 20:
self.rect.centerx = 20
if self.rect.centerx > 620:
self.rect.centerx = 620
class ObstacleClass(pygame.sprite.Sprite):
def __init__(self, image_file, location, obs_type):
pygame.sprite.Sprite.__init__(self)
self.image_file = image_file
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.center = location
self.obs_type = obs_type
self.passed = False
def update(self):
global speed
self.rect.centery = self.rect.centery - speed[1]
if self.rect.centery < -32:
self.kill()
def create_map():
global obstacles
locations = []
for i in range(10):
row = random.randint(0, 9)
col = random.randint(0, 9)
location = [col * 64 + 20, row * 64 + 640]
if not (location in locations):
locations.append(location)
obs_type = random.choice(['tree', 'flag'])
if obs_type == 'tree':
img = 'img/skier_tree.png'
elif obs_type == 'flag':
img = 'img/skier_flag.png'
obstacle = ObstacleClass(img, location, obs_type)
obstacles.add(obstacle)
def animate():
screen.fill([255, 255, 255])
obstacles.draw(screen)
screen.blit(skier.image, skier.rect)
screen.blit(score_text, [10, 10])
pygame.display.flip()
pygame.init()
screen = pygame.display.set_mode([640, 640])
clock = pygame.time.Clock()
skier = SkierClass()
speed = [0, 6]
obstacles = pygame.sprite.Group()
map_position = 0
points = 0
create_map()
font = pygame.font.SysFont('SimHei', 40)
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_a:
speed = skier.turn(-1)
elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
speed = skier.turn(1)
skier.move(speed)
map_position = map_position + speed[1]
if map_position >= 640:
create_map()
map_position = 0
hit = pygame.sprite.spritecollide(skier, obstacles, False)
if hit:
if hit[0].obs_type == 'tree' and not hit[0].passed:
points = points - 100
skier.image = pygame.image.load('img/skier_crash.png')
animate()
pygame.time.delay(1000)
skier.image = pygame.image.load('img/skier_down.png')
skier.angle = 0
speed = [0, 6]
hit[0].passed = True
elif hit[0].obs_type == 'flag' and not hit[0].passed:
points = points + 10
hit[0].kill()
obstacles.update()
score_text = font.render('得分: ' + str(points), 1, (0, 0, 0))
animate()
pygame.quit()
步骤3 测试智能识别代码
我使用米菲爸爸的识别代码,使用的是mediapipe库和cv2库。效果也是非常好的,如下图所示
如果没有安装加载mediapipe库和cv2库的童鞋需要先安装,打开mind+的python模式选择代码选项,右侧有库管理的按钮,点击该按钮
选择pip模式,输入pip install mediapipe
安装成功会提示命令运行完成,其他的库同样可以用该方法。
接着上代码,点击运行后可以在frame窗口中看到智能识别左右手了。
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()
步骤4 将智能识别程序加入滑雪小游戏
打算使用函数的方式,但是这样会造成class类成员无法访问函数内数据,还是为了简单吧,直接将智能识别程序写入到主程序中。点击运行就可以享受小游戏带来的快乐啦。
代码如下;
import pygame, sys, random
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)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 240)
#time.sleep(3000)
last_hand_detected = None
last_detection_time = 0
DETECTION_INTERVAL_SECONDS = 0.15
skier_images = [
'img/skier_down.png',
'img/skier_right1.png',
'img/skier_right2.png',
'img/skier_left2.png',
'img/skier_left1.png',
]
class SkierClass(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('img/skier_down.png')
self.rect = self.image.get_rect()
self.rect.center = [320, 100]
self.angle = 0
def turn(self, direction):
self.angle = self.angle + direction
if self.angle < -2:
self.angle = -2
if self.angle > 2:
self.angle = 2
center = self.rect.center
self.image = pygame.image.load(skier_images[self.angle])
self.rect = self.image.get_rect()
self.rect.center = center
speed = [self.angle, 6 - abs(self.angle) * 2]
return speed
def move(self, speed):
self.rect.centerx = self.rect.centerx + speed[0]
if self.rect.centerx < 20:
self.rect.centerx = 20
if self.rect.centerx > 620:
self.rect.centerx = 620
class ObstacleClass(pygame.sprite.Sprite):
def __init__(self, image_file, location, obs_type):
pygame.sprite.Sprite.__init__(self)
self.image_file = image_file
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.center = location
self.obs_type = obs_type
self.passed = False
def update(self):
global speed
self.rect.centery = self.rect.centery - speed[1]
if self.rect.centery < -32:
self.kill()
def create_map():
global obstacles
locations = []
for i in range(10):
row = random.randint(0, 9)
col = random.randint(0, 9)
location = [col * 64 + 20, row * 64 + 640]
if not (location in locations):
locations.append(location)
obs_type = random.choice(['tree', 'flag'])
if obs_type == 'tree':
img = 'img/skier_tree.png'
elif obs_type == 'flag':
img = 'img/skier_flag.png'
obstacle = ObstacleClass(img, location, obs_type)
obstacles.add(obstacle)
def animate():
screen.fill([255, 255, 255])
obstacles.draw(screen)
screen.blit(skier.image, skier.rect)
screen.blit(score_text, [10, 10])
pygame.display.flip()
pygame.init()
screen = pygame.display.set_mode([640, 640])
clock = pygame.time.Clock()
skier = SkierClass()
speed = [0, 6]
obstacles = pygame.sprite.Group()
map_position = 0
points = 0
create_map()
font = pygame.font.SysFont('SimHei', 40)
running = True
while running:
clock.tick(60)
if capture.isOpened() and time.time() - last_detection_time > DETECTION_INTERVAL_SECONDS:
success, frame = capture.read()
if not success:
print("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"
print(f"Detected: {current_hand}")
if current_hand == "Left":
speed = skier.turn(-1)
if current_hand == "Right":
speed = skier.turn(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)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == event.key == pygame.K_q:
running = False
'''
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_a:
speed = skier.turn(-1)
elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
speed = skier.turn(1)
'''
skier.move(speed)
map_position = map_position + speed[1]
if map_position >= 640:
create_map()
map_position = 0
hit = pygame.sprite.spritecollide(skier, obstacles, False)
if hit:
if hit[0].obs_type == 'tree' and not hit[0].passed:
points = points - 100
skier.image = pygame.image.load('img/skier_crash.png')
animate()
pygame.time.delay(1000)
skier.image = pygame.image.load('img/skier_down.png')
skier.angle = 0
speed = [0, 6]
hit[0].passed = True
elif hit[0].obs_type == 'flag' and not hit[0].passed:
points = points + 10
hit[0].kill()
obstacles.update()
score_text = font.render('得分: ' + str(points), 1, (0, 0, 0))
animate()
cv2.destroyAllWindows()
capture.release()
pygame.quit()
四、游戏体验和不足
1.该游戏太简单,就是有点费手,上下举着权当做锻炼身体了。
2.该游戏界面单一,一直是一个背景,可以使用多个背景避免视觉疲劳。
3.该游戏障碍物只有大树,都是相同的大树,可以加入石头。
4.该游戏没有背景音乐,没有渲染滑雪时的紧张气氛。
接下来的改进中可以从以上方面进行,如果各位还有什么体验感受或者建议评论告诉我吧。
但是不要弄得太复杂了哦。
附件
罗罗罗2024.10.13
666