Paddle object from class wont appear - python

I want to make a flappy bird game and am currently trying to turn paddle a into a class but it wont appear while it should.
Im also not getting any error messages and the code can run but without any signs of paddle x(the object from the class).
this is the code:
class Paddle:
Paddle = turtle.Turtle()
Paddle.penup()
Paddle.goto(0,0)
def __init__(self,shape,color,stretch_wid,stretch_len):
self.shape = shape
self.color = color
self.stretch_wid = stretch_wid
self.stretch_len = stretch_len
paddle_x = Paddle("square","white",5,5)
paddle_a = turtle.Turtle()
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=20,stretch_len=5)
paddle_a.penup()
paddle_a.goto(150,-250)
I already tried putting the 3 lines of codes after the "class Paddle:" under the class and then also changing the "Paddle" into paddle_x but then it says "'Paddle' object has no attribute 'penup'".
First time asking a question.
Thanks in advance.

Having worked with object inheritance with some polygon classes, I believe you will need to reference the "Turtle" object within the class definition of your "Paddle" object as in the following code snippet.
import turtle
class Paddle(turtle.Turtle): # Define as a child of the Turtle object
def __init__(self,shape,color,stretch_wid,stretch_len):
turtle.Turtle.__init__(self) # Use the Turtle object's initialization
self.shape = shape
self.color = color
self.stretch_wid = stretch_wid
self.stretch_len = stretch_len
paddle_x = Paddle("square","white",5,5)
paddle_x.penup()
paddle_x.goto(0,0)
print(paddle_x.shape)
paddle_a = turtle.Turtle()
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=20,stretch_len=5)
paddle_a.penup()
paddle_a.goto(150,-250)
It kind of utilizes the C++ method of initializing a child object based upon the parent (or "super") class. When trying that code snippet out, the screen appears briefly with a turtle pointer and prints out the paddle value requested in the test.
#Una:~/Python_Programs/Paddle$ python3 Paddle.py
square
You might give that a try.
Additional notes.
Referring to your comments and getting a better understanding of what you are trying to do with your "Paddle" class with a one-off initialization of the attributes, following is a slightly revised version of the sample code.
import turtle
class Paddle(turtle.Turtle): # Define as a child of the Turtle object
def __init__(self,shape,color,stretch_wid,stretch_len):
turtle.Turtle.__init__(self) # Use the Turtle objects initialization
self.shape(shape)
self.color(color)
self.shapesize(stretch_wid = stretch_wid, stretch_len=stretch_len)
paddle_x = Paddle("square","blue",5,5)
paddle_x.penup()
paddle_x.goto(0,0)
paddle_a = turtle.Turtle()
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=20,stretch_len=5)
paddle_a.penup()
paddle_a.goto(150,-250)
while True:
pass
That produces a square as per your specifications.
I made the square a blue color since my background happened to be white.
Give that a try.

Related

Drawing Basic Animations in Python

Hello I am trying to create something like this box with controllable dots
I need to be able to move and interact with the dots. I have tried turtle and pyglet, but neither of them seem to do what I want them to do.
Turtle is letting me create dots but it doesnt seem to play well with oop. I'm a super noob at python oop so maybe I'm just doing it wrong but I can't seem to make an turtle object that I can actually use how I want. I would ideally be able to use my own methods built off of the turtle methods, and create and call on data unique to each turtle.
import turtle
import time
import random
wn = turtle.Screen()
wn.title("simulation")
wn.bgcolor("tan")
def rng(whatisrandom):
match whatisrandom:
case 'coords': return(random.randint(-400,400) , random.randint(-400,400))
case 'heading':return(random.randint(0,359))
case 'forward':return(random.randint(0,50))
class bug():
def __init__(self) -> None:
self = turtle.Turtle(shape = "circle",visible=False)
self.speed(0)
self.penup()
self.setpos(rng('coords'))
self.showturtle()
self.speed(1)
self.forward(20)
def move(self):
self.setheading(rng('heading'))
self.forward(rng('forward'))
bug1 = bug()
bug1.move()
wn.mainloop()
this is the error message.
self.setheading(rng('heading'))
^^^^^^^^^^^^
AttributeError: 'bug' object has no attribute 'heading'
I ultimately want to animate these little bugs with neural nets and train them to do different movements, and eventually interact with each other.
This appears to be a misunderstanding of how to subclass an object in Python. Let's rearrange things a bit:
from turtle import Screen, Turtle
from random import randint
class Bug(Turtle):
def __init__(self):
super().__init__(shape='circle', visible=False)
self.speed('fastest')
self.penup()
self.setposition(Bug.rng('coords'))
self.showturtle()
self.speed('slowest')
self.forward(20)
def move(self):
self.setheading(Bug.rng('heading'))
self.forward(Bug.rng('forward'))
#staticmethod
def rng(whatisrandom):
if whatisrandom == 'coords':
return randint(-400, 400), randint(-400, 400)
if whatisrandom == 'heading':
return randint(0, 359)
if whatisrandom == 'forward':
return randint(0, 50)
return None
screen = Screen()
screen.title("Simulation")
screen.bgcolor('tan')
bug1 = Bug()
bug1.move()
screen.mainloop()
I don't have an issue with your match statement, I'm just unfamiliar with it and haven't updated my Python sufficiently!

