Not able to shoot bullet in pygame - python

So recently I have been trying to make my first big game but I'm stuck on the shooting phase. Basically, my problem is I want to make it so that I can shoot multiple bullets and move around while doing so, but I can't seem to figure it out.
Code:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((600,600))
pygame.display.set_caption("Shooter Game!")
#Variables
playerX = 5
playerY = 5
black = (0,0,0)
blue = (0,0,255)
red = (255,0,0)
clicking = False
bulletX = playerX
bulletY = playerY
#End Of Variables#
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
screen.fill(blue)
player = pygame.image.load("Young_Link_2D.png").convert_alpha()
screen.fill(blue)
player1 = pygame.transform.scale(player, (100,100))
screen.blit(player1,(playerX,playerY))
keyPressed = pygame.key.get_pressed()
#Controls
if keyPressed[pygame.K_a]:
playerX -= 1
bulletX = playerX
if keyPressed[pygame.K_d]:
playerX += 1
bulletX = playerX
if keyPressed[pygame.K_w]:
playerY -= 1
bulletY = playerY
if keyPressed[pygame.K_s]:
playerY += 1
bulletY = playerY
#End of Controls
#Shooting
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
Bullet = pygame.draw.rect(screen, red, (bulletX+35,bulletY + 60,10,25))
bulletY = bulletY + 1
pygame.display.update()

Here is what i meant by classes:
import pygame
import Bullet
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Shooter Game!")
# Variables
playerX = 5
playerY = 5
black = (0, 0, 0)
blue = (0, 0, 255)
red = (255, 0, 0)
clicking = False
bulletX = playerX
bulletY = playerY
bullets = []
newBullet = False
# End Of Variables#
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
screen.fill(blue)
player = pygame.image.load("100x100_logo.png").convert_alpha()
screen.fill(blue)
player1 = pygame.transform.scale(player, (100, 100))
screen.blit(player1, (playerX, playerY))
keyPressed = pygame.key.get_pressed()
# Controls
if keyPressed[pygame.K_a]:
playerX -= 1
bulletX = playerX
if keyPressed[pygame.K_d]:
playerX += 1
bulletX = playerX
if keyPressed[pygame.K_w]:
playerY -= 1
bulletY = playerY
if keyPressed[pygame.K_s]:
playerY += 1
bulletY = playerY
# End of Controls
# Shooting
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
bullets.append(Bullet.Bullet(bulletX + 35, bulletY + 60))
for i in range(len(bullets)):
bullets[i].draw(screen, (255, 0, 0))
bullets[i].move(1)
print(len(bullets))
pygame.display.update()
Thats your main code. There is still a bug where there is no cooldown so multiple bullets are created consecutively when holding the mouse button.
import pygame
class Bullet:
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self, win, colour):
pygame.draw.rect(win, colour, (self.x, self.y, 10, 25))
def move(self, speed):
self.y += speed
and thats the bullet class to create multiple instances

See How do I stop more than 1 bullet firing at once? and How can i shoot a bullet with space bar?.
You need to manage the bullets in a list:
bullets = []
Add a new bullet to the list when the mouse click is detected. Use pygame.Rect objects to represent the bullets. The events must be handled in the event loop:
for event in pygame.event.get():
# [...]
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
bullets.append(pygame.Rect(playerX, playerY, 35, 60))
Move the bullets in a loop. Remove the bullets from the list, when they when they move off the screen. See How to remove items from a list while iterating?:
for bullet in bullets[:]:
bullet.y += 5
if bullet.top > 600:
bullets.remove(bullet)
Draw all the bullets in the list in another loop:
for bullet in bullets:
pygame.draw.rect(screen, red, bullet)
Complete example:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((600,600))
pygame.display.set_caption("Shooter Game!")
#Variables
player = pygame.image.load("Young_Link_2D.png").convert_alpha()
playerX, playerY = 5, 5
black = (0,0,0)
blue = (0,0,255)
red = (255,0,0)
clicking = False
bullets = []
#End Of Variables#
clock = pygame.time.Clock()
running = True
while running:
clock.tick(100)
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
bullets.append(pygame.Rect(playerX, playerY, 35, 60))
keyPressed = pygame.key.get_pressed()
playerX += keyPressed[pygame.K_d] - keyPressed[pygame.K_a]
playerY += keyPressed[pygame.K_s] - keyPressed[pygame.K_w]
for bullet in bullets[:]:
bullet.y += 5
if bullet.top > 600:
bullets.remove(bullet)
screen.fill(blue)
player1 = pygame.transform.scale(player, (100,100))
screen.blit(player1,(playerX,playerY))
for bullet in bullets:
pygame.draw.rect(screen, red, bullet)
pygame.display.update()
pygame.quit()
exit()

