Problem
I'm learning PyGame from today. I'm Trying to move images with keys. I've Coded everything. But When I try to move the image, it left his layer on the window. the keys are a,d,s,w. here is a screenshot of it.
Code
Here is the Code:
import pygame as pg
app=pg.init()
win=pg.display
display=win.set_mode((900,500))
display.fill((255,255,255))
win.set_caption('Python Game')
clock=pg.time.Clock()
vel=5
spship_red=pg.image.load('assets/spaceship_red.png')
spship_red=pg.transform.rotate(pg.transform.scale(spship_red,(55,40)),90)
spship_yellow=pg.image.load('assets/spaceship_yellow.png')
spship_yellow=pg.transform.rotate(pg.transform.scale(spship_yellow,(55,40)),270)
sp=pg.image.load('assets/space.png')
#gun=pg.music.load('assets/Gun+Silencer.mp3')
#nade=pg.music.load('assets/Grenade+1.mp3')
def move(key,red,yellow):
if key[pg.K_a]:
red.x-=vel
if key[pg.K_d]:
red.x+=vel
if key[pg.K_w]:
red.y-=vel
if key[pg.K_s]:
red.y+=vel
def draw(red,yellow):
display.blit(spship_red,(red.x,red.y))
display.blit(spship_yellow,(yellow.x,yellow.y))
def main():
red=pg.Rect(100,220,40,55)
yellow=pg.Rect(760,220,40,55)
run=True
while run:
clock.tick(60)
for event in pg.event.get():
if event.type==pg.QUIT:
run=False
key=pg.key.get_pressed()
move(key,red,yellow)
draw(red,yellow)
win.update()
pg.quit()
if __name__ == '__main__':
main()
You have to clear the display in ever frame:
def main():
red=pg.Rect(100,220,40,55)
yellow=pg.Rect(760,220,40,55)
run=True
while run:
clock.tick(60)
for event in pg.event.get():
if event.type==pg.QUIT:
run=False
key=pg.key.get_pressed()
move(key,red,yellow)
display.fill((255,255,255)) # <---
draw(red,yellow)
win.update()
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
Related
I created a class that has a function to draw a surface in screen now i want to append it in a list and draw it multiple times but also delete it from list after it has crossed screen
import pygame
pygame.init()
screen=pygame.display.set_mode((1000,600))
obs_list=[]
class obstacle():
def __init__(self):
self.surface=pygame.surface.Surface((50,50))
self.rect=self.surface.get_rect(center=(500,300))
def draw(self,screen):
screen.blit(self.surface,self.rect)
self.move()
def move(self):
self.rect.centerx+=2
def remove(self):
if self.rect.centerx>=800:
obs_list.remove(self)
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
screen.fill('white')
obs_list.append(obstacle())
for obs in obs_list:
obs.draw(screen)
pygame.display.flip()
i did this but it just kinda like drags the square in the screen leaving trail behind i don't know what is happening and if i am doing it wrong way or cant do what i am trying to do without using sprite
Since the ostacle is append to obs_list in the applicaition loop, the list will keep growing. And all obstacles from all past frames in the list are drawn in each frame. You have to append the obstacle to the list before the application loop instead of in the application loop:
obs_list.append(obstacle()) # <--- insert
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
screen.fill('white')
#obs_list.append(obstacle()) <--- delete
for obs in obs_list:
obs.draw(screen)
pygame.display.flip()
import pygame
import time
# WINDOW SETUP
window = pygame.display.set_mode((900, 500))
pygame.display.set_caption("Pong")
time.sleep(5)
FPS = 60
# RGB VALUE VARIABLES
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
def background(window):
window.fill(WHITE)
pygame.display.update()
# FRAMERATE AND EVENT LOOP INITIALIZATION
def main():
run = True
clock = pygame.time.Clock()
while run:
clock.tick(FPS)
background(window)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if running == False:
pygame.quit()
Above, is my code. I'm trying to make a pong game with pygame. The text editor I am coding with is Visual Studios Code (VSCODE).
Firstly, you need to call the main. You should also make you're code nice and easy to read when possible. I imported pygame as pg which makes typing pygame functions a bit faster as you have less to type. Also, it's better to use global variables to hold variables that won't change through the program, like screen width, height, colours, etc. Then make sure you initialise the module.
As well as that, the only update you have is in background(). You should put the update at the bottom of the loop and remove it from background(). This way everything above will update each loop.
I apologise for not adding you're FPS counter in here as well but I think this should be enough to help you get you're window running with more readable code and a more efficient loop.
import pygame as pg
# Global Variables
screen_width = 900
screen_height = 500
screen = pg.display
window = screen.set_mode((screen_width, screen_height))
colour = 'red'
def main():
# Initialise module
pg.init()
pg.display.set_caption('PONG')
running = True
while running:
# This is a better way of writing your loop
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
# Call background function
background()
# Updates window
# place this inside the loop near the bottom
# so everything is updated at the end of each loop
screen.flip()
def background():
window.fill(colour)
# Remember to call your main function
# This if statement is good practise but not required
# You can just place main() here
if __name__ == '__main__':
main()
this script is supposed to move 2 rectangles whenever the cursor gets in one of them, i see them flashing sometimes, but they're not moving, they move right 30 and then they go back to 0
import pygame
pygame.init()
screen= pygame.display.set_mode((700,500))
while True:
ex = pygame.Rect(30,30,60,60)
exz= pygame.Rect(0,30,30,60)
for event in pygame.event.get():
if event.type == 256:
pygame.quit()
if event.type == 1024:
cursor_pos=pygame.mouse.get_pos()
print(cursor_pos[1].__str__()+"=y")
print(cursor_pos[0].__str__()+"=x")
print(exz.x.__str__()+"exz.x"+", "+exz.y.__str__()+"exz.y")
if(cursor_pos[0]+cursor_pos[1]) < ((exz.x+30)+exz.y*3) and (cursor_pos[0]+cursor_pos[1])>30 and cursor_pos[1]<=90 and cursor_pos[1]>=30:
exz.right+=30
ex.right+=30
print("exz:"+exz.x.__str__()+", "+exz.y.__str__())
print("exs:"+ex.x.__str__()+", "+ex.y.__str__())
pygame.display.set_caption("Cursor is in area")
else:
pygame.display.set_caption("Cursor is not in area")
pygame.draw.rect(screen,(255,0,0),ex)
pygame.draw.rect(screen,(0,255,0),exz)
pygame.display.update()
screen.fill((50,50,50))
your last 5 lines should be inside the while loop block, to update the screen.
I don't know if this is what you wanted, but:
import pygame
pygame.init()
screen= pygame.display.set_mode((700,500))
ex = pygame.Rect(30,30,60,60) #this has to be outside of the while loop, otherwise the position resets every time
exz= pygame.Rect(0,30,30,60) #same of ex
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: #I don't know what 256 and 1024 means, but this is way better
pygame.quit()
#This has to be outside the for event loop
cursor_pos=pygame.mouse.get_pos() #you shall update the cursor every fps, and not by a if statement
if ex.collidepoint(cursor_pos) or exz.collidepoint(cursor_pos): #Idk what you did here, but i think this is just way simpler
exz.x+=30
ex.x+=30
pygame.display.set_caption("Cursor is in area")
else:
pygame.display.set_caption("Cursor is not in area")
pygame.draw.rect(screen,(255,0,0),ex) #the draws methods were outside the while loop
pygame.draw.rect(screen,(0,255,0),exz)
pygame.display.update()
screen.fill((50,50,50))
This code moves the two rects whenever the mouse gets inside of one of them.
Your glitching is because ex and exz are inside the while loop, so you were re-setting the position every time. I removed the prints but those were not a problem
I am creating a very simple game to try and ease into things, but ran into a problem pretty early on.
I have tried re-positioning where the timer is updated, but it just keeps flashing/flickering.
def update_timer():
global timer, timerrect
# make timer text
displaytext(f"{counter}", 50, 50)
# dispay timer
pygame.display.flip()
return timer, timerrect
def displaytext(text, a, b):
x = font.render(text, True, BLACK, WHITE)
xrect = x.get_rect()
xrect.center = (a, b)
screen.blit(x, xrect)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.USEREVENT:
counter-=1
update_timer()
# not-so-elegant displaying of timer
try:
screen.blit(timer, timerrect)
pygame.display.flip()
except:
pygame.display.flip()
# some more code here
# draw all sprites
all_sprites.draw(screen)
# fps
clock.tick(60)
# update screen
pygame.display.flip()
As I said, the timer is constantly flickering. I'd like for it to not induce seizures /s.
Most of the time, when something is flickering in Pygame, there is one cause: You are calling pygame.display.flip() more than once per frame.
You should remove all calls to pygame.display.flip() except the one in your main loop (the one you have commented # update screen). This means that the display is updated only once per frame.
When there are additional flips the screen updates on top of itself, and some frames may not end up with the timer visible.
Also, it looks like your update_timer function would work, if you remove the extra flip. Then you would not need the "not-so-elegant" code that you probably used to try debugging this problem.
I have created some sort of menu navigation system in my game. All the screens are blitted in. The "Play" and "Quit" and "Controls" button works just fine but when I try to press menu from the controls screen, nothing happens. On the controls screen, you can faintly see the first menu screen from before. That might be the problem. I think that as the return to menu button is over the previous controls page button, it somehow is pressing the controls button from before. The button and menu segment of my code will be pasted here and the full thing will be pasted in a pastebin.
def text_to_button(msg,color,buttonx,buttony,buttonwidth,buttonheight,size = "small"):
textSurf, textRect = text_objects(msg,color,size)
textRect.center = ((buttonx + buttonwidth/2)), buttony+(buttonheight/2)
gameDisplay.blit(textSurf, textRect)
def button(text,x,y,width,height,inactive_color,active_color,size = "small",action = None):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
#print(click)
if x + width > cur[0] > x and y + height > cur[1] > y:
pygame.draw.rect(gameDisplay, active_color,(x,y,width,height))
if click[0] == 1 and action != None:
if action == "quit":
pygame.quit()
quit()
if action == "controls":
game_controls()
if action == "play":
gameLoop()
if action == "main":
game_intro()
else:
pygame.draw.rect(gameDisplay, inactive_color,(x,y,width,height))
text_to_button(text,black,x,y,width,height,size)
def game_controls():
gcont = True
while gcont:
gameDisplay.blit(cont,(0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("Main Menu",320,500,150,50,white,gray,"tiny", action = "main")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
def game_intro():
intro = True
while intro:
gameDisplay.blit(imggg,(0,0))
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("ControLs",320,500,150,50,white,gray,"tiny", action = "controls")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
intro = False
Full Code: https://pastebin.com/jrd82gkJ
You will have very hard time to debug your code in order to achieve the behavior you want for one simple reason:
The logic you use to switch between different screens providing different functionality is causing much trouble you can't directly see if you only run the game.
So you think: "oh ... how come the button doesn't work, there must be an issue with the button".
You are probably not aware of the fact that using functions having own while loops you go deeper and deeper into recursive calls with increasing recursion depth with each switch from one view to another - it is not how pygame is thought to be programmed.
I suggest you add some print() commands into your code to see in the console output that the code doesn't really do what you expect even if it appears to be OK at the first glance because it works.
Then I suggest you REWRITE your entire code so that you have one main while notGameExit: loop, and don't use any other looping in the helper functions. If you want use looping in your helper functions at least don't call from the helper functions another functions with own loops (and so on), but RETURN from them with an explicit return to avoid recursion.
If you leave the in the main loop called function with return your main loop will continue running and depending on some switches you can display in it different things on the screen and react differently to user actions.
Maybe looking at a minimal working pygame script showing "action" without usage of a loop you will gain better understanding and some deep "enlightenment" about how pygame works and then start a total rewrite of your game using another approach as this one you have used in the current code? Then come back with what you have achieved if you have further questions, but you won't probably have any, because it would be much easier to debug it yourself if the code will become more straightforward.
import pygame
pygame.init() # start PyGame (necessary because 'import pygame' doesn't start PyGame)
winDisplay = pygame.display.set_mode((1024, 768)) # set PyGame window size to 1024x768 pixel
pygame.display.set_caption("Minimal PyGame Test Script")
# Time in pygame is measured in milliseconds (1/1000 seconds) (defined by TIMER_RESOLUTION constant):
pygame.TIMER_RESOLUTION = 1000 # assure 1000 explicit, don't relay on default value
colorWhite = (255, 255, 255) # RGB color in Pygame format (valueRed=255, valueGreen=255, valueBlue=255)
colorRed = (255, 0, 0)
colorGreen = ( 0, 255, 0)
colorBlue = ( 0, 0, 255)
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorRed)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorGreen)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorBlue)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds