This question already has answers here:
How can i shoot a bullet with space bar?
(1 answer)
How do I stop more than 1 bullet firing at once?
(1 answer)
Closed 2 years ago.
so I was doing the exercise of python crash course 12-6. which places a ship on the left side of the screen and allows the player to move the ship up and down. Make the ship fire the bullet that travels right across the screen when the player presses the space-bar.
I've tried to print the length of the bullets, the animation runs which means it is recognizing that the button is being pressed and the bullets appear but don't move. The bullet appears but stays frozen. It seems the for loop has something to do with it.
I've tried to compare the Alian Invasion code three times which is explained in the chapter for this exercise, which sound stupid but i don't see anything obviously wrong to me.
I'm new to python and pygame and even to stackoverflow, any help will be highly appreciated.
The below is the main code to run the game.
import pygame
import sys
from sideways_shooter import SidewaysShooter
from stone import Stone
from settings import Settings
class SidewaysShooterGame:
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("Sideways Shooter Game")
self.sideways_shooter = SidewaysShooter(self)
self.stones = pygame.sprite.Group()
def run_game(self):
while True:
self._check_events()
self.sideways_shooter.update()
self._stones_update()
self._update_screen()
def _stones_update(self):
self.stones.update()
for stone in self.stones.copy():
if stone.rect.left >= self.sideways_shooter.screen_rect.right:
self.stones.remove(stone)
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_UP:
self.sideways_shooter.moving_up = True
elif event.key == pygame.K_DOWN:
self.sideways_shooter.moving_down = True
elif event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._throw_stones()
def _check_keyup_events(self,event):
if event.key == pygame.K_UP:
self.sideways_shooter.moving_up = False
elif event.key == pygame.K_DOWN:
self.sideways_shooter.moving_down = False
def _throw_stones(self):
if len(self.stones) < self.settings.stones_allowed:
new_stone = Stone(self)
self.stones.add(new_stone)
def _update_screen(self):
self.screen.fill(self.settings.bg_color)
self.sideways_shooter.blitme()
for stone in self.stones:
stone.draw_stone()
pygame.display.flip()
if __name__ == '__main__':
ss_game = SidewaysShooterGame()
ss_game.run_game()
The below are the classes and methods that contains assets and attributes for the main code project.
sideway_shooter file
import pygame
class SidewaysShooter:
def __init__(self, ss_game):
self.screen = ss_game.screen
self.settings = ss_game.settings
self.screen_rect = ss_game.screen.get_rect()
self.image = pygame.image.load('images/resized_shooter_bmp_file.bmp')
self.rect = self.image.get_rect()
self.rect.midleft = self.screen_rect.midleft
self.y = float(self.rect.y)
self.moving_up = False
self.moving_down = False
def update(self):
if self.moving_up and self.rect.top > 0:
self.y -= self.settings.speed
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.y += self.settings.speed
self.rect.y = self.y
def blitme(self):
self.screen.blit(self.image, self.rect)
stone file
import pygame
from pygame.sprite import Sprite
class Stone(Sprite):
def __init__(self, ss_game):
super().__init__()
self.screen = ss_game.screen
self.settings = ss_game.settings
self.color = self.settings.stone_color
self.rect = pygame.Rect(0, 0, self.settings.stone_width,
self.settings.stone_height)
self.rect.midright = ss_game.sideways_shooter.rect.midright
self.x = float(self.rect.x)
def upate(self):
self.x += self.settings.stone_speed
self.rect.x = self.x
def draw_stone(self):
pygame.draw.rect(self.screen, self.color, self.rect)
settings file
class Settings:
def __init__(self):
self.screen_width = 1400
self.screen_height = 700
self.bg_color = (255, 255, 255)
self.speed = 1.5
self.stone_color = (60, 60, 60)
self.stone_width = 15
self.stone_height = 3
self.stone_speed = 1.0
self.stones_allowed = 3
Related
I'm working on the Alien Invasion from "Python Crash Course" by Erick Matthes. I've bogged down on trying to make a ship move across a screen. Most of time, the ship moves as expected. However, after reaching the very right corner of the screen, the ship ceases to react to pressed keys. Pressing a left arrow key on keyboard doesn't move the ship leftwards at all. What's wrong with my code?
alien_invasion.py
"""The main module of the Alien Invasion"""
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion():
"""A class storing and managing all game's functionality."""
def __init__(self):
"""Initialize essential settings."""
self.settings = Settings()
self.screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
self.settings.window_width = self.screen.get_rect().width
self.settings.window_height = self.screen.get_rect().height
pygame.display.set_caption(self.settings.game_title)
self.ship = Ship(self)
self._run_game()
def _end_game(self):
"""Close the game's window."""
pygame.quit()
sys.exit()
def _check_events(self):
"""Check events and react to them."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
self._end_game()
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):
"""Detect pressed keys and react accordingly."""
if event.key == pygame.K_q:
self._end_game()
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
if event.key == pygame.K_LEFT:
self.ship.moving_left = True
def _check_keyup_events(self, event):
"""Detect released keys and react accordingly."""
if event.key == pygame.K_RIGHT:
self.ship_moving_right = False
if event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _update_screen(self):
"""Draw the most recent surface on the screen."""
self.screen.fill(self.settings.background_colour)
self.ship.update()
self.ship.blitme()
pygame.display.flip()
def _run_game(self):
"""Start a new game"""
while True:
#Main loop
self._check_events()
self._update_screen()
ai = AlienInvasion()
ship.py
"""A module containing a Ship class"""
import pygame
class Ship():
"""A simple attempt to represent a ship."""
def __init__(self, ai):
"""Initialize a ship's settings."""
self.ai = ai
self.screen = self.ai.screen
self.image = pygame.image.load('ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.midbottom = self.screen_rect.midbottom
#Motions' attributes
self.moving_right = False
self.moving_left = False
self.x = float(self.rect.x)
self.speed = self.ai.settings.ship_speed
def blitme(self):
"""Draw a ship on the screen."""
self.screen.blit(self.image, self.rect)
def update(self):
"""Update a ship's position on the screen."""
if self.moving_right and self.rect.right < self.screen_rect.right:
self.x += self.speed
if self.moving_left and self.rect.left > 0:
self.x -= self.speed
self.rect.x = self.x
settings.py
"""Module containing a Settings class"""
class Settings():
"""A module managing all game's essential settings."""
def __init__(self):
"""Initialize settings."""
self.background_colour = (230, 230, 230)
self.game_title = 'Alien Invasion'
self.window_width = 1200
self.window_height = 600
self.window_size = (self.window_width, self.window_height)
#Ship's settings
self.ship_speed = 1.5
The ship won't move left, which means it's probably stuck moving right. That points to an issue in releasing the movement to the right, which happens in _check_keydown_events():
def _check_keyup_events(self, event):
"""Detect released keys and react accordingly."""
if event.key == pygame.K_RIGHT:
self.ship_moving_right = False
if event.key == pygame.K_LEFT:
self.ship.moving_left = False
Here's the problematic line:
self.ship_moving_right = False
This should be self.ship.moving_right, not self.ship_moving_right. The correct version finds the ship attribute of the game, and sets the ship's moving_right attribute to False. The incorrect version creates a new game attribute ship_moving_right, and sets it to False; it never changes the value of self.ship.moving_right. So, the ship tries to move right for the rest of the game. This is a great example of how one character can produce no Python errors, but has a significant impact on the overall behavior of the game.
I learned about the events settings through a very helpful user here on stackoverflow already. I think I understand how that function works. I currently spawn 1 enemy on the right side of the screen that moves towards the left. I am attempting to spawn them at certain time intervals.
However, I don't know where I am supposed to put the code in for the event. I've tried adding it into def _create_fleet(self): and def __init__(self): and def __init__(self, placeholder): under the "Alien.py" separate file, but none of them seem to work. Could someone please show me where the correct area to do so is?
I am trying to add this:
FIRE_EVENT = pygame.USEREVENT + 1 # This is just a integer.
pygame.time.set_timer(FIRE_EVENT, 1000) # 1000 milliseconds is 1 seconds.
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == FIRE_EVENT: # Will appear once every second.
***whatever the right place to add will be put in here***
and the full code is here:
import sys
import pygame
from ship import Ship
from bullets import Bullet
from alien import Alien
from time import time, sleep
class Sideways:
"""Overall class to manage game assets"""
def __init__(self):
"""Initialize the game and create game resources"""
pygame.init()
self.screen = pygame.display.set_mode((1200, 600))
self.screen_rect = self.screen.get_rect()
pygame.display.set_caption("Pew Pew")
self.bg_color = (204, 255, 255)
self.ship = Ship(self)
self.moving_up = False
self.moving_down = False
self.moving_left = False
self.moving_right = False
self.bullets = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
self._create_fleet()
def _create_fleet(self):
""""Create a fleet of aliens"""
alien = Alien(self)
self.aliens.add(alien)
def _update_aliens(self):
self.aliens.update()
def run_game(self):
while True:
self._ship_movement_andfiring()
self.ship.blitme()
self._update_screen()
self._update_bullets()
self._update_aliens()
def _update_bullets(self):
self.bullets.update()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
for bullet in self.bullets.copy():
if bullet.rect.right > self.screen_rect.width:
self.bullets.remove(bullet)
collisions = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True)
def _update_screen(self):
pygame.display.flip()
self.screen.fill(self.bg_color)
self.aliens.draw(self.screen)
def _ship_movement_andfiring(self):
if self.moving_up == True:
self.ship.rect.y -= 1
if self.moving_down == True:
self.ship.rect.y += 1
if self.moving_right == True:
self.ship.rect.x += 1
if self.moving_left == True:
self.ship.rect.x -= 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
self.moving_up = True
elif event.key == pygame.K_DOWN:
self.moving_down = True
elif event.key == pygame.K_RIGHT:
self.moving_right = True
elif event.key == pygame.K_LEFT:
self.moving_left = True
elif event.key == pygame.K_SPACE:
self._fire_bullet()
elif event.key == pygame.K_ESCAPE:
sys.exit()
elif event.type == pygame.KEYUP:
if event.key != pygame.K_SPACE:
self.moving_up = False
self.moving_down = False
self.moving_left = False
self.moving_right = False
if self.ship.rect.midleft <= self.ship.screen_rect.midleft:
self.moving_left = False
if self.ship.rect.bottom > self.ship.screen_rect.bottom:
self.moving_down = False
if self.ship.rect.midright >= self.ship.screen_rect.midright:
self.moving_right = False
if self.ship.rect.top <= 0:
self.moving_up = False
def _fire_bullet(self):
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
if __name__ == '__main__':
pewpew = Sideways()
pewpew.run_game()
with a separate "alien.py" file to create the aliens here:
import pygame
from pygame.sprite import Sprite
from random import randint
class Alien(Sprite):
"""A class to represent a single alien in the fleet."""
def __init__(self, placeholder):
"""Initialize the alien and set its starting position"""
super().__init__()
self.screen = placeholder.screen
self.screen_rect = self.screen.get_rect()
#load the alien image and set its rect attribute
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
#Start each new alien randomly on right side of screen
random_number = randint(0, self.screen_rect.height-self.rect.height)
self.rect.x = self.screen_rect.width - self.rect.width
self.rect.y = random_number
#Store the alien's horizontal position
self.x = float(self.rect.x)
def update(self):
"""Move alien to the left"""
self.x -= 0.1
self.rect.x = self.x
Create the timer event in the constructor of the your class Sideways:
class Sideways:
def __init__(self):
# [...]
self.bullets = pygame.sprite.Group()
# self._create_fleet() <--- DELETE
# create timer event
self.FIRE_EVENT = pygame.USEREVENT + 1 # This is just a integer.
pygame.time.set_timer(self.FIRE_EVENT, 1000) # 1000 milliseconds is 1 seconds.
Handle the event tin the event loop and create a new enemy when the event occurs:
class Sideways:
# [...]
def _ship_movement_andfiring(self):
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == self.FIRE_EVENT:
self._create_fleet()
# [...]
I am making a game in python using pygmae. And I am having trouble with Init, it says that It has 2 arguments. but I only gave, one I found other solutions online but those did not quite work, I also got this error multiple times in the past and normally when I would fix it, it would be in very unusual ways such as places where the code is all the way down on the other side of the screen. I get that is how python works, but i'm pretty sure even in the self method I gave, I only gave it one positional argument> Here is the error code if anyone is wondering (I was doing this to make the enemy appear on the screen, so all of that is for the enemy, this problem originated from the fact that I was trying to make the enemy appear on the screen)
enemy = Enemy(enemy_image)
TypeError: init() takes 1 positional argument but 2 were given
Here is my code:
import pygame, sys
# classes
# Player class
class Player(pygame.sprite.Sprite):
def __init__(self, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect(center = (screen_width//2, screen_height//2))
def update(self):
self.rect.center = pygame.mouse.get_pos()
def create_bullet(self):
return Bullet(*pygame.mouse.get_pos())
# bullet class
class Bullet (pygame.sprite.Sprite):
def __init__(self,pos_x,pos_y):
super().__init__()
self.image = pygame.Surface((50,10))
self.image.fill((255,255,0))
self.rect = self.image.get_rect(center = (pos_x,pos_y))
def update(self):
self.rect.x += 5
#Making the enemy work
enemy_speed_factor = 1.5
class Enemy:
def __init__(self):
"""Initialize the enemy and set its starting position"""
self.screen = screen
#Load the enemy image and get its rect
self.image = pygame.image.load("Enemy4.png")
self.rect = self.image.get_rect()
self.scree_rect = screen.get_rect()
#start each new enemy at the bottom of the screen
self.rect.centerx = self.scree_rect.centerx
self.rect.bottom = self.scree_rect.bottom
#store a decimal value for the ships x and y center
self.centerx = float(self.rect.centerx)
self.centery = float(self.rect.centery)
#Movement flag
self.moving_right = False
self.moving_left = False
self.moving_down = False
self.moving_up = False
def update(self):
"""Update the enemys position based on the movement flag"""
#Upade the enemy's center value, not the rect.
if self.moving_right and self.rect.right < self.screen_rect.right:
self.centerx += self.ai_settings.ship_speed_factor
if self.mobing_left and self.rect.left >0:
self.centerx -= self.ai_settings.ship_speed_factor
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.centery =+ self.ai_settings.ship_speed_factor
if self.moving_down and self.rect.top > self.screen_rect.top:
self.centery -= self.ai_settings.ship_speed_factor
#Update rect object from self.center
if self.moving_up or self.moving_down:
self.rect.centery = self.centery
if self.moving_left or self.moving_right:
self.rect.centerx = self.centerx
def blitme(selfself, self):
"""draw the enemy at its current location"""
self.screen.blit(self.image, self.rect)
#making the movements for the enemy
def check_keydown_events(events, ship):
"""responds to keypresses"""
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_DOWN:
ship.moving_down = True
elif event.key == pygame.K_UP:
ship.moving_up = True
def check_keyup_evets(event, ship):
"""responds to key releases"""
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
elif event.key == pygame.K_DOWN:
ship.moving_down = False
elif event.key == pygame.K_UP:
ship.moving_up = False
def check_keyup_events(event, ship):
pass
def check_events(ship):
"""Respond to keypresses and mouse events"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, enemy)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
def update_screen(ai_settings, screen, ship):
"""Update images on the screen and flip to the new screen"""
#Redeaw the screen during each pass through the loop
screen.fill(ai_settings.bg_color)
enemy.blitme()
#Make the most recently drawn screeen visible
pygame.display.flip()
def blitme(self):
self.screen.blit(self)
# general setup
pygame.init()
clock = pygame.time.Clock()
# game screen
screen_width = 1920
screen_height = 1080
screen = pygame .display.set_mode((screen_width, screen_height))
background = pygame.image.load("BackGround.png")
# player
player_image = pygame.image.load("Charachter2.png")
player = Player(player_image)
player_group = pygame.sprite.Group()
player_group.add(player)
# enemy
enemy_image = pygame.image.load("Enemy4.png")
enemy = Enemy(enemy_image)
enemy_group = pygame.sprite.Group()
enemy_group.add(enemy)
# Bullet
bullet_group = pygame.sprite.Group()
# caption
pygame.display.set_caption("Wild-West Shooter")
# makes game quit
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame:quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
bullet_group.add(player.create_bullet())
player_group.update()
bullet_group.update()
# draw
screen.blit(background,(0,0)) # background
player_group.draw(screen) # player
bullet_group.draw(screen) # bullets
enemy.draw(screen)
#thief.draw(screen) # enemy
pygame.display.flip()
clock.tick(120)
# makes game run
if __name__ == "__main__" :
theApp = App()
theApp.on_execute()
The problem is that your __init__ method for the Enemy class takes only 1 argument, which is the self argument. Python passes this automatically when an object is created for a class.
For example, if you have a class Foo, and its __init__ method is defined as:
def __init__ (self):
# Do stuff
and you create an object as such:
bar = Foo()
Python automatically converts the object call and adds a self argument. Think of it as self argument always being there.
Now, if you want to pass two arguments, you need to edit the __init__ method as such:
def __init__(self, image):
# Do stuff
This way, the __init__ method accepts 2 arguments, the self and the image. Then you can proceed to create an object as follows:
enemy = Enemy(enemy_image)
And Python will add the self argument to it automatically so that you final object is enemy = Enemy(self, enemy_image)
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)
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)
I am currently working on a pong clone in Python using Pygame. I am no where near an expert at the subject of programming, and have run into an error. Whenever I run the code I currently have, which will be listed below separated by Blockquotes, the program will freeze up, and not respond. I cannot tell what the issue may be with the little knowledge I have. I was hoping that someone would be able to assist me on this issue. I am currently using a tutorial to help instruct me through the making of this game, and the code looks pretty identical at this point. I will include a hyperink to the tutorial here. I appreciate any and all feedback.
3000X_runner.py
import GameObj
if __name__ == '__main__':
game = GameObj.Game()
game.run()
PongPaddle.py
import os, pygame
class Paddle(pygame.sprite.Sprite):
def __init__(self, user, xy):
pygame.sprite.Sprite.__init__(self)
if user == 1:
self.image = pygame.image.load(os.path.join("images", "playerPaddle.png"))
else:
self.image = pygame.image.load(os.path.join("images", "opponentPaddle.png"))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.movement_speed = 5
self.velocity = 0
def up(self):
self.velocity -= self.movement_speed
def down(self):
self.velocity += self.movement_speed
def move(self, dy):
if self.rect.bottom + dy > 720:
self.rect.bottom = 720
elif self.rect.top + dy < 0:
self.rect.bottom = 0
else: self.rect.y += dy
def update(self):
self.move(self.velocity)
GameObj.py
import os, pygame, PongPaddle
class Game(object):
def __init__(self):
pygame.init()
#setup screen width/height
self.screen = pygame.display.set_mode((1080, 720))
self.clock = pygame.time.Clock() #setups internal pygame clock
#Mandatory silly name featuring extra numbers for game name
pygame.display.set_caption("Hyper Pong 3000-X")
#create background.
self.background = pygame.Surface((1080, 720))
self.background.fill((0,0,0)) #black background
#draws a white line down the middle of screen
#line(Surface, color, start_pos, end_pos, width=1) -> Rect
pygame.draw.line(self.background, (255, 255, 255), (540, 0), (540, 720), 5)
self.screen.blit(self.background, (0, 0)) #blits to screen
#I shall render all the sprites here:
self.sprites = pygame.sprite.OrderedUpdates()
#setting up the paddles and adding them to my sprite group
self.player_paddle = PongPaddle.Paddle(1, (50, 200))
self.sprites.add(self.player_paddle)
self.opponent_paddle = PongPaddle.Paddle(2, (1030, 200))
self.sprites.add(self.opponent_paddle)
def run(self):
stillPlaying= True
while stillPlaying:
self.clock.tick(30)
#handles our pygame events, giving us a easy to view, clutter free game loop
stillPlaying = self.handleEvents
#updates all of our sprites
for sprite in self.sprites:
sprite.update()
self.sprites.clear(self.screen, self.background)
dirty = self.sprites.draw(self.screen)
pygame.display.update(dirty)
def handleEvents(self):
#here we handle all of our events, such as when either player will
#press a key to move, quit the game, etc etc.
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
return False
#player1 keydown events
if event.key == pygame.K_w:
self.player_paddle.up()
if event.key == pygame.K_s:
self.player_paddle.down()
#player2 keydown events
if event.key == pygame.K_UP:
self.opponent_paddle.up()
if event.key == pygame.K_DOWN:
self.opponent_paddle.down()
elif event.type == pygame.KEYUP:
#player1 keyup events
if event.key == pygame.K_w:
self.player_paddle.down()
if event.key == pygame.K_s:
self.player_paddle.up()
#player2 keyup events
if event.key == pygame.K_UP:
self.opponent_paddle.down()
if event.key == pygame.K_DOWN:
self.opponent_paddle.up()
return True
Simply forgot to add () in GameObj.py after
stillPlaying = self.handleEvents
It should look like: stillPlaying = self.handleEvents()