Python Turtle class inheritance not working

I am trying to create a snake with an edited Turtles class. So I create a SnakeSegment class which has Turtle class as a parent. I then add a variable to the SnakeSegment class and also I set things like the colour and speed of the Turtle.
I then create my snake class where I bring in my SnakeSegments. The problem is the snake segments don't bring in their colour which I initiated in the snake segment class.
I think I have got the inheritance wrong, but I am not sure.
I have 2 files: components.py and main.py
components.py:
from turtle import Turtle
class SnakeSegment(Turtle):
def __init__(self, givenListPosition):
super().__init__()
self.segment = Turtle()
self.segment.shape("square")
self.segment.color('white')
self.segment.speed(1)
self.segment.penup()
self.listPosition = givenListPosition
class Snake:
def __init__(self, screen):
self.theScreen = screen
self.pastPositions = [(0.00, 0.00), (-20.00, 0.00), (-30.00, 0.00)]
self.t1 = SnakeSegment(0)
self.t2 = SnakeSegment(1)
self.t2.goto(self.pastPositions[int(self.t2.listPosition)])
self.t3 = SnakeSegment(2)
self.t2.goto(self.pastPositions[int(self.t3.listPosition)])
main.py:
from components import *
from turtle import Screen
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
snake = Snake(screen)
snake.theScreen.exitonclick()
I'm not sure I get your final goal and you did not show how your Turtle class looks. However, it appears you are using a mix of inheritance and composition which doesn't seem correct whatever your goal is. You have to decide if SnakeSegment is a Turtle (inheritance) or has a Turtle (composition) in your data model.
With inheritance, SnakeSegment will have all methods and attributes of the base Turtle class (which I assume has some of the "shape", "color" etc methods) and will "be" a Turtle from any point of view. You could then write something like this
class SnakeSegment(Turtle):
def __init__(self, givenListPosition):
super().__init__()
self.shape("square")
self.color('white')
self.speed(1)
self.penup()
self.listPosition = givenListPosition
With composition instead, SnakeSegment doesn't inherit from anything, it just has a member which is an instance of the Turtle class. In that case, something like that would be used
class SnakeSegment:
def __init__(self, givenListPosition):
self.segment = Turtle()
self.segment.shape("square")
self.segment.color('white')
self.segment.speed(1)
self.segment.penup()
self.listPosition = givenListPosition
I'd suggest you start from that and before taking a decision on your data model, have a read about mixins as well (i.e. https://www.pythontutorial.net/python-oop/python-mixin/)

How to write text on top of rectangle instead of below?

