pygame鼠闯迷宫闯关小游戏

"""鼠闯迷宫闯关小游戏.一只老鼠在一个巨大的迷宫中,它要出去才不致于被饿死,用鼠标牵引它移动即可。
碰撞使用的是mask,老鼠是相对于迷宫的移动(迷宫在动)"""

__author__ = "李兴球"
__date__ = "2018年12月左右"

import os,math,sys
import pygame
from pygame.locals import *

class Maze(pygame.sprite.Sprite):
    def __init__(self,image,scale,screen):
        pygame.sprite.Sprite.__init__(self)
        self.screen = screen
        self.image = pygame.image.load(image).convert_alpha()
        self.__width = self.image.get_width()                    # 获取宽度
        self.__height = self.image.get_height()                  # 获取高度
        newsize = (scale * self.__width,scale * self.__height)   # 新的宽高
        self.image = pygame.transform.scale(self.image,newsize)  # 缩放大小
        self.image = self.image.convert_alpha()         
        self.mask = pygame.mask.from_surface(self.image)         # 设置掩膜 
        self.rect = self.image.get_rect()
        "为了把它放到屏幕中间,这是增加的代码"
        self.rect.center = (screen.get_width()//2,screen.get_height()//2)
        
    def update(self,dx,dy):
        """迷宫朝相反的dx和dy移动"""
        self.rect.move_ip(dx*0.05,dy*0.05)      
        
    def draw(self):
        self.screen.blit(self.image,self.rect)
        
class Mouse(pygame.sprite.Sprite):
    def __init__(self,image,position,screen,maze=None):
        pygame.sprite.Sprite.__init__(self)
        self.position = position                                  # 原始坐标
        self.screen = screen
        self.maze = maze                                          # 引用当前的迷宫对象
        self.raw_image = pygame.image.load(image).convert_alpha() # 原始造型
        "下面这句缩小老鼠的宽度为50,高度按比例调整"
        self.raw_image = pygame.transform.scale(self.raw_image,(50,int(50*self.raw_image.get_height()//self.raw_image.get_width())))
        self.image = self.raw_image                               # 设定image的初始值
        self.rect = self.raw_image.get_rect()                     # 得到矩形对象
        self.rect.center = position                               # 定坐标
        self.angle = 0                                            # 和x轴的夹角,角度
        self.bump_wall = 1
    def towards(self,mousexy):
        """根据鼠标指针的坐标设定方向"""
        dy = -(mousexy[1] - self.rect.centery)
        dx = mousexy[0] - self.rect.centerx        
        self.angle =  math.degrees(math.atan2(dy,dx))
        
    def distance(self,mousexy):
        """到鼠标指针的距离"""
        dy = mousexy[1] - self.rect.centery
        dx = mousexy[0] - self.rect.centerx
        return math.sqrt(dx * dx  + dy * dy)        
        
    def update(self,mousexy,logic):
        """根据方向角度更新图像"""
        if self.distance(mousexy) > 50 :
            self.image = pygame.transform.rotate(self.raw_image,self.angle).convert_alpha()
            self.image.set_colorkey((0,0,0))
            self.mask = pygame.mask.from_surface(self.image)        # 设定掩膜属性,以后用于和迷宫mask的碰撞检测
            self.rect = self.image.get_rect()                       # 得到矩形对象
            self.rect.center = self.position                        # 矩形的中心点位置
            dy = -mousexy[1] + self.rect.centery
            dx = -mousexy[0] + self.rect.centerx
            dy = logic * dy
            dx = logic * dx
            self.maze.update(dx,dy)                                 # 更新迷宫坐标
            
    def bump_check(self):
        """对碰黑墙和碰绿门进行碰撞检测,实际上是对maze进行通过mask的碰撞检测,返回point坐标。
        ,再侦测像素值就知道是碰到门还是碰到绿色"""
        level_end = False
        point = pygame.sprite.collide_mask(self.maze,self)
        "迷宫绿色像素值为:(0, 255, 85, 255),黑色墙壁的像素值为:(0,0,0,255)"
        if point :            
            pixel_maze = self.maze.image.get_at(point)
            #print("碰撞点",point,"迷宫像素值:",pixel_maze)      
            if pixel_maze == (0, 255, 85, 255):                  # 碰到绿色的门,那么此关结束。
                level_end = True
            elif pixel_maze == (0, 0, 0, 255):                   # 碰到黑色的墙,倒回去               
                self.update(mousexy,-1)                
        return level_end        
        
    def draw(self):
        self.screen.blit(self.image,self.rect)

        
def display_shell(screensize,shell_image,begin_button_images):
    width,height = screensize
    index = 0
    button_image = begin_button_images[index]
    
    button_rect = button_image.get_rect()
    button_width = button_rect.width
    button_height = button_rect.height
    button_rect.center = (width//2,100+height//2)
    clock = pygame.time.Clock()
    running = True
    continue_game = True
    while running:
        for event in pygame.event.get():
            if event.type == QUIT:
                running = False
                continue_game = False
                break
        mousexy = pygame.mouse.get_pos()
        mousekeys = pygame.mouse.get_pressed()

        if button_rect.collidepoint(mousexy):                 # 鼠标指针在矩形范围内
            index = 1
        else:
            index = 0
            
        if mousekeys[0] and index == 1:
            running = False

        screen.blit(shell_image,(0,0))
        screen.blit(begin_button_images[index],button_rect)
                    
        pygame.display.update()
        clock.tick(30)
    
    return continue_game


def display_end(end_image):
    clock = pygame.time.Clock()
    running = True    
    while running:
        for event in pygame.event.get():
            if event.type == QUIT:
                running = False              
                break
        mousekeys = pygame.mouse.get_pressed()        
        if mousekeys[0] : running = False
            
        screen.blit(end_image,(0,0))                    
        pygame.display.update()
        clock.tick(30)       
    
    
if __name__ == "__main__":
    
    shell_image = pygame.image.load(os.getcwd() + os.sep + "images" + os.sep + "封面.png")
    begin_button_images = ["开始按钮1.png","开始按钮2.png"]
    begin_button_images = [pygame.image.load(os.getcwd() + os.sep + "images" + os.sep + image) for image in  begin_button_images]
    end_image = pygame.image.load(os.getcwd() + os.sep + "images" + os.sep + "endimage.png")
    
    success_image = pygame.image.load(os.getcwd() + os.sep + "images" + os.sep + "过关界面.png")
    maze_images = [os.getcwd() + os.sep + "images" + os.sep + str(i) + ".png" for i in range(5)]
    maze_amounts = len(maze_images)
    mouse_image = os.getcwd() + os.sep + "images" + os.sep + "mouse1-a.png"
    width,height = 800,600
    game_title = "鼠标迷宫游戏_作者:李兴球,风火轮少儿编程,www.scratch8.net"
    pygame.init()
    screen = pygame.display.set_mode((width,height))
    pygame.display.set_caption(game_title)

    if  display_shell((width,height),shell_image,begin_button_images):       # 显示封面,单击开始按钮继续程序运行。
            
        mazes  = [Maze(maze_images[index],index + 2,screen) for index in range(maze_amounts)]
        current_maze_index = 0
        current_maze = [current_maze_index]
        mouse = Mouse(mouse_image,(width//2,height//2),screen)    
        clock = pygame.time.Clock()
        exit_game = False
        for current_maze in mazes:
            mouse.maze = current_maze        
            running = True
            while running:
                for event in pygame.event.get():
                    if event.type == QUIT:
                        running = False
                        exit_game = True
                        break
                mousexy = pygame.mouse.get_pos()
                mouse.towards(mousexy)
                mouse.update(mousexy,1)                                      # mouse的update会自动调用maze.update

                "给Mouse类增加了这个方法,用于碰墙与碰门的检测"
                level_end = mouse.bump_check()
                if level_end : break        
                screen.fill((255,255,255))
                current_maze.draw()
                mouse.draw()        
                
                pygame.display.update()
                clock.tick(30)

            if exit_game : break
            print("本关结束,单击后开始下一关。")
            running = True
            while running:
                for event in pygame.event.get():
                    if event.type == QUIT:
                        running = False
                        exit_game = True
                        break            
                if pygame.mouse.get_pressed()[0] or pygame.key.get_pressed()[K_RETURN]:running = False
                screen.blit(success_image,(0,0))
                pygame.display.update()
                clock.tick(60)
            if exit_game : break

        display_end(end_image)          
    pygame.quit()
    print("游戏结束。")