How to spawn multiple enemies in pygame - python

So im trying to make a game where the character should dodge enemies which are randomly spawned from above. The problem is, I dont know how to make the Random values different without instanciating another class, which I dont want to do. Also, with Screen.fill(), the enemies wont show up since they're being overlapped by the colour every frame, and if I dont use Screen.fill(), my character would leave a trail everytime it moves. Any Suggestions?
import random
pygame.init()
Running = True
Screen = pygame.display.set_mode((800, 600))
player_img = pygame.image.load('/Users/kevinhadinata/Downloads/ufo.png')
player_updated = pygame.transform.scale(player_img,(60,60))
enemy_list = []
enemy_img = pygame.image.load('/Users/kevinhadinata/Downloads/alien.png')
SPAWNENEMY = pygame.USEREVENT
pygame.time.set_timer(SPAWNENEMY,1000)
class Player:
def __init__(self):
self.ypos = 540
self.xpos = 325
self.height = 60
self.width = 60
self.playerUpdated = player_updated
def create_player(self):
Playerss = pygame.Rect(self.xpos,self.ypos,self.height,self.width)
pygame.draw.ellipse(Screen, (0, 0, 0), Playerss)
Screen.blit(player_updated, (Playerss.x, Playerss.y))
sizee = random.randint(10,40)
randomX = random.randint(0,700)
class Enemy:
def __init__(self):
self.xval = random.randint(0,700)
self.size = random.randint(10,40)
def create_enemy(self):
Enemy = pygame.Rect(self.xval, 0, self.size,self.size)
#enemy_updated = pygame.transform.scale(enemy_img,(self.size,self.size))
enemy_list.append(Enemy)
pygame.draw.ellipse(Screen,(255,255,0),Enemy)
Player = Player()
Enemys = Enemy()
while Running:
Screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
Running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
Player.xpos -= 20
if event.key == pygame.K_RIGHT:
Player.xpos += 20
if event.type == SPAWNENEMY:
Enemys.create_enemy()
Player.create_player()
pygame.display.update()

It's a good idea to not instantiate a new enemy, because just recycling it back to the top of the screen is enough. This amounts to simply changing the size & x,y.
Some of your code is occluding the Enemy class name with an Enemy variable name. I've changed this variable name to new_enemy.
class Enemy:
def __init__(self):
self.recycle() # set the position & size initially
def recycle( self ):
# start or re-start an enemy position
self.size = random.randint(10,40)
self.xval = random.randint(0,700)
self.yval = -self.size # off the screen-top
self.rect = pygame.Rect( self.xval, self.yval, self.size, self.size )
def draw( self, screen ):
pygame.draw.ellipse( screen, (255,255,0), self.rect )
def create_enemy(self):
global enemy_list
new_enemy = Enemy() # create a new Enemy
enemy_list.append( new_enemy ) # add it to the list
Then in your main loop, you can recycle() any Enemy that goes off-screen.
[...] # in main loop
# draw all the enemies, and re-position any enemies that moved off the screen
for enemy in enemy_list:
enemy.draw( screen )
if ( enemy.ypos > 600 ): # TODO - don't use a fixed size
enemy.recycle() # move back to top
The drawing an spawning code was mixed-up, I have re-arranged this into a separate .draw() function. Using this solves the problem with clearing the screen too. Each frame, the code clears the screen, then repaints all the items.

