Python Pyglet Problem (cords of the sprite) - python

(I am not english. Hope you understand.)
Hi, I'm trying to move my "start_button" sprite to x = 150, but it'll duplicate it.
Here's the code:
import pyglet
window = pyglet.window.Window()
window.clear()
#ON_TEXT
def ontext(txt):
start_button.x = 150
#INTERVAL
def interval(int):
print("Running")
pyglet.clock.schedule_interval(interval, 1/30)
#SPRITES
def paint():
start_button.draw()
start_button_pic = pyglet.image.load("start_button.png")
start_button = pyglet.sprite.Sprite(start_button_pic)
#PUSH_HANDLERS
window.push_handlers(
on_text=ontext,
on_draw=paint,
)
pyglet.app.run()
print("Done")
Thanks for answers!
Andrew

You need to clear the window, before drawing the sprite:
def paint():
window.clear()
start_button.draw()
The clear method clears the color and depth buffer (see pyglet.window). Actually, the sprite is not duplicated, but the sprite drawn in the previous frames is still there because the color buffer was never cleared.

Related

Turtle not displaying on screen - Python

I am trying to recreate the snake game, however when I call the function which is supposed to create the initial body of the snake nothing appears on the screen.
The same problem happens if I simply create a turtle object in the main file.
Snake:
from turtle import Turtle
STARTING_POSITIONS = [(0, 0), (-20, 0), (-40, 0)]
class Snake:
def __init__(self):
self.segments = []
self.create_snake()
def create_snake (self):
for position in STARTING_POSITIONS:
n_segment = Turtle("square")
n_segment.color("white")
n_segment.penup()
print(position)
n_segment.goto(position)
self.segments.append(n_segment)
Main:
from turtle import Turtle, Screen
from snake import Snake
screen = Screen()
screen.setup(width = 600 , height= 600)
screen.bgcolor("black")
screen.title("SNAKE")
screen.tracer(0)
game_on = True
segments = []
snake = Snake()
turtle = Turtle()
In order to see the snake, I just added the following code snippet in main.py after the turtle definition to display a stationary snake with a pointer.
while game_on:
screen.update()
screen.exitonclick()
The result was this image.
Hope that helps.
Regards.
this is a minimum reproducible example of the above code which works and draws a square (segment of the snake body) in the snake class:
import turtle as ttl
class Snake:
def __init__(self):
self.segments = []
self.create_snake()
def create_snake (self):
ttl.shape('square')
ttl.color('white')
screen = ttl.Screen()
screen.setup(width=600, height=600)
screen.bgcolor('black')
snake = Snake()
ttl.done()
A lot of the code from the OP question is removed because there were numerous errors. Also, for the purpose of simplicity the class was added to the code, but the OP could break it into two separate files if desired.
I believe that there error in the question code was that the screen was drawing over itself which is why it was always black.
You can build from here.

Conceptual bug in a turtle program using resetscreen()

