why is my sprite.Group list empty when I add objects to it? - python

I want to make it so that when there are more then 3 objects stored in bullet_group it wouldnt add objects to it but for some reason my list stays empty even though I have objects stored in it. Why is that happening?
bullet_group = pygame.sprite.Group()
bullet_group2= pygame.sprite.Group.sprites(bullet_group)
enemy_group = pygame.sprite.Group()
prev_time = time.time()
game_active = False
gameName = pygame.font.Font('font/Pixeltype.ttf',80).render('Asteroids',False,(51,153,255))
gameName_rect = gameName.get_rect(center = (400,70))
text2 = test_font.render('Press "space" to run',False,(51,153,255))
text2_rect = text2.get_rect(center = (400,340))
while True:
dt = time.time() - prev_time
prev_time = time.time()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if game_active:
display_score()
if len(bullet_group2) <= 3 :
print(bullet_group2)
if event.type == pygame.MOUSEBUTTONDOWN:
bullet_group.add(player.create_bullet())

It seems that you are checking the length of bullet_group2 but then adding the bullets to bullet_group. As a result, the length of bullet_group2 never increases, and you will always be able to keep adding bullets.
Try something like this:
if len(bullet_group) <= 3 :
if event.type == pygame.MOUSEBUTTONDOWN:
bullet_group.add(player.create_bullet())

Related

python pygame window wont close "not responding"

I am trying to make a python window for my game from my laptop in pygame... however when I try to close the window I get an error message saying "not responding" im not sure why that if I thought i had done everything right.... the code is below any help is needed.
Thanks!
import pygame
from sys import exit
pygame.init()
screen = pygame.display.set_mode((800,400))
clock = pygame.time.Clock()
sky_surface = pygame.image.load("bg_desert.png").convert()
snail_surface = pygame.image.load("snailWalk1.png").convert_alpha()
player_surf = pygame.image.load("p1_walk01.png")
snail_x_pos = 600
while True:
pygame.time.set_timer(snail_x_pos, 100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("hello")
snail_x_pos -=4
if snail_x_pos < -100: snail_x_pos = 800
screen.blit(sky_surface,(0,0))
screen.blit(snail_surface,(snail_x_pos,350))
screen.blit(player_surf,(80, 200))
pygame.display.update()
clock.tick(60)
All problem makes
pygame.time.set_timer(snail_x_pos, 100)
which you run inside loop.
If I remove it then it closes without problem.
Every set_timer creates new timer which sends event every 100ms (again and again). If you run it in loop then you create hundreds timers.
You should run it only once - before loop - and it will repeatly send event which you can get in for-loop.
Problem is also that you use it in wrong way - you use snail position but it should user_id and time in milliseconds.
my_event_id = pygame.USEREVENT + 1
pygame.time.set_timer(my_event_id, 500) # 500ms = 0.5s
and later you can use it to move snail
elif event.type == my_event_id:
print('0.5 second')
snail_x_pos -= 4
Here my version with other changes.
I use Surfaces instead images so everyone can simply copy and run it.
I also use pygame.Rect to keep position and size - it has useful values (ie. .center to get/set center position) and functions (ie. to detect colisions). I use .left and .right to move snake to right side of window when it leaves window on left side.
import pygame
pygame.init()
screen = pygame.display.set_mode((800,400))
sky_surface = pygame.Surface((800, 100))
sky_surface.fill((0,0,255))
sky_surface_rect = sky_surface.get_rect()
snail_surface = pygame.Surface((100, 10))
snail_surface.fill((0,255,0))
snail_surface_rect = snail_surface.get_rect()
snail_surface_rect.x = 600
snail_surface_rect.y = 350
player_surf = pygame.Surface((10, 50))
player_surf.fill((255,0,0))
player_surf_rect = player_surf.get_rect()
player_surf_rect.x = 80
player_surf_rect.y = 200
clock = pygame.time.Clock()
my_event_id = pygame.USEREVENT + 1
pygame.time.set_timer(my_event_id, 500) # 500ms = 0.1s
while True:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("hello")
elif event.type == my_event_id:
print('0.5 second')
# move snake
snail_surface_rect.x -= 4
# use this event to slow down player
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
player_surf_rect.x -= 4
elif pressed[pygame.K_RIGHT]:
player_surf_rect.x += 4
# - updates -
if snail_surface_rect.right < 0:
snail_surface_rect.left = 800
# - draw -
screen.fill((0,0,0)) # clear screen
screen.blit(sky_surface, sky_surface_rect)
screen.blit(snail_surface, snail_surface_rect)
screen.blit(player_surf, player_surf_rect)
pygame.display.update()
clock.tick(60)

Continuous object creation in pygame?

Okay, so I've researched this topic a bit. I'm creating a game in Python's Pygame, a replica of the famous "Raiden 2". My game loop is fairly similar to those I've seen around. What I'm trying to do is have the constructor create a bullet object (with my Bullet class) while the space bar is being held. However, the following code only creates a single bullet per keypress. Holding the button does nothing, just creates a single bullet.
while game.play is True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
b = Bullet(x, y)
bullet_group.add(b)
bullet_group.draw(screen)
Not sure where to go from here. Any help is welcome and appreciated.
This should work as you expect it:
addBullets = False
while game.play is True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
addBullets = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
addBullets = False
if addBullets:
b = Bullet(x, y)
bullet_group.add(b)
bullet_group.draw(screen)
You move the creation of bullets out of the handling of events and set there only a "flag" which is taken back if the key is released stopping creation of bullets.
And ... as mentioned in the comment by jsbueno this will work too:
while game.play is True:
for event in pygame.event.get():
pass # do something with events
if pygame.key.get_pressed()[pygame.K_SPACE]:
b = Bullet(x, y)
bullet_group.add(b)
I think the other answer is lacking an important detail. You most likely don't want to fire a bullet every frame, so you need to have some kind of timer. The simplest way is to count the frames, but then the game would be frame rate bound (better don't do it in this way).
firing = False
bullet_timer = 0
while game.play:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game.play = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
firing = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
firing = False
if bullet_timer > 0:
bullet_timer -= 1
elif firing: # Timer is less than 0 and we're firing.
bullet = Bullet()
bullet_group.add(bullet)
bullet_timer = 10 # Reset timer to 10 frames.
The frame rate independent variant is to use the time that pygame.Clock.tick returns (the time that has passed since it was called the last time) and subtract it from the timer variable. If the timer is <= 0 we're ready to fire.
clock = pygame.time.Clock()
firing = False
bullet_timer = 0
while game.play:
# `dt` is the passed time since the last tick in seconds.
dt = clock.tick(30) / 1000
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
firing = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
firing = False
if bullet_timer > 0:
bullet_timer -= dt
elif firing: # Timer is below 0 and we're firing.
bullet = Bullet()
bullet_group.add(bullet)
bullet_timer = .5 # Reset timer to a half second.

