How to make a circle semi-transparent in pygame? - python

I'm somewhat new to pygame and trying to figure out how to make a circle semi-transparent. The trick however is that the background for the circle also has to be transparent. Here is the code I'm talking about:
size = 10
surface = pygame.Surface(size, size), pygame.SRCALPHA, 32)
pygame.draw.circle(
surface,
pygame.Color("black"),
(int(size/2), int(size/2)),
int(size/2), 2)
I tried using surface.set_alpha(127) but that didn't work. I'm assuming because the surface is already transparent.
Any help is appreciated.

A couple things. First, your surface definition should crash, as it missing a parenthesis. It should be:
surface = pygame.Surface((size, size), pygame.SRCALPHA, 32)
I assume that somewhere later in your code, you have something to the effect of:
mainWindow.blit(surface, (x, y))
pygame.display.update() #or flip
Here is your real problem:
>>> import pygame
>>> print pygame.Color("black")
(0, 0, 0, 255)
Notice that 255 at the end. That means that pygame.Color("black") returns a fully opaque color. Whereas (0, 0, 0, 0) would be fully transparent. If you want to set the transparency, define the color directly. That would make your draw function look like:
pygame.draw.circle(
surface,
(0, 0, 0, transparency),
(int(size/2), int(size/2)),
int(size/2), 2)

Related

How to create a grid using pygame

I have created a surface but i am not sure how to make a grid because i have tried using the rectangle function but do not fully understand the parameter.
import pygame
pygame.init()
Background = pygame.display.set_mode((900,900))
pygame.draw.rect(Background,green,_____)
I don't understand how i am suppose to use this to create grid because even if i can get the code to work, I don't know how to position the item and there must be a more efficient way to create a grid rather then manually creating and positioning each box.
There is a better way - you should use loops to create grids. The third argument for the pygame.draw.rect is a rectangle, meaning four values that are packed together (say in a tuple): start x, start y, width and height - but lines are more useful for grids usually. This will draw a simple grid, with spaces of 50 pixels, and then keep the display active with a loop:
import pygame
pygame.init()
Background = pygame.display.set_mode((900 ,900))
for i in range(0, 900, 50):
pygame.draw.line(Background, (255, 255, 255), (0, i), (900, i))
pygame.draw.line(Background, (255, 255, 255), (i, 0), (i, 900))
pygame.display.update()
while pygame.event.wait().type != pygame.QUIT:
pass
Really the only slightly complex part here is the lines. The first to arguments are the same as they are for rectangles. The last two arguments are a starting point for the line and an ending point, and optionally you could add width, which I didn't - in which case the get the default width of 1 pixel.

How do I make a circle semi-transparent in pygame?

I want to make a partially transparent circle as an area of effect indicator, but I haven't found any way to do this in pygame.
I tried passing in an rgba 4-tuple as an argument (as suggested by this post), but it didn't change the transparency at all. On top of that, according to this other post, the method shouldn't work at all, since draw doesn't accept alpha values. That's conflicting information.
pygame.draw.circle(screen, (255, 0, 0, 100), (x, y), r)
I've also tried creating a new surface, drawing the circle onto that surface, and then blitting the new surface onto my game screen (as suggested by this post). It gives me a semi-transparent circle as requested, but since surfaces in pygame are rectangular, it also gives me a gray rectangle around the circle, which I don't want.
s = pygame.Surface((1000, 1000))
s.set_alpha(100)
pygame.draw.circle(s, (255, 0, 0), (x, y), r)
screen.blit(s, (0, 0))
Is there any way to make this circle semi-transparent without adding any other visible effects to my screen?
Here's a runnable version of the answer to the last question you linked to titled How to draw a semi-transparent circle in Pygame?. It seems to do what you want, as far as I can tell.
import pygame
width, height = 640, 480
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((width,height))
surface = pygame.display.set_mode((width,height), pygame.SRCALPHA)
while True:
msElapsed = clock.tick(100)
screen.fill((255,255,255))
pygame.draw.circle(surface,(30,224,33,100),(250,100),10)
screen.blit(surface, (0,0))
pygame.display.update()
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()

Is there a way to copy a certain section of a surface using Surface.copy()?

