Why is my Python turtle screen asymmetrical? - python

I created a pong game where I noticed the paddles are not placed equally at the screen edges.
I created an 800 pixel wide screen, and placed paddles at xcor = 380 and xcor = -380 but on the screen left paddle shows some gap but right paddle doesn't. Is my screen unsymmetrical? How do I fix it?
screen.setup(width=800, height=600)
screen.bgcolor("black")
screen.title("PONG")
screen.tracer(0)
l_paddle = Paddle()
l_paddle.create_paddle((-380, 0))
r_paddle = Paddle()
r_paddle.create_paddle((380, 0))
screenshot of screen

When we specify a window size to setup(), we're talking about total pixels used on the screen. Since there is chrome around the window (edges, title bar, etc.) the actual area we have to work with is slightly smaller. Trying to place two turtles at exactly the left and right edge, ignoring chrome:
from turtle import Screen, Turtle
CURSOR_SIZE = 20
WIDTH, HEIGHT = 600, 400
screen = Screen()
screen.setup(WIDTH, HEIGHT)
l_paddle = Turtle('square')
l_paddle.fillcolor('white')
l_paddle.setx(CURSOR_SIZE/2 - WIDTH/2)
r_paddle = Turtle('square')
r_paddle.fillcolor('white')
r_paddle.setx(WIDTH/2 - CURSOR_SIZE/2)
screen.exitonclick()
We get a result similar to yours:
If we compensate for the internal and external chrome elements:
from turtle import Screen, Turtle
CURSOR_SIZE = 20
BORDER_SIZE = 2 # inside the window
CHROME_SIZE = 9 # around the window
WIDTH, HEIGHT = 600, 400
screen = Screen()
screen.setup(WIDTH, HEIGHT)
l_paddle = Turtle('square')
l_paddle.fillcolor('white')
l_paddle.setx(CURSOR_SIZE/2 - WIDTH/2 + BORDER_SIZE)
r_paddle = Turtle('square')
r_paddle.fillcolor('white')
r_paddle.setx(WIDTH/2 - CURSOR_SIZE/2 - BORDER_SIZE - CHROME_SIZE)
screen.exitonclick()
We can get a more precise result:
The problem here is that the amount of chrome is system dependent but turtle doesn't tell us how much to compensate. You might be able to find out from the underlying tkinter code.
My recommendation is you estimate the best you can, assume it's not accurate on all systems, and stay away from the edges so it's less of an issue. The error can be greater in the Y dimension when the title bar is part of the chrome.

Related

Is there a way to avoid the recursion limit in my Turtle-program?

import turtle
from turtle import Turtle
WIDTH = 1000
HEIGHT = 1000
#Screen setup
screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
screen.title(" " *150 + "Test_GIU")
screen.bgcolor("black")
screen.setup(1000, 1000)
#Pen
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed(-1)
def dragging(x, y): # These parameters will be the mouse position
pen.ondrag(None)
pen.setheading(pen.towards(x, y))
pen.goto(x, y)
pen.ondrag(dragging)
def click_on_c():
screen.reset()
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed(-1)
pen.ondrag(dragging)
def main(): # This will run the program
turtle.listen()
pen.ondrag(dragging) # When we drag the turtle object call dragging
turtle.onkeypress(click_on_c, "c")
screen.mainloop() # This will continue running main()
main()
This is my code, im pretty new to it, so its not very good, but its my first real project. I´ve already tried to increase the recursin limit, but it crashes even if I set it to 10000. I also tried to catch the error with an try and exept block, but it also doesnt work.
Let's try a simpler design where instead of calling screen.reset() and recreating the turtle, we instead call pen.reset() to clear the drawing:
from turtle import Screen, Turtle
WIDTH = 1000
HEIGHT = 1000
def dragging(x, y): # Parameters are the mouse position
pen.ondrag(None)
pen.setheading(pen.towards(x, y))
pen.goto(x, y)
pen.ondrag(dragging)
def click_on_c():
pen.reset()
pen.pensize = 5
pen.color("green")
pen.speed('fastest')
# Screen setup
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.title("Test_GUI")
screen.bgcolor("black")
# Pen
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed('fastest')
pen.ondrag(dragging)
screen.onkeypress(click_on_c, "c")
screen.listen()
screen.mainloop()
We have to reset some aspects of the pen after calling reset() as that call clears the settings back to the defaults.

