pygame中主屏幕上的按钮闪烁

问题描述

我正在创建一个游戏。因此,在主菜单上,我有两个用于播放和退出的按钮。 但是,无论以后我调用哪个按钮,即,如果我调用func的“开始”按钮,然后再调用退出”按钮,反之亦然,则第二个被调用按钮开始闪烁。 这是我的代码

import math
import pygame
import random
import time
from pygame import mixer

# Initialising PyGame
pygame.init()

# Creating Screen
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption('Space Invaders')

# Global Variables
playerIMG = pygame.image.load('player.png')
alienIMG = []
bulletIMG = pygame.image.load('bullet.png')
bullet_state = 'ready'
clock = pygame.time.Clock()
start_count = 0
exit_count = 0
# Background
bgIMG = pygame.image.load('C:bgIMG.png')
bgIMG = pygame.transform.scale(bgIMG,(800,600))


# Font
def text_on_screen(text,colour,x,y,size):
    font = pygame.font.Font('Stargaze Regular.otf',size)
    screen_text = font.render(text,True,colour)
    screen.blit(screen_text,[x,y])


def player(x,y):
    screen.blit(playerIMG,(x,y))


def alien(x,i):
    screen.blit(alienIMG[i],y))


def fire_bullet(x,y):
    global bullet_state
    bulletSound = mixer.sound('laser.wav')
    bulletSound.play()
    bullet_state = 'fire'
    screen.blit(bulletIMG,(x + 15,y - 30))


def isCollision(x1,x2,y2,y1):
    dist = math.sqrt(((x1 - x2) ** 2) + ((y1 - y2) ** 2))
    if dist < 23:
        collisionSound = mixer.sound('explosion.wav')
        collisionSound.set_volume(120)
        collisionSound.play()
        return True
    else:
        return False


class Button:
    def __init__(self,color,width,height,text=''):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text = text

    def draw(self,win,font_size,outline=None):
        # Call this method to draw the button on the screen
        if outline:
            pygame.draw.rect(win,outline,(self.x - 2,self.y - 2,self.width + 4,self.height + 4),0)

        pygame.draw.rect(win,self.color,(self.x,self.y,self.width,self.height),0)

        if self.text != '':
            font = pygame.font.Font('Stargaze Regular.otf',font_size)
            text = font.render(self.text,1,(0,0))
            win.blit(text,(
                self.x + (self.width / 2 - text.get_width() / 2),self.y + (self.height / 2 - text.get_height() / 2)))

    def isOver(self,pos):
        # Pos is the mouse position or a tuple of (x,y) coordinates
        if self.x < pos[0] < self.x + self.width:
            if self.y < pos[1] < self.y + self.height:
                return True

        return False


# Game Over
def game_over():
    for i in range(3000):
        text_on_screen('GAME OVER!',(255,255,0),190,220,60)
        text_on_screen('PRESS R TO RESTART',270,310,20)
        text_on_screen('PRESS Q TO QUIT',300,335,20)
        pygame.display.update()
        for e in pygame.event.get():
            if e.type == pygame.KEYDOWN:
                if e.key == pygame.K_r:
                    gameloop()
                    break
                elif e.key == pygame.K_q:
                    pygame.quit()
                    quit()


def Start_button():
    global start_count
    mouse = pygame.mouse.get_pos()
    start_button = Button((255,255),10,370,80,40,'PLAY')
    startwidth = start_button.width
    startheight = start_button.height
    start_text = start_button.text
    if start_button.isOver(mouse):
        start_button.color = (255,255)
        start_button.width += 10
        start_button.height += 10
        loop = 0
        i = 1
        if start_count == 0:
            while loop < 4 and i < 5:
                start_button.text = start_text[:i]
                start_button.draw(screen,23)
                time.sleep(0.08)
                loop += 1
                i += 1
                start_count += 1
                pygame.display.update()
        else:
            start_button.draw(screen,23)
            pygame.display.update()
    else:
        start_button.height = startheight
        start_button.width = startwidth
        start_button.draw(screen,20)
    pygame.display.update()
    if not start_button.isOver(mouse):
        start_count = 0
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN and start_button.isOver(mouse):
            gameloop()


