Named shapes in pyglet - python

Why do shapes and other objects in pyglet have to be named (as in assigned variables) ? The Rectangle below named "test" renders successfully, the one a line below does not. Why is that?
from pyglet import shapes
WHITE = (255, 255, 255)
HEIGHT = 1080
WIDTH = 720
window = pyglet.window.Window(HEIGHT, WIDTH)
background = pyglet.graphics.Batch()
test = shapes.Rectangle(200, 200, 50, 50, color=WHITE, batch=background) # Renders successfuly
shapes.Rectangle(300, 300, 50, 50, color=WHITE, batch=background) # Does not render
#window.event
def on_draw():
window.clear()
background.draw()
pyglet.app.run()

Here you are using pyglet.graphics.Batch() to render the shape objects together i.e. test(the first rectangle) + the second rectangle. A batch manages a set of objects that will be drawn at once, and hence to instantiate the objects that need to be drawn, they need to have a reference against which they can be mapped to that batch.
To draw a rectangle as is, without assigning it to a varible can be done by using the pyglet.graphics.draw() function directly by passing in the primitive type, rectanggle coordinates and formatstring.

Related

Pyglet render into texture

I'm writing a drawing program using pyglet, and I want to be able to have the image being created as separate from the window's buffer (for instance, the image could be larger than the window, or may want to draw to this image at a different rate than the main window is being re-drawn). I want to be able to draw into this off-screen image, then display it in the window, but pyglet doesn't allow drawing to anything else than a window. Is there any simple way I can do this?
I've tried creating a second hidden pyglet window, but this gets rendered at the same rate as the main window which I definitely don't want.
The closest I found was Pyglet draw text into texture, but the code there isn't complete, and also no longer works as the opengl version used by pyglet has moved on.
The following code works for me, perhaps someone else can improve on my answer:
import pyglet
from pyglet.gl import *
from ctypes import byref
W, H = 800, 600
image = pyglet.image.create(W, H)
texture = image.get_texture()
window = pyglet.window.Window(width=W, height=H)
fbo_id = gl.GLuint(0)
glGenFramebuffers(1, byref(fbo_id))
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
glBindTexture(GL_TEXTURE_2D, texture.id)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0)
rect1 = pyglet.shapes.Rectangle(0, 0, W, H, (255, 0, 0) )
rect2 = pyglet.shapes.Rectangle(W//4, H//4, W//2, H//2, (0, 0, 255) )
label = pyglet.text.Label("Hello World", font_name="Times New Roman", font_size=36,
x=W//2, y=H//2, anchor_x="center", anchor_y="center")
rect1.draw()
rect2.draw()
label.draw()
#window.event
def on_mouse_drag(x, y, dx, dy, xxx, modifiers):
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
line = pyglet.shapes.Line(x-dx, y-dy, x, y, 3, (0, 255, 255))
line.draw()
#window.event
def on_draw():
glBindFramebuffer(GL_FRAMEBUFFER, 0)
window.clear()
texture.blit(0, 0)
pyglet.app.run()

Pygame draggable frame seems not to be working

I am working with Pygame currently, and I made a simple function to create window instances much like Windows 10 UI. the code I made doesn't give any errors or any unwanted outputs. It just seems not to be working properly, what I mean by "not working properly"; it just doesn't seem to be moving the frames that are meant to be dragged around by a master frame...
This is my code:
import pygame
from pyautogui import size
import datetime
pygame.init()
infoObject = pygame.display.Info()
surface = pygame.display.set_mode((900, 700))
run = True
clock = pygame.time.Clock()
def draw_text(text, font, text_col, x,y):
img = font.render(text, True, text_col)
rect = img.get_rect()
rect.center = (x,y)
surface.blit(img, rect)
return rect
class make_a_window():
def __init__(self,app,width=750,height=500):
self.app_name = str(app)
self.width = width
self.height = height
def run(self):
self.top_frame = pygame.draw.rect(surface, "#C0C0C0", pygame.Rect(0,0,int(self.width),40))#master frame
self.main_frame = pygame.draw.rect(surface, (255,255,255), pygame.Rect(0,40,int(self.width),int(self.height)))
self.red_frame_for_exit_btn_X = pygame.draw.rect(surface, (255,0,0), pygame.Rect(self.width-42,0,42,40))
self.exit_btn_X = draw_text("x", pygame.font.SysFont("calibri",25), "black", self.width-20, 15)
self.mouse_position = pygame.mouse.get_pos()
if pygame.mouse.get_pressed()[0] == 1:
if self.top_frame.collidepoint(self.mouse_position):
#moving the frames
self.top_frame.move(self.mouse_position[0],self.mouse_position[1])
self.main_frame.move(self.mouse_position[0]-40,self.mouse_position[1])
self.red_frame_for_exit_btn_X.move(self.mouse_position[0]-42,self.mouse_position[1])
self.exit_btn_X.move(self.mouse_position[0]-20,self.mouse_position[1])
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
run = False
app = make_a_window("hello")
app.run()
pygame.display.update()
clock.tick(60)
Sorry for my bad English. and thanks for the help, I really appreciate it 😃!
There is some logic error from line 32 to 41.
Firstly you should use the event queue by pygame.event.get() to track mouse activities(this is really important) and secondly why are you recording the mouse position before hand you are checking for its collision. Instead you should insert your
{self.mouse_position = pygame.mouse.get_pos()}
inside the collision checking if statement (rather that would not work smoothly until you use pygame.event.get())
One more thing that the function
pygame.Rect().move()
takes x and y offesets as its arguments not x and y coordinates.
So, mainly give focus on your event loop and the destination positions of your manual window. Maybe I would share the correct code later (don't wait for it.)
The method pygame.Rect.move doesn't move the rectangle itself, but it returns new rectangle that is moved. In compare, the method pygame.Rect.move_ip move the object in place.
However, these methods do not move anything that has been drawn on the screen. These methods simply move a rectangle representing an area of the screen. This rectangle can later be used to draw something on the screen at a new location.
Create the pygame.Rect objects in the class's constructor and use them to draw the objects. Use move_ip to move the rectangles:
class make_a_window():
def __init__(self,app,width=750,height=500):
self.app_name = str(app)
self.width = width
self.height = height
self.top_frame = pygame.Rect(0,0,int(self.width),40)
self.main_frame = pygame.Rect(0,40,int(self.width),int(self.height))
self.red_frame_for_exit_btn_X = pygame.Rect(self.width-42,0,42,40)
self.exit_btn_X = pygame.Rect(self.width-20, 15, 0, 0)
def run(self):
pygame.draw.rect(surface, "#C0C0C0", self.top_frame)
pygame.draw.rect(surface, (255,255,255), self.main_frame)
pygame.draw.rect(surface, (255,0,0), self.red_frame_for_exit_btn_X)
draw_text("x", pygame.font.SysFont("calibri",25), "black", self.exit_btn_X.topleft)
self.mouse_position = pygame.mouse.get_rel()
if pygame.mouse.get_pressed()[0] == 1:
if self.top_frame.collidepoint(self.mouse_position):
#moving the frames
move_rel = pygame.mouse.get_rel()
self.top_frame.move_ip(*move_rel)
self.main_frame.move_ip(*move_rel)
self.red_frame_for_exit_btn_X.move_ip(*move_rel)
self.exit_btn_X.move_ip(*move_rel)

Pyglet ignores alpha channel

I'm trying to make a level editor for a game I'm writing in Python using Pyglet. I want to be able to modify the darkness of any block I place. As such, I have added a darkness attribute to the Block class. Here is that class:
class Block:
def __init__(self, name, image, wall):
self.name = name
self.image = image
self.wall = wall
self.darkness = 0
def set_darkness(self, darkness):
self.darkness = darkness
def draw(self, x, y):
self.image.blit(x, y)
pyglet.graphics.draw(4, GL_QUADS, ('v2i', (x, y, x + block_width, y, x + block_width, y + block_height, x, y + block_width)), ('c4B', (0, 0, 0, self.darkness) * 4))
I am trying to darken an image by drawing a black rectangle on top of it, and then adjusting the transparency of that rectangle. However, no matter what I set self.darkness to in __init__, the rectangle continues to be completely opaque.
I tried enabling color blending with pyglet.gl by adding this code to the top of my program:
from pyglet.gl import *
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
This changed nothing. I also tried using Pyglet's SolidColorImagePattern class to create a black rectangle with the alpha channel set to self.darkness, but that also did nothing. How do I make this rectangle transparent?
For any OpenGL instruction, a valid and current OpenGL Context is of need. Of course pyglet provides an OpenGL context, but the context is created and made current when the pyglet (OpenGL) window is created (see pyglet.window).
Create the window, before setting up Blending to solve the issue:
from pyglet.gl import *
window = pyglet.window.Window(400, 400, "OpenGL window")
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

Creating pygame.Rect fails when using keyword arguments

I have a working program, but if I change my pygame.Rect() constructor / function, then my program crashes.
If you look at the code below, then
button_rect1 = pygame.Rect(450, 300, 100, 100)
works just fine. But if I change it to
button_rect2 = pygame.Rect(left = 450, top = 300, width = 100, height = 100)
then I get the error:
Traceback (most recent call last):
File "F:\_python_projects\workshift_logger\component_testing.py", line 31, in <module>
button_rect = pygame.Rect(left = 450, top = 300, width = 100, height = 100)
TypeError: Argument must be rect style object
[Finished in 0.7s with exit code 1]
The only thing I've changed is adding names to the arguments. Why can't I do this, and how can I change my code so I can name my arguments (I want to name them for clarity's sake - in some API's rectangles are (x, y, width, height), in others they are (x1, y1, x2, y2)):
Here's a minimal, standalone example:
##### Imports ######
import pygame
##### Settings #####
window_width = 1000
window_height = 600
##### Program #####
pygame.init()
window = pygame.display.set_mode((window_width, window_height))
button_rect1 = pygame.Rect(450, 300, 100, 100) # This works
button_rect2 = pygame.Rect(left = 450, top = 300, width = 100, height = 100) # This doesn't work
Keyword arguments support for, at least, some was added in 2.0.0 as per the official documentation.
Changed in pygame 2.0.0: Added support for keyword arguments.
So Pygame does support keyword arguments (if the version is >= 2.0.0) .. at least for some.
As per the documentation here, you can instantiate a Rect using three methods:
Rect(left, top, width, height) -> Rect
Rect((left, top), (width, height)) -> Rect
Rect(object) -> Rect
May be, still, there is not a support for the pygame.rect even though there is support for pygame.draw.rect ... in terms of keyword arguments. May be your version is less than 2.0.0
Not sure if I was able to answer the question.

Pygame Using Class to Randomize Image Placements

I'm creating a card/tile memory association game. It is a 4x4 grid of 100x100 pixel images, so 16 images in total are displayed (8 pairs).
For now all I want is for the images to be displayed in a grid in a random order each time the game is started, which I feel I am close to doing using shuffling them in a list in a class and then calling that class from the main function in the while loop.
Here is my code:
# Memory Tiles Game
# A Memory Game which users can flip tiles in and remember their placement to match
# all of the tiles
import pygame, sys, time
from pygame.locals import *
# User-defined classes
class memorygame(object):
def __init__(self):
imagelist = [image1,image2,image3,image4,image5,image6,image7
image8,image9]
shuffle.imagelist
screen.blit(imagelist[0],(0,0))
screen.blit(imagelist[1],(104,0))
screen.blit(imagelist[2],(208,0))
screen.blit(imagelist[3],(312,0))
screen.blit(imagelist[4],(0,104))
screen.blit(imagelist[5],(104,104))
screen.blit(imagelist[6],(208,104))
screen.blit(imagelist[7],(312,104))
shuffle.imagelist
screen.blit(imagelist[0],(0,208))
screen.blit(imagelist[1],(104,208))
screen.blit(imagelist[2],(208,208))
screen.blit(imagelist[3],(312,208))
screen.blit(imagelist[4],(0,312))
screen.blit(imagelist[5],(104,312))
screen.blit(imagelist[6],(208,312))
screen.blit(imagelist[7],(312,312))
# User-defined functions
def main():
black = ( 0, 0, 0)
white = (255,255,255)
red = (100, 0, 0)
green = ( 0,153, 0)
blue = ( 0, 0,255)
image1 = pygame.image.load('image0.bmp')
image2 = pygame.image.load('image1.bmp')
image3 = pygame.image.load('image2.bmp')
image4 = pygame.image.load('image3.bmp')
image5 = pygame.image.load('image4.bmp')
image6 = pygame.image.load('image5.bmp')
image7 = pygame.image.load('image6.bmp')
image8 = pygame.image.load('image7.bmp')
image9 = pygame.image.load('image8.bmp')
w = 500
h = 400
screen = pygame.display.set_mode((w, h))
screen.fill((white))
running = 1
# Initialize pygame
pygame.init()
# Set window size and title, and frame delay
surfaceSize = (500, 400) # example window size
windowTitle = 'Memory Game' # example title
frameDelay = 0.02 # smaller is faster game
# Create the window
surface = pygame.display.set_mode(surfaceSize, 0, 0)
pygame.display.set_caption(windowTitle)
# create and initialize objects
gameOver = False
#center = [200, 200] # example - replace
# Draw objects
# The next line is an example - replace it
#pygame.draw.circle(surface, pygame.Color('green'), center, 50, 0)
# Refresh the display
pygame.display.update()
# Loop forever
while True:
# Check event
event = pygame.event.poll()
if event.type == QUIT:
pygame.quit()
sys.exit()
screen.fill((black))
class memorygame(object)
# Handle additional events
# Update and draw objects for the next frame
gameOver = update(center, surface)
# Refresh the display
pygame.display.update()
# Set the frame speed by pausing between frames
time.sleep(frameDelay)
main()
It doesn't seem to compile, and I am not sure why. I get a syntax error in the shell.
First of all, you forgot a comma at the end of the first line in the imagelist in your memorygame class. Changing that to
imagelist = [image1,image2,image3,image4,image5,image6,image7,
image8,image9]
should fix the first syntax error.
Secondly, I'm not sure what you are trying to achieve with the line class memorygame(object) in your main loop. You probably want to create an instance of the class outside of the while loop and call a function that blits the images inside the while loop.
The image variables are local by the way, the memorygame class will not see them, unless you explicitly make them global variables, or pass them to the __init__ method of memorygame.
Besides, the way you're shuffling the imagelist isn't quite right. You should import random, and then call random.shuffle(imagelist) instead.

Categories