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