Weird spawn location of enemies pygame - python

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?

Related

space invader pygame make enemy disappear when shot

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.

How do I make a continuously moving bullet when I'm not holding down the space bar in pygame? [duplicate]

This question already has answers here:
How can i shoot a bullet with space bar?
(1 answer)
How do I stop more than 1 bullet firing at once?
(1 answer)
Closed 1 year ago.
import pygame
# initialize the pygame
pygame.init()
# create the screen
screen = pygame.display.set_mode((800, 600))
# Title and icon
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('Invader2.xcf')
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('Player.xcf')
player_big = pygame.transform.scale(playerImg, (48, 48))
playerX = 370
playerY = 480
vel = 0.15
# Player Bullets
playerBulletImg = pygame.image.load('Player_bullet.xcf')
playerBulletX = playerX + 16
playerBulletY = playerY + 10
bulletVel = 0.3
def player(x, y):
screen.blit(player_big, (playerX, playerY))
def bullet(x, y):
screen.blit(playerBulletImg, (playerBulletX, playerBulletY))
# Game Loop
running = True
while running:
# RGB
screen.fill((18.8, 83.5, 78.4))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and playerX > 0:
playerX -= vel
playerBulletX -= vel
if keys[pygame.K_RIGHT] and playerX < 800 - 48:
playerX += vel
playerBulletX += vel
if keys[pygame.K_SPACE]:
playerBulletY -= 0.5
if playerBulletY == 0:
playerBulletY = 480
bullet(playerBulletX, playerBulletY)
player(playerX, playerY)
pygame.display.update()
Hi! I'm a beginner who has just started using Pygame. I'm making a Space Invaders / Galaga type game. When I press the space bar, the bullet goes up the y-axis, but only when I hold it down. I want the bullet to continue to move up the screen, even when I'm not holding down the space bar. Also, another problem is that when the bullet is in the air it still follows the x-value for the player. So when the bullet shoots up, It moves around depending on where the player is.
you should run your game as a class it is much more easier to code pygame with classes you can change your b.move to where else
import pygame
# initialize the pygame
pygame.init()
# create the screen
screen = pygame.display.set_mode((800, 600))
# Title and icon
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('Invader2.xcf')
pygame.display.set_icon(icon)
# Player
class Player:
def __init__(self):
self.Img = pygame.image.load('Player.xcf')
self.big = pygame.transform.scale(playerImg, (48, 48))
self.x = 370
self.y = 480
self.vel = 0.15
def draw(self,screen):
screen.blit(self.big, (self.x, self.y))
class Bullet:
def __init__(self):
self.Img = pygame.image.load('Player_bullet.xcf')
self.x = playerX + 16
self.y = playerY + 10
self.vel = 0.3
def draw(screen):
screen.blit(self.Img, (self.y, self.y))
def move():
self.y -= self.vel
def draw(p,b):
p.draw()
for i in b:
i.draw()
# Game Loop
def main():
running = True
p = Player()
b = []
while running:
screen.fill((18.8, 83.5, 78.4))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and p.x > 0:
p.x -= p.vel
if keys[pygame.K_RIGHT] and p.x < 800 - 48:
p.x += p.vel
if keys[pygame.K_SPACE]:
b.append(Bullet())
draw(p,b)
for bullet in b:
bullet.move()
pygame.display.update()
Use the keyboard event instead of pygame.key.get_pressed() to shoot a bullet.
pygame.key.get_pressed() returns a sequence with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action.
Add a shootBullet variable that indicates when the bullet will be fired. Set the state when SPACE is pressed. Move and draw the bullet depending on this state. Set the starting position of the bullet when the bullet is fired.
shootBullet = False
clock = pygame.time.Clock()
running = True
while running:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
shootBullet = True
playerBulletX = playerX
playerBulletY = 480
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and playerX > 0:
playerX -= vel
if keys[pygame.K_RIGHT] and playerX < 800 - 48:
playerX += vel
if shootBullet:
playerBulletY -= 1
if playerBulletY <= 0:
shoot_bullet = False
screen.fill((18.8, 83.5, 78.4))
if shootBullet:
bullet(playerBulletX, playerBulletY)
player(playerX, playerY)
pygame.display.update()
Use pygame.time.Clock to control the frames per second and thus the game speed.
The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick():
This method should be called once per frame.
That means that the loop:
clock = pygame.time.Clock()
run = True
while run:
clock.tick(100)
runs 100 times per second.

