Pygame doesn't draw - python

I need help with a program I'm making. It's a version of Conway's Game of Life.
This game is right now made out of 3 files: main.py, cellBoard.py, cell.py
main.py takes care to instance cellboard and make it update its data, give it mouse input, and tell it to draw itself (an instance of the pygame surface is given to it, which handles it to the cells which are the actual ones that draw themselves)
cellboard.py creates a list of cells based off their size and the screen's size, to fill it properly. It's a 2D list. When it creates the cells it sets their state (alive currently) and handles them an instance of its instance of the original surface instance.
cell.py contains all the things a cell can do: die, live, be toggled, be drawn.
In fact, when I need to draw the whole board I just call cellBoard's own draw() and it should take care of calling each cell's draw. And it does.
The execution gets to the point where the cell should be drawn (checked with prints) and the pixel filling function is executed (using a for loop to cover an area). But nothing is actually drawn to the screen, or at least nothing is visible.
I have no idea what is causing this. I checked the code multiple times, I've even rewritten the whole program from scratch to make it more tidy (and I had the same problem as now)
What is causing this? My idea would be that somehow the instance of surface Cell gets is not good anymore to work because something happened to it (it goes through cellboard before getting to each cell, could that be the problem?)
Here's the source code (all 3 files, they are very short and barebones so they should be easy to read) http://dl.dropbox.com/u/2951174/src.zip
Thanks in advance to anyone who feels like helping. I need to complete this project very fast so your help would be greatly appreciated.

First of a quick suggestion:
People are much more likely to help you if they don't have to download a zip file, next time just post the code parts you suspect not to work.
Anyways, problem seems to be in your main loop:
#Keyboard events
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
running = 0
#Mouse events
#todo
#Grid update <------- here you update the grid and the cells are being drawn
cb.draw()
#Graphical output <------------ here you're filling the WHOLE screen with white
screen.fill(THECOLORS["white"])
pygame.display.flip()
You need to move your screen.fill call above cb.draw so you don't paint over the cells.
Also in cell.py your drawing code is A) Broken and B) bad.
Instead of setting every pixel on its own, which is slow and in it's current state doesn't draw the cells correctly, you can just as well draw rectangle:
pygame.draw.rect(self.surface, (100, 10, 10), (self.pos[0], self.pos[1], self.size, self.size))

Related

Replacing a surface instead of blitting to it

I'm having some performance issues in pygame, so I'm trying to optimize the rendering.
Currently, I'm blitting the background image to the display buffer:
self.display.blit(self.bg, (0, 0))
Instead, I'm looking for a way to replace the buffer with a copy of the background surface, and draw over that. This way, I don't have to blit a large image every frame, saving me some time.
Is there any way to do so?
It doesn't matter that much how often you blit something to the screen surface, since the display does only get updated once you call pygame.display.update or pygame.display.flip.
If you're sure that blitting the whole background image to the screen surface is a bottle neck in your game, you can try the following things:
a) Instead of blitting the whole background every frame, use the clear() function to "erase" your sprites from the screen.
b) Instead of calling pygame.display.flip or pygame.display.update without an argument, call pygame.display.update with the list of the areas on the screen that have been changed, which is returned by the draw() function (maybe in combination with clear()).
c) Create your display surface with the FULLSCREEN, DOUBLEBUF and HWSURFACE flags.
But as I already said: make sure you know where your bottle neck is. Some common performance pitfalls are: loading images multiple times from disk, font rendering, using different pixel formats (e.g. not calling convert/convert_alpha on surfaces created from images) and generally the lack of caching.
(also note that python/pygame is generally not the first choice when creating graphically demanding games)
Without seeing your code it will be hard to really see where the bottleneck is. Sloth is correct on his points as a way to optimize. in my experience all images should be pre-processed outside of the main game loop by drawing them onto their own surfaces. Blitting surfaces to surfaces is much faster than blitting images to surfaces.
img_surface = pygame.Surface((img_rect.width, img_rect.height), pygame.SRCALPHA)
img_surface.fill((0, 0, 0, 0))
img_surface.blit(get_image("my_image.png"), img_rect)
This happens outside the game loop. In the game loop you blit the image surface to your surface. If you really want to evaluate you code, use cProfile. This will help you nail down exactly where the bottleneck is. Do as much pre-processing outside the main game loop as possible.
Python getting meaningful results from cProfile
This link really helped me understand cProfile. Sloth is also correct in that pygame is limited, so you are going to need to optimize everything as much as you can. That is where cProfile comes in.
...Also, make sure you are only drawing things that are visible to the user. That can really help improve performance.

Making items appear from obstacles in game?

I'm making a game using Pygame where there are random obstacles on the screen (like boxes). The boxes can be removed by the player when they place a bomb next to it. I have some items that I would like to have randomly appear in place of the box if it is removed. I'm not sure how to go about this logically. Does anyone have any tips? No code is necessary (but helpful), I just want some steps logic-wise to get me started.
In order to have the box removed you need to call a ~destructor function on it, which would remove the image of the box and so on correct?
Take advantage of that and create a function that chooses which item to spawn (could be random, up to you) in the position where the box used to be.
Then call this function at the end of the destructor. That's how imagine it working.

(pygame) Empty squares displaying copies of what was previously there instead of background

