I am trying to add multiple enemies to my game, but even though I have put the code to do so in, no more than one enemy is showing. I have tried to debug to find any errors, but I can't find any.
import random
import math
import pygame
# initialise pygame
pygame.init()
# player 1
playerimage = pygame.image.load("Main Player.png")
playerX = 365
playerY = 700
playerX_change = 0
# laser
# ready - bullet not on screen
# fire - bullet is shown on screen and is moving
laserimage = pygame.image.load("laser.png")
laserX = 0
laserY = 700
laserY_change = 10
laser_currentstate = "ready"
# alien player / random movement = random.randint()
alienimage = []
alienX = []
alienY = []
alienX_change = []
alienY_change = []
amount_aliens = 3
I've attempted to make multiple aliens, but the code doesn't work either.
for i in range(amount_aliens):
alienimage.append(pygame.image.load('alien.png'))
alienX.append(random.randint(0, 735))
alienY.append(random.randint(50, 200))
alienX_change.append(4)
alienY_change.append(7)
score = 0
# define player
def main_player(x, y):
screen.blit(playerimage, (x, y))
# define laster
def fire_laser(x, y):
global laser_currentstate
laser_currentstate = "fire"
screen.blit(laserimage, (x + 16, y + 10))
# define alien
def alien(x, y, i):
screen.blit(alienimage[i], (x, y))
# collision detection
def hascollision(alienX, alienY, laserX, laserY):
distance = math.sqrt((math.pow(alienX - laserX, 2)) + (math.pow(alienY - laserY, 2)))
if distance < 27:
return True
else:
return False
# background
background = pygame.image.load('stars.png')
# display and screen title/icon
(width, height) = (800, 800)
screen = pygame.display.set_mode((width, height))
flip = pygame.display.flip()
pygame.display.set_caption("space fighters")
pygame.event.get()
icon = pygame.image.load('logo.png')
pygame.display.set_icon(icon)
from sys import exit
# loop of functions
executed = True
while executed:
screen.fill((63, 62, 63))
# image background
screen.blit(background, (0, 0))
for event in pygame.event.get():
# if key pressed, check which input, right or left?
if event.type == pygame.KEYDOWN:
print("key pressed")
if event.key == pygame.K_a:
playerX_change = -6
if event.key == pygame.K_s:
playerX_change = 6
if event.type == pygame.KEYUP:
if event.key == pygame.K_a or event.key == pygame.K_s:
playerX_change = 0
if event.key == pygame.K_SPACE:
if laser_currentstate is "ready":
laserX = playerX
fire_laser(laserX, laserY)
# bounrary algorithm, prevents player moving out/enemy.
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
# boundry algorithm, make sure alien doesn't go out of bountry
for i in range(amount_aliens):
alienX[i] += alienX_change[i]
if alienX[i] <= 0:
alienX_change[i] = 4
alienY[i] += alienY_change[i]
elif alienX[i] >= 736:
alienX_change[i] = -4
alienY[i] += alienY_change[i]
# collision
collision = hascollision(alienX[i], alienY[i], laserX, laserY)
if collision:
laserY = 650
laser_currentstate = "ready"
score += 5
print(score)
alienX[i] = random.randint(0, 735)
alienY[i] = random.randint(50, 200)
alien(alienX[i], alienY[i], i)
# movement of laser shot
if laserY <= 0:
laserY = 650
laser_currentstate = "ready"
if laser_currentstate is "fire":
fire_laser(laserX, laserY)
laserY -= laserY_change
# updates screen to show screen
main_player(playerX, playerY)
pygame.display.update()
pygame.quit()
I also can't get the game to quit by pressing the button.
The problemis that you only call
alien(alienX[i], alienY[i], i)
Once, where you should call it once for every one of your aliens (so in your for loop)
It is a matter of Indentation.
The collision detection and alien(alienX[i], alienY[i], i) have to be done in the for loop, which iterates all the aliens:
executed = True
while executed:
# [...]
# boundry algorithm, make sure alien doesn't go out of bountry
for i in range(amount_aliens):
alienX[i] += alienX_change[i]
if alienX[i] <= 0:
alienX_change[i] = 4
alienY[i] += alienY_change[i]
elif alienX[i] >= 736:
alienX_change[i] = -4
alienY[i] += alienY_change[i]
# INDENTATION !!!
# collision
collision = hascollision(alienX[i], alienY[i], laserX, laserY)
if collision:
laserY = 650
laser_currentstate = "ready"
score += 5
print(score)
alienX[i] = random.randint(0, 735)
alienY[i] = random.randint(50, 200)
alien(alienX[i], alienY[i], i)
Related
I'm a beginner and have needed a lot of help to get this far. I'm trying to add more enemies when my score reaches certain values such as 10, 20, etc. Ive tried something along the lines of if score_value >= 10: num_of_enemies = num_of_enemies + 10 but have been failing to produce results. I feel like it should be simple but i am missing how to add values to this list.
import pygame
import random
import math
from pygame import mixer
# initialize game
pygame.init()
# create screen, set height and weight (())
screen = pygame.display.set_mode((800, 600))
# Background
background = pygame.image.load('background1.png')
pygame.display.set_icon(background)
# Background sound
mixer.music.load('troubador.wav')
mixer.music.play(-1)
# Title and Icon
pygame.display.set_caption("Beasts of Cthulu")
icon = pygame.image.load('knight.png')
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('wizard.png')
playerX = 370
playerY = 500
playerX_change = 0
# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 5
max_enemies = 100
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('cthulhu.png'))
enemyX.append(random.randint(0, 735))
enemyY.append(random.randint(10, 150))
enemyX_change.append(3)
enemyY_change.append(40)
# Fireball
# ready - you cannot see fireball on screen
# fire - fireball is currently moving
fireballImg = pygame.image.load('fireball.png')
fireballX = 0
fireballY = 370
fireballX_change = 0
fireballY_change = 8
fireball_state = "ready"
# Score
score_value = 0
previous_score = score_value
font = pygame.font.Font('Enchanted_Land.otf', 32)
textX = 10
textY = 10
# Game over text
over_font = pygame.font.Font('Enchanted_Land.otf', 64)
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, 255, 255))
screen.blit(over_text, (250, 200))
def player(x, y):
screen.blit(playerImg, (x, y))
def enemy(x, y, i):
screen.blit(enemyImg[i], (x, y))
def fire_fireball(x, y):
global fireball_state
fireball_state = "fire"
screen.blit(fireballImg, (x + 16, y + 10))
def isCollision(enemyX, enemyY, fireballX, fireballY):
distance = math.sqrt(math.pow(enemyX - fireballX, 2) + (math.pow(enemyY - fireballY, 2)))
if distance < 27:
return True
else:
return False
# Game Loop
running = True
while running:
screen.fill((0, 0, 0))
# Background image
screen.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Keyboard actions
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -4
if event.key == pygame.K_RIGHT:
playerX_change = 4
if event.key == pygame.K_SPACE:
if fireball_state == "ready":
fireball_Sound = mixer.Sound('fireball-1.wav')
fireball_Sound.play()
fireballX = playerX
fire_fireball(fireballX, fireballY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
# checking for boundaries
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
# Fireball movement
if fireballY <= 0:
fireballY = 480
fireball_state = "ready"
if fireball_state == "fire":
fire_fireball(fireballX, fireballY)
fireballY -= fireballY_change
# Enemy movement
enemyX += enemyX_change
for i in range(num_of_enemies):
# Game Over
if enemyY[1] > 370:
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] = 3
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736:
enemyX_change[i] = -3
enemyY[i] += enemyY_change[i]
# Collision
collision = isCollision(enemyX[i], enemyY[i], fireballX, fireballY)
if collision:
explosion_Sound = mixer.Sound('fireball-explosion.wav')
explosion_Sound.play()
fireballY = 480
fireball_state = "ready"
score_value += 1
enemyX[i] = random.randint(0, 735)
enemyY[i] = random.randint(10, 150)
enemy(enemyX[i], enemyY[i], i)
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
That's a lot of code and we can't run it, because we don't have the assets. What you need is a threshold, which increases once it was reached.
You can implement it like this:
import random
threshold = 10
score = 0
while score < 1000:
score += random.randint(1,4) # wherever points come from
print (f"Score {score}")
if score > threshold:
print (f"You have more than {threshold}. Adding enemies ...")
threshold += 10
See how the score can increase but enemies will only be added every 10 points and it needn't hit the value exactly.
The idea of #ThomasWeller is nice (+1). However, you will have difficulty adding it to your code.
Write a function that adds an enemy and use the function in the loop that creates the initial enemies:
enemySurf = pygame.image.load('cthulhu.png')
def addNewEnemy():
enemyImg.append(enemySurf)
enemyX.append(random.randint(0, 735))
enemyY.append(random.randint(10, 150))
enemyX_change.append(3)
enemyY_change.append(40)
for i in range(num_of_enemies):
addNewEnemy()
Use the idea of #ThomasWeller and add a new enemy when the scooter reaches a certain threshold:
threshold = 10
running = True
while running:
if score_value >= threshold:
addNewEnemy()
num_of_enemies += 1
threshold += 10
print(len(enemyX))
# [...]
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
The community reviewed whether to reopen this question 7 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I'm currently learning Pygame and got stuck on this error:
Class 'int' does not define 'getitem', so the '[]' operator cannot
be used on its instances
It happens on lines 125, 128, 134 and 144.
import pygame
import random
import math
# Initialize pygame module
pygame.init()
# Create the screen
screen = pygame.display.set_mode((800, 600))
# Background
background = pygame.image.load('back.png')
# Caption and Icon
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('ufo (1).png')
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('spaceship.png')
playerX = 370
playerY = 480
playerX_change = 0
speed = 1
minPosition = 0
maxPosition = 736
# Enemy
# corrected a bug where line31 makes enem spawns after 736 pixels which is bigger
# than enemyMaxPosition, causing it to fall off screen.
enemyImg = [] # This means an empty list
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
enemySpeed = []
enemyMinPosition = []
enemyMaxPosition = []
num_of_enemies = 6
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('enemy.png'))
enemyX.append(random.randint(0, 735))
enemyY.append(random.randint(50, 150))
enemyX_change.append(0.5)
enemyY_change.append(40)
enemySpeed.append(0.5)
enemyMinPosition.append(0)
enemyMaxPosition.append(736)
# Bullet
# bullet_isFiring = False // Can't see bullet on screen
# bullet_isFiring = True // Can see bullet on screen
bulletImg = pygame.image.load('bullet.png')
bulletX = 0
bulletY = 480
bulletY_change = 10
bullet_isFiring = False
# Score
score = 0
def player(x, y):
screen.blit(playerImg, (x, y))
def enemy(x, y, i):
screen.blit(enemyImg[i], (x, y))
# global keyword access generic variable bullet_isFiring
def fire_bullet(x, y):
global bullet_isFiring
bullet_isFiring = True
screen.blit(bulletImg, (x + 16, y + 10))
# Define whether a collision between two objects has ocurred or not
# object1 // enemy
# object2 // bullet
def isCollision(object1_X, object1_Y, object2_X, object2_Y):
distance = math.sqrt(math.pow((object2_X - object1_X), 2) + math.pow((object2_Y - object1_Y), 2))
if distance < 27:
return True
# Game Loop
running = True
while running:
screen.fill((0, 0, 0))
screen.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed check whether its right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -speed
if event.key == pygame.K_RIGHT:
playerX_change = speed
if event.key == pygame.K_SPACE:
if bullet_isFiring is False:
bulletX = playerX
fire_bullet(bulletX, bulletY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
playerX += playerX_change
enemyX += enemyX_change
# Player Movement
if playerX <= minPosition:
playerX = minPosition
elif playerX >= maxPosition:
playerX = maxPosition
# Enemy Movement
for i in range(num_of_enemies):
if enemyX[i] <= enemyMinPosition[i]:
enemyX_change[i] = enemySpeed[i]
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= enemyMaxPosition[i]:
enemyX_change[i] = -enemySpeed[i]
enemyY[i] += enemyY_change[i]
# Collision
collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
if collision:
bulletY = 480
bullet_isFiring = False
score += 50
print(score)
enemyX = random.randint(0, 735)
enemyY = random.randint(0, 150)
# Enemy Spawn
enemy(enemyX[i], enemyY[i], i)
# Bullet Movement
if bulletY <= 0:
bullet_isFiring = False
bulletY = 480
if bullet_isFiring is True:
bulletY -= bulletY_change
fire_bullet(bulletX, bulletY)
player(playerX, playerY)
pygame.display.update()
enemyX and enemyY are lists of coordinates. Why you generate a new random position for an enemy you need to set the corresponding coordinate in the list:
for i in range(num_of_enemies):
# [...]
collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
if collision:
# [...]
# REMOVE
# enemyX = random.randint(0, 735)
# enemyY = random.randint(0, 150)
# ADD
enemyX[i] = random.randint(0, 735)
enemyY[i] = random.randint(0, 150)
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
i am new to all this and im trying to make a shoot 'em up game. after i try to run the code, i encounter an error TypeError: 'int' object is not subscriptable at:
line 269:
collision = isCollision(enemyX[i],enemyY[i],knifeX,knifeY)
line 118:
distance = math.sqrt((math.pow(enemyX[i] - knifeX,2)) + (math.pow(enemyY[i] - knifeY,2)))
not just here but pretty much every where in the loop if i put an 'i' on it
import pygame
from pygame import mixer
mixer.init()
import random
import math
#Define some colors
BLACK = (0,0,0)
WHITE = (255,255,255)
#intialize the pygame
pygame.init()
#create the screen
screen = pygame.display.set_mode((700,583))
#Caption and icon
pygame.display.set_caption("Yoshi & the rise of mushroom ")
icon = pygame.image.load("Yoshi_icon.png")
pygame.display.set_icon(icon)
#Player
playerImg = pygame.image.load("YoshiMario.png")
playerX = 370
playerY = 480
playerX_change = 0
playerY_change = 0
#Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 10
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('msh1.png'))
enemyImg.append(pygame.image.load('msh2.png'))
enemyX.append(random.randint(0,583))
enemyY.append(random.randint(50,150))
enemyX_change.append(2)
enemyY_change.append(20)
#Knife
# ready - you cant see the knife on the screen
# fire - the knife is currently moving
knifeImg = pygame.image.load('diamondsword3.png')
knifeX = 0
knifeY = 480
knifeX_change = 0
knifeY_change = 10
knife_state = "ready"
#Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf',28)
testX = 10
testY = 10
#Game Over Text
over_font = pygame.font.Font('freesansbold.ttf',64)
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,255,255))
screen.blit(over_text, (150, 250))
def player(x,y):
screen.blit(playerImg, (x, y))
def enemy(x,y,i):
screen.blit(enemyImg[i], (x, y))
def fire_knife( x, y ):
""" Start a knife flying upwards from the player """
global knife_state, knifeX, knifeY
knifeX = x + 16
knifeY = y + 10
knife_state = "fire"
def knife_hits( enemyX, enemyY ):
""" Return True if the knife hits the enemy at the given (x,y).
If so, prepare the knife for firing again. """
global knife_state, knifeX, knifeY
collision_result = False
if ( knife_state == "fire" and isCollision( enemyX[i], enemyY[i], knifeX, knifeY ) ):
knife_state = "ready"
collision_result = True
return collision_result
def draw_knife( screen ):
""" If the knife is flying, draw it to the screen """
global knife_state, knifeImg, knifeX, knifeY
if ( knife_state == "fire" ):
screen.blit( knifeImg, ( knifeX, knifeY ) )
def update_knife():
""" Make any knife fly up the screen, resetting at the top """
global knife_state, knifeX, knifeY, knifeY_change
# if the knife is already flying, move it
if ( knife_state == "fire" ):
knifeY -= knifeY_change
if ( knifeY <= 0 ):
knife_state = "ready" # went off-screen
def isCollision(enemyX,enemyY,knifeX,knifeY):
distance = math.sqrt((math.pow(enemyX[i] - knifeX,2)) + (math.pow(enemyY[i] - knifeY,2)))
if distance < 27:
return True
else:
return False
#used to manage how fast the screen updates
clock = pygame.time.Clock()
font = pygame.font.Font(None,28)
frame_count = 0
frame_rate = 60
start_time = 90
#game loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#if keystroke is pressed check whether its right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -2
if event.key == pygame.K_RIGHT:
playerX_change = 2
if event.key == pygame.K_UP:
playerY_change = -2
if event.key == pygame.K_DOWN:
playerY_change = 2
if event.key == pygame.K_SPACE:
if knife_state is "ready":
knife_Sound = mixer.Sound("knife_hitwall1.wav")
knife_Sound.play()
# get the current x coordinate of yoshi
knifeX = playerX
fire_knife(playerX,playerY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
playerY_change = 0
## -- Timer going up --
#Calculate total seconds
total_seconds = frame_count // frame_rate
#divide by 60 to get total minures
minutes = total_seconds // 60
#use modulus (remainder) to get seconds
seconds = total_seconds % 60
#use python string formatting to format in leading zeros
output_string = "Time : {0:02}:{1:02}".format(minutes, seconds)
# Blit to the screen
text = font.render(output_string, True, (255,255,255))
screen.blit(text, [10,40])
# --- Timer going down ---
# --- Timer going up ---
# Calculate total seconds
total_seconds = start_time - (frame_count // frame_rate)
if total_seconds < 0:
total_seconds = 0
# Divide by 60 to get total minutes
minutes = total_seconds // 60
# Use modulus (remainder) to get seconds
seconds = total_seconds % 60
# Use python string formatting to format in leading zeros
output_string = "Time left: {0:02}:{1:02}".format(minutes, seconds)
# Blit to the screen
text = font.render(output_string, True,(255,255,255))
screen.blit(text, [10,70])
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
frame_count += 1
# Limit frames per second
clock.tick(frame_rate)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# RGB - Red, Green, Blue
screen.fill((0, 255, 0))
#add a wallpaper
bgimage=pygame.image.load("Background.png")
screen.blit(bgimage, (0, 0))
# 5 = 5 + -0.1 ->5 = 5 - 0.1
# 5 = 5 + 0.1
# checking for boundaries of yoshi/mushroom so it doesnt go out of bounds
playerX += playerX_change
if playerX < 0:
playerX = 0
elif playerX > 645:
playerX = 645
playerY += playerY_change
if playerY < 0:
playerY = 0
elif playerY > 500:
playerY = 500
# enemy movement
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] = 2
enemyY[i] += enemyY_change[i]
elif enemyX[i] > 645:
enemyX_change[i] = -2
enemyY[i] += enemyY_change[i]
update_knife() # move the flying knife (if any)
if ( knife_hits( enemyX[i], enemyY[i] ) ):
score_value += 1
print(score_value)
enemyX[i] = random.randint(0,735)
enemyY[i] = random.randint(50,150)
else:
draw_knife( screen ) # paint the flying knife (if any)
player(playerX,playerY)
enemy(enemyX[i],enemyY[i],i)
pygame.display.update()
# collision
collision = isCollision(enemyX[i],enemyY[i],knifeX,knifeY)
if collision:
pop_Sound = mixer.Sound('pop.wav')
pop_Sound.play()
knifeY = 480
knife_state = "ready"
score_value += 1
enemyX[i] = random.randint(0,735)
enemyY[i] = random.randint(50,150)
enemy(enemyX[i],enemyY[i],i)
# knife movement
if knifeY <= 0:
knifeY = 480
knife_state = "ready"
if knife_state == "fire":
fire_knife(knifeX,knifeY)
knifeY -= knifeY_change
playerX += playerX_change
playerY += playerY_change
player(playerX,playerY)
show_score(testX,testY)
pygame.display.update()
You do the subscription when you call the function isCollision:
if ( knife_state == "fire" and isCollision( enemyX[i], enemyY[i], knifeX, knifeY ) ):
Hence you must remove the subscription in the function:
distance = math.sqrt((math.pow(enemyX[i] - knifeX,2)) + (math.pow(enemyY[i] - knifeY,2)))
def isCollision(enemyX,enemyY,knifeX,knifeY):
distance = math.sqrt((math.pow(enemyX - knifeX,2)) + (math.pow(enemyY - knifeY,2)))
if distance < 27:
return True
else:
return False
You call isCollision() with enemyX[i], but then in isCollision, you try to access enemyX[i]. So you're trying to do enemyX[i][i]. But since enemyX[i] is an integer, trying to get a subscript of it, [i], is invalid so that's why you get that error.
You're already sending the specific number with e.g. enemyX[i] when you call isCollision(enemyX[i], ...). Once in that function, you can just use the passed argument (which you also happen to call enemyX - it's just a different one from the caller's enemyX) by itself, e.g. math.pow(enemyX -.... I recommend reconsidering those variable names.
I am quite new to python just trying to learn it. I've followed a tutorial on how to make this game and added my own stuff but I cant seem to add lives. I've tried all I know (not a lot). Anyway, all the tutorials I have watched have not worked either and I have been pulling my hair out over it for like 2 days now, so if anyone can help it would be very appreciated.
import math
import random
import pygame
from pygame import mixer
# Intialize the pygame
pygame.init( )
# create the screen
screen = pygame.display.set_mode((800, 600))
# Background
background = pygame.image.load('editor.jpg')
opensound = mixer.Sound("ftw.wav")
opensound.play( )
# Sound
mixer.music.load("bg noise.wav")
mixer.music.play(-1)
# Caption and Icon
pygame.display.set_caption("Virus Invader")
icon = pygame.image.load('virus.png')
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('people.png')
playerX = 370
playerY = 480
playerX_change = 0
# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('virus.png'))
enemyX.append(random.randint(0, 736))
enemyY.append(random.randint(50, 150))
enemyX_change.append(1)
enemyY_change.append(40)
# Bullet
# Ready - You can't see the bullet on the screen
# Fire - The bullet is currently moving
bulletImg = pygame.image.load('ligature.png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 2
bullet_state = "ready"
# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
testY = 10
# Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)
def Game_start_text():
over_text = over_font.render("Let the games begin!", True, (64, 64, 64))
screen.blit(over_text, (200, 250))
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, 255, 255))
screen.blit(over_text, (200, 250))
def player(x, y):
screen.blit(playerImg, (x, y))
def enemy(x, y, i):
screen.blit(enemyImg[i], (x, y))
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:
# RGB = Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
for event in pygame.event.get( ):
if event.type == pygame.QUIT:
running = False
# if keystroke is pressed check if its right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -2
if event.key == pygame.K_RIGHT:
playerX_change = 2
if event.key == pygame.K_SPACE:
if bullet_state is "ready":
bulletSound = mixer.Sound("stab.wav")
bulletSound.play( )
# Get the current x cordinate of the charctar
bulletX = playerX
fire_bullet(bulletX, bulletY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
# 5 = 5 + -0.1 -> 5 = 5 - 0.1
# 5 = 5 + 0.1
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
# Enemy Movement
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:
explosionSound = mixer.Sound("street fighter die.wav")
explosionSound.play( )
bulletY = 480
bullet_state = "ready"
score_value += 1
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 is "fire":
fire_bullet(bulletX, bulletY)
bulletY -= bulletY_change
player(playerX, playerY)
show_score(textX, testY)
pygame.display.update( )
The reason adding this to your code is so difficult is because there's a whole bunch of extra code that's in the way.
When this happens, take a step back, and try to write a skeleton to do just what you need. When working on a huge system, say tracking down a complex bug, normally you would comment out sections of the code to pair the problem-space back to something manageable. Your code is pretty small, so maybe you can just ignore a lot of it.
In any event, take a backup of your code, then start adding the changes bit by bit, testing as you go.
First add a life-counter:
# Player
playerLives = 3 # <<-- HERE
playerImg = pygame.image.load('people.png')
playerX = 370
playerY = 480
playerX_change = 0
Then some way to test life-loss:
# if keystroke is pressed check if its right or left
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -2
elif event.key == pygame.K_RIGHT:
playerX_change = 2
elif event.key == pygame.K_d: # TEST CODE - Die on 'd' <<-- HERE
print( "Player Dies" )
playerLives -= 1
Now test this? Did it print "Player Dies" when you press d?
So... what should happen when the lives is zero? Maybe the player can't move any more:
# Has the player run out of lives?
if ( playerLives <= 0 ):
game_over_text()
else:
# Player still alive, allow controls, draw player
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
player(playerX, playerY)
Add these next changes in, test them. Does pressing d three times print "Player Dies" every time, and result in the game_over_text() function being called?
Then change the show_score() function to also draw the lives left:
def show_score(x, y):
score = font.render("Score : " + str(score_value), True, (255, 255, 255))
screen.blit(score, (x, y))
# Write the Lives-left to the right of the score
lives = font.render("Lives : " + str(playerLives), True, (255, 255, 255))
screen.blit(lives, (x+200, y))
Test that. Does the on-screen score work? No? Make some small changes, test again, keep tweaking, keep fixing. If it all goes to hell-in-a-handcart you only need small changes to undo it.
Now that the losing-lives mechanism is working, find where it should actually take away lives, and add the changes in:
# Game Over
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
playerLives -= 1 # <<-- lose a life
#game_over_text( )
reset_enemy_positions() # <<-- move enemies back to top, TODO!
break
Of course if you leave your enemies below line 440, the lose-a-life condition is still true. Thus the player will continue to lose many lives per second, every frame update. The enemies need to move back to start-position (or some suchlike).
Anyway I hope this gives you a nudge in the right direction. Maybe it would help you to try to write something yourself from scratch. Even just opening a window. Then adding key handling. Then drawing something... Incrementally add to your knowledge, I think you'll learn much faster this way. There's a reason every programming book starts with "Hello World".