How to make definiton work?

Please see below examples:
import pygame
pygame.init()
x = 800
y = 600
programDisplay = pygame.display.set_mode((x,y))
pygame.display.set_caption('Title')
pygame.display.update()
programExit = False
while not programExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
programExit = True
pygame.quit()
quit()
Second Example:
import pygame
pygame.init()
x = 800
y = 600
programDisplay = pygame.display.set_mode((x,y))
pygame.display.set_caption('Title')
pygame.display.update()
programExit = False
def programQuit():
for event in pygame.event.get():
if event.type == pygame.QUIT:
programExit = True
while not programExit:
programQuit()
pygame.quit()
quit()
How to make definition from 2nd example work so the outcome is same as in first example?
Think it might be something to do with global and local variables but could not get it working.
Here, I fixed it
import pygame
pygame.init()
x = 800
y = 600
programDisplay = pygame.display.set_mode((x,y))
pygame.display.set_caption('Title')
pygame.display.update()
programExit = False
def checkForProgramQuit():
global programExit
for event in pygame.event.get():
if event.type == pygame.QUIT:
programExit = True
while not programExit:
checkForProgramQuit()
programDisplay.fill((255,255,255))
pygame.display.update()
pygame.quit()
quit()
the programExit variable you were modifying was local to the function.
Carcigenticate is quite right, but here are some notes on what's going on here and some practices that will avoid this in future.
programExit = False
def programQuit(programExit=False):
for event in pygame.event.get():
if event.type == pygame.QUIT:
programExit = True # Issue 1
while not programExit:
programQuit()
Issue 1 is that this assignment is creating a new variable in the scope of the function and setting it's value. It is not changing the value of the module level variable programExit.
A better way to do this is to have the function pass back it's result as a return value like this.
def programContinue():
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
return True
while programContinue():
pass
Also by reversing the boolean logic returned by the function, I think things become a bit clearer and we can get rid of the 'not'. Also expressing the while clause this way seems a bit clearer to me. The 'pass' statement could usefully be replaced with some logging or the display updates from C._'s answer.

