微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

创建一个小行星类型的游戏,问题是当玩家等待按下播放按钮时会产生许多小行星而不是受控数量

如何解决创建一个小行星类型的游戏,问题是当玩家等待按下播放按钮时会产生许多小行星而不是受控数量

大约 500 行代码,所以为了更容易阅读,我相信这个错误来自 _update_asteroids(self) 函数。简单地说,当用户处于暂停游戏状态并且必须按下播放键时,如果玩家决定等待让我们说一分钟。一分钟的小行星将在同一时间产生。我相信这是因为 pygame.time.get_ticks() 函数在游戏暂停时继续获得滴答声。有没有办法重置刻度或使其在用户决定在按下播放按钮之前等待时不会产生 100 颗小行星?

import pygame
import sys
from pygame.sprite import Sprite
import random
from time import sleep
import pygame.font


 
class Game(Sprite):
    """ a class the creates a window with a blue screen """
    def __init__(self):
        pygame.init()
        super().__init__()


        #--------------------------------------------------------------------------------------------
        #screen size,color,caption
        self.screen = pygame.display.set_mode((1200,800))   #create attribute to hold display settings
        self.bg_color = (0,255)                           #create attribute to hold RGB color (blue)
        pygame.display.set_caption("Blue Screen")
        #--------------------------------------------------------------------------------------------


        #--------------------------------------------------------------------------------------------
        #tank drawing
        self.screen_rect = self.screen.get_rect()               #get the screen rect dim
        self.image = pygame.image.load('images/tank.gif')       #load the image from directory
        self.rect = self.image.get_rect()                       #get the image rect dim
        self.rect.center = self.screen_rect.center              #store the screens center x/y coord 

        self.x = float(self.rect.x)
        self.y = float(self.rect.y)

        #tank movement
        self.tank_moving_left = False
        self.tank_moving_right = False
        self.tank_moving_up = False
        self.tank_moving_down = False
        self.tank_speed = 0.5                                                       #tank pixels
        self.direction_right = self.image                                       #holds right image
        self.direction_left = pygame.transform.flip(self.image,True,False)    #holds left image
        #--------------------------------------------------------------------------------------------


        #--------------------------------------------------------------------------------------------
        #UI
        self.health = 100
        self.visable = True
        self.sb = scoreboard(self)
        #--------------------------------------------------------------------------------------------


        #--------------------------------------------------------------------------------------------
        #bullet
        self.bullets = pygame.sprite.Group()
        self.current_direction = self.direction_right
        #--------------------------------------------------------------------------------------------

        #--------------------------------------------------------------------------------------------
        #asteroids
        self.asteroids = pygame.sprite.Group()
        self.next_object_time = 0
        self.time_interval = 250
        #self._create_asteroids()
        #--------------------------------------------------------------------------------------------


        #--------------------------------------------------------------------------------------------
        #button
        self.game_active = False
        self.play_button = Button(self,"Play")
        #--------------------------------------------------------------------------------------------


    def _create_asteroids(self):
        """ create the asteroid shower """
        #create a asteroid
        number_of_aliens = 1
        for asteroid_num in range(number_of_aliens):
            self._create_asteroid()



    def _create_asteroid(self):
        asteroid = Asteroid(self)
        if asteroid.x <= 0:
            asteroid.direction = 1
        elif asteroid.x >= 1160:
            asteroid.direction = -1
        self.asteroids.add(asteroid)

        

    def move(self):
        """ move tnak tank_speed based on direction of movement (key pressed)
            also detect collision """ 
        if self.tank_moving_right and self.rect.right < self.screen_rect.right:
            self.x += self.tank_speed
            self.rect.x = self.x
        if self.tank_moving_left and self.rect.left > self.screen_rect.left:
            self.x -= self.tank_speed
            self.rect.x = self.x
        if self.tank_moving_down and self.rect.bottom < self.screen_rect.bottom:
            self.y += self.tank_speed
            self.rect.y = self.y
        if self.tank_moving_up and self.rect.top > self.screen_rect.top:
            self.y -= self.tank_speed
            self.rect.y = self.y



    def draw_healthbar(self):
        pygame.draw.rect(self.screen,(255,0),(self.rect.x,self.rect.y - 20,100,10))
        pygame.draw.rect(self.screen,(0,255,100 - (100 - self.health),10))



    def blitme(self):
        """ draw the image of the tank """
        self.screen.blit(self.image,self.rect)



    def tank_asteroid_collision(self):
        #get rid of asteroids that collide with tank
        for asteroid in self.asteroids.copy():
            if pygame.Rect.colliderect(self.rect,asteroid.rect):
                if self.health > 25:
                    self.health -= 25  
                    self.asteroids.remove(asteroid)
                    print(self.health)
                else:
                    self._tank_death()
                    self.sb.reset_score()
                    self.game_active = False
                    pygame.mouse.set_visible(True)                  



    def _update_screen(self):
        """ update screen """
        self.screen.fill(self.bg_color)
        self.blitme()
        for bullet in self.bullets.sprites():
            self.bullets.draw(self.screen)
            
        collisions = pygame.sprite.groupcollide(self.bullets,self.asteroids,True)
        if collisions:
            for asteroids in collisions.values():
                self.sb.score += 100 * len(asteroids)
            self.sb.prep_score()
            self.sb.check_high_score()
        #draw healthbar if game active
        if self.game_active:
            self.draw_healthbar()
            self.asteroids.draw(self.screen)

        #draw the play button and other buttons if game is paused
        if not self.game_active:
            self.play_button.draw_button()

        self.sb.show_score()

        pygame.display.flip()



    def _tank_death(self):
        sleep(0.5)
        self.bullets.empty()
        self.asteroids.empty()
        self.center_ship()
        self.health = 100       



    def _check_KEYDOWN(self,event):
        """ when key is press either quit,or move direction of arrow pressed and flip image """
        if event.key == pygame.K_q:
            sys.exit()
        elif event.key == pygame.K_RIGHT:
            self.tank_moving_right = True
            self.image = self.direction_right
            self.current_direction = self.direction_right
        elif event.key == pygame.K_LEFT:
            self.tank_moving_left = True
            self.image = self.direction_left
            self.current_direction = self.direction_left
        elif event.key == pygame.K_UP:
            self.tank_moving_up = True
        elif event.key == pygame.K_DOWN:
            self.tank_moving_down = True
        elif event.key == pygame.K_SPACE:
            self._fire_bullet() 
    


    def _check_KEYUP(self,event):
        """ when key is let go stop moving """
        if event.key == pygame.K_RIGHT:
            self.tank_moving_right = False
        elif event.key == pygame.K_LEFT:
            self.tank_moving_left = False
        elif event.key == pygame.K_UP:
            self.tank_moving_up = False
        elif event.key == pygame.K_DOWN:
            self.tank_moving_down = False



    def _fire_bullet(self):
        """ create a bullet and add it to the bullets group """
        if self.current_direction == self.direction_left:
            #create new bullet and set bullet path
            new_bullet = Bullet(self)
            new_bullet.bullet_shootRight = False
            new_bullet.bullet_shootLeft = True

            #change direction of bullet starting point
            new_bullet.x -= 100

            #add bullet to sprite list
            self.bullets.add(new_bullet)

        elif self.current_direction == self.direction_right:
            #create new bullet and set bullet path
            new_bullet = Bullet(self)
            new_bullet.bullet_shootRight = True
            new_bullet.bullet_shootLeft = False
            
            #add bullet to sprite list
            self.bullets.add(new_bullet)    



    def center_ship(self):
        """ centers the ship in middle of screen """
        self.rect.center = self.screen_rect.center
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)



    def _update_tank(self):
        """ move tank or quit game based on keypress """
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self._check_KEYDOWN(event)
            elif event.type == pygame.KEYUP:
                self._check_KEYUP(event)
            elif event.type == pygame.MOUSEBUTTONDOWN:
                mouse_pos = pygame.mouse.get_pos()
                self._check_play_button(mouse_pos)



    def _check_play_button(self,mouse_pos):
        button_clicked = self.play_button.rect.collidepoint(mouse_pos)
        if button_clicked and self.play_button.rect.collidepoint(mouse_pos):
            self.game_active = True
            pygame.mouse.set_visible(False) 



    def _update_asteroids(self):
        """ afer 'x' milliseconds create a new asteroid """
        current_time = pygame.time.get_ticks()
        if current_time > self.next_object_time:
            self.next_object_time += self.time_interval
            self._create_asteroids()        



    def run_game(self):
        """ loops the game/ updates screen/ checks for key clicks"""
        while True:
            self._update_tank()
            if self.game_active:
                self.move()
                self.bullets.update()
                self.tank_asteroid_collision()
                #after certain number of time create a asteroid
                self._update_asteroids()
                self.asteroids.update()

                #get rid of asteroids that have disapeared
                for asteroid in self.asteroids.copy():
                    if asteroid.x >= 1200 or asteroid.x <= 0:
                        self.asteroids.remove(asteroid)
                
                #get rid of bullets that have disapeared
                for bullet in self.bullets.copy():
                    if bullet.rect.left >= 1200 or bullet.rect.right <= 0:
                        self.bullets.remove(bullet)
            self._update_screen()




