sairate 5488a216f2 feat(第7讲 字母卡牌): 实现记忆游戏并添加开始界面
- 新增 jiyi.py 文件,实现字母翻牌记忆游戏功能
- 添加 youxijiemian.py 文件,创建游戏开始界面
- 使用 turtle 和 tkinter 模块分别实现游戏和界面
- 支持选择不同难度的游戏模式
2025-11-16 13:29:06 +08:00

268 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pgzrun
import random
import itertools
from pgzhelper import *
WIDTH = 1500
HEIGHT = 800
# 背景
bg1 = Actor('连续道路', topleft=(0, 0))
bg2 = Actor('连续道路', topleft=(1500, 0))
# 摩托车
motor = Actor('摩托1', (200, HEIGHT // 2))
motor.images = ['摩托1', '摩托2']
# 障碍物
obstacles = [Actor('路障', (random.randint(WIDTH, WIDTH + 1200),
random.randint(150, HEIGHT - 150))) for _ in range(2)]
# 终点线
line = Actor('终点线', topleft=(30000, 163))
# 钻石
zuan = Actor('钻石', topleft=(WIDTH + 100, random.randint(150, HEIGHT - 150)))
# 游戏参数
speed = 10
flag = 0 # 0=进行中,1=胜利,2=失败
score = 0
combo = 0
particles = []
blink = itertools.cycle([255, 180, 120, 180])
# 加速状态
boost_active = False
boost_time = 0
BOOST_DURATION = 5 # 秒
BOOST_SPEED = 20
BOOST_CD = 8 # 技能冷却时间
boost_cd_timer = 0 # CD倒计时
# 游戏计时
game_time = 0
# 加速提示圆圈参数
boost_circle_radius = 50
boost_circle_pos = (WIDTH - 100, HEIGHT - 100)
# 绘制函数
def draw():
bg1.draw()
bg2.draw()
if flag == 1 or flag == 2:
music.stop()
color = (255, next(blink), next(blink))
result_text = '胜利!' if flag == 1 else '失败!'
screen.draw.text(result_text, center=(WIDTH / 2, HEIGHT / 2 - 100),
fontsize=120, color=color, fontname='simkai')
# 显示用时和钻石数量
screen.draw.text(f'用时:{game_time:.2f}s', center=(WIDTH / 2, HEIGHT / 2 + 50),
fontsize=60, color='white', fontname='simkai')
screen.draw.text(f'收集钻石:{score}', center=(WIDTH / 2, HEIGHT / 2 + 120),
fontsize=60, color='yellow', fontname='simkai')
# 显示总评分
total_score = calculate_score()
screen.draw.text(f'最终评分:{total_score}', center=(WIDTH / 2, HEIGHT / 2 + 190),
fontsize=60, color='orange', fontname='simkai')
else:
for obs in obstacles:
obs.draw()
draw_particles()
motor.draw()
line.draw()
zuan.draw()
# draw_collision_rect() # 可选调试
x = int(line.x - motor.x)
screen.draw.text(f'距终点:{x} m', (50, 700),
fontname='simkai', fontsize=50)
screen.draw.text(f'钻石:{score}', (50, 100),
fontname='simkai', fontsize=50)
screen.draw.text(f'速度:{int(speed)}', (1300, 50),
fontname='simkai', fontsize=40, color='yellow')
# 绘制加速技能圆圈
draw_boost_circle()
def draw_particles():
for p in particles:
screen.draw.filled_circle((p['x'], p['y']), 4,
(255, 255, 150, int(p['alpha'])))
def update_particles():
for p in particles:
p['x'] -= 8
p['alpha'] -= 4
particles[:] = [p for p in particles if p['alpha'] > 0]
# 背景与障碍物移动
def bg_move():
bg1.x -= speed
bg2.x -= speed
if bg1.right <= 0:
bg1.left = bg2.right
if bg2.right <= 0:
bg2.left = bg1.right
line.x -= speed
zuan.x -= speed
if zuan.x <= 0:
zuan.x = random.randint(WIDTH, WIDTH + 1200)
zuan.y = random.randint(150, HEIGHT - 150)
def obs_move():
for obs in obstacles:
obs.x -= speed
if obs.x < -100:
obs.x = random.randint(WIDTH, WIDTH + 1200)
obs.y = random.randint(150, HEIGHT - 150)
def line_collide():
global flag
if motor.collide_pixel(line):
flag = 1
else:
motor.x += 10
def obs_collide():
global flag
mx, my = motor.x, motor.y
mw, mh = motor.width, motor.height
rect_width = int(mw * 0.3)
rect_height = int(mh * 0.2)
left = int(mx - rect_width / 2)
top = int(my + mh / 2 - rect_height)
bottom_center_rect = Rect((left, top), (rect_width, rect_height))
for obs in obstacles:
obs_rect = Rect((obs.left, obs.top), (obs.width, obs.height))
if bottom_center_rect.colliderect(obs_rect):
flag = 2
def zuan_collide():
global score, combo
if motor.collide_pixel(zuan):
combo += 1
score += combo
zuan.x = random.randint(WIDTH, WIDTH + 1200)
zuan.y = random.randint(150, HEIGHT - 150)
else:
combo = max(combo - 0.03, 0)
def draw_collision_rect():
# 调试用,可注释
mx, my = motor.x, motor.y
mw, mh = motor.width, motor.height
rect_width = int(mw * 0.3)
rect_height = int(mh * 0.2)
left = int(mx - rect_width / 2)
top = int(my + mh / 2 - rect_height)
collision_rect = Rect((left, top), (rect_width, rect_height))
screen.draw.rect(collision_rect, (255, 0, 0))
def draw_boost_circle():
# 圆圈颜色随CD变化
if boost_cd_timer > 0:
color = (100, 100, 100)
elif boost_active:
color = (0, 255, 255)
else:
color = (0, 200, 255)
screen.draw.circle(boost_circle_pos, boost_circle_radius, color)
screen.draw.text("SHIFT", center=boost_circle_pos, color="white", fontsize=30)
# 评分计算
def calculate_score():
"""根据用时、钻石和胜利情况计算最终得分"""
global score, game_time, flag
base_score = 0
# 胜利奖励
if flag == 1:
base_score += 500
# 钻石加分每颗钻石10分
base_score += score * 10
# 时间加分,时间越短,额外加分
time_score = max(0, int(1000 - game_time * 10))
base_score += time_score
return base_score
def update():
global speed, boost_active, boost_time, boost_cd_timer, game_time
if flag == 0:
# 计时
game_time += 1 / 60
# 更新技能CD
if boost_cd_timer > 0 and not boost_active:
boost_cd_timer -= 1 / 60
if boost_cd_timer < 0:
boost_cd_timer = 0
# Shift 加速
if (keyboard['lshift'] or keyboard['rshift']) and not boost_active and boost_cd_timer == 0:
boost_active = True
boost_time = BOOST_DURATION
speed = BOOST_SPEED
if boost_active:
boost_time -= 1 / 60
if boost_time <= 0:
boost_active = False
speed = 10
boost_cd_timer = BOOST_CD # 启动冷却
# 正常加减速
if not boost_active:
if keyboard.right:
speed = min(speed + 0.2, 18)
elif keyboard.left:
speed = max(speed - 0.2, 6)
# 背景移动
if line.x > WIDTH - 200:
bg_move()
obs_move()
else:
line_collide()
# 上下移动
if keyboard.up and motor.top > 0:
motor.y -= 6
if keyboard.down and motor.bottom < HEIGHT - 50:
motor.y += 6
# 碰撞检测
obs_collide()
zuan_collide()
# 尾焰粒子
particles.append({'x': motor.x - 40, 'y': motor.y + 10, 'alpha': 255})
update_particles()
def change_image():
motor.next_image()
clock.schedule_interval(change_image, 0.3)
music.play('速度与激情')
pgzrun.go()