I'm trying to create a rectangle with text on top, but the text shows below the rectangle.
How can I make the text go to the front layer?
My code so far:
from turtle import Turtle
class Rectangle(Turtle):
def __init__(self, x, y, width, height, color='white'):
super().__init__()
self.penup()
self.goto(x, y)
self.color(color)
self.shape('square')
self.shapesize(stretch_wid=(height / 20), stretch_len=(width / 20))
class Writer(Turtle):
def __init__(self, x, y):
super().__init__()
self.penup()
self.goto(x, y)
self.hideturtle()
def writetext(self, text, font="Arial", size=8, textType="normal", color="black", x=None, y=None):
if x is None:
x = self.xcor()
if y is None:
y = self.ycor()
self.goto(x, y)
self.color(color)
self.write(text, move=False, align="center", font=(font, size, textType))
class Button(Rectangle):
def __init__(self, position, width, height, text, onclick, color="gray"):
position = list(position)
super().__init__(position[0], position[1], width, height, color)
writer = Writer(position[0], position[1])
writer.writetext(text, color="white")
self.goto(position[0], position[1])
self.color(color)
self.onclick(onclick)
def start_game(_arg1=None, _arg2=None): # requires arguments since Python turtle module passes two in when calling it using onclick
print('game started')
Button((0, 0), 50, 20, 'click me to start the game', start_game)
I've been searching on google for over half an hour and couldn't find anything
I believe the design has some fundamental flaws that arise from subclassing Turtle.
The issue is that the Button drawing is happening outside of the constructor where the text is written. The drawing function is called automatically by the turtle library. Regardless of whether you're hooking into Turtle's classes or not, a constructor isn't typically the ideal place to draw things for this reason. I don't see a clean way to make a Button out of two separate turtles with subclassing.
A quick (but poor) fix is to override the internal method that turtle calls to update the object so your button can inject the text after the super() call draws the rectangle (you could also try to hook into drawing with _drawturtle):
class Button(Rectangle):
# ....
def _update(self):
super()._update()
Writer(*self.position()).writetext("foobar", color="white")
But since the leading _ indicates a private, internal method, this is circumventing the turtle API -- not a good idea.
A second try would be to disable the internal update loop with turtle.tracer(0) and take control of the update loop manually, but then that seems to defeat the purpose of subclassing Turtle, which is that you want things to "just work" automatically.
There's a deeper problem here, though, which is that once you get your text on top of the button as shown above in the workaround, the text blocks clicks from being detected by the rectangle underneath it.
After playing around with it quite a bit, the best alternatives I came up with were to create an image with the text pre-rendered in, or else use a global click listener and use the coordinates to determine if the click occurred on the button. The following code isn't reusable, but it's a proof of concept that you could abstract into a function or class by parameterizing everything:
import turtle
from turtle import Turtle
def handle_btn_click(x, y):
if (x > -btn_size and y > -btn_size / 2 and
x < btn_size and y < btn_size / 2):
print("game started")
turtle.tracer(1)
turtle.clearscreen()
turtle.bye()
turtle.tracer(0)
r = Turtle(shape="square")
btn_size = 80
r.shapesize(btn_size // 20, btn_size // 10)
r.color("black")
turtle.update()
t = Turtle()
t.color("white")
t.ht()
text = "click me to start the game"
t.write(text, move=False, align="center", font=("Arial", 8, "normal"))
turtle.Screen().onclick(handle_btn_click)
turtle.mainloop()
As a final note, if you're only adding a single button, I suggest keeping it simple and imperative. A class structure is often overkill for most turtle apps, and the large parameter lists are a pain to deal with for only a single instance.
The text shows below the button seems to happen when you call any methods of the Button class after you wrote the text.
Try the following code:
class Button(Rectangle):
def __init__(self, position, width, height, text, onclick, color="gray"):
#...
writer.writetext(text, color="red")
self.goto(position[0], position[1])
self.color(color)
self.onclick(onclick)
writer.writetext("abc", color="blue")
If you set turtle.tracer with a bit of delay, you can actually see the grey button being created first, then the text in red on the grey button, then the grey button is brought back up by the three self. methods, then the text "abc" in blue written on top of everything.
Still, as mentioned in ggorlen's answer, the text will block the button from being clicked. Please refer to ggorlen's answer for the alternative solution.

Passing a tkinter canvas between classes without calling the child from within the parent

I am somewhat of a beginner when it comes to Python, but i decided i want to write a basic 2-d physics playground. Unfortionetly i ran straigt into trouble when trying to setup the basic structure.
My plan is to create a GUI with a canvas in a parent function named mainWindow, then i figured i would create a child class (Hero) which creates a circle the user can manipulate on the canvas. This seems to work fairly well.
The problem occurs when i try to do anything with the Hero class, like call a function to delete the circle so i can redraw it in some direction. I can't seem to pass the canvas from the mainWindow to the Hero class. Any help would be greatly appreciated, including telling me that this is the wrong way to do things.
Im adding the two documents im working with since my rambling is probably hard to follow.
I run the program from the phesics.py document, resulting in the GUI poping up with my canvas and a red circle. When i close the window i get the following error:
classes.py", line 29, in moveHeroBody
canvas.delete(heroBody)
NameError: name 'canvas' is not defined
Unfortionetly i dont know how to get the "world" into the child
classes.py
from tkinter import *
class mainWindow():
def __init__(self):
#Setup the GUI
root = Tk()
root.geometry('800x600')
# Setup the canvas within the GUI (master)
world = Canvas(root, height = 600, width = 800, bg = "#FFFFFF")
world.place(relx = 0.5, rely = 0.5, anchor = CENTER)
Hero(world)
root.mainloop()
class Hero(mainWindow):
def __init__(self,world):
#Initial creation of hero at coordinates
x1 = 10
y1 = 10
x2 = 70
y2 = 70
heroBody = world.create_oval(x1,y1,x2,y2, fill = "#FF0000", outline = "#FF0000")
#Move the hero
def moveHeroBody():
print("moveHeroBody")
world.delete(heroBody)
phesics.py
from tkinter import *
from classes import *
mainWindow1 = mainWindow()
moveHero = Hero.moveHeroBody()
You're passing it ok, but you're throwing the value away. Also, Hero shouldn’t inherit from mainWindow.
You need to save world as an attribute so that you can reference it later.
class Hero():
def __init__(self,world):
self.world = world
...
Then, you can use self.world to reference the canvas:
def moveHeroBody():
print("moveHeroBody")
self.world.delete(heroBody)
Though, the above code will fail because heroBody is a variable local to the __init__ - you need to do the same with it:
class Hero():
def __init__(self,world):
self.world = world
...
self.heroBody = world.create_oval(...)
#Move the hero
def moveHeroBody():
print("moveHeroBody")
self.world.delete(self.heroBody)
I think you need to initialize the class Hero in your mainWindow class. The modifications needed to do in the code are:
classes.py
from tkinter import *
from time import sleep
class mainWindow():
def __init__(self):
#Setup the GUI
self.jump_gap = 25
root = Tk()
root.geometry('800x600')
# Setup the canvas within the GUI (master)
self.world = Canvas(root, height = 600, width = 800, bg = "#FFFFFF")
self.world.place(relx = 0.5, rely = 0.5, anchor = CENTER)
self.hero = Hero(self.world)
self.world.pack()
root.bind("<space>",self.jump) # -> [1] Binds the SPACE BAR Key to the function jump
root.mainloop()
def jump(self,event):
gaps = list(range(self.jump_gap))
for i in gaps:
self.world.after(1,self.hero.moveHeroJump(h=i)) # [2] -> Binds the moveHeroJump method with the window action to a queue of updates
self.world.update() #[2] updates the canvas
sleep(0.01*i) # Added some linear wait time to add some look to it
gaps.reverse()
for i in gaps:
self.world.after(1,self.hero.moveHeroJump(h=-i))
self.world.update()
sleep(0.01*i)
class Hero():
def __init__(self,world):
#Initial creation of hero at coordinates
self.world = world
self.x1 = 10
self.y1 = 410
self.x2 = 70
self.y2 = 470
self.heroBody = self.world.create_oval(self.x1,self.y1,self.x2,self.y2, fill = "#FF0000", outline = "#FF0000")
#Move the hero
def moveHeroJump(self,h):
print("moveHeroBody")
self.y1 -= h
self.y2 -= h
self.world.delete(self.heroBody)
self.heroBody = self.world.create_oval(self.x1,self.y1,self.x2,self.y2, fill = "#FF0000", outline = "#FF0000")
physics.py
from tkinter import *
from classes import *
mainWindow1 = mainWindow()
Edit
So this got me playing some minutes ago, and I researched some sources from stack in order to complete this question. Here are the sources (referenced in the code as well):
How to bind spacebar key to a certain method in tkinter python
Moving Tkinter Canvas
The solution edited above is capable to perform a simple animation of a ball jumping. self.jump_gap is a fixed quantity that tells the ball how much does it needs to jump. The jump parses a certain height h to the moveHeroJump method to make the ball change its position, after the change of position is queued into the Canvas an update is called to see the changes on the ball.

Issue deleting a canvas object from class

I have a problem with deleting canvas object from class.
I created an object of type Rectangle called f. Then I need to delete this object. Python deletes f, but does not delete a canvas object, which is on Frame. I don't know where is the problem.
from tkinter import *
class Rectangle():
def __init__(self, coords, color):
self.coords = coords
self.color = color
def __del__(self):
print("In DELETE")
del self
print("Goodbye")
def draw(self, canvas):
"""Draw the rectangle on a Tk Canvas."""
print("In draw ")
print("Canvas = ",canvas)
print("self = ",self)
print("bild canvas = ",canvas.create_rectangle(*self.coords, fill=self.color))
root = Tk()
root.title('Basic Tkinter straight line')
w = Canvas(root, width=500, height=500)
f = []
f = Rectangle((0+30*10, 0+30*10, 100+30*10, 100+30*10), "yellow")
print("Draw object", f.draw(w), f)
f.__del__()
del f
w.pack()
mainloop()
Ok, the problem you are having is you started creating a Rectangle object for your own use, which seems reasonable, but you need to work on its implementation.
Anyways to accomplish what you want to do simply (without your object):
# draws a rectangle and returns a integer
rectangle_id = c.create_rectangle(*(0, 0, 30, 30), fill="yellow")
c.delete(rectangle_id) # removes it from the canvas
To accomplish what you want with your Rectangle object I suggest using an attribute to store the id when you drew it and implement a method that can delete it. It looks like you may want to use the __del__ method to remove it when there are no longer any references to your object. This can be done, but you should be aware of some caveats (outside of the scope of my answer... See: http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/). I personally would opt for explicitly calling a method to delete the object representation from the view to avoid all that nonsense :).
There are many design decisions here I am ignoring, I suggest you put some thought into your use of OO here, or avoid it until you have better understanding of tkinter.

Categories