I made a 2D project with a lot of tile sprites, and one player sprite. I'm trying to get the camera to follow the player, and for the most part it's working. However, there's one problem:
If you go to the edge of the map, it scrolls normally, but instead of the black background, it displays copies of the sprites on the edge of the map instead of the background (black). It has the same problem if I leave some squares empty, when I move it displays a copy of the tile that was previously there.
The camera works like this:
Select sprites that should be visible
Do sprite.visible = 1 for them, and sprite.visible = 0 for all other sprites
Set the position sprite.rect of all sprites to coords - offset
Update the screen (I use flip(), because the camera moves every turn, so the whole screen has to be updated every turn)
All DirtySprites have dirty = 2.
Does anyone know why it's displaying copies of the sprites on the edge instead of the background?
Help would be appreciated!
Unless you manually clear your screen surface, flip will not change its content.
Thus, if you neglect to draw to a certain location, it will remain the same.
If you want to get rid of this effect, usually called "hall of mirrors", you will have to keep track of what portions of the screen have not been drawn to yet and draw over these yourself.
It may be easier to define background sprites around your map's contours and block your camera from going off too far.
Since you use a "dirty/clean" approach to only redrawing what's changed, you won't have the option to just fill the whole screen surface before you draw your frame, because that would draw over anything that's stayed the same since the last frame.

Wrapping a pygame surface around a viewport

I'm coding a game where the viewport follows the player's ship in a finite game world, and I am trying to make it so that the background "wraps" around in all directions (you could think of it as a 2D surface wrapped around a sphere - no matter what direction you travel in, you will end up back where you started).
I have no trouble getting the ship and objects to wrap, but the background doesn't show up until the viewport itself passes an edge of the gameworld. Is it possible to make the background surface "wrap" around?
I'm sorry if I'm not being very articulate. It seems like a simple problem and tons of games do it, but I haven't had any luck finding an answer. I have some idea about how to do it by tiling the background, but it would be nice if I could just tell the surface to wrap.
I don't think so, I have an idea though. I'm guessing your background wraps horizontally and always to the right, then you could attach part of the beginning to the end of the background.
Example, if you have a 10,000px background and your viewport is 1000px, attach the first 1000px to the end of the background, so you'll have a 11,000px background. Then when the vieport reaches the end of the background, you just move it to the 0px position and continue moving right.
I was monkeying around with something similar to what you described that may be of use. I decided to try using a single map class which contained all of my Tiles, and I wanted only part of it loaded into memory at once so I broke it up into Sectors (32x32 tiles). I limited it to only having 3x3 Sectors loaded at once. As my map scrolled to an edge, it would unload the Sectors on the other side and load in new ones.
My Map class would have a Rect of all loaded Sectors, and my camera would have a Rect of where it was located. Each tick I would use those two Rects to find what part of the Map I should blit, and if I should load in new Sectors. Once you start to change what Sectors are loaded, you have to shift
Each sector had the following attributes:
1. Its Coordinate, with (0, 0) being the topleft most possible Sector in the world.
2. Its Relative Sector Coordinate, with (0, 0) being the topleft most loaded sector, and (2,2) the bottom right most if 3x3 were loaded.
3. A Rect that held the area of the Sector
4. A bool to indicate of the Sector was fully loaded
Each game tick would check if the bool to see if Sector was fully loaded, and if not, call next on a generator that would blit X tiles onto the Map surface. I
The entire Surface
Each update would unload, load, or update and existing Sector
When an existing Sector was updated, it would shift
It would unload Sectors on update, and then create the new ones required. After being created, each Sector would start a generator that would blit X amount of tiles per update
Thanks everyone for the suggestions. I ended up doing something a little different from the answers provided. Essentially, I made subsurfaces of the main surface and used them as buffers, displaying them as appropriate whenever the viewport included coordinates outside the world. Because the scrolling is omnidirectional, I needed to use 8 buffers, one for each side and all four corners. My solution may not be the most elegant, but it seems to work well, with no noticeable performance drop.

Pygame (Python) Scale Transform Slow

I'm writing a simple program in python which takes in data over the serial port and updates the screen.
Because I want this program to look the same on whatever computer it runs on, and it needs to be fullscreen, I had the idea that I wanted to draw everything in a small 640, 480 window, and then scale it to a fullscreen window every time I update the frame.
This allows me to keep all the offsets the same for text, etc. It also turns out this is really slow.
Here's about what the important part of the code looks like:
window = pygame.display.set_mode((1920, 1080),pygame.FULLSCREEN)
screenPrescaled=pygame.Surface((640,480))
clock=pygame.time.Clock()
while iterations<400:
#Blit all the stuff to the prescaled surface here
screenPostscaled=pygame.transform.scale(screenPrescaled,(1920, 1080))
window.blit(screenPostscaled,(0,0))
pygame.display.flip()
iterations+=1
clock.tick(40)
This runs a WHOLE lot slower than 40fps.
Everything on the screen is either text or lines, there are no images loaded.
I suspect I'm doing something stupid.
I know I can update "dirty rectangles" only, but I wonder if I'm missing something more fundamental.
Thanks in advance!
You can save one blit by using window as destination surface:
pygame.transform.scale(screenPrescaled, (1920, 1080), window)
If it continues being too slow, you should use update rectangles, you can scale them using the same factor as you scale the image 1920/640 and 1080/480.
The simplest thing is instead of using
pygame.display.flip()
is to use
pygame.display.update()
It's not that big of a difference but it worked pretty well for me on my game, especially when it uses a lot of pictures.
You are updating a huge screen by display.flip(). In SDL (and that's behind pygame) that is not a good idea (try removing everything put the flip, and see how fast that runs, it shouldn't by to much faster).
I have no way to measure, but I would guess the reason your code takes a long time is a problem with the .flip().
Since you are only working with data in 640x480, why are you scaling it up to such a huge dimension? Try setting your screen to 640x480, and take a look at how fast it will be then. It should run four or five times faster, I would think.

Categories