Drawing Basic Animations in Python - 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!

Related

Paddle object from class wont appear

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.

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.

How to use turtle.onclick with an object from a class?

I want to make a class for turtle buttons and have a field to be the turtle
and here is the code I wrote:
class button:
def __init__(self,color,x,y):
self.turtle=turtle.Turtle()
self.turtle.penup()
self.turtle.shape("square")
self.turtle.color(color)
self.turtle.speed(0)
self.turtle.goto(x,y)
Now I want to use the onclick to a button instance, so how do I do that is it something like this?
def click(self,x,y):
print ("hello world")
self.turtle.onclick()
I'm not that good at classes btw so I just want something simple.
Here's how to bind the class' click() method to mouse-click events. See the documentation for the turtle.onclick() method.
import turtle
SCREENWIDTH = 640
SCREENHEIGHT = 480
class Button:
def __init__(self,color,x,y):
self.turtle = turtle.Turtle()
self.turtle.penup()
self.turtle.shape("square")
self.turtle.color(color)
self.turtle.speed(0)
self.turtle.goto(x,y)
self.turtle.onclick(self.click) # Bind mouse-click event to method.
def click(self, x, y):
print ("hello world")
if __name__ == "__main__":
mainscreen = turtle.Screen()
mainscreen.mode("standard")
mainscreen.setup(SCREENWIDTH, SCREENHEIGHT)
Button('red', 0, 0)
turtle.mainloop()
P.S. I strongly suggest you read and start following the coding suggestions in the PEP 8 - Style Guide for Python Code. It will make your code easier to read and understand.

trying to make paint with python turtle module

I'm a beginner and i'm trying to make paint with python turtle but my code gives an error. I've tried everything I could think of but it still isn't working.
from turtle import *
from menuitem import MenuItem
def changePenColor(c):
"""Changes the system turtle's color to c."""
color(c)
def createMenu(callBack):
"""Displays 6 menu items to respond to the given callback function."""
x = - (window_width() / 2) + 30
y = 100
colors = ('red', 'green', 'blue', 'yellow', 'black', 'purple')
shape = "circle"
for color in colors:
MenuItem(x, y, shape, color, callBack)
y -= 30
def main():
"""Creates a menu for selecting colors."""
reset()
shape("turtle")
createMenu(color)
return "done!"
if __name__=='__main__':
msg = main()
print(msg)
mainloop()
And this code in a different file:
from turtle import Turtle
class MenuItem(Turtle):
"""Represents a menu item."""
def __init__(self, x, y, shape, color, callBack):
"""Sets the initial state of a menu item."""
Turtle.__init__(x, y, self, shape = shape, visible = False)
self.speed(0)
self.up()
self.goto(x, y)
self.color(color, color)
self._callBack=callBack
self.onclick(lambda x,y: self._callBack(color))
self.showturtle()
If anyone knows what I can do to fix this, I'd be happy to know.
Thanks 😊
Your code is somewhat confused. Specifically:
from turtle import *
Just don't. Particularly in a module. Import as little as you need to get the job done.
createMenu(color)
This should be createMenu(changePenColor) and changePenColor() should be defined in the main module, not the MenuItem class module.
Turtle.__init__(x, y, self, shape = shape, visible = False)
first three arguments to __init__ shouldn't be there and you should use super, all as #Evan notes.
reset()
self._callBack=callBack
These two statments are effectively no-ops and can be left out.
Below is my rework of your code that I believe does what you're attempting to do. For example purposes, instead of the main module, I just used a if __name__ == '__main__': for testing:
from turtle import Screen, Turtle
COLORS = ('red', 'green', 'blue', 'yellow', 'black', 'purple')
CURSOR_SIZE = 20
class MenuItem(Turtle):
''' Represents a menu item. '''
def __init__(self, x, y, shape, color, callBack):
''' Sets the initial state of a menu item '''
super().__init__(shape=shape, visible=False)
self.penup()
self.goto(x, y)
self.color(color)
self.onclick(lambda x, y: callBack(color))
self.showturtle()
def createMenu(callBack):
''' Displays 6 menu items to respond to the given callback function. '''
screen = Screen()
x = CURSOR_SIZE * 1.5 - screen.window_width() / 2
y = 100
for color in COLORS:
MenuItem(x, y, 'circle', color, callBack)
y -= CURSOR_SIZE * 1.5
if __name__ == '__main__':
from turtle import getscreen, getturtle
def changePenColor(c):
''' Changes the turtle's color to c. '''
turtle.color(c)
screen = getscreen() # singular screen instance
turtle = getturtle() # default turtle
turtle.shape('turtle')
# Create a menu for selecting colors.
createMenu(changePenColor)
screen.mainloop()
In your first line of the __init__ function on your MenuItem class, use this
super().__init__(shape=shape, visible=False)
instead of
Turtle.__init__(x, y, self, shape = shape, visible = False)
You don't need to pass in x, y, or self, because you are already setting the position by saying self.goto(x, y). Also, use super() instead of Turtle, because you need to initialize the superclass, not just another instance of Turtle. By saying Turtle.__init__(...) you are creating an instance of that object and doing nothing with it. By saying super().__init__(...), you are initializing the superclass of your object, which is what you always need to do when you are subclassing an object (in this case Turtle).
Note: your __init__ function needs to be indented, but I'll assume that was a pasting error.

Categories