In pygame <alien invasion>, why my aliens appear just one row? - python

(instance.py)
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
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()
aliens = pygame.sprite.Group()
gf.create_fleet(ai_settings,screen,ship,aliens)
while 1:
gf.check_events(ai_settings,screen,ship,bullets)
ship.update()
gf.update_bullet(bullets)
gf.update_alien(ai_settings,aliens)
gf.update_screen(ai_settings,screen,ship,bullets,aliens)
run_game()
(game_functions.py)
import pygame
import sys
from bullet import Bullet
from alien import Alien
def check_events(ai_settings,screen,ship,bullets):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
check_keydown_events(ai_settings,screen,ship,bullets,event)
if event.type == pygame.KEYUP:
check_keyup_events(ship,event)
def check_keydown_events(ai_settings,screen,ship,bullets,event):
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_UP:
ship.moving['up'] = True
elif event.key == pygame.K_DOWN:
ship.moving['down'] = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings,screen,ship)
bullets.add(new_bullet)
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(ship,event):
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_UP:
ship.moving['up'] = False
elif event.key == pygame.K_DOWN:
ship.moving['down'] = False
def update_screen(ai_settings,screen,ship,bullets,aliens):
screen.fill(ai_settings.bg_color)
ship.blitme()
for bullet in bullets.sprites():
bullet.draw_bullet()
aliens.draw(screen)
pygame.display.flip()
def update_bullet(bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.y < 0:
bullets.remove(bullet)
def create_fleet(ai_settings,screen,ship,aliens):
sample_alien = Alien(ai_settings,screen)
alien_width = sample_alien.rect.width
alien_height = sample_alien.rect.height
available_space_x = ai_settings.screen_width - 2 * alien_width
numbers_alien_x = int(available_space_x / ( 2 * alien_width ))
available_space_y = ai_settings.screen_height - 3 * alien_height - ship.rect.height
numbers_alien_y = int(available_space_y / ( 2 * alien_height ))
for number_alien_y in range(numbers_alien_y):
for number_alien_x in range(numbers_alien_x):
alien = Alien(ai_settings,screen)
alien.rect.x = alien_width + 2 * alien_width * number_alien_x
alien.rect.y = alien_height + 2 * alien_height * number_alien_y
aliens.add(alien)
def update_alien(ai_settings,aliens):
check_fleet_edges(ai_settings,aliens)
aliens.update()
def check_fleet_edges(ai_settings,aliens):
for alien in aliens.sprites():
if alien.check_edges():
change_fleet_direction(ai_settings,aliens)
break
def change_fleet_direction(ai_settings,aliens):
for alien in aliens.sprites():
alien.rect.y += ai_settings.fleet_drop_speed
ai_settings.fleet_direction *= -1
(settings.py)
class Settings(object):
def __init__(self):
self.screen_width = 1200
self.screen_height = 700
self.bg_color = 230,230,230
self.ship_speed_factor = 1.5
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 15,15,15
self.bullet_speed_factor = 1
self.alien_speed_factor = 2
self.fleet_drop_speed = 10
self.fleet_direction = 1
(ship.py)
import pygame
class Ship(object):
def __init__(self,ai_settings,screen):
self.ai_settings = ai_settings
self.screen = screen
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
self.moving = {'right':False,'left':False,'up':False,'down':False}
self.centerx = float(self.rect.centerx)
self.centery = float(self.rect.centery)
self.speed = self.ai_settings.ship_speed_factor
def update(self):
if self.moving['right'] and self.rect.right < self.ai_settings.screen_width:
self.centerx += self.speed
if self.moving['left'] and self.rect.left > 0:
self.centerx -= self.speed
if self.moving['up'] and self.rect.top > 0:
self.centery -= self.speed
if self.moving['down'] and self.rect.bottom < self.ai_settings.screen_height:
self.centery += self.speed
self.rect.centerx = self.centerx
self.rect.centery = self.centery
def blitme(self):
self.screen.blit(self.image,self.rect)
(bullet.py)
import pygame
from random import randint
class Bullet(pygame.sprite.Sprite):
def __init__(self,ai_settings,screen,ship):
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
self.ship = ship
self.rect = pygame.Rect(0,0,self.ai_settings.bullet_width,self.ai_settings.bullet_height)
self.rect.top = self.ship.rect.top
self.rect.centerx = self.ship.rect.centerx
self.speed = self.ai_settings.bullet_speed_factor
self.y = float(self.rect.y)
self.color = randint(1,255),randint(1,255),randint(1,255)
def update(self):
self.y -= self.speed
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen,self.color,self.rect)
(alien.py)
import pygame
class Alien(pygame.sprite.Sprite):
def __init__(self,ai_settings,screen):
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
self.speed = self.ai_settings.alien_speed_factor
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def check_edges(self):
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right:
return True
elif self.rect.left <= 0:
return True
def update(self):
self.x += (self.speed * self.ai_settings.fleet_direction)
self.rect.x = self.x
My goal is create alien fleet in the whole screen.
Why is there just one row of aliens?