Related

Flickering Sprite in Pygame

I know lots of people have had issues with flickering images in pygame on here, but none of the responses have helped me. I am trying to make Space Invaders, however, the bullet flickers as it moves up the screen. Please try to help me, and thank you! I do not currently care about the size, position, or scale of the bullet, I know it does not look great, but I just want it to display properly! Below is the code:
import pygame
#import sys- might use later
import random
#Sets the starting values for screen, etc. of the playing space
pygame.init()
size = (800, 600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Space Invaders")
play = True
clock = pygame.time.Clock()
blkColor = (0, 0, 0)
#Loads and sizes the alien and player ship(s)
playerShip = pygame.image.load('ship.png')
playerShip = pygame.transform.scale(playerShip, (50, 50))
playerX = 370
playerY = 520
alien = pygame.image.load('alien.png')
alien = pygame.transform.scale(alien, (35, 35))
alienX = random.randint(0, 750)
alienY = 0
move = 5
alienMove = 5
bullet = pygame.image.load('bullet.png')
bullet = pygame.transform.scale(bullet, (5, 100))
bulletX = 0
bulletY = 600
hit = False
fire = False
hitRangeMin = -35
hitRangeMax = 35
score = 0
def player():
screen.blit(playerShip, (playerX, playerY))
def enemy():
screen.blit(alien, (alienX, alienY))
def alienMovement():
global alienX
global alienY
global alienMove
#Moves the alien across the screen; when it hits the edge, it shifts down one spot and goes the other direction
alienX += alienMove
if alienX > 750:
alienMove = -5
alienY += 35
if alienX < 0:
alienMove = 5
alienY += 35
def shoot(x, y):
global fire
global bulletY
fire = True
screen.blit(bullet, (x, y))
pygame.display.flip()
if bulletY < 0:
fire = False
bulletY = 550
elif bulletY >= 0:
fire = True
def gameOver(score):
print('Will add score and display and stuff- does noo matter.')
# Keeps the game window open until exited
while not hit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
player()
enemy()
key_input = pygame.key.get_pressed()
if key_input[pygame.K_LEFT]:
playerX -= move
elif key_input[pygame.K_RIGHT]:
playerX += move
if playerX > 800:
playerX = 0
if playerX < 0:
playerX = 800
#For shooting the bullet
if key_input[pygame.K_SPACE]:
bulletX = playerX + 23
shoot(bulletX, bulletY)
##Loops with function "shoot" to move bullet up the screen
if fire:
shoot(bulletX, bulletY)
bulletY -= 5
screen.fill(blkColor)
alienMovement()
player()
enemy()
pygame.display.flip()
clock.tick(60)
The problem is caused by multiple calls to pygame.display.update(). An update of the display at the end of the application loop is sufficient. Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering.
Remove pygame.display.flip() from shoot:
def shoot(x, y):
global fire
global bulletY
fire = True
screen.blit(bullet, (x, y))
# pygame.display.flip() <--- DELETE
if bulletY < 0:
fire = False
bulletY = 550
elif bulletY >= 0:
fire = True
And you have to clear the screen before drawing the bullet:
while not hit:
# [...]
screen.fill(blkColor) # <--- INSERT
if key_input[pygame.K_SPACE]:
bulletX = playerX + 23
shoot(bulletX, bulletY)
##Loops with function "shoot" to move bullet up the screen
if fire:
shoot(bulletX, bulletY)
bulletY -= 5
# screen.fill(blkColor) <--- DELETE
alienMovement()
player()
enemy()
pygame.display.flip()
clock.tick(60)

How can i make function that makes my player move in Pygame

I'm trying to make space invaders in Pygame. I am trying to make the player move I saw few tutorials and that suppose to work but nothing happening when I am pressing the button.
this is the code:
import pygame
pygame.init()
WIN = pygame.display.set_mode((800, 600))
WIDTH, HEIGHT = 800, 600
VEL = 3
FPS = 60
WHITE_COLOR = (255, 255, 255)
pygame.display.set_caption("Space Invaders")
ufo_icon = pygame.image.load('ufo.png')
player = pygame.image.load('space-invaders.png')
player = pygame.transform.scale(player, (60, 60))
playerX = 400 - player.get_width()/2
playerY = 300
pygame.display.set_icon(ufo_icon)
def player_movement(playerX , keys):
if keys[pygame.K_LEFT]:
playerX += VEL
def draw_window(player, playerX, playerY):
WIN.fill((WHITE_COLOR))
WIN.blit(player, (playerX, playerY + 100))
pygame.display.update()
def main():
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
player_movement(playerX, keys)
draw_window(player, playerX, playerY)
main()
Python has no concept of in-out parameters. You need to return the new value from the function:
def player_movement(playerX , keys):
if keys[pygame.K_LEFT]:
playerX -= VEL
if keys[pygame.K_RIGHT]:
playerX += VEL
return playerX
def main():
playerX = 400 - player.get_width()/2
playerY = 300
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
playerX = player_movement(playerX, keys)
draw_window(player, playerX, playerY)

Trying to add a restart keystroke to my problem but facing encounters

So I was trying to build this game using a free course on Youtube by Freecodeacademy(feel free to check them out) and after I finished I tried to add my own restart key log to the game. In the sense that I wanted that if people press R the game restarts.
I have tried the following methods
Put the game loop in a separate function and try to use recursion to replay the function over and over again but while the game does work, the images such as the bullet image or background does not load and hence it does not work properly
I have also tried creating a new python file in the same project and tried to import the main file over and over again using importlib.reload(main) but I can't seem to do that either.
I was wondering what else could the solution be and if there is a more efficient solution. I will leave my code down below and would appreciate any help.
Ps: I am only a armature in coding right now so I understand this problem might be small and stupid but I do want to learn from my failures and mistakes. Also I apologize if there is something wrong with anything in my question. This is my first question on stack overflow.
import pygame
import random
import math
from pygame import mixer
pygame.init() # This is to Initialise the game
screen = pygame.display.set_mode((800, 600)) # create screen and set height
# Background
background = pygame.image.load('background.png')
# Background sound
mixer.music.load("background.wav")
mixer.music.play(-1)
# Title and Icon
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('ufo.png')
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load("space-invaders.png")
playerX = 370
playerY = 480
playerX_change = 0
def player(x, y): # This function is used to display the value on the screen
screen.blit(playerImg, (x, y)) # Blit is used to display stuff on the screen
# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load("invader.png"))
enemyX.append(random.randint(0, 736))
enemyY.append(random.randint(50, 150))
enemyX_change.append(4)
enemyY_change.append(40)
def enemy(x, y, i): # This function is used to display the value on the screen
screen.blit(enemyImg[i], (x, y)) # Blit is used to display stuff on the screen
# Bullet
bulletImg = pygame.image.load('bullet.png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 10
bullet_state = "ready" # Ready state means bullet has not yet been fired, we use this as a bool
# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 16)
textX = 10
textY = 10
# Game Over Text
over_font = pygame.font.Font("freesansbold.ttf", 64)
def show_score(x, y):
over_text = font.render("Score: " + str(score_value), True, (255, 255, 255))
screen.blit(over_text, (x, y))
def game_over_text():
over_text = over_font.render("GAME OVER ", True, (255, 255, 255))
screen.blit(over_text, (200, 250))
def fire_bullet(x, y):
global bullet_state
bullet_state = "fire"
screen.blit(bulletImg, (x + 16, y + 10))
def isCollision(enemyX, enemyY, bulletX, bulletY):
distance = math.sqrt((math.pow(enemyX - bulletX, 2)) + (math.pow(enemyY - bulletY, 2)))
if distance < 27:
return True
else:
return False
# Game Loop
running = True
while running:
# Background color
screen.fill((0, 0, 0))
# Background image
screen.blit(background, (0, 0))
for event in pygame.event.get(): # pygame.event.get() function is used to create a container of every action done
if event.type == pygame.QUIT: # Close game when cross is clicked
running = False
# Recording Keystrokes
if event.type == pygame.KEYDOWN: # KEYDOWN is used to check if key is pressed
if event.key == pygame.K_LEFT:
playerX_change -= 5
if event.key == pygame.K_RIGHT:
playerX_change += 5
if event.key == pygame.K_SPACE: # Bullet Shot
if bullet_state == "ready":
bullet_sound = mixer.Sound("laser.wav")
bullet_sound.play()
bulletX = playerX
fire_bullet(bulletX, playerY)
if event.key == pygame.K_r:
restart = True
if event.type == pygame.KEYUP: # KEYUP is used to know if the key is released
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
# Player Call
playerX += playerX_change
# Setting Boundaries
if playerX <= 0:
playerX = 0
if playerX >= 736:
playerX = 736
for i in range(num_of_enemies):
# Game Over
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
break
enemyX[i] += enemyX_change[i]
if enemyX[i] <= 0:
enemyX_change[i] = 4
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736:
enemyX_change[i] = -4
enemyY += enemyY_change
# Collision
collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
if collision:
explosion_sound = mixer.Sound("explosion.wav")
explosion_sound.play()
bulletY = 480
score_value += 1
bullet_state = "ready"
enemyX[i] = random.randint(0, 736)
enemyY[i] = random.randint(50, 150)
enemy(enemyX[i], enemyY[i], i)
# Bullet Movement
if bulletY <= 0:
bulletY = 480
bullet_state = "ready"
if bullet_state == "fire":
fire_bullet(bulletX, bulletY)
bulletY -= bulletY_change
player(playerX, playerY)
show_score(textX, textY)
# Constantly updates the changes
pygame.display.update()
Write a function that will reset any variables that change when the game is running:
enemy_image = pygame.image.load("invader.png")
def resetGame():
global playerX, playerY, playerX_change
global enemyImg, enemyX, enemyY, enemyX_change, enemyY_change
global score_value
global bulletX, bulletY, bulletX_change, bulletY_change, bullet_state
playerX = 370
playerY = 480
playerX_change = 0
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6
for i in range(num_of_enemies):
enemyImg.append(enemy_image)
enemyX.append(random.randint(0, 736))
enemyY.append(random.randint(50, 150))
enemyX_change.append(4)
enemyY_change.append(40)
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 10
bullet_state = "ready"
score_value = 0
Call the function once if the game needs to be restarted. You can even call the function before the application loop instead of setting all the variables.

How do I spawn multiple enemies in pygame [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am working on a game which involves the user to control a spaceship (player in code) and and shoot aliens (enemy in code) spawned randomly in the surface.
As of now, I have only successfully made one alien spawn at a time. How do I add say, 6 aliens simultaneously, that respawn (in random places of the surface) after a bullet hits it?
import pygame
import random
import math
# for initialising pygame (req for every pygame app)
pygame.init()
# making the basic window (dimensions must be written inside a tuple )
screen = pygame.display.set_mode((500, 500))
# background
background = pygame.image.load('C:/Users/aryan/Downloads/background.jpg')
# load and set the logo
logo = pygame.image.load('C:/Users/aryan/Downloads/bp.png') # directory of logo
pygame.display.set_icon(logo)
pygame.display.set_caption("space wars") # program name
# define a variable to control the main loop
running = True
# player
playerimg = pygame.image.load('C:/Users/aryan/Downloads/spaceship.png')
playerX = 218 # x and y coordinates of image
playerY = 350
playerxchange = 0 # this will be the change in movement in x direction of our image
playerychange = 0 # this will be the change in movement in y direction of our image
def player(x, y):
screen.blit(playerimg, (x, y)) # blit draws our image on the surface(basically the background)
# syntax for blit(imagename, (xcoordinate,ycoordinate))
# enemy
enemyimg = pygame.image.load('C:/Users/aryan/Downloads/enemy.png')
enemyX = random.randint(0, 464)
enemyY = random.randint(0, 30)
enemyxchange = 0.2
enemyychange = 40
# game over
overimg = pygame.image.load('C:/Users/aryan/Downloads/gameover.png')
# bullet
bulletimg = pygame.image.load('C:/Users/aryan/Downloads/bullet.png')
bulletX = 0
bulletY = 350
bulletxchange = 0
bulletychange = 1
bullet_state = "ready" # "ready" you cant see bullet on screen
# "fire" you can see bullet firing
bullets = [] # bullets is a list that contains the coordinates of every bullet
score = 0
font30 = pygame.font.SysFont(None, 30)
# Functions
def enemy(x, y):
screen.blit(enemyimg, (x, y)) # blit draws our image on the surface(basically the background)
# syntax for blit(imagename, (xcoordinate,ycoordinate))
def firebullet(x, y):
global bullet_state
bullet_state = "ready"
bullets.append([x + 12, y + 6]) # Creating a new bullet
def iscollision(enemyX, enemyY, bulletX, bulletY):
distance = math.sqrt(math.pow(enemyX-bulletX, 2)+ math.pow(enemyY-bulletY,2)) # distance formula
if distance <= 20:
return True
else:
return False
def TextScore(game):
text2 = font30.render("Your Score is: " + str(game), True, (37, 97, 188))
screen.blit(text2, (10, 45))
# main loop
while running:
screen.fill((120, 120, 120)) # in order (r, g, b) . (0, 0, 0) is black (255, 0, 0) is red...
screen.blit(background, (0, 0))
# event handling, gets all event from the event queue
for event in pygame.event.get():
# only do something if the event is of type QUIT
if event.type == pygame.QUIT:
# change the value to False, to exit the main loop
running = False
# checking keystroke
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
playerxchange += 0.3 # change in movement will be 0.2 towards the right
if event.key == pygame.K_LEFT:
playerxchange -= 0.3 # change in movement will be 0.2 towards the right
if event.key == pygame.K_UP:
playerychange -= 0.3
if event.key == pygame.K_DOWN:
playerychange += 0.3
if event.key == pygame.K_SPACE:
bullet_state = "fire"
firebullet(playerX, playerY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_DOWN or event.key == pygame.K_UP:
playerxchange = 0
playerychange = 0
playerY += playerychange
playerX += playerxchange # the value of playerx changes by +- 0.1 depending on keystroke
if playerX <= -64: # this teleports the spaceship from left end to right end
playerX = 564
elif playerX >= 564: # this teleports spaceship from right end to left
playerX = -64
if playerY >= 436: # this prevents spaceship from leaving vertically
playerY = 436
if playerY <= 0:
playerY = 0
# enemy movement
enemyX += enemyxchange
if enemyY >= 476:
enemyY = 476
enemyYchange = 0
enemyXchange = 0
if enemyX <= 0:
enemyxchange = 0.2
enemyY += enemyychange
elif enemyX >= 465:
enemyxchange = -0.2
enemyY += enemyychange
# bullet movement
if bullet_state == "fire":
firebullet(playerX, playerY)
for bullet in bullets:
screen.blit(bulletimg, (bullet[0], bullet[1])) # Print a bullet
bullet[0] -= bulletxchange # Updates its position
bullet[1] -= bulletychange
if bullet[1] < 0:
bullets.remove(bullet)
# collision
for bullet in bullets: # Use a for-loop to iterate through all the bullets in the list.
collision = iscollision(enemyX, enemyY, bullet[0], bullet[1])
if collision: # Test if a single bullet collides with the enemy inside the loop.
score += 1
print(score)
bullets.remove(bullet) # Remove the bullet from the list when it collides with the enemy.
enemyX = random.randint(0, 476) # if collision takes place, alien respawns
enemyY = random.randint(0, 30)
TextScore(score)
player(playerX, playerY) # player method is called AFTER screen.fill otherwise the screen will fill after image has been blitted
enemy(enemyX, enemyY)
pygame.display.update() # necessary for events to keep updating
Create an Enemy class with a move and a draw method (see Classes):
class Enemy:
def __init__(self):
self.x = random.randint(0, 476)
self.y = 20
self.moveX = 0.2
self.moveY = 40
def move(self):
self.x += self.moveX
if self.y >= 476:
self.y = 476
self.moveY = 0
self.moveX = 0
if self.x <= 0:
self.moveX = 0.2
self.y += self.moveY
elif self.x >= 465:
self.moveX = -0.2
self.y += self.moveY
def draw(self):
screen.blit(enemyimg, (self.x, self.y))
Create a number of enemies and store them in a list (enemy_list ) instead of the global variables enemyX, enemyY, enemyxchange and enemyychange:
enemyimg = pygame.image.load('C:/Users/aryan/Downloads/enemy.png')
enemy_list = []
for i in range(5):
new_enemy = Enemy()
enemy_list.append(new_enemy)
move and draw the enemies in a loop. For the collision test, you need to check if any of the bullets hits any of the enemies. Therefore, the collision test has to be done in nested loops. Note that the loop that goes through the bullets has to be the inner loop because the bullets are removed from the list:
# main loop
while running:
# [...]
for enemy in enemy_list:
enemy.move()
# [...]
# collision
for enemy in enemy_list:
for bullet in bullets: # Use a for-loop to iterate through all the bullets in the list.
collision = iscollision(enemy.x, enemy.y, bullet[0], bullet[1])
if collision: # Test if a single bullet collides with the enemy inside the loop.
score += 1
print(score)
bullets.remove(bullet) # Remove the bullet from the list when it collides with the enemy.
enemy.x = random.randint(0, 476) # if collision takes place, alien respawns
enemy.y = random.randint(0, 30)
# [...]
for enemy in enemy_list:
enemy.draw()
Complete code:
import pygame
import random
import math
# for initialising pygame (req for every pygame app)
pygame.init()
# making the basic window (dimensions must be written inside a tuple )
screen = pygame.display.set_mode((500, 500))
# background
background = pygame.image.load('C:/Users/aryan/Downloads/background.jpg')
# load and set the logo
logo = pygame.image.load('C:/Users/aryan/Downloads/bp.png') # directory of logo
pygame.display.set_icon(logo)
pygame.display.set_caption("space wars") # program name
# define a variable to control the main loop
running = True
# player
playerimg = pygame.image.load('C:/Users/aryan/Downloads/spaceship.png')
playerX = 218 # x and y coordinates of image
playerY = 350
playerxchange = 0 # this will be the change in movement in x direction of our image
playerychange = 0 # this will be the change in movement in y direction of our image
def player(x, y):
screen.blit(playerimg, (x, y)) # blit draws our image on the surface(basically the background)
# syntax for blit(imagename, (xcoordinate,ycoordinate))
class Enemy:
def __init__(self):
self.x = random.randint(0, 476)
self.y = 20
self.moveX = 0.2
self.moveY = 40
def move(self):
self.x += self.moveX
if self.y >= 476:
self.y = 476
self.moveY = 0
self.moveX = 0
if self.x <= 0:
self.moveX = 0.1
self.y += self.moveY
elif self.x >= 465:
self.moveX = -0.1
self.y += self.moveY
def draw(self):
screen.blit(enemyimg, (self.x, self.y))
# enemy
enemyimg = pygame.image.load('C:/Users/aryan/Downloads/enemy.png')
enemy_list = []
for i in range(5):
new_enemy = Enemy()
enemy_list.append(new_enemy)
# game over
overimg = pygame.image.load('C:/Users/aryan/Downloads/gameover.png')
# bullet
bulletimg = pygame.image.load('C:/Users/aryan/Downloads/bullet.png')
bulletX = 0
bulletY = 350
bulletxchange = 0
bulletychange = 1
bullet_state = "ready" # "ready" you cant see bullet on screen
# "fire" you can see bullet firing
bullets = [] # bullets is a list that contains the coordinates of every bullet
score = 0
font30 = pygame.font.SysFont(None, 30)
def firebullet(x, y):
global bullet_state
bullet_state = "ready"
bullets.append([x + 12, y + 6]) # Creating a new bullet
def iscollision(enemyX, enemyY, bulletX, bulletY):
distance = math.sqrt(math.pow(enemyX-bulletX, 2)+ math.pow(enemyY-bulletY,2)) # distance formula
if distance <= 20:
return True
else:
return False
def TextScore(game):
text2 = font30.render("Your Score is: " + str(game), True, (37, 97, 188))
screen.blit(text2, (10, 45))
# main loop
while running:
screen.fill((120, 120, 120)) # in order (r, g, b) . (0, 0, 0) is black (255, 0, 0) is red...
screen.blit(background, (0, 0))
# event handling, gets all event from the event queue
for event in pygame.event.get():
# only do something if the event is of type QUIT
if event.type == pygame.QUIT:
# change the value to False, to exit the main loop
running = False
# checking keystroke
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
playerxchange += 0.3 # change in movement will be 0.2 towards the right
if event.key == pygame.K_LEFT:
playerxchange -= 0.3 # change in movement will be 0.2 towards the right
if event.key == pygame.K_UP:
playerychange -= 0.3
if event.key == pygame.K_DOWN:
playerychange += 0.3
if event.key == pygame.K_SPACE:
bullet_state = "fire"
firebullet(playerX, playerY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_DOWN or event.key == pygame.K_UP:
playerxchange = 0
playerychange = 0
playerY += playerychange
playerX += playerxchange # the value of playerx changes by +- 0.1 depending on keystroke
if playerX <= -64: # this teleports the spaceship from left end to right end
playerX = 564
elif playerX >= 564: # this teleports spaceship from right end to left
playerX = -64
if playerY >= 436: # this prevents spaceship from leaving vertically
playerY = 436
if playerY <= 0:
playerY = 0
for enemy in enemy_list:
enemy.move()
# bullet movement
if bullet_state == "fire":
firebullet(playerX, playerY)
for bullet in bullets:
screen.blit(bulletimg, (bullet[0], bullet[1])) # Print a bullet
bullet[0] -= bulletxchange # Updates its position
bullet[1] -= bulletychange
if bullet[1] < 0:
bullets.remove(bullet)
# collision
for enemy in enemy_list:
for bullet in bullets: # Use a for-loop to iterate through all the bullets in the list.
collision = iscollision(enemy.x, enemy.y, bullet[0], bullet[1])
if collision: # Test if a single bullet collides with the enemy inside the loop.
score += 1
print(score)
bullets.remove(bullet) # Remove the bullet from the list when it collides with the enemy.
enemy.x = random.randint(0, 476) # if collision takes place, alien respawns
enemy.y = random.randint(0, 30)
TextScore(score)
player(playerX, playerY) # player method is called AFTER screen.fill otherwise the screen will fill after image has been blitted
for enemy in enemy_list:
enemy.draw()
pygame.display.update() # necessary for events to keep updating
If you want to spawn non-overlapping enemies, see the answers to the following questions:
Is there a better way to spawn enemy locations?
Random non overlapping circles(with circle number controlled) in python and pygame

Why does my game made with Pygame suddenly lag for a few seconds? [duplicate]

This question already has answers here:
Lag when win.blit() background pygame
(2 answers)
Closed 2 years ago.
I made a little space invaders game with pygame, I noticed that the game lags for a few seconds periodically. I do not know what the problem is. I am a beginner.
Can you tell me why this happens? Is there any fix to this?
Also, why does everything slow down once you add the background image in the main game loop?
import pygame
from pygame import mixer
import random
import math
# Starting pygame
pygame.init()
# window
screen = pygame.display.set_mode((800, 600))
background = pygame.image.load('background.png')
# title and icon
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('icon.png')
pygame.display.set_icon(icon)
# background
mixer.music.load('galaxy.ogg')
mixer.music.play(-1)
# player
playerimg = pygame.image.load('rocket.png')
playerX = 370
playerY = 480
playerX_change = 0
# Enemy
enemy_img = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 1
for i in range(num_of_enemies):
enemy_img.append(pygame.image.load('Enemy.png'))
enemyX.append(random.randint(0, 735))
enemyY.append(random.randint(50, 300))
enemyX_change.append(4)
enemyY_change.append(40)
# Bullet
bulletimg = pygame.image.load('bullet.png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 10
bullet_state = "ready"
# ready = you can't see the bullet on the screen
# fire = the bullet is currently moving
# score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
textY = 10
# gameover text
over_font = pygame.font.Font('freesansbold.ttf', 70)
def show_score(x, y):
score = font.render("Score: " + str(score_value), True, (255, 255, 255))
screen.blit(score, (x, y))
def game_over_text():
over_text = over_font.render("GAME OVER!", True, (255, 0, 0))
screen.blit(over_text, (200, 250))
def player(x, y):
screen.blit(playerimg, (x, y))
def enemy(x, y, i):
screen.blit(enemy_img[i], (x, y))
def fire_bullet(x, y):
global bullet_state
bullet_state = "fire"
screen.blit(bulletimg, (x + 25, y + 10))
def iscollision(enemyX, enemyY, bulletX, bulletY):
distance = math.sqrt(math.pow(enemyX - bulletX, 2) + math.pow(enemyY - bulletY, 2))
if distance < 30:
return True
else:
return False
# gameloop
running = True
while running:
# RGB screen
screen.fill((0, 0, 0))
screen.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Check keystroke left or right
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -10
if event.key == pygame.K_RIGHT:
playerX_change = 10
if event.key == pygame.K_SPACE:
if bullet_state is "ready":
bullet_sound = mixer.Sound('shoot.wav')
bullet_sound.play()
# gets the current x cor of the player
bulletX = playerX
fire_bullet(bulletX, bulletY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
playerX_change = 0
if event.key == pygame.K_RIGHT:
playerX_change = 0
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
for i in range(num_of_enemies):
# game over
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
break
enemyX[i] += enemyX_change[i]
if enemyX[i] <= 0:
enemyX_change[i] *= -1
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736:
enemyX_change[i] *= -1
enemyY[i] += enemyY_change[i]
# collision
collision = iscollision(enemyX[i], enemyY[i], bulletX, bulletY)
if collision:
explosion_sound = mixer.Sound('explosion.wav')
explosion_sound.play()
bulletY = 480
bullet_state = "ready"
score_value += 1
# print(score)
enemyX[i] = random.randint(0, 735)
enemyY[i] = random.randint(50, 300)
enemy(enemyX[i], enemyY[i], i)
# if enemyY <= 50:
# enemyY_change *= -1
# elif enemyY >= 300:
# enemyY_change *= -1
if bulletY <= 0:
bulletY = 480
bullet_state = "ready"
if bullet_state is "fire":
fire_bullet(bulletX, bulletY)
bulletY -= bulletY_change
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
Call convert() on the background image. That ensures that the image has the same pixel format as the display Surface and will help blit to operate with optimal performance:
screen = pygame.display.set_mode((800, 600))
background = pygame.image.load('background.png').convert()
Note, if the surface has a different format than the display, then blit has to convert the format on the fly in every frame.

Categories