Is there a way to save all the pixels that were in the place of a rect before drawing it? So that when I draw that rect again in a different place I can replace the old one with the saved pixels instead of filling that area with colors mamually?
You can define a subsurface that is directly linked to the source surface with the method subsurface:
subsurface(Rect) -> Surface
Returns a new Surface that shares its pixels with its new parent. The new Surface is considered a child of the original. Modifications to either Surface pixels will effect each other.
Create a copy of the subsurface to store it permanently:
rect_area = pygame.Rect(x, y, width, height)
area_surf = screen.subsurface(rect_area).copy()
Use the Surface later to replace the rectangular area:
screen.blit(area_surf, region)
This question already has an answer here:
Why is my collision test always returning 'true' and why is the position of the rectangle of the image always wrong (0, 0)?
(1 answer)
Closed 2 years ago.
player_rect = Pfront_n.get_rect()
Here 'Pfront_n' is a sprite, and I am getting a rect for that sprite. This is outside of the main loop. When inside the main loop, print(player_rect) shows that when my player moves, the rect doesn't follow. My players movement system is a velocity based one, if that makes any difference. How can I have the rect stay around the player?
Following this, I have another similar question...
for layer in room2:
r_x = 0
for tile in layer:
if tile == '2':
bat_create()
if tile == '1':
screen.blit(grass, (r_x*40, r_y*40))
if tile != '0':
tile_rects.append(pygame.Rect)
r_x += 1
r_y += 1
Outside the main loop, I have created a rect for grass in the same was as I have for my player. The method I am using in the above code has multiple grass blocks appear in positions pre-determined by an array. How can I get the rects for each individual grass block?
Fairly Irrelevant Sidenote for Context -The ultimate goal is to use my players rect, and the grass rect so my player gets stopped when hitting the grass. Any help on either of these questions would be great. Thanks!
The class Sprite has no method get_rect. Probably Pfront_n is a Surface. A surface has no position, not, a surface is blit at a position onto another surface. The x and y coordinate which is returned by get_rect() is (0, 0). But you can set the position. The keyword arguments to get_rect are set to the corresponding virtual attribute of pygame.Rect. e.g:
(player_x, player_y is supposed to be the position of the player)
player_rect = Pfront_n.get_rect(topleft = (player_x, player_y))
What is tile_rects.append(pygame.Rect) supposed to do? pygame.Rect is a class. If you want to append a pygame.Rect object, which represents a tile to tile_rects, then it has to be:
tile_rects.append(pygame.Rect(r_x*40, r_y*40, 40, 40))
This question already has an answer here:
Pygame Image position
(1 answer)
Closed 9 years ago.
I'm trying to implement collisions into my game but I do not know how to get the rect attributes for my images. The player gets to choose where the images spawn(he places them) so I cannot set an exact number etc.
The pygame.Surface object has a method get_rect which returns an instance of a pygame.Rect that encloses the Surface. Note that the position (x and y attributes of the Rect) starts at (0,0), but you can change this value and reference it whenever you blit to another surface.
So if you have a pygame.Surface named surf, and a screen surface called screen, you could do something like this:
surf_rect = surf.get_rect()
# move the surface 20 units to the right, and 15 units down
surf_rect.x += 20
surf_rect.y += 15
# now draw this surface to the screen based on the surf_rect's position
screen.blit(surf, (surf_rect.x, surf_rect.y))
http://www.pygame.org/docs/ref/surface.html#pygame.Surface.get_rect
Additionally, pygame.Surface also has get_width and get_height methods that are pretty self-explanatory.
I'm looking for the easiest way to implement this. I'm trying to implement platforms (with full collision detection) that you can draw in via mouse. Right now I have a line drawing function that actually draws small circles, but they're so close together that they more or less look like a line. Would the best solution be to create little pygame.Rect objects at each circle? That's going to be a lot of rect objects. It's not an image so pixel perfect doesn't seem like an option?
def drawGradientLine(screen, index, start, end, width, color_mode):
#color values change based on index
cvar1 = max(0, min(255, 9 * index-256))
cvar2 = max(0, min(255, 9 * index))
#green(0,255,0), blue(0,0,255), red(255,0,0), yellow(255,255,0)
if color_mode == 'green':
color = (cvar1, cvar2, cvar1)
elif color_mode == 'blue':
color = (cvar1, cvar1, cvar2)
elif color_mode == 'red':
color = (cvar2, cvar1, cvar1)
elif color_mode == 'yellow':
color = (cvar2, cvar2, cvar1)
dx = end[0] - start[0]
dy = end[1] - start[1]
dist = max(abs(dx), abs(dy))
for i in xrange(dist):
x = int(start[0]+float(i)/dist*dx)
y = int(start[1]+float(i)/dist*dy)
pygame.draw.circle(screen, color, (x, y), width)
That's my drawing function. And here's my loop that I have put in my main game event loop.
i = 0
while (i < len(pointList)-1):
drawGradientLine(screen, i, pointList[i], pointList[i + 1], r, mode)
i += 1
Thanks for any help, collision detection is giving me a huge headache right now (still can't get it right for my tiles either..).
Any reason you want to stick with circles?
Rectangles will make the line/rectangle a lot more smooth and will make collision detecting a lot easier unless you want to look into pixel perfect collision.
You also don't seem to save your drawn objects anywhere (like in a list or spritegroup), so how are you going to check for collision?
Here's a leveleditor I did for game awhile back, it's not perfect, but it works:
https://gist.github.com/marcusmoller/bae9ea310999db8d8d95
How it works:
The whole game level is divided up into 10x10px grid for easier drawing
The leveleditor check if the mouse is being clicked and then saves that mouse position
The player now moves the mouse to another position and releases the mouse button, the leveleditor now saves that new position.
You now have two different coordinates and can easily make a rectangle out of them.
Instead of creating a whole bunch of rect objects to test collision against, I'm going to recommend creating something called a mask of the drawn-in collideable object, and test for collision against that. Basically, a mask is a map of which pixels are being used and which are not in an image. You can almost think of it as a shadow or silhouette of a surface.
When you call pygame.draw.circle, you are already passing in a surface. Right now you are drawing directly to the screen, which might not be as useful for what I'm suggesting. I would recommend creating a rect which covers the entire area of the line being drawn, and then creating a surface of that size, and then draw the line to this surface. My code will assume you already know the bounds of the line's points.
line_rect = pygame.Rect(leftmost, topmost, rightmost - leftmost, bottommost - topmost)
line_surf = pygame.Surface((line_rect.width, line_rect.height))
In your drawGradientLine function, you'll have to translate the point coordinates to the object space of the line_surf.
while (i < len(pointList)-1):
drawGradientLine(line_surf, (line_rect.x, line_rect.y), i, pointList[i], pointList[i+1], r, mode)
i += 1
def drawGradientLine(surf, offset, index, start, end, width, color_mode):
# the code leading up to where you draw the circle...
for i in xrange(dist):
x = int(start[0]+float(i)/dist*dx) - offset[0]
y = int(start[1]+float(i)/dist*dy) - offset[1]
pygame.draw.circle(surf, color, (x, y), width)
Now you'll have a surface with the drawn object blitted to it. Note that you might have to add some padding to the surface when you create it if the width of the lines you are drawing is greater than 1.
Now that you have the surface, you will want to create the mask of it.
surf_mask = pygame.mask.from_surface(line_surf)
Hopefully this isn't getting too complicated for you! Now you can either check each "active" point in the mask for collision within a rect from your player (or whatever other objects you want to collide withe drawn-in platforms), or you can create a mask from the surface of such a player object and use the pygame.Mask.overlap_area function to check for pixel-perfect collision.
# player_surf is a surface object I am imagining exists
# player_rect is a rect object I am imagining exists
overlap_count = surf_mask.overlap_area(player_surf, (line_rect.x - player_rect.x, line_rect.y - player_rect.y))
overlap_count should be a count of the number of pixels that are overlapping between the masks. If this is greater than zero, then you know there has been a collision.
Here is the documentation for pygame.Mask.overlap_area: http://www.pygame.org/docs/ref/mask.html#pygame.mask.Mask.overlap_area
What would be the best way to use negative coordinates in pygame?
At the moment I have a surface that is 1.5 times the original surface then everything that needs to be drawn is shifted up by a certain amount (to ensure the negative coordinates become positive) and drawn.
Is there an easier/alternate way of doing this?
A simple solution is to write a linear mapping function from world coordinates to pygame screen coordinates
def coord(x,y):
"Convert world coordinates to pixel coordinates."
return 320+170*x, 400-170*y
and use it when drawing all world objects. Have a look here for a complete example.
There is no way to move the origin of a surface from 0,0.
Implement your own drawing class which transforms all the coordinates passed in into the space of the surface.
If it's similar to an RPG map situation, where you have world coordinates and screen coordinates:
use a function that translates world to local, and vice versa.
But I wasn't sure I'd you were looking for Rect's properties?
rect.bottomright = (width, height) # bottom right at window corner
If you want to use center coordinates to blit, vs top left being (0,0)
ship.rect.center = (20, 30) # don't need to translate by adding w/2 to topleft
See also: Rect.move_ip()