The problem is that in Alien you update(self) using the value of self.x, but you never set this value when you run create_fleet(...). So all your aliens are there already, they are just all on top of each other!
A simple solution is to set self.x at the same time as you set self.rect.x for each Alien when you initialize them in create_fleet(...). So instead of:
alien.rect.x = alien_width + 2 * alien_width * number_alien_x
you would have:
alien.rect.x = alien.x = alien_width + 2 * alien_width * number_alien_x

Related

Creating a game in Pygame encountered an IndentationError error

I ran into an indentation problem, but I rechecked my code and couldn't find the error, please help
Game:
import pygame, controls
from gun import Gun
from pygame.sprite import Group
from stats import Stats
def run():
pygame.init()
screen = pygame.display.set_mode((700, 600))
pygame.display.set_caption('Game1')
bg_color = (0, 0, 0)
gun = Gun(screen)
bullets = Group()
inos = Group()
controls.create_army(screen, inos)
stats = Stats()
while True:
controls.events(screen, gun, bullets)
gun.update_gun()
controls.update(bg_color, screen, gun, inos, bullets)
controls.update_bullets(inos, bullets)
controls.update_inos(stats, screen, gun, inos, bullets)
run()
Gun:
import pygame
class Gun():
def __init__(self, screen):
self.screen = screen
self.image = pygame.image.load(r"C:\Users\ralph\Downloads\Python\Game\Image\t2.png")
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.center = float(self.rect.centerx)
self.rect.bottom = self.screen_rect.bottom
self.mright = False
self.mleft = False
def output(self):
self.screen.blit(self.image, self.rect)
def update_gun(self):
if self.mright and self.rect.right < self.screen_rect.right:
self.center += 1.5
if self.mleft and self.rect.left > 0:
self.center -= 1.5
self.rect.centerx = self.center
def create_gun(self):
self.center = self.screen_rect.centerx
Bullet:
import pygame
class Bullet(pygame.sprite.Sprite):
def __init__(self, screen, gun):
super(Bullet, self).__init__()
self.screen = screen
self.rect = pygame.Rect(0, 0, 3, 12)
self.color = 150, 150, 150
self.speed = 1.5
self.rect.centerx = gun.rect.centerx
self.rect.top = gun.rect.top
self.y = float(self.rect.y)
def update(self):
self.y -= self.speed
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect)
Control:
import pygame
import sys
from bullet import Bullet
from ino import Ino
import time
def events(screen, gun, bullets):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
gun.mright = True
elif event.key == pygame.K_a:
gun.mleft = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(screen, gun)
bullets.add(new_bullet)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
gun.mright = False
elif event.key == pygame.K_a:
gun.mleft = False
def update(bg_color, screen, gun, inos, bullets):
screen.fill(bg_color)
for bullet in bullets.sprites():
bullet.draw_bullet()
gun.output()
inos.draw(screen)
pygame.display.flip()
def update_bullets(inos, bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
collisions = pygame.sprite.groupcollide(bullets, inos, True, True)
def gun_kill(stats, screen, gun, inos, bullets):
stats.guns_left -= 1
inos.empty()
bullets.empty()
create_army(screen, inos)
gun.create_gun()
time.sleep(2)
def update_inos(stats, screen, gun, inos, bullets):
inos.update()
if pygame.sprite.spritecollideany(gun, inos):
gun_kill(stats, screen, gun, inos, bullets)
def create_army(screen, inos):
ino = Ino(screen)
ino_width = ino.rect.width
number_ino_x = int((700 - 2 * ino_width) / ino_width)
ino_height = ino.rect.height
number_ino_y = int((800 - 300 - 2 * ino_height) / ino_height)
for row_number in range(number_ino_y):
for ino_number in range(number_ino_x):
ino = Ino(screen)
ino.x = ino_width + (ino_width * ino_number)
ino.y = ino_height + (ino_height * row_number)
ino.rect.x = ino.x
ino.rect.y = ino.rect.height + (ino.rect.height * row_number)
inos.add(ino)
Army:
import pygame
class Ino(pygame.sprite.Sprite):
def __init__(self, screen):
super(Ino, self).__init__()
self.screen = screen
self.image = pygame.image.load(r'C:\Users\ralph\Downloads\Python\Game\Image\solder.png')
self.rect = self.image.get_rect()
self.rect.x = self.rect.width
self.rect.y = self.rect.height
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def draw(self):
self.screen.blit(self.image, self.rect)
def update(self):
self.y += 0.05
self.rect.y = self.y
Stat
class Stats():
def __init__(self):
def reset_stats(self):
self.guns_left = 2
Error:
Traceback (most recent call last):
File "C:\Users\ralph\Downloads\Python\Game\game1.py", line 4, in
from stats import Stats
File "C:\Users\ralph\Downloads\Python\Game\stats.py", line 7
def reset_stats(self):
^
IndentationError: expected an indented block after function definition on line 3
I couldn't find the cause of the error but I believe the whole code is correct

Python Crash Course Alien Invasion the alien group reach the edge of the screen no response of turning back [duplicate]

(instance.py)
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
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()
aliens = pygame.sprite.Group()
gf.create_fleet(ai_settings,screen,ship,aliens)
while 1:
gf.check_events(ai_settings,screen,ship,bullets)
ship.update()
gf.update_bullet(bullets)
gf.update_alien(ai_settings,aliens)
gf.update_screen(ai_settings,screen,ship,bullets,aliens)
run_game()
(game_functions.py)
import pygame
import sys
from bullet import Bullet
from alien import Alien
def check_events(ai_settings,screen,ship,bullets):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
check_keydown_events(ai_settings,screen,ship,bullets,event)
if event.type == pygame.KEYUP:
check_keyup_events(ship,event)
def check_keydown_events(ai_settings,screen,ship,bullets,event):
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_UP:
ship.moving['up'] = True
elif event.key == pygame.K_DOWN:
ship.moving['down'] = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings,screen,ship)
bullets.add(new_bullet)
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(ship,event):
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_UP:
ship.moving['up'] = False
elif event.key == pygame.K_DOWN:
ship.moving['down'] = False
def update_screen(ai_settings,screen,ship,bullets,aliens):
screen.fill(ai_settings.bg_color)
ship.blitme()
for bullet in bullets.sprites():
bullet.draw_bullet()
aliens.draw(screen)
pygame.display.flip()
def update_bullet(bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.y < 0:
bullets.remove(bullet)
def create_fleet(ai_settings,screen,ship,aliens):
sample_alien = Alien(ai_settings,screen)
alien_width = sample_alien.rect.width
alien_height = sample_alien.rect.height
available_space_x = ai_settings.screen_width - 2 * alien_width
numbers_alien_x = int(available_space_x / ( 2 * alien_width ))
available_space_y = ai_settings.screen_height - 3 * alien_height - ship.rect.height
numbers_alien_y = int(available_space_y / ( 2 * alien_height ))
for number_alien_y in range(numbers_alien_y):
for number_alien_x in range(numbers_alien_x):
alien = Alien(ai_settings,screen)
alien.rect.x = alien_width + 2 * alien_width * number_alien_x
alien.rect.y = alien_height + 2 * alien_height * number_alien_y
aliens.add(alien)
def update_alien(ai_settings,aliens):
check_fleet_edges(ai_settings,aliens)
aliens.update()
def check_fleet_edges(ai_settings,aliens):
for alien in aliens.sprites():
if alien.check_edges():
change_fleet_direction(ai_settings,aliens)
break
def change_fleet_direction(ai_settings,aliens):
for alien in aliens.sprites():
alien.rect.y += ai_settings.fleet_drop_speed
ai_settings.fleet_direction *= -1
(settings.py)
class Settings(object):
def __init__(self):
self.screen_width = 1200
self.screen_height = 700
self.bg_color = 230,230,230
self.ship_speed_factor = 1.5
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 15,15,15
self.bullet_speed_factor = 1
self.alien_speed_factor = 2
self.fleet_drop_speed = 10
self.fleet_direction = 1
(ship.py)
import pygame
class Ship(object):
def __init__(self,ai_settings,screen):
self.ai_settings = ai_settings
self.screen = screen
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
self.moving = {'right':False,'left':False,'up':False,'down':False}
self.centerx = float(self.rect.centerx)
self.centery = float(self.rect.centery)
self.speed = self.ai_settings.ship_speed_factor
def update(self):
if self.moving['right'] and self.rect.right < self.ai_settings.screen_width:
self.centerx += self.speed
if self.moving['left'] and self.rect.left > 0:
self.centerx -= self.speed
if self.moving['up'] and self.rect.top > 0:
self.centery -= self.speed
if self.moving['down'] and self.rect.bottom < self.ai_settings.screen_height:
self.centery += self.speed
self.rect.centerx = self.centerx
self.rect.centery = self.centery
def blitme(self):
self.screen.blit(self.image,self.rect)
(bullet.py)
import pygame
from random import randint
class Bullet(pygame.sprite.Sprite):
def __init__(self,ai_settings,screen,ship):
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
self.ship = ship
self.rect = pygame.Rect(0,0,self.ai_settings.bullet_width,self.ai_settings.bullet_height)
self.rect.top = self.ship.rect.top
self.rect.centerx = self.ship.rect.centerx
self.speed = self.ai_settings.bullet_speed_factor
self.y = float(self.rect.y)
self.color = randint(1,255),randint(1,255),randint(1,255)
def update(self):
self.y -= self.speed
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen,self.color,self.rect)
(alien.py)
import pygame
class Alien(pygame.sprite.Sprite):
def __init__(self,ai_settings,screen):
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
self.speed = self.ai_settings.alien_speed_factor
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def check_edges(self):
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right:
return True
elif self.rect.left <= 0:
return True
def update(self):
self.x += (self.speed * self.ai_settings.fleet_direction)
self.rect.x = self.x
My goal is create alien fleet in the whole screen.
Why is there just one row of aliens?
The problem is that in Alien you update(self) using the value of self.x, but you never set this value when you run create_fleet(...). So all your aliens are there already, they are just all on top of each other!
A simple solution is to set self.x at the same time as you set self.rect.x for each Alien when you initialize them in create_fleet(...). So instead of:
alien.rect.x = alien_width + 2 * alien_width * number_alien_x
you would have:
alien.rect.x = alien.x = alien_width + 2 * alien_width * number_alien_x