pygame continuous and simultaneous key inputs

I am stuck again and cannot find any valid solutions online. I am trying to use pygame and its key inputs to control various things. Now I need to use several keys simultaneously. My code is as follows:
pygame.key.set_reapeat(50,50)
bProgramLoop = True
while (bProgramLoop == True):
for event in pygame.event.get():
if (event.type == pygame.QUIT):
bProgramLoop = False
if (pygame.key.get_pressed()[pygame.K_LEFT]):
EXECUTE_FUNCTION1()
print "left"
if (pygame.key.get_pressed()[pygame.K_RIGHT]):
EXECUTE_FUNCTION2()
print "right"
Now the problem that I have is:
When I hold down "LEFT of RIGHT" it correctly and continuously registers that I pressed left/right. BUT when I hold in "LEFT" and just tap "RIGHT", it registers that left and right were pressed but it then stops to register that "LEFT" is still being pressed.
Any ideas anyone?
Any help would be greatly appreciated.
Misha
In my code the "repeat" is correctly spelt.
I found the work around for my problem. The above code needs to be modified.
pygame.key.set_repeat(50,50)
bProgramLoop = True
while (bProgramLoop == True):
for event in pygame.event.get():
if (event.type == pygame.QUIT):
bProgramLoop = False
if (event.type == pyame.KEYDOWN):
if (event.key == pygame.K_a) # if A is pressed
bKeyA = True # set the Boolean True
if (event.key == pygame.K_s)
bKeyS = True
if (event.type == pyame.KEYDOWN):
if (event.key == pygame.K_a) # if A is released
bKeyA = False# set the Boolean False
if (event.key == pygame.K_s)
bKeyS = False
if (bKeyA == True):
Execute_function1()
if (bKeyB == True):
Execute_function2()
I double checked, the repeat is correctly spelt and it would not continue a keyboard input once another one was tapped. The problem is, as far as I can figure it out, and even occurs once at the point when a key is pressed. When another key is simultaneously pressed the event is lost.
Thus the solution is to set a variable true until the key is lifted up, and thus the variable is set false.
You have misspelled repeat in pygame.key.repeat(). I corrected this and it worked for me.
def main():
while Running:
check_events()
update()
clock.tick(FPS)
def check_events():
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
sys.exit()
if key == pygame.K_q:
Running = False
return
if (pygame.key.get_pressed()[pygame.K_LEFT]):
#EXECUTE_FUNCTION1()
print "left"
if (pygame.key.get_pressed()[pygame.K_RIGHT]):
#EXECUTE_FUNCTION2()
print "right"
If you want to use continuous inputs than try this, it is my code.
import pygame as py
import time
sc = py.display.set_mode((800, 600))
x = 350
y = 300
blue = (0, 0, 255)
last = 0
while True:
key = py.key.get_pressed()
for event in py.event.get():
if event.type == py.KEYDOWN:
last = event.key
else:
last = 0
if last == py.K_UP:
y -= 0.1
if last == py.K_DOWN:
y += 0.1
if last == py.K_LEFT:
x -= 0.1
if last == py.K_RIGHT:
x += 0.1
sc.fill((0,255,0))
py.draw.rect(sc, blue, (x,y,50,50))
py.display.flip()
If you want to use simultaneous input, then here:
import pygame as py
import time
sc = py.display.set_mode((800, 600))
x = 350
y = 300
blue = (0, 0, 255)
last = 0
def move(times, yspeed, xspeed):
for i in range(times):
global x, y
x += (xspeed / times)
y += (yspeed / times)
time.sleep((xspeed / times / 10) + (yspeed / times / 10))
while True:
key = py.key.get_pressed()
for event in py.event.get():
if event.type == py.KEYDOWN:
last = event.key
else:
last = 0
if event.key == py.K_UP and event.key == py.K_l:
y -= 0.1
sc.fill((0,255,0))
py.draw.rect(sc, blue, (x,y,50,50))
py.display.flip()

