space invader pygame make enemy disappear when shot - python

I have a list with all my enemies and when the distance between the players bullet and the enemy is close enough, I can make a enemy disappear but its never the right one that was hit with the bullet, its always the enemy with the greatest x value(in my case the one at the end of the list) so my questions is how do I make the specific enemy disappear. here is my code for reference.
import pygame
import random
import math
# initalize pygame
pygame.init()
# creates game screen to display game
game_window = pygame.display.set_mode((800, 570))
# Title and icon for window
pygame.display.set_caption("Power of the Doctor")
icon = pygame.image.load('tardisShooter.png')
pygame.display.set_icon(icon)
# backgroun picture
background = pygame.image.load('SpaceTardissmall.png')
# player info
Playerimg = pygame.image.load('tardisShooter.png')
playerx = 370 # players x axis
playery = 470 # players y axis
playerx_change = 0 # adds constant change while added in loop
def player(x, y):
# blit draws image on screen: x axis y axis
game_window.blit(Playerimg, (x, y))
# enemy info
Enemyimg = []
enemyx = []
enemyy = []
enemyx_change = 1
enemyy_change = 0
num_enemies = 2
enemyspawnx = 50
enemyspawny = 200
for i in range(num_enemies):
Enemyimg.append(pygame.image.load('CybermanShooter.png'))
enemyx.append(enemyspawnx) # random x axis for enemy
enemyy.append(enemyspawny) # random y axis for enemy
enemyspawnx += 70
def enemy(x, y, i):
game_window.blit(Enemyimg[i], (x, y))
# bullet info
bulletimg = pygame.image.load('torpedo32.png')
bullety = playery
bulletx = playerx
bulletstate = "idle"
bullety_change = 5
def bullet(x, y):
global bulletstate
bulletstate = "FIRE"
game_window.blit(bulletimg, (x + 15.5, y - 25))
def collision(enemyx, enemyy, bulletx, bullety):
distance = math.sqrt((math.pow(bulletx - enemyx, 2)) + (math.pow(bullety - enemyy, 2)))
if distance < 27:
return True
else:
return False
rand = random.randint(0, num_enemies)
# timer info
bulletevent = pygame.USEREVENT
pygame.time.set_timer(bulletevent, 2000)
# get a rabdom number
# when the timer hits 2 secodsn spawsn bomb at the index of the random number that corresponds witht the enemy
# enemy bomb
bombimg = []
bombx = []
bomby = []
bomby_change = 1
bombstate = "idle"
num_bombs = 2
for i in range(num_bombs):
bombimg.append(pygame.image.load('bomb.png'))
bombx.append(enemyx[i])
bomby.append(enemyy[i])
def bomb(x, y, i):
global bombstate
bombstate = "fire"
game_window.blit(bombimg[i], (x + 15, y + 65))
# player hit detection
def enemyhit(bombx, bomby, x, y):
distance2 = math.sqrt((math.pow(bombx - x, 2)) + (math.pow(bomby - (y - 50), 2)))
if distance2 < 20:
return True
else:
return False
# loop to keep screen running
Running = True
while Running:
# background color
game_window.fill((0, 0, 0))
# background image in loop
game_window.blit(background, (0, 0))
# checks anything typed while game is running
for event in pygame.event.get():
# if they click x to quit close window
if event.type == pygame.QUIT:
Running = False
if event.type == bulletevent:
if bombstate == 'idle':
bomb(bombx[rand], bomby[rand], i)
bombx[rand] = enemyx[rand]
bomby[rand] = enemyy[rand]
# means key has been pressed(not released)
if event.type == pygame.KEYDOWN:
# escape key closes game
if event.key == pygame.K_ESCAPE:
Running = False
# right key moves player 5 spaces
if event.key == pygame.K_RIGHT:
playerx_change = 5
# left key moves players back 5 spaces
if event.key == pygame.K_LEFT:
playerx_change = -5
if event.key == pygame.K_SPACE:
bulletx = playerx
if bulletstate == "idle":
bullet(bulletx, bullety)
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT:
playerx_change = 0
playerx += playerx_change # constantly adds user input to player model
# player bounds
if playerx >= 740:
playerx = 740
if playerx <= 0:
playerx = 0
# player fucntion draws image
player(playerx, playery)
# loops through all the items in the lists named
for i in range(num_enemies):
# draws all enemies
enemy(enemyx[i], enemyy[i], i)
enemyx[i] += enemyx_change
if enemyx[i] >= 735:
enemyx_change = -.8
enemyy[i] += 10
if enemyx[i] <= 0:
enemyx_change = .8
enemyy[i] += 10
# is state is fire
if bulletstate == "FIRE":
# draws torpepd at coordinates
bullet(bulletx, bullety)
bullety -= bullety_change # decreases y axis moving bullet
if bullety <= 0: # if goes past border
bulletstate = "idle" # ittl switch back to idle
bullety = playery # moves bullet y back to player y
for i in range(num_enemies):
collided = collision(enemyx[i], enemyy[i], bulletx, bullety)
if collided == True:
bulletstate = 'idle'
bullety = playery
Enemyimg.remove(Enemyimg[i])
num_enemies -= 1
# when enemy fires
if bombstate == 'fire':
bomb(bombx[rand], bomby[rand], i)
bomby[rand] += bomby_change
if bomby[rand] > 570:
bombstate = 'idle'
bomby[rand] = enemyy[rand]
rand = random.randint(0, 1)
# enemy bullets hit player
enemyhits = enemyhit(bombx[rand], bomby[rand], playerx, playery)
if enemyhits == True:
playerx = 370
bombstate = 'idle'
bomby[rand] = enemyy[rand]
# updates the screen in loop
pygame.display.update()

