Avoid to reload a background at every frame in pygames - python

I want to make a game using pygames in python and I have a background which I want to load only at the beginning of the game not at every frame and the background should still appear.
I load the background like this in a init function:
self.window = pygame.display.set_mode((self.SCREEN_WIDTH, self.SCREEN_HEIGHT))
self.screen = pygame.display.get_surface()
self.rasp = "../images/image.jpg"
self.rasp_surface = pygame.image.load(self.rasp)
self.rasp_surface = pygame.transform.scale(self.rasp_surface, (self.SCREEN_WIDTH, self.SCREEN_HEIGHT))
self.screen.blit(self.rasp_surface, (0,0))
and in a run function I do this :
while True:
...
self.screen.blit(self.rasp_surface, (0,0))
pygame.display.update()

If you have a while loop with pygame.display.update() in it, you are constantly doing this. This is unnecessary. However, it is likely you are moving sprites or images over the background, so just make sure to fill in the portion of the image that the sprite is moving over as it moves. You can make a move function to do that for you.

Related

Pygame and pygame.time.wait() function is working in a bizarre way

I am trying to change the pygame screen. First, I draw a rect. Then, I fill the screen again. In-between I add wait function to see the change. When I run program, screen starts black and waits for every wait function without doing any changes. Then, it shows the end result.
import pygame
BlockList=[]
pygame.init()
block_side_length=30
black = 0,0,0
GameArea_start_x=5
GameArea_start_y=5
GameArea_width=300
GameArea_height=270
gameDisplay = pygame.display.set_mode((400,300))
pygame.display.set_caption("Tetris")
gameDisplay.fill((0,100,100))
GameArea = pygame.draw.rect(gameDisplay,black,[GameArea_start_x,GameArea_start_y,GameArea_width,GameArea_height])
lowest_block_y =GameArea_start_y+GameArea_height-block_side_length
pygame.time.wait(2000)
gameDisplay.fill((0,100,100))
pygame.draw.rect(gameDisplay,(0,250,0),[50,50,40,90])
pygame.time.wait(2000)
gameDisplay.fill((0,100,100))
GameArea
Output:
After 4 secs
Note: I am trying to draw the rectangle by calling its name. It doesn't work. Is there any similar fashion?
In order to update what is shown in the pygame window, you must call pygame.display.update(), like so:
import pygame
BlockList=[]
pygame.init()
block_side_length=30
black = 0,0,0
GameArea_start_x=5
GameArea_start_y=5
GameArea_width=300
GameArea_height=270
gameDisplay = pygame.display.set_mode((400,300))
pygame.display.set_caption("Tetris")
gameDisplay.fill((0,100,100))
GameArea = pygame.draw.rect(gameDisplay,black,[GameArea_start_x,GameArea_start_y,GameArea_width,GameArea_height])
lowest_block_y =GameArea_start_y+GameArea_height-block_side_length
pygame.display.update()
pygame.time.wait(2000)
gameDisplay.fill((0,100,100))
pygame.draw.rect(gameDisplay,(0,250,0),[50,50,40,90])
pygame.display.update()
pygame.time.wait(2000)
gameDisplay.fill((0,100,100))
pygame.display.update()
Note that your approach of calling pygame.time.wait() for long periods of time will cause the window to freeze and become unresponsive while waiting. Some better approaches are described in this stackoverflow question.

Take screenshot then blit it

Is there a way to take a screenshot (a copy of the previous frame blitted) with pygame from the GUI, assign it to a surface variable and blit it? Without saving the screenshot to a file, then loading it, and finally blitting it,
import pygame, os
pygame.init()
screen = pygame.display.set_mode((800, 400))
def TakeScreenShot(screen):
pygame.image.save(screen, 'ScreenShot.png')
pic = pygame.image.load(os.path.join('ScreenShot.png')).convert()
return pic
pic = TakeScreenShot(screen)
screen.blit(pic, [0,0])
pygame.display.flip()
The saving screenshot then loading seems really unneccsary...is there a method to bypass this and directly blit the screenshot taken to the GUI?
I.e., something such as,
import pygame, os
pygame.init()
screen = pygame.display.set_mode((800, 400))
pic = screen.getLastFrameBlitted()
screen.blit(pic, [0,0])
pygame.display.flip()
You can take a copy of the screen anytime you want and save it in a variable.
screenshot = screen.copy()
screen is just a regular Surface object and can be treated as such. Blitting the screenshot is done as usual
screen.blit(screenshot, (0, 0))

How to use pygame.surface.scroll()?

