Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
741 views
in Technique[技术] by (71.8m points)

python - end the pygame when player mises the target more than three times

I was trying to do the python crash course exercise 14-2, which is create a rectangle at the right edge of the screen that moves up and down at a steady rate. Then have a ship appear on the left edge of the screen that the player can move up and down while firing bullets at the moving rectangle target. Add a play button that starts the game, and the player misses the target three times, end the game and make the play button reappear. Let the player restart this game with the play button.

the game runs as normal, objects moving as programmed and key events also detected and moved up and down accordingly, but it is not detecting the condition of setting the game status for False. So the play_button never appears and the game keep playing even the player misses the target more than three times.

I've set the bullet allowed to fire one at a time, so it is easier to see by eye and more countable to test.

I think my if len(self.bullets) >= self.settings.firing_limit and not pygame.sprite.spritecollideany(self.rectangle, self.bullets): statement is wrong, cause I just come up with it on my own, cause from the level of my programming, I don't know how to keep a count of the bullets missing target. correct me if I'm wrong.

Below is the main file to run the game.

target_practice.py


import pygame
import sys
from time import sleep

from settings_target_practice import Settings 
from ship import Ship 
from bullet import Bullet 
from rectangle import Rectangle 
from game_stats import GameStats
from button import Button 

class TargetPractice:
    def __init__(self):
        pygame.init()
        self.settings = Settings()
        self.screen = pygame.display.set_mode((self.settings.screen_width, 
                        self.settings.screen_height))
        pygame.display.set_caption("Target Practice")
        self.stats = GameStats(self)
        self.ship = Ship(self)
        self.rectangle = Rectangle(self)
        self.bullets = pygame.sprite.Group()
        self.play_button = Button(self, "Play")

    def run_game(self):
        while True:
            self._check_events()
            if self.stats.game_active:
                self.ship.update()
                self._update_bullet()
                self._update_rectangle()
            self._update_screen()

    def _fire_bullet(self):
        new_bullet = Bullet(self)
        if len(self.bullets)  < self.settings.bullets_allowed:
            self.bullets.add(new_bullet)

    def _update_bullet(self):
        self.bullets.update()
        self.screen_rect = self.screen.get_rect()
        for bullet in self.bullets:
            self._check_bullet_rectangle_collision()
        for bullet in self.bullets.copy():
            if bullet.rect.left >= self.screen_rect.right:
                self.bullets.remove(bullet)

    def _update_rectangle(self):
        self.rectangle.update()
        self._rectangle_check_edges()

    def _rectangle_check_edges(self):
        if self.rectangle.check_edges():
            self._change_direction()

    def _change_direction(self):
        self.settings.rectangle_direction *= -1

    def _check_bullet_rectangle_collision(self):
        if pygame.sprite.spritecollideany(self.rectangle, self.bullets):
            self._start_game()
        if len(self.bullets) >= self.settings.firing_limit and not pygame.sprite.spritecollideany(self.rectangle, self.bullets):
            self.stats.game_active = False
            pygame.mouse.set_visible(True)

    def _check_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_events(event)
            elif event.type == pygame.KEYUP:
                self._check_keyup_events(event)

    def _check_keydown_events(self, event):
        if event.key == pygame.K_q:
            sys.exit()
        elif event.key == pygame.K_UP:
            self.ship.moving_up = True
        elif event.key == pygame.K_DOWN:
            self.ship.moving_down = True
        elif event.key == pygame.K_SPACE:
            self._fire_bullet()
        elif event.key == pygame.K_p:
            self._check_play_button( )

    def _check_keyup_events(self, event):
        if event.key == pygame.K_UP:
            self.ship.moving_up = False
        elif event.key == pygame.K_DOWN:
            self.ship.moving_down = False

    def _check_play_button(self):
        if not self.stats.game_active:
            self.stats.reset_stats()
            self.stats.game_active = True
            self._start_game()

    def _start_game(self):
        if self.stats.game_active:
            #Get rid of any bullets.
            self.bullets.empty()

            #Create a new fleet and center the ship.
            self.rectangle.draw()
            self.ship.center_ship()

            #Hide the mouse curser
            pygame.mouse.set_visible(True)

            sleep(0.5)


    def _update_screen(self):
        self.screen.fill(self.settings.bg_color)
        self.ship.blitme()
        for bullet in self.bullets:
            bullet.draw_bullet()
        self.rectangle.draw()
        if self.stats.game_active:
            pygame.mouse.set_visible(False)
        if not self.stats.game_active:
            self.play_button.draw_button()

        pygame.display.flip()

    if __name__ == '__main__':
        tp_game = TargetPractice()
        tp_game.run_game()

The below are the files which supplementing the above main file.

ship.py