A big problem with your code is having different lists for each attribute of your enemies.
You wrote this :
Enemyimg = []
enemyx = []
enemyy = []
Meaning that you always need to sync those three lists at all time to get coherent results. Which you are not doing, when you "remove" an enemy, you just remove the img from Enemyimg and not removing its coords in enemyy and enemyx.
While you could manage to make it work with three lists, you are just overcomplicating things. Let me show you what you may want to do to make your life way easier :)
I'm going to assume, you don't know about OOP (Object Oriented Programming) yet ? I Would be a great time to use it but it can be a little complexe if you are just starting out with programming.
So let's introduce python's dict !
What you really want to do is have one single list :
enemies = []
But how to store everything in one list you might wonder ?
Well, it will be a list of dict. A dict looks something like that :
example = {'image': pygame.image.load('CybermanShooter.png'), 'x': enemyspawnx, 'y': enemyspawny}
(Note that if you always use the same image, you don't need to put it here, you can just draw your image at the position)
Now if you do something like :
print(example['x'])
It will print your enemy's x value.
So, to sum up :
You want to have one single list : enemies = []
To add an enemy you will do :
enemies.append({'image': pygame.image.load('CybermanShooter.png'), 'x': enemyspawnx, 'y': enemyspawny})
To detect your collisions :
# Your collision function
def collision(enemy, bulletx, bullety):
distance = math.sqrt((math.pow(bulletx - enemy['x'], 2)) + (math.pow(bullety - enemy['y'], 2)))
if distance < 27:
return True
return False
# Your loop (in 2 steps: 1 - find enemies to remove, 2 - actually remove them)
enemies_to_remove = []
for enemy in enemies :
if collision(enemy, bulletx, bullety):
bulletstate = 'idle'
bullety = playery
enemies_to_remove.append(enemy)
num_enemies -= 1
for enemy in enemies_to_remove:
enemies.remove(enemy)
To draw your enemies:
# Your draw_enemy function (which you called `enemy(...)` for some reason)
def draw_enemy(enemy):
game_window.blit(enemy['image'], (enemy['x'], enemy['y']))
# Inside the main loop
for enemy in enemies:
draw_enemy(enemy)
To update the position of enemies:
# Make a move_enemy function
def move_enemy(enemy):
# put your moving logic here
# Inside the main loop:
for enemy in enemies:
move_enemy(enemy)
Do you get the principle ?
I've tried to stay as close as your original code as possible so it's not too many information to take in at once.
But technically you should apply the same principle for your bullets and to some extend to your player.

Related

what is Not BytesIO?

I'm kind of new to this site and pygame and I was hoping for a bit of help. So I made this space invader clone which is about 180 lines right, when I run it on Pycharm, it works fine. So I decided to try testing it out further and tried converting it into an .exe file which is where my troubles began. Every time I try running the .exe, this message appears
Traceback (most recent call last):
File "main.py", line 62, in <module>
font = pygame.font.Font('freesansbold.ttf',32)
TypeError: expected str, bytes or os.PathLike object, not BytesIO
I used freeCodeCamp.org's template and applied my own customs, here's a video incase you're interested: https://www.youtube.com/watch?v=FfWpgLFMI7w&t=7041s
Here's the code as well:
import math
import random
import pygame
from pygame import mixer
# Initialize the pygame
pygame.init()
# Create the screen
screen = pygame.display.set_mode((600, 400))
# Background Sound
mixer.music.load('Here he comes.mp3')
mixer.music.play(-1)
# Title and icon
pygame.display.set_caption("Defender of The Blue")
icon = pygame.image.load("Submarine of Vengeance.png")
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('Protagonist.png')
playerX = 250
playerY = 300
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('Antagonist.png'))
enemyX.append(random.randint(0, 500))
enemyY.append(random.randint(10, 100))
enemyX_change.append(0.1)
enemyY_change.append(20)
# Energy Blast
# Ready - You can't see the bullet state on the screen
# Fire - The blast is currently moving
energyblastImg = pygame.image.load('energy-blasts.png')
energyblastX = 0
energyblastY = 300
energyblastX_change = 0
energyblastY_change = 1
energyblast_state = "ready"
# score
score_value = 0
font = pygame.font.Font('freesansbold.ttf',32)
textX = 10
textY = 10
game_over_font = pygame.font.Font('freesansbold.ttf',50)
# Game Over Text
def show_score(x,y):
score = font.render("Score :" + str(score_value),True, (250,100,0))
screen.blit(score, (x, y))
def game_over_text():
game_over_text = game_over_font.render("GAME OVER",True, (250,0,0))
screen.blit(game_over_text, (150, 100))
def player(x, y):
screen.blit(playerImg, (x, y))
def enemy(x, y, i):
screen.blit(enemyImg[i], (x, y))
def fire_energyblast(x, y):
global energyblast_state
energyblast_state = "fire"
screen.blit(energyblastImg, (x + -1, y + 10))
def isCollison(enemyX, enemyY, energyblastX, energyblastY):
distance = math.sqrt((math.pow(enemyX - energyblastX, 2)) + (math.pow(enemyY - energyblastY, 2)))
if distance < 27:
return True
else:
return False
# Game Loop
running = True
while running:
# RGB = Red, Green, Blue
screen.fill((0, 0, 128))
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 = -1
if event.key == pygame.K_RIGHT:
playerX_change = 1
if event.key == pygame.K_SPACE:
if energyblast_state is "ready":
energyblast_sound = mixer.Sound('Energy Blast.mp3')
energyblast_sound.play()
# Get the current x coordinate of the submarine
energyblastX = playerX
fire_energyblast(energyblastX, energyblastY)
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
# Checking for boundaries of submarine so it doesn't go out of bounds
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 500:
playerX = 500
# enemy movement
for i in range(num_of_enemies):
# Game Over
if enemyY[i] > 272:
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] >= 500:
enemyX_change[i] = -1
enemyY[i] += enemyY_change[i]
# Collision
collison = isCollison(enemyX[i], enemyY[i], energyblastX, energyblastY)
if collison:
explosion_Sound = mixer.Sound('Explode.mp3')
explosion_Sound.play()
energyblastY = 300
energyblast_state = "ready"
score_value += 50
enemyX[i] = random.randint(0, 500)
enemyY[i] = random.randint(10, 100)
enemy(enemyX[i],enemyY[i], i)
# energy blast movement
if energyblastY <= 0:
energyblastY = 300
energyblast_state = "ready"
if energyblast_state is "fire":
fire_energyblast(energyblastX, energyblastY)
energyblastY -= energyblastY_change
player(playerX, playerY)
show_score(textX,textY)
pygame.display.update()
I'm not quite sure what BytesIO is. Is it like having something used twice and cancels out? How can I change this?
Are you certain that "freesansbold.ttf" is downloaded and in the same directory as the code youre trying to run, if this isnt possible for whatever reason you should be able to replace the
font = pygame.font.Font('freesansbold.ttf',32)
with
font = pygame.font.Font('(file path)freesansbold.ttf',32)

