pygame drawing a filled rectangle overwrite border, but only sometimes? - python

I have a class in my pygame program that extends sprite, and effectively gives collision and whatnot to a rectangle. The __init__ of the class is as follows:
def __init__(self,topleft,size,label):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface(size)
self.rect = self.image.get_rect()
self.rect.topleft = topleft
self.image.fill([128,128,128])
pygame.draw.rect(self.image, [200,200,200], self.rect, 5)
And this works great... for one rectangle. Problem is, after that rectangle, any others are solidly colored rectangles set to the fill color (128,128,128) instead of being a filled rectangle with a differently colored (200,200,200) border. I'm expecting this is some sort of issue with class variables as opposed to instance variables, but I'm unsure where the problem lies.

Okay, I figured it out. The Rect argument in the draw function is relative to the position of the image. Since I had set its rect to its location on the screen, it was drawing the rectangle way offset from the corner. It worked on my first one only because it happened to start at [0,0]. Here is the fixed draw code:
pygame.draw.rect(self.image, [200,200,200],pygame.Rect([0,0],size), 5)

Related

using the pygame: [spritesheet].subsurface function, is there a way to draw the sprite from the bottom rather than the top left corner

I have a set of sprites, also on a spritesheet, which bounces slightly up and down, so the sprite height changes slightly.
By coding: spritesheet.subsurface(x, y, width, height), it will draw the sprite starting from (x, y) and then the width and height to the right and down respectively, however, when drawing the frames from the same screen-relative position, the sprite looks like the feet are moving down and up.
So that, if I had positioned frame 1 of the sprite to have the feet touching the floor, frame 2 would have the feet through the floor.
Is there a way to draw the sprite, say, from the bottom left, or bottom centre?
Many thanks
pygame.Surface.subsurface uses a rectangular area to create a new surface that references its parent. The origin (0, 0) of the pygame coordinate system is the top left. This cannot be changed.
However, if you know the bottom left coordinate (left_x, bottom_y) of a sprit on a spritsheet the rectangle of the sprite can be computed (spritesheet is a pygame.Surface object):
sheet_height = spritsheet.get_height()
sprite = spritsheet.subsurface((left_x, sheet_height - bottom_y - height, width, height))
The code can be made more comprehensible with a pygame.Rect object:
sheet_height = spritsheet.get_height()
sprite_rect = pygame.Rect(left_x, 0, height, height)
sprite_rect.bottom = sheet_height - bottom_y
sprite = spritsheet.subsurface(sprite_rect )

Pygame rect.centre attribute

So here is two parts of pygame python code:
a = self.img.get_rect(topleft = (self.x, self.y))
print(a.topleft)
The output of this code is :
(200, 189)
Another pygame code:
a = self.img.get_rect(topleft = (self.x, self.y)).center
print(a)
The output of this code:
(234, 213)
Note: The value of self.x is 200 and self.y is 200
So now my question is how after we put .center after the pygame rect object or the variable a when i print the value of a it changes and what does a .center after a pygame rect object do?
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, but it returns a rectangle that always starts at (0, 0) since a Surface object has no position. The position of the rectangle can be specified by a keyword argument. For example, the top left of the rectangle can be specified with the keyword argument topleft.
The pygame.Rect object has various virtual attriubtes:
The Rect object has several virtual attributes which can be used to move and align the Rect:
x,y
top, left, bottom, right
topleft, bottomleft, topright, bottomright
midtop, midleft, midbottom, midright
center, centerx, centery
size, width, height
w,h
You actually set the top left corner of a rectangle, the size of the image:
self.img.get_rect(topleft = (self.x, self.y))
Finally, you get the center point of this rectangle by reading the center attribute. Since the size of the image is not 0, the center differs from the topleft.

Pygame: How do I add an image to a rect?

I'm making my own game on Pygame, and I want to add images to rects instead of having a coloured rectangle.
I know how to add an image to pygame, but I want to know if there's some way to add the image and use the Pygame.rect properties such us rect.centerY and rect.centerX.
Does anyone know how?
Load your image, call its get_rect method to get a rect with the size of the image, then set the coordinates of the rect (there are several attributes like x, y, topleft, center, etc.) ...
IMAGE = pg.image.load('an_image.png').convert() # or .convert_alpha()
# Create a rect with the size of the image.
rect = IMAGE.get_rect()
rect.center = (200, 300)
... and pass the rect as the dest argument to pygame.Surface.blit to blit the image at the rect.topleft coordinates.
screen.blit(IMAGE, rect)

TypeError: argument 1 must be pygame.Surface, not pygame.Rect

pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((width_display,height_display))
pygame.display.set_caption("Ballzy")
ballImg = pygame.draw.circle(screen,(255,0,0),(250,250),36)
def ball(x,y):
screen.blit(ballImg,(x,y))
I got an error which said
TypeError: argument 1 must be pygame.Surface, not pygame.Rect
inside the ball function. This would work if the ball was an actual image but I need it to be a shape drawn in pygame.
The Pygame documentation says this about pygame.draw.circle:
pygame.draw.circle()
draw a circle around a point
circle(Surface, color, pos, radius, width=0) -> Rect
This means that this function returns a pygame rectangle. Pygame rectangles simply store a x and y coordinate and a width and height. This means that ballImg is a rectangle, not an image. It does not store any image data but rather just an area.
Your function ball blits ballImg to the screen.
def ball(x,y):
screen.blit(ballImg,(x,y))
The pygame documentation says this about blit:
blit()
draw one image onto another
blit(source, dest, area=None, special_flags = 0) -> Rect
Source should be a surface and dest should be a position where the image is blit on to.
In your code, however, you try and blit a rectangle to the screen, which does not work. In fact, when you call pygame.draw.circle(), you have already drawn the circle to the screen. You do not need to blit any images to the screen at all.
If instead of blitting ballImg to the screen in ball(), you simply draw a circle at the x and y coordinates as so, your problem should be fixed:
def ball(x,y):
pygame.draw.circle(screen, (255,0,0), (x, y), 36)

Drawn surface transparency in pygame?

I'm writing a predator-prey simulation using python and pygame for the graphical representation. I'm making it so you can actually "interact" with a creature (kill it, select it and follow it arround the world, etc). Right now, when you click a creature, a thick circle(made of various anti-aliased circles from the gfxdraw class) sorrounds it, meaning that you have succesfully selected it.
My goal is to make that circle transparent, but according to the documentation you can't set an alpha value for drawn surface. I have seen solutions for rectangles (by creating a separate semitransparent surface, blitting it, and then drawing the rectangle on it), but not for a semi-filled circle.
What do you suggest? Thank's :)
Have a look at the following example code:
import pygame
pygame.init()
screen = pygame.display.set_mode((300, 300))
ck = (127, 33, 33)
size = 25
while True:
if pygame.event.get(pygame.MOUSEBUTTONDOWN):
s = pygame.Surface((50, 50))
# first, "erase" the surface by filling it with a color and
# setting this color as colorkey, so the surface is empty
s.fill(ck)
s.set_colorkey(ck)
pygame.draw.circle(s, (255, 0, 0), (size, size), size, 2)
# after drawing the circle, we can set the
# alpha value (transparency) of the surface
s.set_alpha(75)
x, y = pygame.mouse.get_pos()
screen.blit(s, (x-size, y-size))
pygame.event.poll()
pygame.display.flip()

Categories