import pygame
class Ship:
    def __init__(self, tr_game):
        self.screen = tr_game.screen
        self.settings = tr_game.settings
        self.screen_rect = self.screen.get_rect()

        self.image = pygame.image.load('images/ship.bmp')
        self.rect = self.image.get_rect()


        self.rect.midleft = self.screen_rect.midleft

        self.y = self.rect.y
        self.moving_up = False
        self.moving_down = False

    def blitme(self):
        self.screen.blit(self.image, self.rect)

    def update(self):
        if self.moving_up and self.rect.top > self.screen_rect.top:
            self.y -= self.settings.ship_speed
        if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
            self.y += self.settings.ship_speed

        self.rect.y = self.y

    def center_ship(self):
        self.rect.midleft = self.screen_rect.midleft
        self.y = float(self.rect.y)

retangle.py


import pygame.font
class Rectangle:

    def __init__(self, tp_game):
        self.screen = tp_game.screen
        self.screen_rect = self.screen.get_rect()
        self.rectangle_width, self.rectangle_height = 200, 50
        self.rectangle_color = (0, 0, 255)
        self.rect = pygame.Rect(0, 0, self.rectangle_width, 
                    self.rectangle_height)
        self.rect.midright = self.screen_rect.midright
        self.settings = tp_game.settings

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

    def update(self):
        self.y += self.settings.rectangle_speed * self.settings.rectangle_direction
        self.rect.y = self.y

    def check_edges(self):
        if self.rect.bottom >= self.screen_rect.bottom or self.rect.top <= 0:
            return True

    def draw(self):
         pygame.draw.rect(self.screen, self.rectangle_color, self.rect)

bullet.py


from pygame.sprite import Sprite
import pygame

class Bullet(Sprite):
    def __init__(self, tr_game):
        super().__init__()
        self.screen = tr_game.screen
        self.settings = tr_game.settings
        self.color = self.settings.bullet_color
        self.rect = pygame.Rect(0, 0, self.settings.bullet_width, 
                    self.settings.bullet_height)
        self.rect.midright = tr_game.ship.rect.midright
        self.x = float(self.rect.x)

    def update(self):
        self.x += self.settings.bullet_speed
        self.rect.x = self.x

    def draw_bullet(self):
        pygame.draw.rect(self.screen, self.color, self.rect) 

settings.py


class Settings:
    def __init__(self):
        self.screen_width = 1400
        self.screen_height = 700
        self.bg_color = (255, 255, 255)

        self.ship_speed = 1.5
        self.firing_limit = 3

        self.bullet_speed = 2
        self.bullet_width = 15
        self.bullet_height = 5
        self.bullet_color = (60, 60, 60)
        self.bullets_allowed = 1

        self.rectangle_speed = 1.0
        self.rectangle_direction = 1

game_stats.py


class GameStats:
    def __init__(self, rp_game):
        self.settings = rp_game.settings
        self.reset_stats()
        self.game_active = True

    def reset_stats(self):
        self.player_chance = self.settings.firing_limit

button.py


import pygame.font
class Button:

    def __init__(self, tp_game, msg):
        """Initialize button attributes."""
        self.screen = tp_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, 255, 0)
        self.text_color = (255, 255, 255)
        self.font = pygame.font.SysFont(None, 48)

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

        #The button message needs to be prepped only once.
        self._prep_msg(msg)

    def _prep_msg(self, msg):
        """Turn message into a rendered image and center text on the screen."""
        self.msg_image = self.font.render(msg, True, 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 and then draw message.
        self.screen.fill(self.button_color, self.rect)
        self.screen.blit(self.msg_image, self.msg_image_rect)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The bullets are Sprites contained in the Group bullets.
If you want to remove a Sprite from all Groups, then all you have to do is to call the method kill() on the Sprite instance. e.g:

bullet.kill()

To count the miss add an attribute (self.missed) to the class TargetPractice. If the bullet leaves the screen the increment self.missed and if it exceeds the limit then end the game:

class TargetPractice:
    def __init__(self):
        pygame.init()
        self.settings = Settings()
        self.screen = pygame.display.set_mode((self.settings.screen_width, 
                        self.settings.screen_height))
        pygame.display.set_caption("Target Practice")
        self.stats = GameStats(self)
        self.ship = Ship(self)
        self.rectangle = Rectangle(self)
        self.bullets = pygame.sprite.Group()
        self.play_button = Button(self, "Play")

        self.missed = 0 # <----

    # [...]

    def _update_bullet(self):
        self.bullets.update()
        self.screen_rect = self.screen.get_rect()
        for bullet in self.bullets:
            self._check_bullet_rectangle_collision()

        # find missing bullets and increment the counter for each      
        for bullet in self.bullets:

            if bullet.rect.left >= self.screen_rect.width: 
                bullet.kill()
                self.missed += 1
                if self.missed >= 3:
                    self.stats.game_active = False
                    pygame.mouse.set_visible(True)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...