Weird spawn location of enemies pygame

This is the code of a survive the horde type game I'm working on. I have been facing an issue where the alien(s) sometimes (enemy in code) randomly spawns at the bottom of the surface, even though I have specified their spawn location to be randomized (within a certain part of the surface).
What has made them spawn at the bottom of the surface, where they cannot be touched by bullets?
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 = random.randint(0, 300)
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)
#class
# 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
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: # new edit
enemy.draw()
pygame.display.update() # necessary for events to keep updating
The problem is that you are generating number out out of bounds defined in the move method of Enemy class. Specifically, the problem is with x for which the upper bound seems to be 465, but you are generating numbers up to 476.
I obviously can't test this, but replace
enemy.x = random.randint(0, 476) # if collision takes place, alien respawns
enemy.y = random.randint(0, 30)
with
enemy.x = random.randint(1, 464) # if collision takes place, alien respawns
enemy.y = random.randint(1, 30)
and the problem should go away.
After looking through your code, it seems like after a collision you set the respawn y coordinate to be between 0 and 30, which I assume is what you want. Although, your original y coordinate for spawning aliens goes from 0 to 300; this may be your issue as to why they are spawning farther down the screen?

Pygame - alien invasion

I'm doing the alien invasion game and my bullets are just appearing and disappearing. I checked my code many times and I don't know why it is not traveling up the screen. can someone please help me. I don't want to try another method I want to learn by seeing the flaws in my code so I don't repeat the same mistakes again
import sys
import pygame
pygame.init()
# Setting up a window
screen = pygame.display.set_mode((1200, 800))
screen_rect = screen.get_rect()
# Caption
pygame.display.set_caption("space shooter".title())
# Setting up the icon
icon = pygame.image.load("undertake.png").convert_alpha()
pygame.display.set_icon(icon)
# Identifying a Background
bg = pygame.image.load("bg.png").convert_alpha()
# Adding the jet
jet = pygame.image.load("jet.png").convert_alpha()
jet_rect = jet.get_rect()
jet_rect.centerx = screen_rect.centerx
jet_rect.bottom = screen_rect.bottom
# Adding bullets to the left of the jet
bullet = pygame.image.load("pixel_laser_red.png").convert_alpha()
bullet_rect = bullet.get_rect()
bullet_state = "ready"
# Moving the jet
def move_jet(x):
jet_rect.centerx += x
# Firing the bullet
def fire_bullet(x, y):
bullet_state = "fire"
screen.blit(bullet, (x, y))
# Adding Boundaries
def boundaries():
if jet_rect.left >= 1200:
jet_rect.right = 0
elif jet_rect.right <= 0:
jet_rect.left = 1200
# Game Loop
while True:
screen.blit(bg, (0, 0))
screen.blit(jet, jet_rect)
# EVENTS
for event in pygame.event.get():
# Quitting
if event.type == pygame.QUIT:
sys.exit()
# KeyStrokes
pressed = pygame.key.get_pressed()
jet_xincrement = 0
if pressed[pygame.K_RIGHT]:
jet_xincrement += 3
if pressed[pygame.K_LEFT]:
jet_xincrement -= 3
if pressed[pygame.K_SPACE]:
bullet_x = jet_rect.centerx
bullet_y = jet_rect.top
fire_bullet(bullet_x - 28, bullet_y + 7)
if bullet_state == "fire" :
bullet_y -= 10
boundaries()
move_jet(jet_xincrement)
pygame.display.flip()
Actually the bullet is just drawn when space is pressed. You have to draw the bullet continuously in every frame.
The function fire_bullet just sets the state and the position of the bullet. The variables are in global namespace. Hence you have to use the global statement to set them:
bullet_state = "ready"
bullet_x = 0
bullet_y = 0
# Firing the bullet
def fire_bullet(x, y):
global bullet_state, bullet_x, bullet_y
bullet_state = "fire"
bullet_x = x
bullet_y = y
When space is pressed, then the fire_bullet is invoked. The arguments are the current position of the jet. When bullet_state is "fire", then the bullet has to be drawn in the main application loop:
while True:
# [...]
if pressed[pygame.K_SPACE]:
fire_bullet(jet_rect.centerx - 28, jet_rect.top + 7)
if bullet_state == "fire":
bullet_y -= 10
screen.blit(bullet, (bullet_x, bullet_y))
# [...]