def Exit_Button():
    global exit_count
    mouse = pygame.mouse.get_pos()
    exit_button = Button((255,425,'EXIT')
    exitwidth = exit_button.width
    exitheight = exit_button.height
    exit_text = exit_button.text
    if exit_button.isOver(mouse):
        exit_button.color = (255,255)
        exit_button.width += 10
        exit_button.height += 10
        loop = 0
        i = 1
        if exit_count == 0:
            while i < 5:
                exit_button.text = exit_text[:i]
                exit_button.draw(screen,23)
                time.sleep(0.08)
                loop += 1
                i += 1
                exit_count += 1
                pygame.display.update()
        else:
            exit_button.draw(screen,23)
            pygame.display.update()
    else:
        exit_button.height = exitheight
        exit_button.width = exitwidth
        exit_button.draw(screen,20)
    pygame.display.update()
    if not exit_button.isOver(mouse):
        exit_count = 0
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN and exit_button.isOver(mouse):
            pygame.quit()
            quit()


# Welcome
def welcome():
    run = True
    global clock

    while run:
        screen.fill((0,0))
        Start_button()
        Exit_Button()
        pygame.display.update()
        clock.tick(60)


# Pause
def pause_game():
    pause = True
    while pause:
        mixer.music.pause()
        screen.fill((0,0))
        text_on_screen('PAUSE',40)
        pygame.display.update()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    mixer.music.unpause()
                    pause = False


# Game Loop
def gameloop():
    mixer.music.load('background.wav')
    mixer.music.set_volume(50)
    mixer.music.play(-1)
    # Player
    global bullet_state
    playerX = 370
    playerY = 500
    player_changeX = 0
    fps = 30

    # Alien Invader

    alienX = []
    alienY = []
    alien_changeX = []
    number_of_aliens = 5
    for i in range(number_of_aliens):
        alienIMG.append(pygame.image.load('alien.png'))
        alienX.append(random.randint(0,735))
        alienY.append(random.randint(0,100))
        alien_changeX.append(7)

    # Bullet

    bulletX = 0
    bulletY = 500
    bullet_changeY = 20

    score = 0
    running = True
    while running:

        screen.fill((0,0))
        screen.blit(bgIMG,0))
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                running = False
            if e.type == pygame.KEYDOWN:
                if e.key == pygame.K_F4 and pygame.key.get_mods() & pygame.KMOD_ALT:
                    running = False
                if e.key == pygame.K_LEFT or e.key == pygame.K_a:
                    player_changeX = -7
                if e.key == pygame.K_RIGHT or e.key == pygame.K_d:
                    player_changeX = 7
                if e.key == pygame.K_SPACE or e.key == pygame.K_RETURN:
                    bulletX = playerX
                    fire_bullet(bulletX,bulletY)
                if e.key == pygame.K_ESCAPE:
                    pause_game()
            if e.type == pygame.KEYUP:
                if e.key == pygame.K_LEFT or e.key == pygame.K_RIGHT or e.key == pygame.K_a or e.key == pygame.K_d:
                    player_changeX = 0
        playerX += player_changeX
        if playerX < 0:
            playerX = 0
        elif playerX >= 736:
            playerX = 736
        if bulletY <= 0:
            bulletY = 500
            bullet_state = 'ready'
        if bullet_state == 'fire':
            fire_bullet(bulletX,bulletY)
            bulletY -= bullet_changeY

        for i in range(number_of_aliens):
            if abs(alienY[i] - playerY) < 50 and abs(alienX[i] - playerX) < 67:
                for h in range(number_of_aliens):
                    alienY[h] = 2000
                game_over()
                break
            alienX[i] += alien_changeX[i]
            if alienX[i] < 0:
                alienX[i] = 0
                alien_changeX[i] = 7
                alienY[i] += 40
            elif alienX[i] > 736:
                alienX[i] = 736
                alien_changeX[i] = -7
                alienY[i] += 40
            collisionbullet = isCollision(alienX[i],bulletX,alienY[i],bulletY)
            if collisionbullet:
                bulletY = 480
                bullet_state = 'ready'
                alienX[i] = random.randint(0,735)
                alienY[i] = random.randint(0,120)
                score += 10

            alien(alienX[i],i)

        player(playerX,playerY)
        text_on_screen('score:' + str(score),20)
        clock.tick(fps)
        pygame.display.update()

    pygame.quit()
    quit()


welcome()

关于如何解决此问题或问题所在的任何想法?

解决方法

仅在应用程序循环结束时执行一次显示更新,而不在框架中执行多次更新。多次更新显示会导致闪烁。在帧末尾一个pygame.display.update()pygame.display.flip()就足够了。

pygame.display.update() Start_button中删除对Exit_Button的所有(6)调用,并在pygame.display.update()中调用一次welcome

类似于Start_button Exit_Button中的代码重复是一种代码味道。避免他们。实现一个可以表示和设置按钮动画的按钮类。删除start_countexit_count,但向count添加Button签名:

class Button:
    def __init__(self,color,x,y,width,height,text=''):
        self.color = color
        self.text = text
        self.rect = pygame.Rect(x,height)
        self.normal = pygame.Surface((width,height))
        self.normal.fill(self.color) 
        self.highlight = [pygame.Surface((width,height)),pygame.Surface((width + 10,height + 10))]
        self.highlight[0].fill((255,255,255))
        self.highlight[1].fill((255,255))
        small_font = pygame.font.Font('Stargaze Regular.otf',20)
        large_font = pygame.font.Font('Stargaze Regular.otf',23)
        text_small = small_font.render(self.text,1,(0,0))
        text_large = large_font.render(self.text,0))
        self.normal.blit(text_small,text_small.get_rect(center = self.normal.get_rect().center))
        self.highlight[0].blit(text_small,text_small.get_rect(center = self.highlight[0].get_rect().center))
        self.highlight[1].blit(text_large,text_large.get_rect(center = self.highlight[1].get_rect().center))
        self.count = 0

    def draw(self,win,pos,outline = None):
        text_surf = self.normal
        if self.isOver(pos):
            text_surf = self.highlight[0]
            self.count += 1
            if self.count < 200:
                text_surf = self.highlight[self.count // 20 % len(self.highlight)]              
        else:
           self.count = 0
        text_rect = text_surf.get_rect(center = self.rect.center) 
        if outline:
            pygame.draw.rect(win,outline,text_rect.inflate(2,2),2)
        win.blit(text_surf,text_rect)

    def isOver(self,pos):
        return self.rect.collidepoint(pos)

通过此类,您可以简化功能welcome,并且根本不需要功能Start_button Exit_Button

def welcome():
    exit_button = Button((255,255),10,425,80,40,'EXIT')
    start_button = Button((255,370,'PLAY')

    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                if exit_button.isOver(event.pos):
                    run = False
                if start_button.isOver(event.pos):
                    gameloop()
        mouse = pygame.mouse.get_pos()

        screen.fill((0,0))
        exit_button.draw(screen,mouse)
        start_button.draw(screen,mouse)
        pygame.display.update()

    pygame.quit()
    quit()