Criteria I'm trying to meet:
The screen resets when the user presses the SPACEBAR, meaning the drawn lines go away and the unnamed turtle returns to the center but it doesn’t return to the default turtle color and shape!
""" A simple drawing program
Click and drag the center turtle to draw
Click the colorful buttons to change the
turtle's color,
and then draw different shapes.
Press the SPACEBAR key to reset the
drawing.
"""
from turtle import *
turtle_1 = Turtle()
turtle_2 = Turtle()
turtle_3 = Turtle()
def callback_1(x,y):
color("red")
shape("circle")
circle(100)
def callback_2(x,y):
color("blue")
shape("square")
circle(100,steps=4)
def callback_3(x,y):
color("green")
shape("triangle")
circle(100,steps=3)
def place_turtles():
turtle_1.color("red")
turtle_1.shape("circle")
turtle_1.penup()
turtle_1.goto(-200,-200)
turtle_2.color("blue")
turtle_2.shape("square")
turtle_2.penup()
turtle_2.goto(0,-200)
turtle_3.color("green")
turtle_3.shape("triangle")
turtle_3.penup()
turtle_3.goto(200,-200)
def start_over():
resetscreen()
place_turtles()
listen()
onkey(start_over, "space")
ondrag(goto)
place_turtles()
This code allows the user to drag the turtle, press buttons, and reset the screen when they press SPACEBAR. For some reason, though, resetting the screen also resets the color of the turtle. How can I prevent this from happening?
Basically what I want to happen is if, say, the user clicks on the blue square button, then resets the screen to hide the shape drawn by the button, all of the turtles return to their original positions, but the unnamed turtle does not change its previous color and shape. Let me know if I need to elaborate further.
With a "better late than never" attitude, I believe I've reworked your code to get the behavior you desired. I also reworked your drag logic to give you better drawing capability:
from turtle import Turtle, Screen, getturtle
def callback_1(x, y):
anonymous.color(*turtle_1.color())
anonymous.shape(turtle_1.shape())
anonymous.circle(100)
def callback_2(x, y):
anonymous.color(*turtle_2.color())
anonymous.shape(turtle_2.shape())
anonymous.circle(100, steps=4)
def callback_3(x, y):
anonymous.color(*turtle_3.color())
anonymous.shape(turtle_3.shape())
anonymous.circle(100, steps=3)
def setup_turtles():
turtle_1.onclick(callback_1)
turtle_1.color("red")
turtle_1.penup()
turtle_1.goto(-200, -200)
turtle_2.onclick(callback_2)
turtle_2.color("blue")
turtle_2.penup()
turtle_2.goto(0, -200)
turtle_3.onclick(callback_3)
turtle_3.color("green")
turtle_3.penup()
turtle_3.goto(200, -200)
def start_over():
colors = anonymous.color()
anonymous.reset()
anonymous.color(*colors)
def drag_handler(x, y):
anonymous.ondrag(None) # disable event inside event handler
anonymous.goto(x, y)
anonymous.ondrag(drag_handler) # reenable event on event handler exit
anonymous = getturtle()
anonymous.ondrag(drag_handler)
turtle_1 = Turtle(shape="circle")
turtle_2 = Turtle(shape="square")
turtle_3 = Turtle(shape="triangle")
setup_turtles()
screen = Screen()
screen.onkey(start_over, "space")
screen.listen()
screen.mainloop()
Many of the changes are just for personal style reasons. The two key changes are: just reset the anonymous turtle itself, not the screen; rather than use goto as an event handler, wrap it in a function that turns off drag events during the goto call.

Pygame, Adding quit function to a rectangle