Why can't I shoot with pygame?

I've been trying to make something cool with Python and Pygame for fun. I know a thing or two about Python in general but I'm quite a beginner with Pygame.
So the problem is: I have created a movable player and a moving enemy. I want to make the player shoot when I press the spacebar. I loaded a .png image, defined a function for shooting, and made so that the bullet keeps moving once shot. For some reason when I call the function, it just does nothing. It doesn't even give an error. I know I can shoot only one bullet with the current code and whatnot, but I would like to just get the current code working as a start.
"""
player and enemy functions are defined above and work well, I didn't include
them in this post for the sake of saving everyone's time
"""
# bullet
bullet_pic = pygame.image.load("bullet.png")
bullet_pic_reverse = pygame.image.load("bullet reverse.png")
bullet_state = "nope"
def shoot(pic, x, y):
global bullet_state
bullet_state = "jes"
screen.blit(pic, (x, y + 30))
player_dir = player_pic # direction of the player (left or right)
enemy_dir = enemy_pic # direction of the enemy
enemyX_change = 2.5
running = True
while running:
screen.blit(back, (0, 0)) # background picture
player(player_dir, playerX, playerY)
enemy(enemy_dir, enemyX, enemyY)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key == K_ESCAPE:
running = False
elif event.type == pygame.KEYDOWN:
# shooting
if event.key == K_SPACE:
if player_dir == player_pic:
bulletX = playerX + 100
bulletX_change = 20
bullet_dir = bullet_pic
else:
bulletX = playerX
bulletX_change = -20
bullet_dir = bullet_pic_reverse
shoot(bullet_dir, bulletX, playerY)
# player movement
hold = pygame.key.get_pressed()
if hold[K_LEFT] and playerX > 0:
playerX -= 7
player_dir = player_pic_reverse
if hold[K_RIGHT] and playerX < 1100:
playerX += 7
player_dir = player_pic
# enemy movement
enemyX += enemyX_change
if enemyX >= 1125:
enemyX_change = -2.5
enemy_dir = enemy_pic_reverse
elif enemyX <= 900:
enemyX_change = 2.5
enemy_dir = enemy_pic
# bullet constant movement
if bullet_state == "jes":
shoot(bullet_dir, bulletX, playerY)
bulletX += bulletX_change
I think the problem is with pygame.display.update(), you should put it always in the end of while running: loop. If you update display before calling shoot() background picture will be over bullet picture and you won't see it.
Another thing, you write K_ESCAPE instead of pygame.K_ESCAPE same with spacebar key. Does it work correctly for you? I didn't do anything with pygame for some time, maybe it's fine, but check it :)