Not sure why key press is not doing anything

I'm having some trouble getting a reaction from pressing the D key in my program. I will show and then explain. (Irrelevant things omitted)
Main.py
while True:
process(Cursor,movie,music)
Effects.List.draw(screen)
pygame.display.flip()
Classes.py
class BaseClass(pygame.sprite.Sprite):
allsprites = pygame.sprite.Group()
def __init__(self,x,y,image_string):
pygame.sprite.Sprite.__init__(self)
BaseClass.allsprites.add(self)
self.image = pygame.image.load(image_string)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def destroy(self, ClassName):
ClassName.List.remove(self)
BaseClass.allsprites.remove(self)
del self
class Effects(BaseClass):
List = pygame.sprite.Group()
def __init__(self,x,y,image_string):
BaseClass.__init__(self,x,y,image_string)
Effects.List.add(self)
Process.py
def process(Cursor,movie,music):
for event in pygame.event.get():
Stage = True
Stage2 = False
keys = pygame.key.get_pressed()
if Stage:
if Cursor.rect.collidepoint(370,340): #Start
if keys[pygame.K_RETURN]:
Stage2 = True
if Stage2:
Stage = False
hitkeys = HitKeys(65,600,"Images/Hit Keys.png") #520
lane = KeyLane(50,0,"Images/4k lane.png")
movie.play()
pygame.mixer.music.play()
if keys[pygame.K_d]:
effect1 = Effects(55,0,"Images/Effect.png")
I am not experienced in programming so my methods to achieve what I want are very roundabout. As you can see, I want the Effect.png to appear when I press D but to only appear during Stage2. It just doesn't happen. It would work if I dedented it one part but that would mean it would appear during Stage. Not what I want.
Would appreciate if you could help me determine why it isn't showing up in Stage2.
In for event in pygame.event.get(): you set
Stage = True
Stage2 = False
so every time you run process() you go to Stage (Stage = True)
You have to set
Stage = True
Stage2 = False
at the beginning of game (before while True:)
BTW: you will have to use Stage and Stage2 in
process(Cursor,movie,music, Stage, Stage2)
Maybe better use one Stage and assign stage number 1, 2
BTW: there are python rules how to name functions and variables (PEP8) - use lowercase (and _) for variable names (stage, stage1, all_sprites) and use upper letter in class names. Event Stackover use that rules and it use light blue color for class names.
EDIT:
I made script to test keyboard. Check what you get.
keys = pygame.key.get_pressed() works but only when screen/window exists.
import pygame
import pygame.locals
pygame.init()
screen = pygame.display.set_mode((800,600))
d_pressed = False
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_ESCAPE:
running = False
elif event.key == pygame.K_d:
d_pressed = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
d_pressed = False
keys = pygame.key.get_pressed()
if d_pressed:
print '> d_pressed <'
if keys[pygame.K_RETURN]:
print '> K_RETURN <'
if keys[pygame.K_d]:
print '> K_d <'
EDIT: sending stages as list - not (separated) values
stages = [True, False]
while True:
process(Cursor, movie, music, stages)
Effects.List.draw(screen)
pygame.display.flip()
-
while True
def process(Cursor,movie,music, stages):
for event in pygame.event.get():
keys = pygame.key.get_pressed()
if stages[0]:
if Cursor.rect.collidepoint(370,340): #Start
if keys[pygame.K_RETURN]:
stages[0] = False
stages[1] = True
if stage[1]:
hitkeys = HitKeys(65,600,"Images/Hit Keys.png") #520
lane = KeyLane(50,0,"Images/4k lane.png")
movie.play()
pygame.mixer.music.play()
if keys[pygame.K_d]:
effect1 = Effects(55,0,"Images/Effect.png")

Categories