You need to create a list of enemies and iterate the list in the main loop to draw each enemy. Use randint to randomly place the enemies.
Try this code:
import random, pygame
pygame.init()
Running = True
Screen = pygame.display.set_mode((800, 600))
player_img = pygame.image.load('/Users/kevinhadinata/Downloads/ufo.png')
player_updated = pygame.transform.scale(player_img,(60,60))
enemy_list = []
enemy_img = pygame.image.load('/Users/kevinhadinata/Downloads/alien.png')
SPAWNENEMY = pygame.USEREVENT
pygame.time.set_timer(SPAWNENEMY,1000)
class Player:
def __init__(self):
self.ypos = 540
self.xpos = 325
self.height = 60
self.width = 60
self.playerUpdated = player_updated
def create_player(self):
self.Playerss = pygame.Rect(self.xpos,self.ypos,self.height,self.width)
pygame.draw.ellipse(Screen, (0, 0, 0), self.Playerss)
Screen.blit(player_updated, (self.Playerss.x, self.Playerss.y))
def draw(self): # draw player
Screen.blit(player_updated, (self.xpos,self.ypos))
sizee = random.randint(10,40)
randomX = random.randint(0,700)
class Enemys:
def __init__(self):
#self.xval = random.randint(0,700)
self.size = random.randint(10,40)
def create_enemy(self):
Enemy = pygame.Rect(random.randint(100,700), 0, self.size,self.size)
#enemy_updated = pygame.transform.scale(enemy_img,(self.size,self.size))
enemy_list.append(Enemy)
pygame.draw.ellipse(Screen,(255,255,0),Enemy)
def draw(self): # draw all enemies
for e in enemy_list:
pygame.draw.ellipse(Screen,(255,255,0),e)
Player = Player() # player object
Enemys = Enemys() # collection of enemies
Player.create_player()
while Running:
Screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
Running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
Player.xpos -= 20
if event.key == pygame.K_RIGHT:
Player.xpos += 20
if event.type == SPAWNENEMY:
Enemys.create_enemy()
Player.draw() # draw player
Enemys.draw() # draw all enemies
pygame.display.update()

Related

i want to change the location of my sprite when i click.... who to do that?

from numpy import place
import pygame, sys ,random as ran
start = True
ref_x = ran.randint(18,387)
ref_y = ran.randint(18,387)
class Player(pygame.sprite.Sprite):
def __init__(self, pos_x, pos_y):
super().__init__()
self.attack_animation = False
self.sprites_1 = []
self.sprites_1.append(pygame.image.load('.\crossHair.png'))
self.sprites_1.append(pygame.image.load('.\crossHair_2.png'))
self.sprites_1.append(pygame.image.load('.\crossHair_3.png'))
self.sprites_1.append(pygame.image.load('.\crossHair_4.png'))
self.sprites_1.append(pygame.image.load('.\crossHair_5.png'))
self.sprites_1.append(pygame.image.load('.\FIRE.png'))
self.current_sprite = 0
self.image = self.sprites_1[self.current_sprite]
self.image.set_colorkey('white')
for items in self.sprites_1:
items.set_colorkey('white')
self.rect = self.image.get_rect()
self.rect.topleft = [pos_x,pos_y]
def attack(self):
self.attack_animation = True
self.image.set_colorkey('white')
if mouse[0]+24 >= ref_x and ref_x+4 >= mouse[0] and mouse[1]+24 >= ref_y and ref_y+13 >= mouse[1]:
get_shot()
else :
print(ref_x,'here')
def update(self,speed):
self.image.set_colorkey('white')
mouse = pygame.mouse.get_pos()
if self.attack_animation == True:
self.current_sprite += speed
if int(self.current_sprite) >= len(self.sprites_1):
self.current_sprite = 0
self.attack_animation = False
print(mouse)
print('shot')
self.image = self.sprites_1[int(self.current_sprite)]
# self.image = self.sprites_1[int(self.current_sprite)]
self.rect = mouse
class enemy(pygame.sprite.Sprite):
def __init__(self, pos_x, pos_y):
super().__init__()
self.image = pygame.image.load('sp_1.png')
self.rect = self.image.get_rect()
self.rect.center = [pos_x, pos_y]
self.image.set_colorkey((255,255,255))
# General setup
pygame.init()
pygame.mouse.set_visible(0)
clock = pygame.time.Clock()
# Game Screen
screen_width = 400
screen_height = 400
mouse = pygame.mouse.get_pos()
screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption("Sprite Animation")
# Creating the sprites and groups
moving_sprites = pygame.sprite.Group()
crosshair = Player(mouse[0],mouse[1])
enemy_x = ref_x
enemy_y = ref_y
print(enemy_x,enemy_y)
enemy_ = enemy(enemy_x,enemy_y)
moving_sprites.add(enemy_,crosshair)
def get_shot():
moving_sprites.remove(enemy_)
moving_sprites.add(enemy_)
moving_sprites.remove(crosshair)
moving_sprites.add(crosshair)
pygame.display.flip()
while True:
# Player.set_pos(*pygame.mouse.get_pos())
globals()['mouse'] = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pressed()[0]:
crosshair.attack()
# enemy.checkCollision(enemy,crosshair,enemy_)
# enemy.attack()
# pygame.sprite.spritecollide(Player,enemy,True)
screen.fill((120,220,150))
#this is causing the problem
# get_hit = pygame.sprite.spritecollide(Player,enemy,True)
# Drawing
screen.set_colorkey('white')
moving_sprites.draw(screen)
moving_sprites.update(0.06)
pygame.display.flip()
clock.tick(120)
on function get_shot i want to create my sp_1 at a new place i already tried to change the rect but it didn't work so what can I do to make it work and tell me it get_shot is the best method or not or do i have to create another sprite to make it work also i am a beggener to pygame so tr y to make it easy as possible ...
kill the enemy and spawn a new enemy in a new random position:
enemy_ = enemy(ref_x, ref_y)
moving_sprites.add(enemy_, crosshair)
def get_shot():
global enemy_, ref_x, ref_y
enemy_.kill()
ref_x = ran.randint(18,387)
ref_y = ran.randint(18,387)
enemy_ = enemy(ref_x, ref_y)
moving_sprites.add(enemy_)