class Bullet(Sprite):
    """ A class to manage bullets fired from the ship """
    def __init__(self,game):
        """ create a bullet object at the ships current position """
        super().__init__()
        self.screen = game.screen
        self.bullet_speed = 2.0
        self.bullet_width = 20
        self.bullet_height = 5
        self.bullet_color = (0,200,200)
        self.bullet_shootRight = False
        self.bullet_shootLeft = False

        self.image = pygame.Surface((self.bullet_width,self.bullet_height))
        self.image.fill(self.bullet_color)
        self.rect = self.image.get_rect()
        self.rect.midright = game.rect.midright
        self.rect.y -= 5 #the tanks barrel is 5 pixels above center
        self.rect.x += 15
    
        #store the bullets position as a decimal value
        self.y = float(self.rect.y)
        self.x = float(self.rect.x)



    def update(self):
        """ move the bullet up the screen """
        #update the decimal position of the bullet.
        if self.bullet_shootRight:
            self.x += self.bullet_speed
            self.rect.x = self.x
        elif self.bullet_shootLeft:
            self.x -= self.bullet_speed
            self.rect.x = self.x




class Asteroid(Sprite):
    """ a class that represents a single asteroid """
    def __init__(self,game):
        """ initialize the asteroid and set its starting position """
        super().__init__()
        self.screen = game.screen
        self.speed = 0.1
        self.direction = 1

        #load the asteroid image onto the screen
        self.image = pygame.image.load('images/asteroid.gif')
        self.rect = self.image.get_rect()

        #start each new asteroid in a random part just outside the map on either the left or right
        self.rect.x = random.randint(*random.choice([(0,(1160,1160)]))
        self.rect.y = random.randint(0,760)

        #store the asteroid's exact horizontal positon
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)



    def update(self):
        """ move the asteroid to the right or left """
        self.x += self.speed * self.direction
        self.rect.x = self.x

        self.y += (self.speed / 3) * self.direction
        self.rect.y = self.y