I just found out about pygame.surface.scroll() and what I understand from the pygame documents that scroll() is for moving surface without the need to rebuild the background again to cover the old surface, just like pygame.rect.move_ip() but for surfaces.
Anyway, I don't know how to use it and the examples in the pygame documents are hard to me to understand as long as I am beginner and, after searching for long time, I couldn't found anything useful to understand how to use it.
Here is my code.
import pygame
from pygame.locals import*
screen=pygame.display.set_mode((1250,720))
pygame.init()
clock=pygame.time.Clock()
boxx=200
boxy=200
image = pygame.Surface([20,20]).convert_alpha()
image.fill((255,255,255))
while True :
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type==pygame.QUIT :
pygame.quit()
quit()
image.scroll(10,10)
screen.blit(image,(boxx,boxy))
pygame.display.update()
clock.tick(60)
EDIT: Your image and screen variables are backwards. That is also causing you some confusion I'm sure..
Your problem may is that you are trying to scroll an all black background. It is probably scrolling, and you just don't know it because the white box you used blit() to draw on the screen is stationary.
Try using something you can see scroll, like an image file. If you wanna move the white box, you can add a counter as a speed variable. Read this, then run it.
import pygame
from pygame.locals import*
screen=pygame.display.set_mode((1250,720))
pygame.init()
clock=pygame.time.Clock()
boxx=200
boxy=200
image = pygame.Surface([20,20]).convert_alpha()
image.fill((255,255,255))
speed = 5 # larger values will move objects faster
while True :
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type==pygame.QUIT :
pygame.quit()
quit()
image.scroll(10,10)
# I did modulus 720, the surface width, so it doesn't go off screen
screen.blit(image,((boxx + speed) % 720, (boxy + speed) % 720))
pygame.display.update()
clock.tick(60)
I can't say for sure the scroll function is working or not, learn to use an image as your background so you can see it moving first.

How can I load a huge image with pygame as a background?

I'm making a fighting game in pygame but whenever I load a background (940x680 PNG) the program starts to lag really badly, here is my code:
#import section
import os
import pygame
import time
from pygame.locals import *
#end of import section
#initiazing pygame
pygame.init()
print "Loaded Pygame 100%"
#lengths
width, height = 940,680
#opening window
screen = pygame.display.set_mode((width, height))
#position
background = [0,0]
#loading images
back = pygame.image.load("resources/image/Back.png")
print "Loaded graphics 100%"
while 1:
#clear to reload
screen.fill(0)
#drawing background
screen.blit(back, background )
#update
pygame.display.flip()
This may be a newbie question but I just started so yeah...
In pygame you need to use this code you wrote.
#clear to reload
screen.fill(0)
#drawing background
screen.blit(back, background )
#update
pygame.display.flip()
If you add a player to the screen and then move him. You will notice that unless you redraw the background, you will see the character more than once.
Pygame doesn't just let you add an image to the screen and move it around, you must redraw the background to get rid of a previous frame.
Another thing you should add to your code is a wait.
clock = pygame.time.Clock()
FPS = 30
while 1:
clock.tick(FPS)
This will set the frame rate. I'd say you would generally want this at 30 - 60 frames, depending on the game / hardware.
Your current program is probably redrawing the frame a several hundred times, so this will definately add lag.
When I checked this on my pc Ubuntu 12.04 without a background. i.e. A Black screen.
My frame rate was between 1000 - 2000 FPS.

How to get rid of pygame surfaces?

In the following code, there is not just one circle on the screen at any given point in time.
I want to fix this to make it so that it looks like there is only one circle, instead of leaving a smudge trail where ever the mouse cursor has been.
import pygame,sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((640,400),0,32)
radius = 25
circle = pygame.Surface([radius*2]*2,SRCALPHA,32)
circle = circle.convert_alpha()
pygame.draw.circle(circle,(25,46,100),[radius]*2,radius)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
screen.blit(circle,(pygame.mouse.get_pos()[0],100))
pygame.display.update()
pygame.time.delay(10)
You need to specifically erase the circle before you blit it again. Depending on how complicated your scene is, you may have to try different methods. Generally what I do is have a "background" surface that a blit to the screen every frame and then blit the sprites/other surfaces in their new positions (blits in Pygame are very fast, so even in fairly large screens I haven't had speed issues doing this). For your code above, it's simple enough just to use surface.fill(COLOR) where COLOR is your background color; eg, (255,255,255) for white:
# ...
screen = pygame.display.set_mode((640,400),0,32)
backgroundColor = (255,255,255)
# ...
while True:
# ...
screen.fill(backgroundColor)
screen.blit(circle,(pygame.mouse.get_pos()[0],100))
pygame.display.update()
pygame.time.delay(10)
Edit in answer to your comment: It is possible to do this in a more object-oriented way.
You will need to have a background Surface associated with your screen (I usually have a Display or Map class (depending on the type of game) that does this). Then, make your object a subclass of pygame.sprite. This requires that you have self.image and self.rect attributes (the image being your surface and the rect being a Pygame.rect with the location). Add all of your sprites to a pygame.group object. Now, every frame, you call the draw method on the group and, after you update the display (ie, with pygame.display.update()), you call the clear method on the group. This method requires that you provide both the destination surface (ie, screen above) and a background image.
For example, your main loop may look more like this:
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
circle.rect.center = (pygame.mouse.get_pos()[0],100)
circleGroup.draw(screen)
pygame.display.update()
circleGroup.clear(screen, backgroundSurface)
pygame.time.delay(10)
See the documentation on the Sprite and Group classes for more information.

Categories