Space Invaders - Pygame - Make enemy shoot

I am making the game Space Invaders with Pygame and I am trying to make the enemy shoot, firstly by pressing the TAB button. When I get this working I will let the enemy shoot randomly. At this moment I cannot see the BulletEnemy and when I press TAB it does not shoot anything. What am I doing wrong?
Thanks.
import pygame, sys
from pygame.locals import *
import random
screenWidth = 800
screenHeight = 600
FPS = 60
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()
shipWidth = 78
#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)
def app_quit():
pygame.quit()
sys.exit("System exit.")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("spaceship7.png").convert()
self.image.set_colorkey(white)#make white transparant
self.rect = self.image.get_rect()
self.rect.centerx = screenWidth / 2
self.rect.bottom = screenHeight - 10
self.speedx = 0
def update(self):
self.speedx = 0
if event.type == KEYDOWN and event.key == K_LEFT:
self.speedx = -2
elif event.type == KEYDOWN and event.key == K_RIGHT:
self.speedx = 2
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.right = screenWidth
if self.rect.left < 0:
self.rect.left = 0
def shootPlayer(self):
bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
allSprites.add(bulletPlayer)
bulletsPlayer.add(bulletPlayer)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("enemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = random.randrange(0, 200)
self.speedx = random.randrange(1,2)
def update(self):
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.x = 50
self.rect.y = random.randrange(0, 250)
self.speedx = random.randrange(1,3)
if self.rect.x > screenWidth:
self.kill()
def shootEnemy(self):
bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
allSprites.add(bulletEnemy)
bulletsEnemy.add(bulletEnemy)
class BulletPlayer(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class BulletEnemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bulletenemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom > screenHeight:
self.kill()
class Wall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("wall.png").convert()
self.rect = self.image.get_rect()
self.rect.center = 100, 300
allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)
for i in range(1):
e = Enemy()
allSprites.add(e)
enemy.add(e)
running = True
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
running = False
app_quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_TAB:
enemy.shootEnemy()
allSprites.update()
screen.fill(black)
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
Spaceship
Enemy
Wall
BulletPlayer
BulletEnemy
The problem is here:
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_TAB:
enemy.shootEnemy()
Once event.type == KEYDOWN one time, the second evaluation is ignored.
Try this
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.key == pygame.K_TAB:
enemy.shootEnemy()
This checks for a KEYDOWN event, then for the specific key that's pressed.

Space Invaders - pygame - AttributeError

I want to make the enemies shoot, firstly with the tab butten, after I get this working I want to make them shoot randomly. When I press the tab button it says AttributeError: 'Group' object has no attribute 'shootEnemy'.
What is going wrong?
At this moment there is no collision detection. I will add this later.
import pygame, sys
from pygame.locals import *
import random
screenWidth = 800
screenHeight = 600
FPS = 60
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()
shipWidth = 78
#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)
def app_quit():
pygame.quit()
sys.exit("System exit.")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("spaceship7.png").convert()
self.image.set_colorkey(white)#make white transparant
self.rect = self.image.get_rect()
self.rect.centerx = screenWidth / 2
self.rect.bottom = screenHeight - 10
self.speedx = 0
def update(self):
self.speedx = 0
if event.type == KEYDOWN and event.key == K_LEFT:
self.speedx = -2
elif event.type == KEYDOWN and event.key == K_RIGHT:
self.speedx = 2
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.right = screenWidth
if self.rect.left < 0:
self.rect.left = 0
def shootPlayer(self):
bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
allSprites.add(bulletPlayer)
bulletsPlayer.add(bulletPlayer)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("enemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = random.randrange(0, 200)
self.speedx = random.randrange(1,2)
def update(self):
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.x = 50
self.rect.y = random.randrange(0, 250)
self.speedx = random.randrange(1,3)
if self.rect.x > screenWidth:
self.kill()
def shootEnemy(self):
bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
allSprites.add(bulletEnemy)
bulletsEnemy.add(bulletEnemy)
class BulletPlayer(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class BulletEnemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bulletenemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom > screenHeight:
self.kill()
class Wall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("wall.png").convert()
self.rect = self.image.get_rect()
self.rect.center = 100, 300
allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)
for i in range(1):
e = Enemy()
allSprites.add(e)
enemy.add(e)
running = True
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
running = False
app_quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
if event.key == pygame.K_TAB:
enemy.shootEnemy()
allSprites.update()
screen.fill(black)
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
Change the line:
enemy.shoot()
to
random.choice(enemy.sprites()).shoot()
This will call the shoot() method of a random sprite from your SpriteGroup enemy.

Two enemy movement glitches

So this is my game I've bean working on and so have things are going very well, the player can move around and shoot down the boxes which are ment to be moving but theres these small glitches, but before I go on heres the code:
import pygame, math, random, sys
from pygame import *
import random, math, cmath
pygame.init()
#variables end----------------------------------------------------------------
#imagers
grass = "grass_shit.png" #grass image
player_img = "shithead.png" #player name
ali_img = "shit_head2.png" #alien image
dead_screen = "dead_shit.png"
cross_hair = "crosshair.png"
playButton = "playbutton.png"
#screen
screen = pygame.display.set_mode((850, 640),0,32) #set screen
background = pygame.image.load(grass).convert() #load image to screen
health = 100
#mouse things
crosshair = pygame.image.load(cross_hair).convert_alpha()
#variables end----------------------------------------------------------------
pygame.mouse.set_visible(False)
black = ( 0, 0, 0)
white = ( 255, 255, 255)
red = ( 255, 0, 0)
blue = ( 0, 0, 255)
player_x, player_y = 0, 0
move_player_x, move_player_y = 0, 0
move_ali_x, move_ali_y = 0, 0
class Block(pygame.sprite.Sprite):
def __init__(self, color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
def update(self):
global move_ali_x
global move_ali_y
if block.rect.x < player_x:
move_ali_x =+ 0.05
elif block.rect.x > player_x:
move_ali_x =- 0.05
if block.rect.y < player_y:
move_ali_y =+ 0.05
elif block.rect.y > player_y:
move_ali_y =- 0.05
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(red)
self.rect = self.image.get_rect()
def update(self):
pos = pygame.mouse.get_pos()
self.rect.x = player_x
self.rect.y = player_y
class Bullet(pygame.sprite.Sprite):
def __init__(self, mouse, player):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([4, 10])
self.image.fill(black)
self.mouse_x, self.mouse_y = mouse[0], mouse[1]
self.player = player
self.rect = self.image.get_rect()
def update(self):
speed = 10
range = 50000
distance = [self.mouse_x - self.player[0], self.mouse_y - self.player[1]]
norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
direction = [distance[0] / norm, distance[1] / norm]
bullet_vector = [direction[0] * speed, direction[1] * speed]
self.rect.x += bullet_vector[0]
self.rect.y += bullet_vector[1]
pygame.init()
screen_width = 850
screen_height = 640
screen = pygame.display.set_mode([screen_width,screen_height])
all_sprites_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
for i in range(5):
block = Block(blue)
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(350)
block_list.add(block)
all_sprites_list.add(block)
player = Player()
all_sprites_list.add(player)
done = False
clock = pygame.time.Clock()
score = 0
player.rect.y = 370
# -------- Main Program Loop -----------
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
bullet = Bullet(event.pos, [player.rect.x, player.rect.y])
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
all_sprites_list.add(bullet)
bullet_list.add(bullet)
if event.type== pygame.KEYDOWN:
if event.key==K_a:
move_player_x=-4
elif event.key==K_d:
move_player_x=+4
elif event.key==K_w:
move_player_y=-4
elif event.key==K_s:
move_player_y=+4
if event.type== pygame.KEYUP:
if event.key==K_a:
move_player_x=0
elif event.key==K_d:
move_player_x=0
elif event.key==K_w:
move_player_y=0
elif event.key==K_s:
move_player_y=0
# --- Game logic
all_sprites_list.update()
player_x += move_player_x
player_y += move_player_y
block.rect.y += move_ali_y
block.rect.x += move_ali_x
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
for block in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 1
print( score )
if bullet.rect.y < -10:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
if player.rect.colliderect(block.rect):
health =- 35
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_x -= crosshair.get_width() / 2
mouse_y -= crosshair.get_height() / 2
screen.blit(background,(0,0))
all_sprites_list.draw(screen)
screen.blit(crosshair,(mouse_x, mouse_y))
pygame.display.flip()
pygame.display.update()
clock.tick(20)
pygame.quit()
So glitch number one:
only one of the boxers moves, I cant figure out why it only one of them is moving towards the player, all the boxers are meant to move towards the player as this is hoping to become a zombie shooter.
Glitch two:
At a random point the box that does move does stops moving in all directions but one, so lets say this happens when the box in in the center of the screen, if the player goes to the left of the box, nothing, but when the player moves to thr right of the player it moves right, but only right not up or down, and this seams to happen at soem point everytime.
Well thats it, hope you can help thanks heaps stackoverflow
Your code should looks like this:
import pygame
from pygame import *
import sys
import math
import random
import cmath
#----------------------------------------------------------------------
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
#imagers
IMAGE_GRASS = "grass_shit.png" #grass image
IMAGE_PLAYER = "shithead.png" #player name
IMAGE_ALI = "shit_head2.png" #alien image
IMAGE_DEAD_SCREEN = "dead_shit.png"
IMAGE_CROSSHAIR = "crosshair.png"
IMAGE_PLAYBUTTON = "playbutton.png"
#~ IMAGE_GRASS = "ball3.png" #grass image
#~ IMAGE_PLAYER = "ball2.png" #player name
#~ IMAGE_ALI = "ball3.png" #alien image
#~ IMAGE_DEAD_SCREEN = "ball3.png"
#~ IMAGE_CROSSHAIR = "ball1.png"
#~ IMAGE_PLAYBUTTON = "ball3.png"
#----------------------------------------------------------------------
class Block(pygame.sprite.Sprite):
def __init__(self, color, x, y, player = None):
pygame.sprite.Sprite.__init__(self)
self.player = player
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.move_x = self.move_y = 0
def update(self):
if self.player:
player_x, player_y = self.player.rect.center
if self.rect.x < player_x:
self.rect.x += 1
elif self.rect.x > player_x:
self.rect.x -= 1
if self.rect.y < player_y:
self.rect.y += 1
elif self.rect.y > player_y:
self.rect.y -= 1
#----------------------------------------------------------------------
class Player(pygame.sprite.Sprite):
def __init__(self, screen_rect, x=0, y=0):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.min_x = screen_rect.left
self.min_y = screen_rect.top
self.max_x = screen_rect.right
self.max_y = screen_rect.bottom
self.move_x = self.move_y = 0
self.health = 100
def update(self):
pos = pygame.mouse.get_pos()
self.rect.x += self.move_x
self.rect.y += self.move_y
if self.rect.top < self.min_x:
self.rect.top = self.min_x
elif self.rect.bottom > self.max_y:
self.rect.bottom = self.max_y
if self.rect.left < self.min_x:
self.rect.left = self.min_x
elif self.rect.right > self.max_x:
self.rect.right = self.max_x
def event_handler(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
self.move_x = -4
elif event.key == pygame.K_d:
self.move_x = +4
elif event.key == pygame.K_w:
self.move_y = -4
elif event.key == pygame.K_s:
self.move_y = +4
if event.type == pygame.KEYUP:
if event.key in (pygame.K_a, pygame.K_d):
self.move_x = 0
elif event.key in (pygame.K_w, pygame.K_s):
self.move_y = 0
#----------------------------------------------------------------------
class Bullet(pygame.sprite.Sprite):
def __init__(self, start_pos, mouse_pos):
pygame.sprite.Sprite.__init__(self)
self.start_rect = start_pos.rect.copy()
self.mouse_x, self.mouse_y = mouse_pos # mouse[0], mouse[1]
self.image = pygame.Surface([5, 5])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.centerx = self.start_rect.centerx
self.rect.centery = self.start_rect.centery
self.speed = 10
self.max_range = 50
self.current_range = 0
distance_x = self.mouse_x - self.start_rect.centerx
distance_y = self.mouse_y - self.start_rect.centery
norm = math.sqrt(distance_x ** 2 + distance_y ** 2)
direction_x = distance_x / norm
direction_y = distance_y / norm
self.bullet_vector_x = direction_x * self.speed
self.bullet_vector_y = direction_y * self.speed
def update(self):
self.current_range += 1
if self.current_range < self.max_range:
print self.start_rect.centerx + (self.bullet_vector_x*self.current_range),
print self.rect.centerx + self.bullet_vector_x,
#self.rect.centerx += self.bullet_vector_x
self.rect.centerx = self.start_rect.centerx + (self.bullet_vector_x*self.current_range)
print self.rect.centerx
#self.rect.centery += self.bullet_vector_y
self.rect.centery = self.start_rect.centery + (self.bullet_vector_y*self.current_range)
else:
self.kill()
#----------------------------------------------------------------------
class Crosshair(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(IMAGE_CROSSHAIR).convert_alpha()
self.rect = self.image.get_rect()
def update(self):
mouse_x, mouse_y = pygame.mouse.get_pos()
self.rect.centerx = mouse_x
self.rect.centery = mouse_y
def draw(self, screen):
screen.blit(self.image,self.rect.topleft)
#----------------------------------------------------------------------
class Background(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(IMAGE_GRASS).convert_alpha()
self.rect = self.image.get_rect()
def draw(self, screen):
screen.fill((128,128,128))
screen.blit(self.image,(0,0))
#----------------------------------------------------------------------
class Game():
def __init__(self):
pygame.init()
screen_width = 850
screen_height = 640
self.screen = pygame.display.set_mode( (screen_width,screen_height) )
pygame.mouse.set_visible(False)
#-----
self.all_sprites_list = pygame.sprite.Group()
self.block_list = pygame.sprite.Group()
self.bullet_list = pygame.sprite.Group()
# --- create sprites ---
self.background = Background()
self.player = Player(self.screen.get_rect(), 0, 370)
self.all_sprites_list.add(self.player)
for i in range(5):
block = Block(BLUE, random.randrange(100, screen_width), random.randrange(10, screen_height-10), self.player)
self.block_list.add(block)
self.all_sprites_list.add(block)
self.crosshair = Crosshair()
#-----
font = pygame.font.SysFont("", 72)
self.text_pause = font.render("PAUSE", -1, RED)
self.text_pause_rect = self.text_pause.get_rect(center=self.screen.get_rect().center) # center text
#-----
self.score = 0
def bullet_create(self, start_pos, mouse_pos):
bullet = Bullet(start_pos, mouse_pos)
self.all_sprites_list.add(bullet)
self.bullet_list.add(bullet)
def bullets_update(self):
for bullet in self.bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, self.block_list, True)
for block in block_hit_list:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
self.score += 1
print self.score
if bullet.rect.y < -10:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
if pygame.sprite.collide_rect(self.player, block):
self.player.health =- 35
# -------- Main Program Loop -----------
def run(self):
clock = pygame.time.Clock()
RUNNING = True
PAUSED = False
while RUNNING:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = false
elif event.key == pygame.K_SPACE:
PAUSED = not PAUSED
elif event.type == pygame.MOUSEBUTTONDOWN:
self.bullet_create(self.player, event.pos)
# send event to player
self.player.event_handler(event)
# send event to crosshair for mousebuttondown
#if not PAUSED:
# self.crosshair.event_handler(event)
# --- updates ---
if not PAUSED:
self.all_sprites_list.update()
self.bullets_update()
self.crosshair.update()
# --- draws ---
self.background.draw(self.screen)
self.all_sprites_list.draw(self.screen)
self.crosshair.draw(self.screen)
if PAUSED:
self.screen.blit(self.text_pause, self.text_pause_rect.topleft)
pygame.display.update() # use flip() OR update()
# --- FPS ---
clock.tick(20)
# --- quit ---
pygame.quit()
#----------------------------------------------------------------------
Game().run()
Changes:
player can move but can leave screen
press space to pause game - but you can still move cursor and fire :)
bullet has max range - than it is removed
i change bullet vetor calculations because value was rounded to integer every frame and bullet trajectory was incorrect
bullet never change trajectory when player is moving
all code is in classes except some constant values. I add class Crosshair and Background
you can see how class (Player) handle events in event_handle
I use pygame.Rect() (screen.get_rect(), image.get_rect()) to get rect.top, rect.left, rect.center, rect.centerx, rect.topleft, etc.
There is still many things to do.
ps. if someone needs images 'ball1.png', 'ball2.png', 'ball3.png' to run this example you can find it in answer to
Space invaders project
Pygame- window and sprite class - python

Categories