class Button:

    def __init__(self,game,msg):
        """ Initialize button """
        self.screen = game.screen
        self.screen_rect = self.screen.get_rect()

        #set the dimensions and properties of the button
        self.width,self.height = 200,50
        self.button_color = (0,0)
        self.text_color = (255,255)
        self.font = pygame.font.SysFont(None,48)

        #Build the button's rect object and center it.
        self.rect = pygame.Rect(0,self.width,self.height)
        self.rect.center = self.screen_rect.center

        self._prep_msg(msg)



    def _prep_msg(self,msg):
        """ Turn msg into a rendered image and center text on the button """
        self.msg_image = self.font.render(msg,self.text_color,self.button_color)
        self.msg_image_rect = self.msg_image.get_rect()
        self.msg_image_rect.center = self.rect.center



    def draw_button(self):
        """ draw blank button then draw message """
        self.screen.fill(self.button_color,self.rect)
        self.screen.blit(self.msg_image,self.msg_image_rect)




class scoreboard:
    """ A class to report scoring information """

    def __init__(self,game):
        """ initialize scorekeeping attributes """
        self.screen = game.screen
        self.screen_rect = self.screen.get_rect()
        self.score = 0
        self.highscore = 0

        # Font settings for scoring information
        self.text_color = (30,30,30)
        self.font = pygame.font.SysFont(None,48)

        self.prep_score()
        self.prep_highscore()



    def reset_score(self):
        self.score = 0
        self.prep_score()



    def prep_highscore(self):
        """ Turn the high score into a rendered image. """
        high_score = round(self.highscore,-1)
        high_score_str = "{:,}".format(high_score)
        self.high_score_image = self.font.render(high_score_str,255))

        #center the high score at the top of the screen
        self.high_score_rect = self.high_score_image.get_rect()
        self.high_score_rect.centerx = self.screen_rect.centerx
        self.high_score_rect.top = self.score_rect.top



    def check_high_score(self):
        """ check to see if there's a new high score """
        if self.score > self.highscore:
            self.highscore = self.score
            self.prep_highscore()

    def prep_score(self):
        """ Turn the score into a renered image """
        rounded_score = round(self.score,-1)

        score_str = "{:,}".format(rounded_score)
        self.score_image = self.font.render(score_str,255))

        #display the score at the top of the screen
        self.score_rect = self.score_image.get_rect()
        self.score_rect.right = self.screen_rect.right
        self.score_rect.top = 0

    def show_score(self):
        """ draw the score to the screen """
        self.screen.blit(self.score_image,self.score_rect)
        self.screen.blit(self.high_score_image,self.high_score_rect)


if __name__ == '__main__':
    a = Game()
    a.run_game()

解决方法

小行星的生成取决于 next_object_timenext_object_time 初始化为 0。您需要在按下播放按钮时设置 self.next_object_time

class Game(Sprite):
    # [...]

    def _check_play_button(self,mouse_pos):
        if self.play_button.rect.collidepoint(mouse_pos):
            self.game_active = True
            pygame.mouse.set_visible(False)
 
            self.next_object_time = pygame.time.get_ticks() + self.time_interval

为了使算法更加稳健,您可以根据小行星产生的当前时间设置 next_object_time(这是可选的):

class Game(Sprite):
    # [...]

    def _update_asteroids(self):
        """ afer 'x' milliseconds create a new asteroid """
        current_time = pygame.time.get_ticks()
        if current_time > self.next_object_time:
 
            # self.next_object_time += self.time_interval
            self.next_object_time = current_time + self.time_interval 
 
            self._create_asteroids()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。