I have a problem I can't seem to solve. I have tried to find a way to add a function like quitting a program to a rectangle in Pygame. Here is the code I have so far. I would like to add an on click quit feature to the quit box in the corner.
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (white), (300, 200, 300, 200), 2)
pygame.display.update()
def addText(self):
self.screen.blit(self.font.render('Quit', True, (84,84,84)), (550, 375))
pygame.display.update()
I have it working with the bits above and below and it does make a "Quit" Image at the bottom corner where I need it. However, I'm again stuck on the function!
I did something very similar to this, and the way that I handled it was I made a list in the main program that had all of the "inner windows" or whatever you want to call them. Whenever the main program received a signal from a window to close it, it deleted it from the list.
To make the signal, you will want to create a rect in the location where you want the button to be. Make a function for the "inner window" and have it test for that rect being clicked. If it is clicked, have the function return something like 'closed' or whatever you want. In the main program, say something like
for window in windows:
if window.update()=='closed':
windows.remove(window)
to remove any window which is closed.
EDIT:
After looking at your code a bit more in depth, it looks like how you're doing it won't work. To add a rect, you will need to have something in your main code to store whether or not the rect is there. To close the window, you will have to change that variable.
To check if the rect should be closed, make another rect that is where the text which should be closing the window is. When this text is clicked, have the function return something which should be interpreted by the main code to close the window.
A basic example is shown below.
The class:
def update(self):
#set up the test rect
text=self.font.render('Quit', True, (84,84,84))
textrect=text.get_rect()
textrect.topleft=(550, 375)
#see if the button is pressed
if textrect.collidepoint(pygame.mouse.get_pos()) and pygame.mouse.get_pressed()[0]:
return 'closed'
#render stuff
self.rect = pygame.draw.rect(self.screen, (white), (300, 200, 300, 200), 2)
self.screen.blit(text, (550, 375))
Note that I combined your two original classes into one, as I don't see a reason why you would ever want the rect but not the text or vise versa. This is a pretty simple change if you don't like it.
Also note that this will close the window if the mouse is pressed off the button, then dragged onto it. To avoid this, you will have to pass the list gotten from pygame.event.get() as an argument for the update function, and search through it for a MOUSEBUTTONDOWN event, but this would cause unnecessary complications that I tried to avoid.
The main code:
rectOn=False
while True:
if rectOn:
if rect.update()=='closed':
rectOn=False
To make the rect appear again after it has been closed, simply set rectOn to True.
A made a small example that you can work on. Instead of buttons returning something on click, they have a function assigned to the click.
import pygame,sys
from pygame.locals import *
screen_color = (0,0,0)
class Button:
def __init__(self,pos,action):
self.rect = pygame.Rect(pos)
self.action = action
def draw(self,screen):
pygame.draw.rect(screen, (255,255,255), self.rect)
def checkCollide(self,x,y):
return self.rect.collidepoint(x,y)
def do(self):
self.action()
def action():
global screen_color
screen_color = (255,255,0)
pygame.init()
screen = pygame.display.set_mode((640,360),0,32)
buttons = []
buttons.append(Button((10,10,50,50),action))
while True:
screen.fill(screen_color)
for button in buttons:
button.draw(screen)
pygame.display.flip()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
x,y = pygame.mouse.get_pos()
for button in buttons:
if (button.checkCollide(x,y)):
button.do()

Pygame Menu: calling another .py file

I'm learning pygame by helping a friend make a Menu for his interactive TicTacToe game. It's simple enough, a title and 2 buttons for starting and exiting the game. He has the game done, I just need to link my menu to his game.
After fiddling with pygame, I finally finished making the images appear in the pygame window(I never thought that seeing text appear in a blank window for the first time could look so beautiful! T^T). I believe that the next step is to make the images act like buttons to call another python file.
Here is my simple code for the menu:
import pygame
from pygame.locals import *
from sys import exit
pygame.init()
resX, resY = 640, 480
windowObj = pygame.display.set_mode((resX,resY))
titleImg = pygame.image.load("title.png")
startImg = pygame.image.load("start.png")
exitImg = pygame.image.load("exit.png")
def width_center(img):
"""For horizontally setting an image."""
return resX/2 - x(img)/2
def height_center(img):
"""For vertically setting an image."""
return resY/2 - y(img)/2
def x(img):
"""Width of object."""
return img.get_width()
def y(img):
"""Height of object."""
return img.get_height()
while True:
pygame.display.update()
windowObj.fill((255,255,255))
windowObj.blit(titleImg,(width_center(titleImg), 30))
#This I want to link:
windowObj.blit(startImg,(width_center(startImg),height_center(startImg)-10))
windowObj.blit(exitImg,(width_center(exitImg),height_center(exitImg)+y(startImg)))
for i in pygame.event.get():
if i.type == QUIT:
exit()
Simply put, I want to know how to make the startImg call TTTClick.py. Should there also be a certain format for his TTTClick.py?
Thanks :)
If it's one project, you can have 'title screen' state, and 'game' states.
Psuedo code:
class Game():
def __init__(self):
self.done = False
self.state = "title"
def game_draw(self):
# game draw
def game_update(self):
# game event handling, and physics
def title_draw(self):
# title draw
def title_update(self):
# on event click
self.state = "game"
def loop(self):
# main loop
while not self.done:
if state == 'title':
title_update()
title_draw()
elif state == 'game':
game_update()
game_draw()
if __name__ == "__main__":
game = Game()
game.loop()
Note: x, height_center ect. already exist in pygame.Rect
# if Surface
titleImage.get_rect().width
# if Sprite
titleImage.rect.width
There's more, rect.center, rect.centerx, see the full listing at http://www.pygame.org/docs/ref/rect.html