Entire screen not moving with the turtle

I am making a game in python using the turtle module in python.
I want the screen to move with the turtle. Is there any way to do it? Thanks
The problem is that the screen isn't moving with the turtle ... Does
anyone know why?
I know why. First, #martineau is correct, as usual +1, about passing the wrong range of values to yview_moveto(). But there's another piece to this puzzle: tkinter and turtle do not use the same coordinate system! You need to correct for the coordinate system difference, then turn the value into a percentage.
Here's a stripped down example based on your code and desired behavior. It keeps the ball in the middle of the window but you can tell from the numbers, and the vertical scroll bar, it's falling. Tap the the up arrow to slow it down -- tap it again to stop the motion. Tap it once more to start rising. Or use the down arrow to reverse your movement again:
from turtle import Screen, Turtle
WIDTH, DEPTH = 300, 10_000
CURSOR_SIZE = 20
vy = -10
def rise():
global vy
vy += 5
def fall():
global vy
vy -= 5
def move():
global vy
if abs(ball.ycor()) < DEPTH/2:
ball.forward(vy)
canvas.yview_moveto((DEPTH/2 - ball.ycor() - WIDTH/2 + CURSOR_SIZE) / DEPTH)
screen.update()
screen.ontimer(move)
screen = Screen()
screen.setup(WIDTH, WIDTH) # visible window
screen.screensize(WIDTH, DEPTH) # area window peeps into
screen.tracer(False)
canvas = screen.getcanvas()
marker = Turtle()
marker.hideturtle()
marker.penup()
marker.setx(-WIDTH/4) # so we can see we're moving
for y in range(-DEPTH//2, DEPTH//2, 100):
marker.sety(y)
marker.write(y, align='right')
ball = Turtle('circle')
ball.speed('fastest')
ball.setheading(90)
ball.penup()
screen.onkey(rise, 'Up')
screen.onkey(fall, 'Down')
screen.listen()
move()
screen.mainloop()

How can I make the picture run perfectly on the screen?

I want to make the background perfect for the running screen, but the vertical axis of the picture doesn't stretch even if I keep changing it in the code.
How can I get it right?
import pygame
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 600
pygame.init()
SCREEN = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("pygame test")
screen= pygame.image.load("그림.png")
SCREEN.blit(screen,(0,100))
SCREEN.blit(player, player_Rect)
pygame.display.flip()
if i add screen=pygame.transform.scale(500,600) this code
print black screen
pygame.transform.scale() takes two arguments, the source surface and a tuple with the size of the new and scaled surface:
screen=pygame.transform.scale(500,600)
screen = pygame.transform.scale(screen, (500, 600))
Scale the surface immediately after loading it:
screen = pygame.transform.scale(pygame.image.load("그림.png").convert_alpha(), (500, 600))

How to draw a filled rectangle in python turtle

import turtle
def penup():
for x in drawings:
x.penup()
penup()
def drawgrass():
for x in range(10):
grass.goto(300,300)
grass.color("green")
grass.begin_fill()
grass.forward(200)
grass.left(300)
grass.forward(200)
grass.left(300)
grass.end_fill()
penup()
drawgrass()
So I am creating this program that will make a landscape of some kind, and I am trying to make the grass. I was thinking of placing the cursor at 300,300, then drawing a huge rectange and then filling it making it green. So far I can not make the rectangle work, or make it cover the whole bottom half of the screen. Can someone help me please?
As in your other question, your penup() function makes no sense. Here's how I might go about filling half the screen with green:
from turtle import Screen, Turtle
def drawgrass():
grass.color("green")
width, height = screen.window_width(), screen.window_height()
grass.penup()
grass.goto(-width/2, 0)
grass.pendown()
grass.begin_fill()
for _ in range(2):
grass.forward(width)
grass.right(90)
grass.forward(height/2)
grass.right(90)
grass.end_fill()
screen = Screen()
grass = Turtle()
grass.speed('fastest') # because I have no patience
drawgrass()
grass.hideturtle()
screen.exitonclick()
But what I would really do is stamp it:
from turtle import Screen, Turtle
CURSOR_SIZE = 20
def drawgrass():
grass.color('green')
grass.shape('square')
width, height = screen.window_width(), screen.window_height()
grass.penup()
grass.goto(0, -height/4)
grass.shapesize(height/2 / CURSOR_SIZE, width / CURSOR_SIZE)
grass.stamp()
screen = Screen()
grass = Turtle()
grass.hideturtle()
drawgrass()
screen.exitonclick()

pygame "Paint" program - drawing empty rectangle on canvas

So I'm making an MS-Paint-like program using pygame (to which I'm completely new), which has been going well so far, except for this annoying problem that I have.
I want the user to have the ability to draw a rectangle by dragging the mouse along the canvas, similar to how you do in MS-Paint, and I want it to look as if the rectangle is "moving" as long as the mouse is being dragged.
I managed to have it work perfectly yet inefficiently until I was advised that I should use some other pygame methods to make it more efficient. So I did, and the one problem I can't solve is that previous images of the rectangle remain on the screen. Like so:
Top-left is where I started to draw
Here's the relevant portion of my code:
if canvas.collidepoint(cursor) and pygame.mouse.get_pressed()[0] and mode == 'Square' and not draw_square:
start_x, start_y = find_pixel(mouse_x, mouse_y)
width, height = find_pixel(mouse_x, mouse_y)
save_last = screen.subsurface(start_x, start_y, width - start_x, height - start_y)
square = pygame.draw.rect(screen, current_color, (start_x, start_y, width - start_x, height - start_y), 5)
temp_square = square
draw_square = True
if draw_square and canvas.collidepoint(cursor) and pygame.mouse.get_pressed()[0]:
# Mouse is being held down outside canvas, show square progress
prev_width, prev_height = width, height
save_last = screen.subsurface(temp_square)
width, height = find_pixel(mouse_x, mouse_y)
if width != prev_width or height != prev_height:
square = temp_square.inflate(width - start_x, height - start_y)
square.topleft = start_x, start_y
pygame.draw.rect(screen, current_color, square, 5)
if not canvas.collidepoint(cursor) and draw_square:
# Mouse is being held down outside canvas, show square progress
width, height = find_pixel(mouse_x, mouse_y)
if width < 150: # Cursor is left of the canvas
width = 150
if width > 980: # Cursor is right of the canvas
width = 980
if height < 20: # Cursor is above the canvas
height = 20
if height > 580: # Cursor if below the canvas
height = 580
square = temp_square.inflate(width - start_x, height - start_y)
square.topleft = start_x, start_y
pygame.draw.rect(screen, current_color, square, 5)
if draw_square and not pygame.mouse.get_pressed()[0]:
draw_square = False
pygame.display.flip()
I've tried blitting save_last onto the screen but it gives me this error:
Traceback (most recent call last):
File "C:/Users/yargr/PycharmProjects/Paint/PaintApp.py", line 548, in <module>
main()
File "C:/Users/yargr/PycharmProjects/Paint/PaintApp.py", line 435, in main
screen.blit(save_last, (mouse_x, mouse_y))
pygame.error: Surfaces must not be locked during blit
I've tried using screen.unlock() but it didn't work (I guess I don't completely understand how that works). Anyway, if anyone has any idea, I;d love to hear suggestions :)
The issue is that save_last is a subsurface of screen, because of
save_last = screen.subsurface(start_x, start_y, width - start_x, height - start_y)
respectively
save_last = screen.subsurface(temp_square)
subsurface() creates a surface which references to the other surface. The new Surface shares its pixels with the other parent. The new surface has no own data.
If you do
screen.blit(save_last, (mouse_x, mouse_y))
then it seems that the screen gets temporary looked, when save_last is read, because it is referenced. Finally writing to screen fails.
But you can solve the issue by directly copying a region of screen to screen by .blit(). Do not create a subsurface, just notice the rectangular region (pygame.Rect) and copy the region form the screen Surface to another position on screen. e.g:
save_rect = pygame.Rect(start_x, start_y, width - start_x, height - start_y)
# [...]
save_rect = pygame.Rect(temp_square)
# [...]
screen.blit(screen, (mouse_x, mouse_y), area=save_rect)
Alternatively you can crate a copy of the rectangular region and blit the copy to screen:
save_rect = pygame.Rect(start_x, start_y, width - start_x, height - start_y)
save_last = pygame.Surface(save_rect.size)
save_last.blit(screen, (0, 0), save_rect)
# [...]
save_rect = pygame.Rect(temp_square)
save_last = pygame.Surface(save_rect.size)
save_last.blit(screen, (0, 0), save_rect)
# [...]
screen.blit(save_last, (mouse_x, mouse_y))

Categories