How to make enemy follow player? Pygame

I know this has been asked before but I can't get it to work with my code.
I think this is where to have the enemy follow the player should be. I'm not sure how exactly to implement it.
I want the enemies to follow the player and when they run into the player the game ends. I also want this to be able to work with multiple enemies as well.
# player class
class player:
def __init__(self, x, y, w, h, xChange, yChange, vel):
self.x = x # plater x value
self.y = y # player y value
self.w = w # player w (width)
self.h = h # player h (height)
self.xChange = xChange # player xChange (to add to x value to move player horizontally)
self.yChange = yChange # player yChange (to aad to y value to move player vertically)
self.vel = vel # velocity of player (needed for collision)
# enemy class
class enemy:
def __init__(self, x, y, w, h):
self.x = x # enemy x value
self.y = y # enemy y value
self.w = w # enemy w (width) value
self.h = h # enemy h (height) value
# ----------------------------------------------------------------
"""enemy's x value (random value) (we pick 750 because the enemy width is 50 and
the screen width is 800. If we set the random value to 800, then the enemy has a
chance of spawning outside of the screen.)"""
enemyX = random.randint(0, 700)
"""enemy's y value (random value) (we pick 540 because the enemy height is 60
and the screen height is 600. If we set the random value to 600, the enemy has a
chance of spawning outside of the screen.)"""
enemyY = random.randint(0, 540) # enemy's y value
score = 0 # score set to 0. Will update in while loop.
rec = player(50, 50, 24, 32, 0, 0, 5) # the player's values (x, y, w, h, xChange, yChange, vel)
redRec = enemy(enemyX, enemyY, 24, 32) # the enemy's values (x, y, w, h)
# mainloop #
def mainloop():
global running, score, intro, sprite, next_zombie_time
while running:
"""keeps filling window with the background image"""
window.blit(background, (0, 0))
pygame.time.delay(25) # delay
for event in pygame.event.get(): # for every event in game
if event.type == pygame.QUIT: # if I exit the game
quitGame()
if event.type == pygame.KEYUP: # if any keys are let go
if event.key == pygame.K_a: # if key a
rec.xChange = 0 # set xChange to 0 (stop moving rec)
if event.key == pygame.K_d: # if key d
rec.xChange = 0 # set xChange to 0 (stop moving rec)
if event.key == pygame.K_w: # if key w
rec.yChange = 0 # set xChange to 0 (stop moving rec)
if event.key == pygame.K_s: # if key s
rec.yChange = 0 # set xChange to 0 (stop moving rec)
if event.type == pygame.KEYDOWN: # if any keys are pressed
if event.key == pygame.K_F4: # if key F4
pygame.quit() # set running to false
if event.key == pygame.K_a: # if key a
rec.xChange += -5 # add -5 to xChange (move rec left)
sprite = spriteLeft
if event.key == pygame.K_d: # if key a
rec.xChange += 5 # adds 5 to xChange (move rec right)
sprite = spriteRight
if event.key == pygame.K_w: # if key a
#adds -5 to yChange (moves rec up). Yes, this is supposed to say up.
rec.yChange += -5
sprite = spriteUp
if event.key == pygame.K_s: # if key a
# adds 5 to yChange (moves rec down). Yes, this is supposed to say down.
rec.yChange += 5
sprite = spriteDown
# pause key to pause game
if event.key == pygame.K_o: # if key o
running = False # set running to false
intro = False # intro set to False
pauseMenu() # pauseMenu is called
rec.x += rec.xChange # add rec's xChange to x (to do the moving)
rec.y += rec.yChange # adds rec's yChange to y (to do the moving)
# ----------------BOUNDARIES------------------------------
if rec.x <= 0: # if rec's x is less than or equal to 0 (if tries to escape screen)
rec.x = 0 # rec's x is set to 0 so it won't go off screen.
"""(we pick 750 because the player width is 50 and the screen width is 800.
If we set it to 800, then the player can go outside of screen."""
if rec.x >= 750: # if rec's x is greater than or equal to 750 (if tries to escape screen)
rec.x = 750 # set rec's x to 750 so it won't go off screen
if rec.y <= 0: # if rec's y is less than or equal to 0 (if tries to escape screen)
rec.y = 0 # set rec's y to 0 so it won't go off screen
"""we pick 540 because the player height is 60 and the screen height is 600.
If we set it to 600, then the player can go outside of screen"""
if rec.y >= 540: # if rec'y is greater than or equal to 540 (if tries to escape screen)
rec.y = 540 # set rec's y to 540 so it won't go off screen
#enemy.update(delta_time, player)
collisions = detCollision(rec.x, rec.y, rec.w, rec.h, redRec.x, redRec.y, redRec.w, redRec.h)
# activate the redrawWin function
redrawWin(collisions)
You need a few peices of information to do this. Firstly, you will need the distance between the player and the enemy. You can work out the distance using math.hypot function like this distance = (math.hypot(enemy.x - player.x, enemy.y - player.y) ). Then you would want to work out the angle between them in radians by using math.atan2 funciton. Note that this function takes y positional argument first. You can use this as follows
angle_radians = (math.atan2(enemy.y - player.y , enemy.x - player.x))
Now to get the enemy to move in the direction of the player, you can do this
enemy.y += math.sin(angle_radians)
enemy.x += math.cos(angle_radians)
See why this works http://setosa.io/ev/sine-and-cosine/.
You can even add a range on how close you want the player to be to the enemy when it starts following by setting a condition on distance between them like this.
if distance < range:
You can also control the speed by multiplying both the sin and cosine by the same number and this works because they are ratios.It can looks something like this
enemy.y += math.sin(angle_radians) * speed # Note both speeds must be the same nnumber
enemy.x += math.cos(angle_radians) * speed
For the last part of your question, if you want this to work for all the enemies, i would recommend adding your game objects to a list. For exmple, you can add enemies to a list
and make them follow the player. Lets say you make a list of all the enemies by doing this
all_enemies = []
for i in range(number of enemies you want):
all_enemies.append(enemy())
You could have an end result that looks something like this:
def Follow_player(self):
for e in all_enemies:
distance = (math.hypot(e.x - player.x, e.y - player.y) )
angle_radians = (math.atan2(e.y - player.y , e.x - player.x))
e.y += math.sin(angle_radians)
e.x += math.cos(angle_radians)
if distance < 1:
# they have collided
EDIT
Here's a link to a very good youtube video that describes all of this
https://www.youtube.com/watch?v=DVYDkHdsTIM

Categories

Resources