I am using pygame and python for a project I am building, and I am building a splashscreen for when the game first opens. I have a .png that I want to show for the splashscreen, and decided to fade it in and out from black. the best way I found to do this was by blitting the image with a set alpha. I made this code, but it runs really slowly (the program hangs for 30 seconds) and doesn't give an alpha. Only displays the picture onscreen. What am i doing wrong?
screen = pygame.display.set_mode([1066,600])
#Drawable surface
background = pygame.Surface(screen.get_size())
#Used for converting color maps
background = background.convert()
#Splashscreen
#image fades in
for i in range (225):
background.fill((0,0,0))
image = pygame.image.load("logo.png")
image.set_alpha(i)
logoimage = screen.blit(image,(0,0))
pygame.display.flip()
pygame.time.delay(2000)
#image fades out
#goes on to display main menu
Another problem that you might be having (besides what monkey said) is that you might need to use surface.convert() which converts the image into a form where the alpha can be changed. You can do either of the following.
image = pygame.image.load("logo.png")
image = image.convert()
or
image = pygame.image.load("logo.png").convert()
I have found that, although surface.convert_alpha() should do pretty much the same thing, it doesn't usually work. Try this test code to check.
import pygame, sys
pygame.init()
window=pygame.display.set_mode((1500, 800))
background=pygame.Surface((window.get_rect().width, window.get_rect().height))
background.fill((0, 0, 0))
image=pygame.image.load('InsertImageHere.png')
image=image.convert()
image2=pygame.image.load('InsertImage2Here.png')
image2=image2.convert_alpha()
rect=image.get_rect()
rect2=image2.get_rect()
rect2.left=rect.width+1
i=1
while True:
for event in pygame.event.get():
if event.type==12:
pygame.quit()
sys.exit()
image.set_alpha(i)
image2.set_alpha(i)
window.fill((255, 255, 255))
window.blit(background, background.get_rect())
window.blit(image, rect)
window.blit(image2, rect2)
pygame.time.delay(20)
i+=1
if i==255:
i=1
pygame.display.update()
In my testings, image 1 faded in properly, but image 2 stayed dark the whole time. You should try it for yourself; your computer might work differently.
If surface.convert_alpha() does work for you, you should use it, otherwise, do what I said before. This should solve your problem.
You should also note that I used pygame.time.delay(20) rather than 2000 like you had before. 2000 would be a bit too long if you are increasing the alpha in incraments of one.
[1] You don't want to load the image every iteration. Because creating a new surface is a slow operation. [2] Your loop draws 225 times, then afterward the final iteration, waits 2000ms.
You want:
image = pygame.image.load("logo.png")
for i in range (225):
background.fill((0,0,0))
image.set_alpha(i)
screen.blit(image,(0,0))
pygame.display.flip()
pygame.time.delay(20)
To fade in and out, you need to keep looping until the player clicks/hits a button. Like this:
import pygame
from pygame.locals import *
# ...
def title_loop():
# title screen main loop
image = pygame.image.load("logo.png")
done = False
alpha = 0
alpha_vel = 1
# fade alpha in-out while waiting
while not done:
# get key input
for event in pygame.event.get():
if event.type == QUIT:
done = true
if event.type == KEYDOWN:
if event.key = K_ESCAPE:
done = true
# draw
if alpha >= 255 or alpha <= 0:
alpha_vel *= -1
alpha += alpha_vel
background.fill((0,0,0))
image.set_alpha(i)
screen.blit(image,(0,0))
pygame.display.flip()
pygame.time.delay(20)
PygameNerd your example is close, but it doesn't really work.
The image.convert() will fade properly, but it doesn't support alpha channel. Try it on a non black background & it shows.
The image.convert_alpha() will not fade, but the alpha channel does work properly.
I'm surprised that pygame doesn't support this out of the box, but anyway. Here is an answer:
http://www.nerdparadise.com/tech/python/pygame/blitopacity/
Its a bit complex, but works fine. Transparent background & fading all in one package.
Related
I just started playing around with python a bit and tried to do some silly grafix stuff to see how it worked. Now I got stuck with one precise problem: I am trying to read the color value of a pixel from a pygame surface - but I can't. The below code - which I found in several (perhaps outdated) manuals and samples - throws an error I don't understand:
(Line 38 is the one containing the "screen.get_at()" part)
File "/home/mark/devel/python/./test.py", line 38, in
color = screen.get_at((x, y))
TypeError: 'list' object cannot be interpreted as an integer
What I guess from the stuff I found online: pygame.surface changed the type of the return value for get_at() a short while ago. Now it doesn't return four integers for R, G, B and alpha. but it returns a type "color". However, I was unable to find an explanation what this type "color" actually is or how it works, resp. how I get just the RGB values out of it.
A shortened sample of my code which throws the above error is as follows:
#!/usr/bin/python3
import pygame
from pygame.locals import *
import numpy as np
WIDTH = 1200
HEIGHT = 800
WHITE = (255, 255, 255)
pygame.init()
# Set width and height of the screen
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Ant")
pygame.draw.rect(screen, WHITE, (0,0,WIDTH,HEIGHT))
pos = ([0],[0])
# Loop until the user clicks the close button.
done = False
clock = pygame.time.Clock()
# Loop as long as done == False
while not done:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: # If user wants to exit
done = True # Flag that we are done so we exit this loop
x = pos[0] # horizontal position
y = pos[1] # vertical position
color = screen.get_at((x, y))
print (color)
pygame.display.flip()
# This limits the while loop to a max of 60 times per second.
# Leave this out and we will use all CPU we can.
clock.tick(600)
# Be IDLE friendly
pygame.quit()
I'd really appreciate if someone could give me a hint how to get the RGB (integer) values from this "color" type get_at() returns.
thx,
Mark
I am trying to make a game where if someone press left-click, pygame draws a circle, then a line connecting the circle to the upper left corner. If he/she press right-click, it removes everything created from the screen. I thought about just covering everything with a big black square, but that is not really clearing the screen, just covering it. My code is as follow:
from pygame import *
init()
size = width, height = 650, 650
screen = display.set_mode(size)
button = 0
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
def drawScene(screen, button):
# Draw circle if the left mouse button is down.
if button==1:
draw.circle(screen,GREEN,(mx,my), 10)
draw.line(screen,GREEN, (0,0),(mx,my))
if button == 3:
mouse.set_visible(False)
display.flip()
running = True
myClock = time.Clock()
# Game Loop
while running:
for e in event.get(): # checks all events that happen
if e.type == QUIT:
running = False
if e.type == MOUSEBUTTONDOWN:
mx, my = e.pos
button = e.button
drawScene(screen, button)
myClock.tick(60) # waits long enough to have 60 fps
quit()
Kindly guide me in this situation. Thanks in advance.
I thought about just covering everything with a big black square, but that is not really clearing the screen, just covering it.
There is not any difference between cover and clear. The screen consist of pixels. Drawing an object just changes the color of the pixels. Drawing a black square changes the color of the pixel again.
Note, operations like pygame.draw.circle() and pygame.draw.line() do not create any object. They just change the colors of some pixels of the surface which is passed to the operation.
The easiest way to clear the entire window is pygame.Surface.fill():
screen.fill((0, 0, 0))
respectively
screen.fill(BLACK)
In computer graphics, there is no such thing as "clearing" a screen. you can only overwrite the previous drawing with new pixels. your idea of drawing a big black rectangle would work perfectly but I may be more efficient to use screen.fill(0)
I am a beginner in Pygame. I have coded a function for moving two balls in different direction and I follow the instructions coding it but it seems to be not working. I can draw two balls in screen but they will not move. I fixed it for almost 1 hour but no idea why balls aren't moving.
So, Can someone helps me check my code and just give me some hints. I will really appreciate anyone who helps me!
My code shows below
import pygame,sys,time
from pygame.locals import *
# User define function
def ball_move(Surface,white,pos,rad,speed):
size=Surface.get_size()
for item in [0,1]:
pos[item]=pos[item]+speed[item]
if pos[item]<rad:
speed[item]=-speed[item]
if pos[item]+rad>size[item]:
speed[item]=-speed[item]
# Open a brand-new window
pygame.init()
Screen_size = (500,400)
Title = ('Pong')
Frame_Delay = 0.01
Surface= pygame.display.set_mode(Screen_size,0,0)
pygame.display.set_caption(Title)
# Set up white color for drawing balls
white=pygame.Color('white')
# Now, we start to draw two balls
pos1=(100,200)
pos2=(400,200)
rad=10
ball1=pygame.draw.circle(Surface,white,pos1,rad,0)
ball2=pygame.draw.circle(Surface,white,pos2,rad,0)
pygame.display.update()
# Now, define speed
speed1=(2,-2)
speed2=(-2,2)
# Now, we define a loop
while ball1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Now, we move the ball
ball1move=ball_move(Surface,white,pos1,rad,speed1)
ball2move=ball_move(Surface,white,pos2,rad,speed2)
pygame.draw.circle(Surface,white,pos1,rad,0,0)
pygame.draw.circle(Surface,white,pos2,rad,0,0)
surface.fill(pygame.Color('black'))
Part of saulspatz answer is correct, part is incorrect. You don't have to use sprites if you dont want to. pygame.draw is not pretty but perfectly usable. The main problem does seem to be your understanding of what to do in your event loop. All this should go in it:
while running:
# Handdle your events
# update your state
# draw to your display
pygame.display.update()
Also I notice in your unreachable code after the loop you are filling after your draws. Remember whether you fill, blit, or draw the latest thing goes over the rest. So for your example:
import pygame ,sys, time
from pygame.locals import *
# User define function
def ball_move(surface, pos, rad, speed):
def _add(l_pos, l_speed, l_size):
l_pos += l_speed
if l_pos <= rad or l_pos >= l_size - rad:
l_speed = -l_speed
return l_pos, l_speed
size = surface.get_size()
pos_x, speed_x = _add(pos[0], speed[0], size[0])
pos_y, speed_y = _add(pos[1], speed[1], size[1])
return (pos_x, pos_y), (speed_x, speed_y)
pygame.init()
screen_size = (500, 400)
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption('Pong')
running = True
pos1 = (100, 200)
pos2 = (400, 200)
speed1 = (2, -2)
speed2 = (-2, 2)
rad = 10
while running:
# Handdle your events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# update your state
pos1, speed1 = ball_move(screen, pos1, rad, speed1)
pos2, speed2 = ball_move(screen, pos2, rad, speed2)
# draw to your display
screen.fill(pygame.Color('black'))
pygame.draw.circle(screen, pygame.Color('white'), pos1, rad)
pygame.draw.circle(screen, pygame.Color('white'), pos2, rad)
pygame.display.update()
There are a lot of problems with your code. The most basic is that you haven't figured out how event-driven programming works. You need to put the code that moves the balls inside your loop.
Another problem is that I don't think you want to use the pygame.draw module. It's been a long time since I wrote any pygame scripts, but as I remember, this module is useful for drawing fixed objects, like the background. A quick look at the docs seems to confirm this.
For moving objects, I think you need to look at the pygame.sprite module. Even if you got this code to work, it wouldn't move the balls. It would just draw a new ball at another position. So you would have first two balls, then four, then eight, ... . Sprites actually move. Not only is the object drawn at the new position, but it's erased at the old position. Your code don't address erasure at all.
Hope this helps.
I have the general outline code. But i need a background which can change color once you run the program at an reasonable speed between the colors red, green, blue, black and white. I know it has to do with the while loop, i just do not know how to incorporate it.
from __future__ import division
import pygame
pygame.init()
width = 640
height = 480
size = (width, height)
screen = pygame.display.set_mode(size)
background = (0,0,0)
fps = 60
clock = pygame.time.Clock()
while True:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
screen.blit(background)
pygame.display.flip()
clock.tick(1)
If you already know that colors are composite of red, green and blue that will help you already, those are called color channels and change between 0 and 255. I would first take a paper and draw how would change each of the channels with time. So you'll have 3 functions on the same time scale. Then I would brake the time axis in sections, where the functions are linear (or some other standard function), and define the function depending on in which section I am now. I gave just a general approach, since it's quite a big amount of job to do.
Another approach is to set up the table will the sequence of all colors that are to be shown and just cycle through them in a loop and filling the display.
I am asking if it is possible to draw a list of sprites in Pygame, and if so how?
I am attempting to draw from a two dimensional list, that will draw the map
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode([screen_width, screen_height])
pygame.init()
image = pygame.image.load("Textures(Final)\Grass_Tile.bmp").convert()
imagerect = image.get_rect()
tilemap = [
[image, image, image],
[image, image, image]
]
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
screen.blit(tilemap, imagerect)
clock.tick(20)
pygame.display.flip()
pygame.quit()
I know I can do something much simpler, like drawing each image. But, I am wondering if I can do this, so in the future when I have more sprites I can just add to the list, and create the map.
Thank you!
I don't believe this is quite possible as you describe it, but if these images aren't going to change often I would suggest pre-blitting all your map images to a pygame Surface which can later be used, using something like:
map_surface = pygame.Surface(( len(tilemap[0])*TILE_WIDTH, len(tilemap)*TILE_HEIGHT ))
for y,row in enumerate(tilemap):
for x,tile_surface in enumerate(row):
map_surface.blit(tile_surface,(x*TILE_WIDTH,y*TILE_HEIGHT))
and then later you can simply use:
screen.blit(map_surface)
One thing to note is that even if your map does change, you will only have to blit the changed tiles onto the map_surface surface, and not have to recreate the whole thing.