I am new to dirty rect animation and I am currently trying to store a snapshot of the main display surface window, however I would only like to store the area where my item is going to be blit so the next frame I can call this stored snapshot instead of re blitting the whole background.
I looked at the documentation for Surface.copy() but it doesn't take arguments and I couldn't find anything similar other than pygame.pixelcopy() which from what I understand is not what I am looking for. If Surface.copy() isn't what I am looking for, please let me know of alternatives.
import pygame, time
pygame.init()
screen = pygame.display.set_mode((500, 500))
screen.fill((128, 128, 128))
pygame.display.update()
#immagine a complex pattern being blit to the screen here
pygame.draw.rect(screen, (128, 0, 0), (0, 0, 50, 50))
pygame.draw.rect(screen, (0, 128, 0), (50, 0, 50, 50))
pygame.draw.rect(screen, (0, 0, 128), (200, 0, 50, 50))
#my complex background area that i want to save ()
area_to_save = pygame.Rect(0, 0, 100, 50)
rest_of_background = pygame.Rect(200, 0, 50, 50)
#updating for demo purposes
dirty_rects = [area_to_save, rest_of_background]
for rect in dirty_rects:
pygame.display.update(rect)
temp_screen = screen.copy()
time.sleep(3)
#after some events happen and I draw the item thats being animated onto the background
item_to_animate = pygame.Rect(35, 10, 30, 30)
pygame.draw.rect(screen, (0, 0, 0), item_to_animate)
pygame.display.update(item_to_animate)
time.sleep(3)
item_to_animate = pygame.Rect(50, 60, 30, 30)
pygame.draw.rect(screen, (0, 0, 0), item_to_animate)
#now that the item has moved, draw back old frame, which draws over the whole surface
screen.blit(temp_screen, (0, 0))
pygame.display.update()
#I understand swapping the drawing of the new item location to after temp_surface blit
#will provide me the desired outcome in this scenario but this is a compressed version of my problem
#so for simplicity sake, is there a way of not saving the whole surface, only those rects defined?
I expect the output of this code to be displaying my background for 3 seconds, then the black square overlaying the patter and then after another 3 seconds, the black square appearing below my pattern.
P.S.:I am new to this site, let me know if I did something wrong please!
Edit: For anyone wondering if this solution (of saving the background before blitting an item over it and then redrawing the saved background before the new item location is blit over) is more efficient than redrawing the whole background and then blitting the item, using a simple square animation over a chequered pattern with redrawing the whole background each time reduced my overall fps by around 50% from 1000 (before redrawing the background) to 500 average. While using dirty rects and this method above I get around 900 fps.
What you want to do can be achieved by pygame.Surface.blit().
Create a surface with the decided size and blit an area of the screen to this surface. Note, the 3rd argument to bilt is an optional parameter which selects a rectangular area of the source surface:
# create a surface with size 'area_to_save.size'
temp_screen = pygame.Surface(area_to_save.size)
# blit the rectangular area 'area_to_save' from 'screen' to 'temp_screen' at (0, 0)
temp_screen.blit(screen, (0, 0), area_to_save)
You could use subsurface to specify the area you want to copy, and then call copy on the returned Surface.
But note that it may happend that this will not increase the performance of your game at all, since copying a lot of Surfaces around does not come free. Just try and check yourself if it actually better then drawing a background surface every frame.
Also note that you should never use time.sleep in your game. While sleep is blocking your game's process, your game can't process events, so you e.g. can't quit the game in this time. Also, it may happen that your game's window will just not be redrawn if you don't process events by calling pygame.event.get; and once the event queue fills up because you never call pygame.event.get, your game will freeze.

Is there a way to change the Python Imaging Library (PIL)'s default fill color?

I'm currently using Python Imaging Library's (PIL) transform with EXTENT function to allow users to do some basic editing of images i.e. simple zoom in / zoom out, x and y-axis offsets, set background color, rotation etc
And so one problem is that they are able to zoom out or offset enough so that parts of the final output image goes beyond the bounds of the source image. When this happens, PIL fills this portion with a black color
Does anybody know if there's a way to set a custom fill color rather than the black default or has any suggestions on ways to get around this? Much appreciated
I was originally thinking of pre-pasting an alpha layer to where the bounds are exceeded but this seems to get complicated quite quickly..
[Edit] Maybe this will help. So, do something like (don't pay too much attention to the exact integers ) ...
image2 = image1.transform((600, 400), Image.EXTENT, (0, 0, 1200, 800))
draw = ImageDraw.Draw(image2)
# Fill in rectangle below the real image
draw.rectangle( (0, 50, 1200, 600), fill=(255, 150, 0))
# Fill in rectangle to the right of the real image
draw.rectangle( (100, 0, 800, 50), fill=(150, 255, 0))
del draw
image2.save(SAVE_NAME)

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