Pygame drawing a certain number of objects on the screen at a time

I wanted to make a simple dance game using pygame.
class Sword():
def __init__(self, image, speed, center):
self.image = pygame.image.load(image)
self.rect = self.image.get_rect()
self.rect.center = center
self.speed = speed # object speed
self.alive = True # draw object if not hit the enemey
def live(self, enemy): # check if hit the enemy
if self.rect.colliderect(enemy):
self.alive = False
mixer.music.play()
def update(self): # move object
self.rect.x += self.speed
def draw(self, surface): # draw object
if self.alive:
surface.blit(self.image, (self.rect))
I can draw and move my object on the screen.
sword = [Sword('sword.png',1,(100,420))],
[Sword('sword.png',5,(200,420))],
[Sword('sword.png',3,(300,420))]]
while (True):#Mainloop
kare = pygame.draw.rect(display,((255,0,0)), pygame.Rect(700,420,100,100))
for i, tile in sorted(enumerate(sword), reverse=True):
tile.update()
tile.live(kare)
tile.draw()
if not tile.live:
sword.pop(i)#delete object
my code works flawlessly so far;=)
but when I want to draw 4 objects on the screen every time, things don't go as I want.
def main():
extend = []
running = True
while running:
if len(extend) >= 3:
running = False
else:
for i in range(4):
extend.append(Sword('sword.png',1,(100,420)))
return extend
i have a simple function to draw 4 objects at a time to the screen but when i use this in my main loop my objects don't move
while True:
sword = main()#call function
kare = pygame.draw.rect(display,((255,0,0)), pygame.Rect(700,420,100,100))
for i, tile in sorted(enumerate(sword), reverse=True):
tile.update()
tile.live(kare)
tile.draw(display)
if not tile.alive:
sword.pop(i)
First of all, I apologize for this long post, but I wanted the topic to be clear, how do I edit my code so that there are 4 on the screen each time?
Thank you for your interest...
Here is the full code of the solution:
import pygame, sys, math, random
from pygame import mixer
from pygame.locals import *
mainClock = pygame.time.Clock()
pygame.init()
pygame.display.set_caption('game base')
WINDOW_SIZE = (980,570)
screen = pygame.display.set_mode((WINDOW_SIZE), 0, 32)
display = pygame.Surface((WINDOW_SIZE))
RIGHT_KEY,UP_KEY,LEFT_KEY,DOWN_KEY = False,False,False,False
class Sword():
def __init__(self, image, speed, center):
self.image = pygame.image.load(image)
self.rect = self.image.get_rect()
self.rect.center = center
self.speed = speed
self.alive = True
def live(self, enemy):
if self.rect.colliderect(enemy):
self.alive = False
#mixer.music.play()
def update(self):
self.rect.x += self.speed
def draw(self, surface):
if self.alive:
surface.blit(self.image, (self.rect))
def main():
extend = []
running = True
if len(extend) >= 3:
running = False
while running:
if len(extend) >= 4:
running = False
else:
for i in range(5):
extend.append(Sword('sword.png',i,(100,420)))
return extend
sword = main()
while True:
display.fill((250,198,14))
kare = pygame.draw.rect(display,((255,0,0)), pygame.Rect(700,420,100,100))
all_not_alive = True
for tile in sword:
tile.update()
tile.live(kare)
tile.draw(display)
if not tile.alive:
tile.rect.x = 100
tile.alive = True
# Buttons ------------------------------------------------ #
RIGHT_KEY,UP_KEY,LEFT_KEY,DOWN_KEY = False,False,False,False
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == pygame.K_UP:
UP_KEY = True
if event.key == pygame.K_DOWN:
DOWN_KEY = True
if event.key == pygame.K_LEFT:
LEFT_KEY = True
if event.key == pygame.K_RIGHT:
RIGHT_KEY = True
# Update -------------------------------------------------
screen.blit(display,(0,0))
pygame.display.update()
mainClock.tick(60)
The problem was that you have recreated all swords every time when the game updated. You should recreate the sword only if it is not alive.
EDIT
I have moved the code which generates the Swords out of the loop:
sword = main()
and I am moving all swords to the start after they collide:
if not tile.alive:
tile.rect.x = 100
tile.alive = True

