代码拉取完成,页面将自动刷新
# 设置代码页为UTF-8,正常显示中文
# -*- coding: UTF-8 -*-
import sys
# import win32api, win32con
import pygame
from pygame import mixer
from shape import *
from shape import get_random_shape
############
# 初始化 #
############
pg.init()
####################
# 播放声音和音乐 #
####################
mixer.music.load('background.wav')
mixer.music.set_volume(0.2)
mixer.music.play(-1)
rotate_sound = mixer.Sound('can_rotate.wav')
rotate_sound.set_volume(1)
tilt_rotate_sound = mixer.Sound('tilt_rotate.wav')
tilt_rotate_sound.set_volume(1)
speed_mode_sound = mixer.Sound('speed_mode.wav')
speed_mode_sound.set_volume(1)
# UI设置
class GameMetaData(object):
font_type = 'Aabadaokai.ttf'
comment_font_type = "simhei.ttf"
map_row_no = 20
map_column_no = 10
screen_width = map_column_no * 30 + 250
screen_height = map_row_no * 30 + 100
screen_center_width = int(screen_width / 2)
screen_center_height = int(screen_height / 2)
width_offset = 50
height_offset = 50
score_window_pos = 30 * map_column_no + width_offset + 30
score_window_text_pos = 30 * map_column_no + width_offset + 50
background = 'bkgrnd.jpg'
class Scenes(object):
titleScene = None
gameScene = None
active_scene = None
class State(object):
level = 1
score = 0
full_line_no = 0
@staticmethod
def reset_new_game():
State.score = 0
State.full_line_no = 0
State.level = 1
class SceneBase:
def __init__(self):
self.next = self
self.score_font = pg.font.Font(GameMetaData.font_type, 20)
self.full_line_font = pg.font.Font(GameMetaData.font_type, 20)
self.level_font = pg.font.Font(GameMetaData.font_type, 20)
self.next_font = pg.font.Font(GameMetaData.font_type, 18)
self.comment_text = pg.font.Font(GameMetaData.comment_font_type, 18)
self.arrow_text = pg.font.Font(GameMetaData.comment_font_type, 13)
self.spacekey_text = pg.font.Font(GameMetaData.comment_font_type, 13)
def process_input(self, events):
raise NotImplementedError("哦,你没有在子类中重写这个输入过程。")
def update(self):
raise NotImplementedError("哦,你没有在子类中重写这个更新。")
def render(self, screen):
raise NotImplementedError("哦,你没有在子类中重写这个渲染。")
# 绘制文字区域
def draw_score_area(self, main_screen):
# 成绩
# 有背景框,不用再绘制边框
# pg.draw.rect(main_screen, Colour.FIREBRICK.value, (GameMetaData.score_window_pos, 55, 155, 85), 1)
score_text = self.score_font.render("得分:" + str(State.score), True, Colour.WHITE.value)
full_line_text = self.full_line_font.render("消行:" + str(State.full_line_no), True,
Colour.WHITE.value)
level_text = self.level_font.render("等级:" + str(State.level), True, Colour.WHITE.value)
score_text_y = 65
main_screen.blit(score_text, (GameMetaData.score_window_text_pos -15, score_text_y))
main_screen.blit(full_line_text, (GameMetaData.score_window_text_pos - 15, score_text_y + 25 * 1))
main_screen.blit(level_text, (GameMetaData.score_window_text_pos - 15, score_text_y + 25 * 2))
# 绘制文本“下个方块:”
# 有背景框,不用再绘制边框
# pg.draw.rect(main_screen, Colour.FIREBRICK.value, (GameMetaData.score_window_pos, 175, 155, 80), 1)
next_text = self.next_font.render('下个方块:', True, Colour.WHITE.value)
main_screen.blit(next_text, (GameMetaData.score_window_text_pos - 15, 178))
# 绘制操作说明
comment_y = 425
# 有背景框,不用再绘制边框
# pg.draw.rect(main_screen, Colour.GREEN.value, (GameMetaData.score_window_pos, comment_y, 155, 180), 1)
comment_text = self.comment_text.render('操作说明', True, Colour.WHITE.value)
uparrow_text = self.arrow_text.render('【Tab】:旋转', True, Colour.GOLD.value)
leftarrow_text = self.arrow_text.render('【←】:向左移动', True, Colour.GOLD.value)
rightarrow_text = self.arrow_text.render('【→】:向右移动', True, Colour.GOLD.value)
downarrow_text = self.arrow_text.render('【↓】:加速下移', True, Colour.GOLD.value)
spacekey_text = self.arrow_text.render('【空格】:超速下移', True, Colour.RED.value)
esc_text = self.arrow_text.render('【ESC】:暂停', True, Colour.TEAL.value)
main_screen.blit(comment_text, (GameMetaData.score_window_text_pos - 15, comment_y + 6)) #起点 234
comment_y = comment_y + 15
main_screen.blit(uparrow_text, (GameMetaData.score_window_text_pos - 15, comment_y + 25 * 1))
main_screen.blit(leftarrow_text, (GameMetaData.score_window_text_pos - 15, comment_y + 25 * 2))
main_screen.blit(rightarrow_text, (GameMetaData.score_window_text_pos - 15, comment_y + 25 * 3))
main_screen.blit(downarrow_text, (GameMetaData.score_window_text_pos - 15, comment_y + 25 * 4))
main_screen.blit(spacekey_text, (GameMetaData.score_window_text_pos - 15, comment_y + 25 * 5))
main_screen.blit(esc_text, (GameMetaData.score_window_text_pos - 15, comment_y + 25 * 6))
# 背景图片
@staticmethod
def load_backgound(main_screen):
background = pygame.image.load(GameMetaData.background)
main_screen.blit(background,(0, 0))
@staticmethod
def draw_area_grid(main_screen):
for row_no in range(0, GameMetaData.map_row_no + 1):
pg.draw.line(main_screen, Colour.DEEP_GREY.value, (GameMetaData.width_offset, 50 + (row_no * 30)),
(30 * GameMetaData.map_column_no + GameMetaData.width_offset, 50 + (row_no * 30)), 1)
if row_no < GameMetaData.map_column_no + 1:
pg.draw.line(main_screen, Colour.DEEP_GREY.value, (GameMetaData.width_offset + (row_no * 30),
GameMetaData.height_offset),
(GameMetaData.width_offset + (row_no * 30),
30 * GameMetaData.map_row_no + GameMetaData.height_offset))
def switch_to_scene(self, next_scene):
self.next = next_scene
class TitleScene(SceneBase):
def __init__(self):
SceneBase.__init__(self)
self._is_continue = False
self._is_game_over = False
self.options = 0 if self.is_continue else 1
self.default = Colour.WHITE.value
self.selected = Colour.RED.value
self.continue_font = pygame.font.Font(GameMetaData.font_type, 36)
self.new_game_font = pygame.font.Font(GameMetaData.font_type, 36)
self.options_font = pygame.font.Font(GameMetaData.font_type, 36)
self.exit_game_font = pygame.font.Font(GameMetaData.font_type, 36)
self.new_game_rect = None
self.options_rect = None
self.exit_game_rect = None
self.continue_rect = None
@property
def is_continue(self):
return self._is_continue
@is_continue.setter
def is_continue(self, is_continue):
self._is_continue = is_continue
self.options = 0
@property
def is_game_over(self):
return self._is_game_over
@is_game_over.setter
def is_game_over(self, is_game_over):
self._is_game_over = is_game_over
self._is_continue = False
self.options = 1
#判断一个点是否在指定范围内
@staticmethod
def in_rect(pos,rect):
x,y =pos
rx,ry,rw,rh = rect
if (rx <= x <=rx+rw)and(ry <= y <= ry +rh):
return True
return False
def process_input(self, events):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
self.options += 1
# TODO:选项功能暂未实现,跳过
if self.options == 2:
self.options = 3
if self.options > 3:
self.options = 0 if self.is_continue else 1
if event.key == pygame.K_UP:
self.options -= 1
# TODO:选项功能暂未实现,跳过
if self.options == 2:
self.options = 1
lower_limit = 0 if self.is_continue else 1
if self.options < lower_limit:
self.options = 3
if event.key == pygame.K_ESCAPE:
if self.is_continue:
Scenes.active_scene = Scenes.gameScene
if event.key == pygame.K_RETURN or event.key == pygame.K_KP_ENTER:
if self.options == 0: # 继续游戏
Scenes.active_scene = Scenes.gameScene
if self.options == 1: # 开始游戏
self._is_game_over = False
State.reset_new_game()
Scenes.gameScene = GameScene()
Scenes.active_scene = Scenes.gameScene
if self.options == 2: # 选项
pass
if self.options == 3: # 退出
quit_game()
# 鼠标移动
if event.type == pygame.MOUSEMOTION:
# 获取鼠标位置
pos = pygame.mouse.get_pos()
if self.new_game_rect != None:
#if self.in_rect(pos, rect=(GameMetaData.screen_center_width - 70, GameMetaData.screen_center_height - 35 - 15, 140, 30)):
if self.in_rect(pos, self.new_game_rect):
self.options = 1
if self.exit_game_rect != None:
#if self.in_rect(pos, rect=(GameMetaData.screen_center_width - 40, GameMetaData.screen_center_height + 35 - 15, 80, 30)):
if self.in_rect(pos, self.exit_game_rect):
self.options = 3
if self.continue_rect != None:
if self.in_rect(pos, self.continue_rect):
self.options = 0
# 鼠标单击
if event.type == pygame.MOUSEBUTTONDOWN:
# 鼠标左键单击
if event.button == pygame.BUTTON_LEFT:
pos = pygame.mouse.get_pos()
# 测试
# if self.in_rect(pos, self.new_game_rect):
# poss = '在开始游戏区'
# else:
# poss = '不在开始游戏区'
# win32api.MessageBox(0, '您点击了鼠标左键,pos=' + str(pos) + ' ' + poss , '鼠标点击', win32con.MB_OK)
# if self.new_game_rect == None or self.exit_game_rect == None or self.continue_rect == None:
# return;
# 必须检查对象是否未空
if self.continue_rect != None:
if self.in_rect(pos, self.continue_rect):
if (self.options == 0): # 继续游戏
Scenes.active_scene = Scenes.gameScene
if self.new_game_rect != None:
if self.in_rect(pos, self.new_game_rect):
if (self.options == 1): # 开始游戏
self._is_game_over = False
State.reset_new_game()
Scenes.gameScene = GameScene()
Scenes.active_scene = Scenes.gameScene
if self.options == 2: # 选项
pass
if self.exit_game_rect != None:
if self.in_rect(pos, self.exit_game_rect):
if (self.options == 3): # 退出
quit_game()
if event.type == pygame.QUIT:
quit_game()
def update(self):
pass
def render(self, screen):
if not self.is_game_over:
screen.fill(Colour.BLACK.value)
# 背景图片
SceneBase.load_backgound(screen)
self.draw_score_area(screen)
# 不绘制表格线
# SceneBase.draw_area_grid(screen)
new_game_text = self.new_game_font.render("开始游戏", True,
self.selected if self.options == 1 else self.default)
self.new_game_rect = new_game_text.get_rect(center=(GameMetaData.screen_center_width, GameMetaData.screen_center_height - 35))
options_text = self.options_font.render("选项", True,
self.selected if self.options == 2 else self.default)
exit_game_text = self.exit_game_font.render("退出", True,
self.selected if self.options == 3 else self.default)
self.exit_game_rect = exit_game_text.get_rect(center=(GameMetaData.screen_center_width, GameMetaData.screen_center_height + 35))
menu_background = pygame.Rect((0, 0), (250, 250))
menu_rect = options_text.get_rect(center=(GameMetaData.screen_center_width,
GameMetaData.screen_center_height))
menu_offset = 25 if self.is_continue else 0
menu_background.center = (menu_rect.width / 2 + menu_rect.x,
(menu_rect.height / 2 + menu_rect.y) - menu_offset)
pg.draw.rect(screen, Colour.BLACK.value, menu_background, 0)
pg.draw.rect(screen, Colour.WHITE.value, menu_background, 1)
if self.is_game_over:
game_over_font = pg.font.Font(GameMetaData.font_type, 72)
game_over_text = game_over_font.render("游戏结束!", True, Colour.RED.value)
screen.blit(game_over_text,
game_over_text.get_rect(center=(GameMetaData.screen_center_width,
GameMetaData.screen_center_height - 160)))
#self.is_continue = True
if self.is_continue:
continue_game_text = self.continue_font.render("继续游戏", True,
self.selected if self.options == 0 else self.default)
self.continue_rect = continue_game_text.get_rect(center=(GameMetaData.screen_center_width, GameMetaData.screen_center_height - 100))
#screen.blit(continue_game_text, continue_game_text.get_rect(center=(GameMetaData.screen_center_width, GameMetaData.screen_center_height - 100)))
screen.blit(continue_game_text, self.continue_rect)
#screen.blit(new_game_text, new_game_text.get_rect(center=(GameMetaData.screen_center_width, GameMetaData.screen_center_height - 35)))
screen.blit(new_game_text, self.new_game_rect)
# TODO: 选项功能暂未实现,暂不显示
#screen.blit(options_text, menu_rect)
#screen.blit(exit_game_text, exit_game_text.get_rect(center=(GameMetaData.screen_center_width, GameMetaData.screen_center_height + 35)))
screen.blit(exit_game_text, self.exit_game_rect)
pygame.display.update()
class GameScene(SceneBase):
def __init__(self):
SceneBase.__init__(self)
self.empty_line = []
for i in range(GameMetaData.map_column_no):
self.empty_line.append(0)
self.tetris_map = [self.empty_line[:] for _ in range(GameMetaData.map_row_no)]
self.moving_object = [get_random_shape(GameMetaData.map_row_no, GameMetaData.map_column_no),
get_random_shape(GameMetaData.map_row_no, GameMetaData.map_column_no)]
self.movement_fps = 0
self.keyboard_speed = 0
self.movement_speed = 50
self.maximum_movement_speed = 5
self.super_speed_mode = False
self.game_over = False
def process_input(self, events):
keys = pygame.key.get_pressed()
for event in events:
if event.type == pg.QUIT:
quit_game()
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
Scenes.titleScene.is_continue = True
Scenes.active_scene = Scenes.titleScene
if event.key == pg.K_LEFT:
self.keyboard_speed = -2
self.moving_object[0].move_left(self.tetris_map)
if event.key == pg.K_RIGHT:
self.keyboard_speed = -2
self.moving_object[0].move_right(self.tetris_map)
if event.key == pg.K_DOWN and not self.super_speed_mode:
self.keyboard_speed = -2
self.moving_object[0].move_down(self.tetris_map)
State.score += 1
if event.key in (pg.K_UP, pg.K_TAB): # 向上箭头或TAB键旋转 == pg.K_UP or event.key == pg.K_LSHIFT or event.key == pg.K_RSHIFT:
could_rotate = self.moving_object[0].rotate(self.tetris_map)
if could_rotate:
rotate_sound.play()
else:
tilt_rotate_sound.play()
if event.key == pg.K_SPACE:
if not self.super_speed_mode:
self.super_speed_mode = True
speed_mode_sound.play()
self.movement_speed = 1
else:
self.super_speed_mode = False
self.calculate_speed()
if keys[pg.K_LEFT]:
self.keyboard_speed += 1
if self.keyboard_speed >= 4:
self.keyboard_speed = 0
self.moving_object[0].move_left(self.tetris_map)
if keys[pg.K_RIGHT]:
self.keyboard_speed += 1
if self.keyboard_speed >= 4:
self.keyboard_speed = 0
self.moving_object[0].move_right(self.tetris_map)
if keys[pg.K_DOWN]:
self.keyboard_speed += 1
if self.keyboard_speed >= 4:
self.keyboard_speed = 0
State.score += 1
self.moving_object[0].move_down(self.tetris_map)
def update(self):
self.movement_fps += 1
if self.movement_fps >= self.movement_speed:
self.movement_fps = 0
self.move_object_down_or_game_over()
def draw_next_shape(self, main_screen):
self.moving_object[1].draw_next(main_screen, GameMetaData.score_window_text_pos - 20)
def render(self, main_screen):
main_screen.fill(Colour.BLACK.value)
#背景图片
SceneBase.load_backgound(main_screen)
# 绘制成绩
self.draw_score_area(main_screen)
# 绘制下个方块
self.draw_next_shape(main_screen)
# 绘制移动对象
self.moving_object[0].draw(main_screen)
# 绘制被使用的块
self.draw_used_blocks(main_screen)
if self.game_over:
GameScene.draw_game_over()
pg.display.update()
def draw_used_blocks(self, main_screen):
for row_no, row in enumerate(self.tetris_map):
for column_no, column_value in enumerate(row):
if column_value != 0:
block_color = get_colour_by_number(column_value)
pg.draw.rect(main_screen, block_color.value, (50 + (column_no * 30), 50 + (row_no * 30), 30, 30), 2)
pg.draw.rect(main_screen, block_color.value, (50 + (column_no * 30) + 5, 50 + (row_no * 30) + 5, 21,
21))
# 不绘制表格线
# SceneBase.draw_area_grid(main_screen)
@staticmethod
def draw_game_over():
Scenes.titleScene.is_game_over = True
Scenes.active_scene = Scenes.titleScene
def calculate_speed(self):
if State.level < 10:
State.level = int(State.full_line_no / 10) + 1
new_movement_speed = 50 - ((State.level - 1) * 5)
if not self.super_speed_mode and self.movement_speed != new_movement_speed:
self.movement_speed = new_movement_speed
elif not self.super_speed_mode:
self.movement_speed = self.maximum_movement_speed
def move_object_down_or_game_over(self):
if self.moving_object[0].is_finished_or_collided(self.tetris_map):
self.movement_speed = 0
is_game_over = False
for block in self.moving_object[0].blocks:
if block[0] == 0:
is_game_over = True
self.tetris_map[block[0]][block[1]] = get_colour_number_by_name(self.moving_object[0].colour.name)
if not is_game_over:
temp = []
full_line = 0
for row in list(reversed(self.tetris_map)):
if 0 not in row:
full_line += 1
else:
temp.append(row)
if full_line > 0:
State.full_line_no += full_line
State.score += full_line * 100
for _ in range(full_line):
temp.append(self.empty_line[:])
self.tetris_map = list(reversed(temp))
self.moving_object.append(get_random_shape(GameMetaData.map_row_no, GameMetaData.map_column_no))
self.moving_object.pop(0)
if self.super_speed_mode:
self.super_speed_mode = False
self.calculate_speed()
self.game_over = is_game_over
else:
if self.super_speed_mode:
State.score += 1
self.moving_object[0].move_down(self.tetris_map)
def quit_game():
pygame.quit()
sys.exit()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。