I am learning Python from the book, "PYTHON CRASH COURSE: A Hands-On, Project-Based Introduction to Programming", 2E.
In that while making game, I am getting the error
Traceback (most recent call last):
File "d:\BOOKS\python\my-projects\AlienInvasion\tempCodeRunnerFile.py", line 69, in <module>
alinv = AlienInvasion()
File "d:\BOOKS\python\my-projects\AlienInvasion\tempCodeRunnerFile.py", line 22, in __init__
self.ship = Ship(self.screen)
File "d:\BOOKS\python\my-projects\AlienInvasion\ship.py", line 10, in __init__
self.screen = alinv_game.screen
AttributeError: 'pygame.Surface' object has no attribute 'screen'
My Code is:
AlienInvasion.py
# Importing modules
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion:
'''Class to manage game assets and behavior'''
def __init__(self):
'''Constructor to initialize the game and its assets'''
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().height
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self.screen)
def run_game(self):
'''Starts the main loop for the game'''
while True:
self._check_events()
self.ship.update()
self._update_screen()
def _check_events(self):
'''Watch for the keyboard and mouse events'''
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):
"""Respond to keypresses."""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.key == pygame.K_ESCAPE:
sys.exit()
def _check_keyup_events(self, event):
"""Respond to key releases."""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _update_screen(self):
'''Redraw the screen during each pass of the loop'''
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
'''Make the most recently drawn screen visible'''
pygame.display.flip()
if __name__ == '__main__':
'''Make a game instance, and run the game'''
alinv = AlienInvasion()
alinv.run_game()
ship.py
import pygame
class Ship:
'''A class to manage the ship'''
def __init__(self, alinv_game):
'''Initialize the ship and set its starting position'''
self.screen = alinv_game.screen
self.settings = alinv_game.settings
self.screen_rect = alinv_game.screen.get_rect()
'''Load the ship image and get its rect'''
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
'''Start each new ship at the bottom-center of the screen'''
self.rect.midbottom = self.screen_rect.midbottom
'''Store a decimal value for ship's horizontal position'''
self.x = float(self.rect.x)
'''Movement Flag'''
self.moving_right = False
self.moving_left = False
def update(self):
if self.moving_right and self.rect.right < self.screen_rect.right:
self.x += self.settings.ship_speed
if self.moving_left and self.rect.left > 0:
self.x -= self.settings.ship_speed
'''Update rect obj from self.x'''
self.rect.x = self.x
def blitme(self):
'''Draw the ship at its current location.'''
self.screen.blit(self.image, self.rect)
In the update method of class Ship, I Implemented two separate blocks to allow ship.rect.x value
to be increased and then decreased when both left and right
arrow keys are pressed. Otherwise, the self.moving_right will
have more priority if 'elif' is implemented.
settings.py
class Settings:
'''A class to store all settings for Alien Invasion Game.'''
def __init__(self):
'''Initialize the game's settings'''
# Screen Settings:
self.screen_width = 1280
self.screen_height = 720
self.bg_color = (230, 230, 230)
# Ship Settings:
self.ship_speed = 1.5
I think the error should be with the screen declaration because I think Pygame.Surface do not have 'screen' attribute but we can though get it by get_rect method. Kindly help me finding the bug. I am not able to solve the issue.
I believe you meant to make the line self.ship = Ship(self.screen) say self.ship = Ship(self). That way the Ship object can access all of the attributes of the AlienInvasion object, instead of just it's screen attribute (and that attribute doesn't have a screen attribute, thus the error).
Related
I have an error where python is not able to find my file. (if I understand correctly) I can't find what I have missed. If anyone could take the time to point it out to me, it would be much appreciated.
def _check_target_edges(self):
"""Respond appropriately if the target has reached an edge."""
if sideways_target.check_edges():
self._change_target_direction()
this code is giving error messages
pygame 2.1.2 (SDL 2.0.18, Python 3.10.5)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "C:\Users\2\Desktop\python_work\Chapter 11 - 15\Chapter 14\14.2 Target Practice.py", line 218, in <module>
ss.run_game()
File "C:\Users\2\Desktop\python_work\Chapter 11 - 15\Chapter 14\14.2 Target Practice.py", line 53, in run_game
self._update_target()
File "C:\Users\2\Desktop\python_work\Chapter 11 - 15\Chapter 14\14.2 Target Practice.py", line 157, in _update_target
self._check_target_edges()
File "C:\Users\2\Desktop\python_work\Chapter 11 - 15\Chapter 14\14.2 Target Practice.py", line 207, in _check_target_edges
if sideways_target.check_edges():
NameError: name 'sideways_target' is not defined
[Finished in 2.7s]
def check_edges(self):
"""Return True if target is at edge of screen."""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom or self.rect.top <= 0:
return True
This is what I want the code to find. So it updates any changes in True/False.
I would like to know where can I define 'sideways_target' so the error clears up and I can run the project.
If you need more detail... the files are down below
File of the 1st piece of code
# ship spawns on the left side
# bullets travel to the right
# target moves up and down
# shoot the target
#
import sys, pygame
from sideways_settings import Settings
from sideways_ship import Ship
from sideways_bullet import Bullet
from sideways_game_stats import GameStats
from sideways_target import Target
from sideways_button import Button
class ShipShooter:
"""Overall class to manage game assets and behavior."""
def __init__(self):
"""Initialize the game, and create game resources."""
pygame.init()
self.sideways_settings = Settings()
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
self.sideways_settings.screen_width = self.screen.get_rect().width
self.sideways_settings.screen_width = self.screen.get_rect().height
pygame.display.set_caption("Sideways Shooter")
# Create an instance to store game statistics.
self.sideways_stats = GameStats(self)
self.sideways_ship = Ship(self)
self.bullets = pygame.sprite.Group()
# Make the button.
self.sideways_play_button = Button(self, "Play")
# Make the target
self.sideways_target = Target(self)
# Set the background color.
self.bg_color = (230, 230, 230)
def run_game(self):
"""Start the main loop for the game."""
while True:
self._check_events()
if self.sideways_stats.game_active:
self.sideways_ship.update()
self._update_bullets()
self._update_target()
self._update_screen()
def _check_events(self):
"""Respond to keypresses and mouse events."""
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)
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
self._check_play_button(mouse_pos)
def _check_play_button(self, mouse_pos):
"""Start a new game when the player clicks Play."""
button_clicked = self.sideways_play_button.rect.collidepoint(mouse_pos)
if button_clicked and not self.sideways_stats.game_active:
# Reset the game statistics.
self.sideways_stats.reset_stats()
self.sideways_stats.game_active = True
# Get rid of any remaining bullets.
self.bullets.empty()
# Center the ship
self.sideways_ship.center_ship()
# Hide the mouse cursor.
pygame.mouse.set_visible(False)
def _check_play_button2(self):
"""Start a new game when the player clicks Play."""
if self.key_p == True:
# Reset the game statistics.
self.sideways_stats.reset_stats()
self.sideways_stats.game_active = True
# Get rid of any remaining bullets.
self.bullets.empty()
# Center the ship
self.sideways_ship.center_ship()
# Hide the mouse cursor.
pygame.mouse.set_visible(False)
def _check_keydown_events(self, event):
"""Respond to keypresses."""
if event.key == pygame.K_UP:
self.sideways_ship.moving_up = True
elif event.key == pygame.K_DOWN:
self.sideways_ship.moving_down = True
elif event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._fire_bullet()
elif event.key == pygame.K_p:
self.key_p = True
self._check_play_button2()
def _check_keyup_events(self, event):
"""Respond to key releases."""
if event.key == pygame.K_UP:
self.sideways_ship.moving_up = False
elif event.key == pygame.K_DOWN:
self.sideways_ship.moving_down = False
def _fire_bullet(self):
"""Create a new bullet and add it to the bullets group."""
if len(self.bullets) < self.sideways_settings.bullets_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _update_bullets(self):
"""Update position of bullets and get rid of old bullets."""
# Update bullet positions.
self.bullets.update()
# Get rid of bullets that have disappeared.
for bullet in self.bullets.copy():
if bullet.rect.right >= self.sideways_ship.screen_rect.right :
self.bullets.remove(bullet)
# print(len(self.bullets))
# Look for bullets hitting the side of the screen.
self._check_bullets_bottom()
def _check_bullet_target_collisions(self):
"""Respond to bullet-target collisions."""
# Remove any bullets that have collided with the target
collisions = pygame.sprite.groupcollide(
self.bullets, self.sideways_target, True, True)
def _update_target(self):
"""
Check if the target is at the edge,
then update the position of the target
"""
self._check_target_edges()
self.sideways_target.update()
# Look for bullet-target collisions.
if pygame.sprite.spritecollideany(self.bullets, self.sideways_target):
self._target_hit()
def _target_hit(self):
"""Respond to the target being hit by a bullet."""
if self.sideways_stats.targets_left > 0:
# Decrement targets_left.
self.sideways_stats.targets_left -= 1
# Get rid of any remaining bullets.
self.bullets.empty()
# Center the ship.
self.sideways_ship.center_ship()
# Pause.
sleep(1.5)
else:
self.sideways_stats.game_active = False
pygame.mouse.set_visible(True)
def _check_bullets_bottom(self):
"""Check if any bullets have reached the side of your screen."""
screen_rect = self.screen.get_rect()
for bullet in self.bullets.sprites():
if bullet.rect.right >= screen_rect.right:
# Treat this the same as if the target got hit.
self.target_hit()
break
def _update_screen(self):
"""Update images on the screen, and flip to the new screen."""
self.screen.fill(self.sideways_settings.bg_color)
self.sideways_ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.sideways_target.draw_target()
# Draw the play button if the game is inactive.
if not self.sideways_stats.game_active:
self.sideways_play_button.draw_button()
pygame.display.flip()
def _check_target_edges(self):
"""Respond appropriately if the target has reached an edge."""
if sideways_target.check_edges():
self._change_target_direction()
def _change_target_direction(self):
"""Change the target's direction."""
self.sideways_settings.target_direction *= -1
if __name__ == '__main__':
# Make a game instance, and run the game.
ss = ShipShooter()
ss.run_game()
File of the 2nd piece of code
import pygame
from pygame.sprite import Sprite
class Target:
def __init__(self, ai_game):
"""Initialize target attributes."""
self.screen = ai_game.screen
self.screen_rect = self.screen.get_rect()
# Set the dimensions and properties of the target
self.width, self.height = 70, 300
self.target_color = (0, 0, 0)
# Build the target's rect object and center it.
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.midright = self.screen_rect.midright
# Store the target's exact vertical position.
self.y = float(self.rect.y)
def check_edges(self):
"""Return True if target is at edge of screen."""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom or self.rect.top <= 0:
return True
def update(self):
"""Move the target up or down."""
self.y += (self.sideways_settings.target_speed *
self.sideways_settings.target_direction)
self.rect.y = self.y
def draw_target(self):
# Draw the target to the screen
pygame.draw.rect(self.screen, self.target_color, self.rect)
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 am using a book called Python Crash Course by Eric Matthes. A part of the book deals with python code projects and I started coding for an Alien Invasion Game. I attached the code written so far for the game to work but whenever I run the code, the spaceship does not move regardless of whether I press my keyboard's right or left key. I have ran the code several times but my editor doesn't indicate that there are errors. Is there something I need to fix in my code? I would greatly appreciate it if someone knows how to fix this.
Alien_invasion.py code:
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion:
"""Overall class to manage game assets and behavior."""
def __init__(self):
"""Initialize the game, and create game resources."""
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self)
# Set the background color.
self.bg_color = (230, 230, 230)
def run_game(self):
"""Start the main loop for the game."""
while True:
self._check_events()
self.ship.update()
self._update_screen()
# Redraw the screen during each pass through the loop.
def _check_events(self):
"""Respond to keypresses and mouse events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
# Move the ship to the right.
self.ship.rect.x += 1
def _update_screen(self):
"""Update images on the screen, and flip to the new screen."""
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
pygame.display.flip()
if __name__ == '__main__':
# Make a game instance, and run the game.
ai = AlienInvasion()
ai.run_game()
Ship.py code:
import pygame
class Ship:
"""A class to manage the ship."""
def __init__(self, ai_game):
"""Initialize the ship and set its starting position."""
self.screen = ai_game.screen
self.screen_rect = ai_game.screen.get_rect()
# Load the ship image and get its rect.
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
# Movement flags
self.moving_right = False
self.moving_left = False
def update(self):
"""Update the ship's position based on the movement flag."""
if self.moving_right:
self.rect.x += 1
if self.moving_left:
self.rect.x -= 1
# Start each new ship at the bottom center of the screen.
self.rect.midbottom = self.screen_rect.midbottom
def blitme(self):
"""Draw the ship at its current location."""
self.screen.blit(self.image, self.rect)
Settings.py code:
class Settings:
"""A class to store all settings for Alien Invasion."""
def __init__(self):
"""Initialize the game's settings."""
# Screen settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
I got the code working, it was a typo error.
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if **event.key** == pygame.K_RIGHT:
self.ship.moving_right = True
elif **event.key** == pygame.K_LEFT:
self.ship.moving_left = True
elif event.type == pygame.KEYUP:
if **event.key** == pygame.K_RIGHT:
self.ship.moving_right = False
elif **event.key** == pygame.K_LEFT:
self.ship.moving_left = False
Earlier I coded event.type instead of event.key
The code is working now, will continue working on the project.
As a beginner, I was trying the "Alien invasion' project in the python crash course a hands-on project-based introduction to programming and got stuck, I was just trying to copy the code but it always get the same feedback:
Traceback (most recent call last):
File "D:/snake/venv/Alien_Invasion/main_game.py", line 29, in <module>
run_game()
File "D:/snake/venv/Alien_Invasion/main_game.py", line 26, in run_game
bullets.update_bullets()
AttributeError: 'Group' object has no attribute 'update_bullets'
and here's my code:
main_game.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
import bullet
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien_Invasion")
#创建一艘飞船
ship = Ship(ai_settings, screen)
#创建一个子弹编组
bullets = pygame.sprite.Group()
#游戏主循环
while True:
gf.check_events(ai_settings, screen, ship, bullets)
ship.update_ship()
bullets.update_bullets()
gf.update_screen(ai_settings, screen, ship, bullets)
run_game()
bullet.py
import pygame
class Bullet(pygame.sprite.Sprite):
"""一个对飞船发射的子弹管理的类"""
def __init__(self, ai_settings, screen, ship):
"""在飞船所在位置创建一个子弹对象"""
self.screen = screen
super(Bullet, self).__init__()
#在(0,0)处创建一个表示子弹的矩形,在放置到正确的位置
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width,
ai_settings.bullet_height)
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
#存储用小数表示的子弹位置
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update_bullets(self):
"""向上移动子弹"""
#更新浮点数的子弹纵坐标
self.y -= self.speed_factor
#更新子弹纵坐标位置
self.rect.y = self.y
def draw_bullet(self):
"""在屏幕上绘制子弹"""
pygame.draw.rect(screen, self.color, self.rect)
game_functions.py
import sys
import pygame
def check_keydown_event(event, ai_settings, screen, ship, bullets):
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
#创建一个子弹,并加入bullets编组
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keyup_event(event, ship):
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_event(ai_settings, screen, ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_event(event, ship)
def update_screen(ai_settings, screen, ship, bullets):
"""更新屏幕上的图像并切换到新屏幕"""
#每次循环时都重新绘制屏幕
screen.fill(ai_settings.bg_color)
#在飞船和外星人后面重绘所有子弹
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme()
#最近绘制屏幕可见
pygame.display.flip()
there are two other files, but I don't think they are related to this problem.
settings.py
class Settings():
"""存储所有设置的类"""
def __init__(self):
"""初始化屏幕设置"""
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
#飞船速度
self.ship_speed_factor = 1.5
#子弹设置
self.bullet_speed_factor = 1
self.bullet_width = 3
self.bullet_heght = 15
self.bullet_color = 60, 60, 60
ship.py
import pygame
class Ship():
def __init__(self, ai_settings, screen):
self.screen = screen
self.ai_settings = ai_settings
""""加载飞船并获取其外接矩形"""
self.image = pygame.image.load("images/ship.bmp")
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
"""将每艘飞船放在屏幕中央底部"""
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
#创建属性center存储坐标小数值
self.center = float(self.rect.centerx)
#飞船移动标志
self.moving_right = False
self.moving_left = False
def update_ship(self):
"""根据移动标志调整飞船位置"""
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
#根据center更新rect.centerx值
self.rect.centerx = self.center
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image, self.rect)
Can someone please tell me what I did wrong here? It would be much appreciated!
In your traceback error it says:
Traceback (most recent call last):
File "D:/snake/venv/Alien_Invasion/main_game.py", line 2, in <module>
from pygame import Group
importError: cannot import name 'Group' from 'pygame' (D:\snake\venv\lib\site-packages\pygame\__init__.py)
Which says there should be this line:
from pygame import Group
on line 2 of your main_game.py module. However in the code you have included, that is not there:
main_game.py
import pygame
from settings import Settings
from ship import Ship
Are you sure you are showing he correct code?
Ignoring the code and just looking at the error message it shows that you had this line:
from pygame import Group
There is no pygame.Group which is why you are getting the error telling you that. I think you are looking for pygame.sprite.Group
Edit
Now that we have the right code and the right question :-)
Sprite groups have some built-in methods which can be seen in the docs here. One of these is update() which will then call the update() function in all the sprites in the group. Your problem is that you named your sprite function update_bullets() not just update() and then you tried to call update_bullets() on the group and the group does not have that method.
So to fix your code you have to rename your Bullet method to just update() and then call the sprite.Group method update() to have it called on all the bullets in the group.
You have the same issue with your draw_bullet() method but you worked around it by iterating over the group and calling your method. That works, but you should correct it to take advantage of the builtin group method. You need to change it to just draw() and then you can call it on all the bullets by just calling bullets.draw(). As I said, in your code now, because you are not using the name that the sprite.Group knows how to find, you are iterating over the group. If you rename it, you can then replace this:
for bullet in bullets.sprites():
bullet.draw_bullet()
with just:
bullets.draw()
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