Can't move character in pygame

I am trying to move my character (a spaceship) in pygame but what I have done so far has not worked. Everything runs and it displays the character but it does not move when I press the keys.
class Player:
vel = 10
x = width/2-PLAYER.get_width()/2
y = 450
def __init__(self, width, height):
self.width = width
self.height = height
def draw_player(self, win):
win.blit(PLAYER, (self.x, self.y))
def main():
running = True
clock = pygame.time.Clock()
fps = 30
while running:
bg = Background(0, 0)
bg.draw_background()
sc = Score(f"Score: {score}", WHITE)
sc.draw_score()
player = Player(50, 50)
player.draw_player(win)
pygame.display.set_caption("Space Invaders Game")
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
player.x += 1
if keys[pygame.K_LEFT]:
player.x -= 1
pygame.display.flip()
clock.tick(fps)
if __name__ == "__main__":
main()
When you create an instance of a class, the constructor is executed and the object attributes are initialized. Hence, you continuously create a new player in his starting position. You are drawing the player at the same position over and over again. Actually the player is moving, but you never see the movement because a new player is immediately created at the starting position to replace the first player.
You must create the instance object of the Player class before the application loop instead of in the application loop:
def main():
player = Player(50, 50) # <--- ADD
running = True
clock = pygame.time.Clock()
fps = 30
while running:
bg = Background(0, 0)
bg.draw_background()
sc = Score(f"Score: {score}", WHITE)
sc.draw_score()
# player = Player(50, 50) <--- REMOVE
player.draw_player(win)
pygame.display.set_caption("Space Invaders Game")
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
player.x += 1
if keys[pygame.K_LEFT]:
player.x -= 1
pygame.display.flip()
clock.tick(fps)

Python - Pygame - Class __init___ question/Not drawing