How do I make my background scroll as my Sprite moves left and right? Pygame

Right now my game works as so: My sprite can move right or left, jump and shoot fireballs (bullets). However, once my sprite walks past the limit of my background surface, it goes off-screen. So I want to make the background move along with my sprite. As soon as my player sprite moves about 50 pixels towards the edges of the screen, the background moves too. How do I create this with Pygame? I've found quite an amount of sources which shows you how to do this but with a plain colour background. But my background is an image I load into the game, so I would like to learn how to do so with an image as background. How to make it repeat once the sprite comes near the limit of both sides. I separated my codes into 3 different files: a Main.py, settings.py and Sprite1.py. Here's Main.py:
import pygame
import os
import sys
import time
from pygame import mixer
from Sprite1 import *
from settings import *
'''
Setup
'''
pygame.init()
clock = pygame.time.Clock()
pygame.mixer.music.load('.\\sounds\\Fairy.mp3')
pygame.mixer.music.play(-1, 0.0)
all_sprites = pygame.sprite.Group()
player = Player(all_sprites)
player.rect.x = 50
player.rect.y = 500
showStartScreen(surface)
'''
Main loop
'''
main = True
while main == True:
background = pygame.image.load(os.path.join('images', 'Bg.png'))
surface.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(-steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(steps,0)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(-steps,0)
keys = pygame.key.get_pressed()
if not(isJump):
if keys[pygame.K_UP]:
isJump = True
else:
if jumpCount >= -10:
player.rect.y -= (jumpCount * abs(jumpCount)) * 1
jumpCount -= 2
else:
jumpCount = 10
isJump = False
# dt = time since last tick in milliseconds.
dt = clock.tick(60) / 1000
all_sprites.update(dt)
player.update(dt)
all_sprites.draw(surface) #refresh player position
pygame.display.flip()
Here's settings.py:
import pygame
isJump = False
jumpCount = 10
width = 960
height = 720
fps = 40 # frame rate
#ani = 4 # animation cycles
pygame.display.set_caption('B.S.G.')
surface = pygame.display.set_mode((width, height))
PLAYER_ACC = 0.5
PLAYER_FRICTION = -0.12
PLAYER_GRAV = 0.8
PLAYER_JUMP = 20
PLAYER_LAYER = 2
PLATFORM_LAYER = 1
steps = 10 # how fast to move
And here's Sprite1.py:
import pygame
import sys
import os
import time
from pygame import mixer
from pygame.locals import *
from settings import *
vec = pygame.math.Vector2
def showStartScreen(surface):
show = True
while (show == True):
background = pygame.image.load(os.path.join('images', 'Starting_scr.png'))
# rect = surface.get_rect()
surface.blit(background, (0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
show = False
class Player(pygame.sprite.Sprite):
def __init__(self, all_sprites):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
self.jumping = False
self.images = []
self.imagesleft = []
self.imagesright = []
self.direction = "right"
self.alpha = (0,0,0)
self.ani = 4 # animation cycles
self.all_sprites = all_sprites
self.add(self.all_sprites)
self.bullet_timer = .1
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesright.append(img)
self.image = self.imagesright[0]
self.rect = self.image.get_rect()
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img = pygame.transform.flip(img, True, False)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesleft.append(img)
self.image = self.imagesleft[0]
self.rect = self.image.get_rect()
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey -= y
def update(self, dt):
'''
Update sprite position
'''
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesleft[self.frame//self.ani]
self.direction = "left"
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesright[self.frame//self.ani]
self.direction = "right"
#enemy_hit_list = pygame.sprite.spritecollide(self,enemy_list, False)
#for enemy in enemy_hit_list:
#self.health -= 1
#print(self.health)
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
self.bullet_timer -= dt # Subtract the time since the last tick.
if self.bullet_timer <= 0:
self.bullet_timer = 100 # Bullet ready.
if keys: # Left mouse button.
# Create a new bullet instance and add it to the groups.
if self.direction == "right":
Bullet([self.rect.x + self.image.get_width(), self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
else:
Bullet([self.rect.x, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
self.bullet_timer = .1 # Reset the timer.
class Bullet(pygame.sprite.Sprite):
IMAGE = None
FLIPPED_IMAGE = None
def __init__(self, pos, direction, *sprite_groups):
super().__init__(*sprite_groups)
# cache images
if not Bullet.IMAGE:
Bullet.IMAGE = pygame.image.load(os.path.join('images','fireball.png'))
Bullet.FLIPPED_IMAGE = pygame.transform.flip(Bullet.IMAGE, True, False)
if direction == "right":
self.vel = pygame.math.Vector2(750, 0)
self.image = Bullet.IMAGE
else:
self.vel = pygame.math.Vector2(-750, 0)
self.image = Bullet.FLIPPED_IMAGE
self.pos = pygame.math.Vector2(pos)
self.rect = self.image.get_rect(center=pos)
def update(self, dt):
# Add the velocity to the position vector to move the sprite
self.pos += self.vel * dt
self.rect.center = self.pos # Update the rect pos.
if not pygame.display.get_surface().get_rect().colliderect(self.rect):
self.kill()
I'm open to any suggestions. Thanks beforehand!
Here's how I would approach this...
set up a scrolling background as in the tutorial and make sure you can get that working OK by moving the background back & forth instead of the player (just freeze the player's x coordinate in the center and move the background with your left/right keys.
Add some constants into your settings for an edge buffer (the number of x-increments you want the player to avoid the boundaries by
AFTER you get the key input (left or right) set up a conditional statement. For this, you will have to access the player's x-coordinate and compare it to the buffer. Well, either 0+buffer or width-buffer actually and then based on those cases either move the player or the background. See if you can get that working.
Then, you will realize that when you move the background, you are moving the frame of reference for everything else, meaning things like the fireball, so if you are moving the background left or right, you will need to apply those updates to the other objects as well so it looks correct.
If yer stuck, make those updates to code above & message me back in a comment.

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))
# [...]

Updating Score Pygame Pong

For whatever reason, the score display in my pong game is not updating. It just keeps saying "0". I checked to see if the score was actually being updated in the logic of the game and it is (printed it out to console). I have the text being "blitted" every time a new display is drawn so can anyone tell me why it won't update?
import pygame
import random
pygame.init()
# Create colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# Create screen and set screen caption
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Pong")
# Loop until user clicks close button
done = False
# Used to manage how fast the screen is updated
clock = pygame.time.Clock()
# Create player class
class Player():
# Initialize player paddles
def __init__(self, x, y, color, height, width):
self.x = x
self.y = y
self.color = color
self.height = height
self.width = width
self.y_speed = 0
self.score = 0
self.font = pygame.font.SysFont('Calibri', 24, True, False)
self.display_score = self.font.render("Score: %d " % (self.score), True, WHITE)
# Updates with new position of paddle every frame
def draw(self, y):
pygame.draw.rect(screen, self.color, [self.x, y, self.height, self.width])
# Keeps paddle from going off screen
def keepOnScreen(self):
if self.y < 0:
self.y = 0
elif self.y > 410:
self.y = 410
# Create Ball class
class Ball():
# Initialize ball in the middle of the screen with no movement
def __init__(self, color, height, width):
self.x = 325
self.y = random.randrange(150, 350)
self.color = color
self.height = height
self.width = width
self.y_speed = 0
self.x_speed = 0
# Updates new position of ball every frame
def draw(self, x, y):
pygame.draw.rect(screen, self.color, [x, y, self.height, self.width])
# Create instances of both players and ball
player1 = Player(50, 100, WHITE, 25, 90)
player2 = Player(625, 100, WHITE, 25, 90)
ball = Ball(WHITE, 20, 20)
# --- Main Program Loop ---
while not done:
# --- Main event loop
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # We are done so we exit this loop
if event.type == pygame.KEYDOWN: # Players utilize keyboard to move paddles
if event.key == pygame.K_w:
player1.y_speed = -6
if event.key == pygame.K_UP:
player2.y_speed = -6
if event.key == pygame.K_s:
player1.y_speed = 6
if event.key == pygame.K_DOWN:
player2.y_speed = 6
if event.key == pygame.K_SPACE: # Starts the ball movement
ball.x_speed = 3 * random.randrange(-1, 1, 2)
ball.y_speed = 3 * random.randrange(-1, 1, 2)
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
player1.y_speed = 0
if event.key == pygame.K_UP:
player2.y_speed = 0
if event.key == pygame.K_s:
player1.y_speed = 0
if event.key == pygame.K_DOWN:
player2.y_speed = 0
# Calculate the movement of the players
player1.y += player1.y_speed
player2.y += player2.y_speed
# Prevents paddles from going off-screen
player1.keepOnScreen()
player2.keepOnScreen()
# Checks to see if ball has made contact with paddle, then reverses direction of the ball
# Had to give a 4 pixel buffer since the ball won't always exactly hit the same part of paddle in x direction
if ball.x <= player1.x + 27 and (ball.x >= player1.x + 23):
if ball.y >= player1.y and (ball.y <= player1.y + 100):
ball.x_speed *= -1
if ball.x >= player2.x - 27 and (ball.x <= player2.x - 23):
if ball.y >= player2.y and (ball.y <= player2.y + 100):
ball.x_speed *= -1
# Checks to see if ball has made contact with top or bottom of screen
if ball.y <= 0 or ball.y >= 480:
ball.y_speed *= -1
# Calculates movement of the ball
ball.x += ball.x_speed
ball.y += ball.y_speed
# Updates score
if ball.x < 0:
player2.score += 1
ball.__init__(WHITE, 20, 20)
if ball.x > 700:
player1.score += 1
ball.__init__(WHITE, 20, 20)
# Set background
screen.fill(BLACK)
# Draw players and ball on screen
player1.draw(player1.y)
player2.draw(player2.y)
ball.draw(ball.x, ball.y)
screen.blit(player1.display_score, [0, 0])
screen.blit(player2.display_score, [615, 0])
# Update display
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
# Close the window and quit
pygame.quit()
It looks like the problem is you're setting each player's display_score only in their __init__ function.
# Initialize player paddles
def __init__(self, x, y, color, height, width):
...
self.score = 0
...
self.display_score = self.font.render("Score: %d " % (self.score), True, WHITE)
Because of the way you initialize the variable, changing the value of player.score does not change the value of player.display_score.
Solution 1
You could change the value of display_score when you change the player scores, which would be easily done through a function call:
def player_scores( player, ball ):
player.score += 1
player.display_score = player.font.render("Score: %d " % (player.score), True, WHITE)
ball.__init__(WHITE, 20, 20)
Then in your game loop:
# Updates score
if ball.x < 0:
player_scores( player2, ball )
if ball.x > 700:
player_scores( player1, ball )
Solution 2
You could render the score text when you display it, rather than creating it on the players. In your game loop:
screen.blit(player1.font.render("Score: %d " % (player1.score), True, WHITE), [0, 0])
screen.blit(player2.font.render("Score: %d " % (player2.score), True, WHITE), [615, 0])
This invalidates the display_score variable completely

Categories

Resources