rotate animation board (python, pygame)

This is more of a conceptual question:
If I want to rotate an entire playing board (a chess board for example) by 90 degrees, am I better off rotating the individual fields of the board around its center point individually, or is there a way for me to take a 'screenshot' of the field and rotate that as a single picture? I would have the code rotate the actual values of the board separately from the animation (once the animation was done, I would just redraw the screen with everything now in the right positions).
I hope my question is understandable. I have just started programming in python a couple of days ago and have so far only done text based games, but want to move onto GUI based games,
thank you in advance, your help is very much appreciated,
keelboat
You should rotate the board completely.
Taking a screenshot, and rotating that would be almost as taxing as just rotating the objects of the chessboard. Batching the objects and rotate them would be a solution.
Edit: i just realized that Pygame is one of the few libraries that might miss batched rendering. Pygame is nice, for a started learning curve but you're better off with other libraries (this is just a friendly suggestion)
Friendly suggestion
I'd go with Pyglet if I really wanted to do some cool stuff (including game development of your scale).
It's cross-platform, doesn't depend on Python version in the sense that all the others do and you get a direct hook to the OpenGL library making it redicilously fast. And it's quite easy to use actually.
Here's and example of drag and drop:
#!/usr/bin/python
import pyglet
from time import time, sleep
class Window(pyglet.window.Window):
def __init__(self, refreshrate):
super(Window, self).__init__(vsync = False)
self.frames = 0
self.framerate = pyglet.text.Label(text='Unknown', font_name='Verdana', font_size=8, x=10, y=10, color=(255,255,255,255))
self.last = time()
self.alive = 1
self.refreshrate = refreshrate
self.click = None
self.drag = False
def on_draw(self):
self.render()
def on_mouse_press(self, x, y, button, modifiers):
self.click = x,y
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
if self.click:
self.drag = True
print 'Drag offset:',(dx,dy)
def on_mouse_release(self, x, y, button, modifiers):
if not self.drag and self.click:
print 'You clicked here', self.click, 'Relese point:',(x,y)
else:
print 'You draged from', self.click, 'to:',(x,y)
self.click = None
self.drag = False
def render(self):
self.clear()
if time() - self.last >= 1:
self.framerate.text = str(self.frames)
self.frames = 0
self.last = time()
else:
self.frames += 1
self.framerate.draw()
self.flip()
def on_close(self):
self.alive = 0
def run(self):
while self.alive:
self.render()
# ----> Note: <----
# Without self.dispatc_events() the screen will freeze
# due to the fact that i don't call pyglet.app.run(),
# because i like to have the control when and what locks
# the application, since pyglet.app.run() is a locking call.
event = self.dispatch_events()
sleep(1.0/self.refreshrate)
win = Window(23) # set the fps
win.run()
Pyglet also enables you to do batched rendering (meaning you can send instructions to the GPU in a large chunk instead of item-per-item which makes it easy to make complex tasks quick and painless.. also you can do batch.rotate(90) and you're all done)
In Pygame you have a surface that is created when you initialize and configure your display. Often, people will blit other images directly to this surface, then update the display to render the image to the screen, but there's no reason why you can't create another surface to draw to, which can then be rotated and drawn to the surface rendered by the display.
screen = pygame.display.set_mode((500,500))
middle_man = pygame.Surface((500,500))
# draw stuff to middle_man here
....
# rotate middle_man
# note that this creates a padded surface if not rotating in 90 degree increments
rotated_middle_man = pygame.transform.rotate(middle_man, 45.0)
# draw middle_man back to the screen surface
crop_rect = pygame.Rect(rotated_middle_man.get_width() / 2 - screen.get_width() / 2,
rotated_middle_man.get_height() / 2 - screen.get_height() / 2,
screen.get_width(), screen.get_height())
screen.blit(rotated_middle_man, (0,0), crop_rect)
# update the screen
pygame.display.update()

Categories