I'm learning OOP and I have a few questions.
When the initiliazer is called, is the code automatically processed?
Cause if that's the case, I don't understand why my game isn't drawing the rectangle i ask it to draw in the init part of the player class.
I'm very new to OOP and as such I'm not sure of what I'm doing, to some extent.
Here's my code:
import pygame
white = (255, 255, 255)
black = (0, 0, 0)
class Game():
width = 800
height = 600
screen = pygame.display.set_mode((width, height))
def __init__(self):
pass
def fill_screen(self, color):
self.color = color
self.screen.fill(self.color)
class Player(pygame.sprite.Sprite):
lead_x = 800/2
lead_y = 600/2
velocity = 0.002
block_size = 10
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.draw.rect(game.screen, black, [self.lead_x, self.lead_y, self.block_size, self.block_size])
def move_player_x_left(self):
self.lead_x += -self.velocity
def move_player_x_right(self):
self.lead_x += self.velocity
def move_player_y_up(self):
self.lead_y += -self.velocity
def move_player_y_down(self):
self.lead_y += self.velocity
game = Game()
player = Player()
exitGame = False
while not exitGame:
game.fill_screen(white)
for event in pygame.event.get():
if event.type == pygame.QUIT:
exitGame = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player.move_player_y_up()
if event.key == pygame.K_s:
player.move_player_y_down()
if event.key == pygame.K_d:
player.move_player_x_right()
if event.key == pygame.K_a:
player.move_player_x_left()
pygame.display.update()
pygame.quit()
quit()
You are constantly filling the screen with white in your mainloop. The Player class only draws on __init__. This means that the rect is drawn for a split second and then covered over by white.
Your assumption about the code in __init__ automatically being called is correct. These methods with double underscores are called by python in special cases, they are called magic methods. You can find a list of them here.
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# The rect drawing part was moved from here.
def update(self):
# You were previously assigning this to a variable, this wasn't necessary.
pygame.draw.rect(game.screen, black, [self.lead_x, self.lead_y, self.block_size, self.block_size])
You will need to call the new update method in the mainloop after you fill the screen.
while True:
game.fill_screen(white)
player.update()

Enemy Object wont move in Pygame

I'm trying to make a character move across the screen from the top to the bottom, where it will disappear. However, the code I have doesn't return any errors, but it won't move the character either. Here is my code:
import pygame
import sys
import random
pygame.init()
width , height = 600 , 500
display = pygame.display.set_mode((width, height ) )
pygame.display.set_caption("Class Test")
primoimage = pygame.image.load("/home/pi/Downloads/PRIMO/primo_0.png").convert()
class Enemy:
def __init__(self, name, shoot, speed, image):
self.name = name
self.shoot = shoot
self.speed = speed
self.image = image
def move(self):
enemyRack = []
if len(enemyRack) == 0:
enemyRack.append([width/2, 0])
for enemy in enemyRack:
display.blit(self.image, pygame.Rect(enemy[0], enemy[1], 0,0))
for e in range(len(enemyRack)):
enemyRack[e][1]+=2
for enemy in enemyRack:
if enemy[1] > height:
enemyRack.remove(enemy)
primo = Enemy("primo", 2, False, primoimage)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
pass
primo.move()
pygame.display.update()
pygame.quit()
sys.exit()
The problem is in the move() function.
If you could figure it out that would be great! Thanks.
I added some indentation so things work again. (I'm assuming you just broke the indentation when posting your code). Your error was re-initializing enemyRack = [] every time move is called. That way you'll always have [300, 0] in the enemyRack.
import pygame
import sys
import random
pygame.init()
width , height = 600 , 500
display = pygame.display.set_mode((width, height ) )
pygame.display.set_caption("Class Test")
primoimage = pygame.image.load("player.png").convert()
class Enemy:
def __init__(self, name, shoot, speed, image):
self.name = name
self.shoot = shoot
self.speed = speed
self.image = image
self.enemyRack = [] # let's make this a class variable so we don't lose the contents
def move(self):
if len(self.enemyRack) == 0:
self.enemyRack.append([width/2, 0])
for enemy in self.enemyRack:
display.blit(self.image, pygame.Rect(enemy[0], enemy[1], 0,0))
for e in range(len(self.enemyRack)):
self.enemyRack[e][1]+=2
for enemy in self.enemyRack:
if enemy[1] > height:
self.enemyRack.remove(enemy)
primo = Enemy("primo", 2, False, primoimage)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
pass
primo.move()
pygame.display.update()
pygame.quit()
sys.exit()

Categories

Resources