I also have been having difficulties getting glumpy to work well with transparent colormaps, and transparency in general.
Below is a simple script that should draw two transparent glumpy Images, one on top of the other. The second simply overwrites the first, so you can't see the one behind the other.
I have experimented with different opengl enable/disable commands, but with no joy! Any help or suggestions would be much appreciated.
from pylab import *
import pygame
from pygame.locals import *
import glumpy
import OpenGL.GL as gl
import OpenGL.GLU as glu
# Set the width and height of the screen [width,height]
size=[256,256]
screen=pygame.display.set_mode(size,OPENGL|DOUBLEBUF)
## I think something here might get this to work, but I've
## experimented turining these off and on. Any suggestions?
gl.glDisable(gl.GL_DEPTH_TEST)
gl.glDisable(gl.GL_LIGHTING)
gl.glEnable(gl.GL_BLEND)
gl.glBlendFunc (gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
a = np.random.rand(256,256).astype('f')
a[0:128,:] = 1.0
b = np.random.rand(256,256).astype('f')
b[:,0:128] = 1.0
# cmaps
aCM = glumpy.colormap.Colormap("Rd", (0., (1.,1.,0.,0.0)), (1., (1.0,0.0,0.0,1.0)))
bCM = glumpy.colormap.Colormap("Bl", (0., (0.,1.0,1.,0.0)), (1., (0.0,0.0,1.0,1.0)))
# glumpy images
ai = glumpy.image.Image(a,colormap=aCM)
bi = glumpy.image.Image(b,colormap=bCM)
print('press q or ESC to quit')
while True :
gl.glPushMatrix()
gl.glLoadIdentity()
gl.glViewport(0, 0, size[0],size[1])
# draw a diagonal line underneath everything
gl.glColor4d(1,0,0,1)
gl.glBegin(gl.GL_LINES)
gl.glVertex3d(0,0,-0.1)
gl.glVertex3d(1,1.0,-0.1)
gl.glEnd()
# draw the glumpy images, with ai beneath bi
ai.draw(x=-1,y=-1,z=0,width=2.0,height=2.0)
bi.draw(x=-.9,y=-.9,z=0.1,width=1.8,height=2.0)
gl.glPopMatrix()
pygame.display.flip()
gl.glClearColor(0.1, 0.1, 0.1, 0.1);
gl.glClear(gl.GL_COLOR_BUFFER_BIT);
for event in pygame.event.get(): # User did something
if event.type == pygame.KEYDOWN:
if event.key in [pygame.K_q, pygame.K_ESCAPE] :
pygame.quit()
sys.exit()
I believe that the problem above was caused by a bug in glumpy. I have outlined a very simple patch that appears to rectify the problem here: https://groups.google.com/forum/#!topic/glumpy-users/UUi4yzl0ktU
Related
This question already has an answer here:
How can I move the ball instead of leaving a trail all over the screen in pygame?
(1 answer)
Closed 6 months ago.
We are trying to create a program using pygame that allows preset image files to be dragged around over another PNG image as the background. Used some code from a tutorial for pygame and tweaked it to fit our specific needs. We have gotten the images to populate and are movable but only with a white background. When importing the PNG file for the background instead, the moveable image disappears behind the background. I have replace the the two filepaths with just "filepath." Still fairly new to python so sorry for ugly code.
Code:
# Import the library pygame
import pygame
from pygame.locals import *
##background
bg = pygame.image.load(filepath)
# Take colors input
YELLOW = (255, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
# Construct the GUI game
pygame.init()
# Set dimensions of game GUI
w, h = 1280, 720
screen = pygame.display.set_mode((w, h))
# Take image as input
img = pygame.image.load(filepath)
img.convert()
# Draw rectangle around the image
rect = img.get_rect()
rect.center = w//2, h//2
# Set running and moving values
running = True
moving = False
# Setting what happens when game
# is in running state
while running:
screen.blit(bg, (320,0))
for event in pygame.event.get():
# Close if the user quits the
# game
if event.type == QUIT:
running = False
# Making the image move
elif event.type == MOUSEBUTTONDOWN:
if rect.collidepoint(event.pos):
moving = True
# Set moving as False if you want
# to move the image only with the
# mouse click
# Set moving as True if you want
# to move the image without the
# mouse click
elif event.type == MOUSEBUTTONUP:
moving = False
# Make your image move continuously
elif event.type == MOUSEMOTION and moving:
rect.move_ip(event.rel)
# Set screen color and image on screen
screen.fill(WHITE)
screen.blit(img, rect)
# Construct the border to the image
pygame.draw.rect(screen, BLACK, rect, 2)
# Update the GUI pygame
pygame.display.update()
##trying to draw the background
# Quit the GUI game
pygame.quit()
I tried out your code and through a bit of experimentation, came up with some refinements that display the image in front of the background. Following is your program with a few tweaks.
# Import the library pygame
import pygame
from pygame.locals import *
##background
bg = pygame.image.load("background.png") # Just a sky blue background
bg = pygame.transform.scale(bg, (1280, 720)) # Made it fit the screen size
# Take colors input
YELLOW = (255, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
# Construct the GUI game
pygame.init()
# Set dimensions of game GUI
w, h = 1280, 720
screen = pygame.display.set_mode((w, h))
# Take image as input
img = pygame.image.load("car.png")
img.convert()
# Draw rectangle around the image
rect = img.get_rect()
rect.center = w//2, h//2
# Set running and moving values
running = True
moving = False
# Setting what happens when game
# is in running state
while running:
screen.blit(bg, (0,0)) # Start the background at the upper left
for event in pygame.event.get():
# Close if the user quits the
# game
if event.type == QUIT:
running = False
# Making the image move
elif event.type == MOUSEBUTTONDOWN:
if rect.collidepoint(event.pos):
moving = True
# Set moving as False if you want
# to move the image only with the
# mouse click
# Set moving as True if you want
# to move the image without the
# mouse click
elif event.type == MOUSEBUTTONUP:
moving = False
# Make your image move continuously
elif event.type == MOUSEMOTION and moving:
rect.move_ip(event.rel)
# Set screen color and image on screen
#screen.fill(WHITE)
screen.blit(img, rect) # Changing the indentation seems to make it visible
# Construct the border to the image
#pygame.draw.rect(screen, BLACK, rect, 2)
# Update the GUI pygame
pygame.display.update()
##trying to draw the background
# Quit the GUI game
pygame.quit()
Following are the highligts.
I utilized a "png" file I had for a sky blue background which was loaded and then transformed to fill the entire 1280 x 720 screen.
The placement of the background was set to start at the upper left; if your background image needs to be centered or oriented differently, keep that in mind.
The indentation of the load of the image to be moved (in my case a "car") was revised to be a part of the "while" loop and not a part of the "for" loop; otherwise, the image only flashes and appears during the handling of the mouse events.
After those tweaks, the image appeared and was moved around by the mouse.
The takeaway from this is that you would want your image to be handled within your drawing/blit cycle. That appears to be where you got tripped up.
Give that a try.
I'm having a problem. I want to load and play a video in pygame but it doesn't start. The only thing that I am seeing is a black screen. Here is my code:
import pygame
from pygame import display,movie
pygame.init()
screen = pygame.display.set_mode((1024, 768))
background = pygame.Surface((1024, 768))
screen.blit(background, (0, 0))
pygame.display.update()
movie = pygame.movie.Movie('C:\Python27\1.mpg')
mrect = pygame.Rect(0,0,140,113)
movie.set_display(screen, mrect.move(65, 150))
movie.set_volume(0)
movie.play()
Can you help me??
The pygame.movie module is deprecated and not longer supported.
If you only want to show the video you can use MoviePy (see also How to be efficient with MoviePy):
import pygame
import moviepy.editor
pygame.init()
video = moviepy.editor.VideoFileClip("video.mp4")
video.preview()
pygame.quit()
An alternative solution is to use the OpenCV VideoCapture. Install OpenCV for Python (cv2) (see opencv-python). However, it should be mentioned that cv2.VideoCapture does not provide a way to read the audio from the video file.
This is only a solution to show the video but no audio is played.
Opens a camera for video capturing:
video = cv2.VideoCapture("video.mp4")
Get the frames per second form the VideoCapture object:
fps = video.get(cv2.CAP_PROP_FPS)
Create a pygame.time.Clock:
clock = pygame.time.Clock()
Grabs a video frame and limit the frames per second in the application loop:
clock.tick(fps)
success, video_image = video.read()
Convert the camera frame to a pygame.Surface object using pygame.image.frombuffer:
video_surf = pygame.image.frombuffer(video_image.tobytes(), video_image.shape[1::-1], "BGR")
See also Video:
Minimal example:
import pygame
import cv2
video = cv2.VideoCapture("video.mp4")
success, video_image = video.read()
fps = video.get(cv2.CAP_PROP_FPS)
window = pygame.display.set_mode(video_image.shape[1::-1])
clock = pygame.time.Clock()
run = success
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
success, video_image = video.read()
if success:
video_surf = pygame.image.frombuffer(
video_image.tobytes(), video_image.shape[1::-1], "BGR")
else:
run = False
window.blit(video_surf, (0, 0))
pygame.display.flip()
pygame.quit()
exit()
You are not actually blitting it to a screen. You are also not utilizing a clock object so it will play as fast as possible. Try this:
# http://www.fileformat.info/format/mpeg/sample/index.dir
import pygame
FPS = 60
pygame.init()
clock = pygame.time.Clock()
movie = pygame.movie.Movie('MELT.MPG')
screen = pygame.display.set_mode(movie.get_size())
movie_screen = pygame.Surface(movie.get_size()).convert()
movie.set_display(movie_screen)
movie.play()
playing = True
while playing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
movie.stop()
playing = False
screen.blit(movie_screen,(0,0))
pygame.display.update()
clock.tick(FPS)
pygame.quit()
I just got that MELT.MPG from the link provided in the comment. You should be able to simply switch out that string for your actual MPG you want to play and it will work... maybe.
As you probably know, the pygame.movie module is deprecated and no longer exists in the latest version of pygame.
An alternative would be to read in frames of the video one by one and blit them onto the pygame screen using the the cv2 module (OpenCV), that can be installed with the command prompt command:
pip install opencv-python
Then, you can run the code:
import cv2
import pygame
cap = cv2.VideoCapture('video.mp4')
success, img = cap.read()
shape = img.shape[1::-1]
wn = pygame.display.set_mode(shape)
clock = pygame.time.Clock()
while success:
clock.tick(60)
success, img = cap.read()
for event in pygame.event.get():
if event.type == pygame.QUIT:
success = False
wn.blit(pygame.image.frombuffer(img.tobytes(), shape, "BGR"), (0, 0))
pygame.display.update()
pygame.quit()
I'm having a problem. I want to load and play a video in pygame but it doesn't start. The only thing that I am seeing is a black screen. Here is my code:
import pygame
from pygame import display,movie
pygame.init()
screen = pygame.display.set_mode((1024, 768))
background = pygame.Surface((1024, 768))
screen.blit(background, (0, 0))
pygame.display.update()
movie = pygame.movie.Movie('C:\Python27\1.mpg')
mrect = pygame.Rect(0,0,140,113)
movie.set_display(screen, mrect.move(65, 150))
movie.set_volume(0)
movie.play()
Can you help me??
The pygame.movie module is deprecated and not longer supported.
If you only want to show the video you can use MoviePy (see also How to be efficient with MoviePy):
import pygame
import moviepy.editor
pygame.init()
video = moviepy.editor.VideoFileClip("video.mp4")
video.preview()
pygame.quit()
An alternative solution is to use the OpenCV VideoCapture. Install OpenCV for Python (cv2) (see opencv-python). However, it should be mentioned that cv2.VideoCapture does not provide a way to read the audio from the video file.
This is only a solution to show the video but no audio is played.
Opens a camera for video capturing:
video = cv2.VideoCapture("video.mp4")
Get the frames per second form the VideoCapture object:
fps = video.get(cv2.CAP_PROP_FPS)
Create a pygame.time.Clock:
clock = pygame.time.Clock()
Grabs a video frame and limit the frames per second in the application loop:
clock.tick(fps)
success, video_image = video.read()
Convert the camera frame to a pygame.Surface object using pygame.image.frombuffer:
video_surf = pygame.image.frombuffer(video_image.tobytes(), video_image.shape[1::-1], "BGR")
See also Video:
Minimal example:
import pygame
import cv2
video = cv2.VideoCapture("video.mp4")
success, video_image = video.read()
fps = video.get(cv2.CAP_PROP_FPS)
window = pygame.display.set_mode(video_image.shape[1::-1])
clock = pygame.time.Clock()
run = success
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
success, video_image = video.read()
if success:
video_surf = pygame.image.frombuffer(
video_image.tobytes(), video_image.shape[1::-1], "BGR")
else:
run = False
window.blit(video_surf, (0, 0))
pygame.display.flip()
pygame.quit()
exit()
You are not actually blitting it to a screen. You are also not utilizing a clock object so it will play as fast as possible. Try this:
# http://www.fileformat.info/format/mpeg/sample/index.dir
import pygame
FPS = 60
pygame.init()
clock = pygame.time.Clock()
movie = pygame.movie.Movie('MELT.MPG')
screen = pygame.display.set_mode(movie.get_size())
movie_screen = pygame.Surface(movie.get_size()).convert()
movie.set_display(movie_screen)
movie.play()
playing = True
while playing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
movie.stop()
playing = False
screen.blit(movie_screen,(0,0))
pygame.display.update()
clock.tick(FPS)
pygame.quit()
I just got that MELT.MPG from the link provided in the comment. You should be able to simply switch out that string for your actual MPG you want to play and it will work... maybe.
As you probably know, the pygame.movie module is deprecated and no longer exists in the latest version of pygame.
An alternative would be to read in frames of the video one by one and blit them onto the pygame screen using the the cv2 module (OpenCV), that can be installed with the command prompt command:
pip install opencv-python
Then, you can run the code:
import cv2
import pygame
cap = cv2.VideoCapture('video.mp4')
success, img = cap.read()
shape = img.shape[1::-1]
wn = pygame.display.set_mode(shape)
clock = pygame.time.Clock()
while success:
clock.tick(60)
success, img = cap.read()
for event in pygame.event.get():
if event.type == pygame.QUIT:
success = False
wn.blit(pygame.image.frombuffer(img.tobytes(), shape, "BGR"), (0, 0))
pygame.display.update()
pygame.quit()
Currently, I am working on a game in which you are asked a mathematical question such as 2 + 1 and numbers will fall from the top of the screen. The player has to click the right answer before it falls below the screen. However, I don't want to download images of the numbers because it would waste lots of time. Is there a way to draw or blit numbers instead? If there is, can the numbers be in a circle shape instead of a rectangle?
EDIT: I could create the numbers by displaying them as text. However, that would mean I have to create hundreds of different rectangles for each possible answer. My question then is, is there a way for me to tell Python to generate numbers and place them on a rectangle without me having to do it manually?
One solution would be to create a class in which you store the actual answer, the text surface and the rect for the collision detection. I use a pygame.sprite.Sprite subclass here, but you can do the same with a normal class. When a new question gets asked, you can just create a bunch of instances and add them to a sprite group, so that you can update them altogether in the main loop. You can use the pygame.Rect.collidepoint method for the collision detection.
import random
import pygame as pg
from pygame.math import Vector2
pg.init()
BLUE = pg.Color('dodgerblue1')
FONT = pg.font.Font(None, 42)
class Answer(pg.sprite.Sprite):
def __init__(self, pos, number):
super().__init__()
# Store the actual number, so that we can compare it
# when the user clicks on this object.
self.number = number
# Render the new text image/surface.
self.image = FONT.render(str(number), True, BLUE)
# A rect with the size of the surface, used for collision
# detection and rendering.
self.rect = self.image.get_rect(topleft=pos)
self.vel = Vector2(0, random.uniform(1, 4))
self.pos = Vector2(pos)
def update(self):
self.pos += self.vel
self.rect.center = self.pos
if self.rect.top > 480: # Screen bottom.
self.kill() # Remove the sprite from all groups.
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
if event.button == 3: # Right mouse button.
# Add 20 numbers (Answer objects).
for _ in range(20):
number = random.randrange(100)
all_sprites.add(Answer((random.randrange(620), -20), number))
elif event.button == 1: # Left mouse button.
# See if the user clicked on a number.
for answer in all_sprites:
# event.pos is the mouse position.
if answer.rect.collidepoint(event.pos):
print(answer.number)
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
(Right click to spawn the numbers, left click to touch single numbers.)
How do you get the screen contents into an array in pygame? I have tried this from the documentation:
self.screen.lock()
tmp_frame = pygame.surfarray.array3d(self.screen)
self.screen.unlock()
I have tried all sorts of things, such as using pixelcopy to get a copy of the surface first, but I always get a segmentation fault.
Fatal Python error: (pygame parachute) Segmentation Fault Aborted
(core dumped)
Is it because I am trying to copy from the screen directly?
This is what screen contains:
self.screen = pygl2d.display.set_mode((self.SCREEN_WIDTH, self.SCREEN_HEIGHT), pygame.DOUBLEBUF, depth=24)
And this is the definition of set_mode:
def set_mode(resolution=(0,0), flags=0, depth=0):
flags |= pygame.OPENGL
screen = pygame.display.set_mode(resolution, flags, depth)
init_gl()
return screen
Edit followup:
I also tried copying the screen surface into another surface first with
tmp_surface= self.screen.copy()
But I get
pygame.error: Cannot copy opengl display
So really, I suppose the question is how do you copy this opengl display contents into an array?
To anyone who might experience something similar:
I was not able to find a direct solution, all methods of accessing the hardware accelerated surface resulted in a segmentation error. (array3d,array2d,accessing a reference array pixels3d etc).
However, I was able to figure out a workaround. It appears that you are able to save images with
pygame.image.save(self.screen, 'output.png')
Similarly, you can do
string_image = pygame.image.tostring(self.screen, 'RGB')
temp_surf = pygame.image.fromstring(string_image,(self.SCREEN_WIDTH, self.SCREEN_HEIGHT),'RGB' )
tmp_arr = pygame.surfarray.array3d(temp_surf)
This should get you a numpy array of the screen contents.
import pygame
import numpy as np
import time
from pandas import *
pygame.init()
display = pygame.display.set_mode((350, 350))
x = np.arange(0, 300)
y = np.arange(0, 300)
X, Y = np.meshgrid(x, y)
Z = X + Y
Z = 255*Z/Z.max()
surf = pygame.surfarray.make_surface(Z)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
display.blit(surf, (0, 0))
pygame.display.update()
# Convert the window in black color(2D) into a matrix
window_pixel_matrix = pygame.surfarray.array2d(display)
print(window_pixel_matrix)
time.sleep(10)
pygame.quit()
COMMENT :
"pygame.surfarray.array2d()" is what you're looking for I guess.
Of course, you can use "pygame.surfarray.array3d()" function as well.
You can refer to the official website : "https://www.pygame.org/docs/ref/surfarray.html#pygame.surfarray.array2d"