tkinter: object with different movement patterns - python

I'm working on a simulation in which some cubes of the same class are moving randomly. My aim is to give them another moving pattern, when they fulfill some characteristics (for example their object number).
My Problem:
If they fulfill the characteristics, how can I "switch off" the first moving pattern and activate the next?
Here a strongly simplified example of the simulation, and how it doesn't work:
from tkinter import *
from random import *
class Cubes:
def __init__(self, master, canvas, number, x1, y1, color):
self.master = master
self.canvas = canvas
self.number = number
self.x1 = x1
self.y1 = y1
self.x2 = x1 + 15
self.y2 = y1 + 15
self.color = color
self.rectangle = canvas.create_rectangle(x1, y1, self.x2, self.y2, fill=color)
def movement(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
if self.number == 2:
def movementII(self):
canvas.move(self.rectangle, 0, 0)
self.canvas.after(100, self.movementII)
self.canvas.after(100, self.movement)
if __name__ == "__main__":
master = Tk()
canvas = Canvas(master, width=900, height=600)
canvas.pack()
master.title("Simulation")
cube = Cubes(master, canvas, 2, randint(50, 800), randint(25, 500), "black")
cube.movement()
mainloop()

how can I "switch off" the first moving pattern and activate the next?
When you call after, it returns a unique identifier. You can save that identifier and then later pass it to after_cancel to cancel the job if it hasn't already run.
I'm not entirely clear what you want, but if you want to turn off the old movement when you switch to the new, it would look something like this:
class Cubes:
def __init__(self, master, canvas, number, x1, y1, color):
...
self.after_id = None
...
def cancel(self):
if self.after_id is not None:
self.after_cancel(self.after_id)
self.after_id = None
def movement(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
if self.number == 2:
def movementII(self):
canvas.move(self.rectangle, 0, 0)
self.cancel()
self.after_id = self.canvas.after(100, self.movementII)
self.after_id = self.canvas.after(100, self.movement)
A better way might be to have a single method that you call with after, and it simply calls the appropriate method.
For example, something like this:
def move(self):
if self.number == 1:
self.movement_1()
elif self.number == 2:
self.movement_2()
self.canvas.after(100, self.move)
def movement_1(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
def movement_2(self):
canvas.move(self.rectangle, 0, 0)
Then, to switch the movement method, just change self.number and it will automatically be called at the appropriate time.

Related

Modeling simultaneous moving bodies in canvas

I'm strugling with canvas.move in a simulation of a celestial system. How can I simultaneously move multiple objects in a defined Space instance? I guess I have to do something with the identity of the body objects. But I cannot find it out. Perhaps I should use repeating draw en delete methods in stead of canvas.move? See a simplified version of the coden below. Does some body has a suggestion? Many thanks
import tkinter as tk
class Space(tk.Frame):
def __init__(self, master, size, bg=None):
super().__init__(master)
frame = tk.Frame(master, border = 5)
frame.pack()
self.width, self.height = size[0], size[1]
self.canvas = tk.Canvas(frame,
width = self.width,
height = self.height,
borderwidth= 0,
highlightthickness= 0,
bg=bg)
self.canvas.pack()
def place_body(self, body):
x1, y1 = body.loc[0], body.loc[1]
x2, y2 = x1+body.size, y1+body.size
self.canvas.create_oval(x1,y1,x2,y2, fill=body.color)
def distance_step(self):
pass
def move_body(self, body):
# in stead of distance_step:
dx, dy = body.speed[0], body.speed[1]
self.canvas.move(body, dx, dy)
self.canvas.after(1, lambda: self.move_body(body))
class CelestialBody:
def __init__(self, name, size, mass, loc, speed, color="white"):
self.name = name
self.size = size
self.mass = mass
self.loc = loc
self.speed = speed
self.color = color
def __repr__(self):
return f"{self.name}"
class App:
def __init__(self):
x, y = 1000, 800
size = (x,y)
space = Space(root,size, bg = 'black')
sun1_size = 30
sun1_mass = 10
sun1_loc = (700, 450)
sun1_speed = (-200,0)
sun2_size = 30
sun2_mass = 10
sun2_loc = (300, 350)
sun2_speed = (200,0)
sun1 = CelestialBody("sun1", sun1_size, sun1_mass, sun1_loc, sun1_speed, color = "yellow")
sun2 = CelestialBody("sun2", sun2_size, sun2_mass, sun2_loc, sun2_speed, color ="yellow")
space.place_body(sun1)
space.place_body(sun2)
space.move_body(sun1)
space.move_body(sun2)
print(sun1, sun2)
root.mainloop()
root = tk.Tk()
root.title('UNIVERSE')
app = App()```
You need to keep track of the tag returned from canvas.create_oval(). See .tk_tag below. I had to slow down your speeds because the object immediately left the screen. Also note: instead of dx, dy = body.speed[0], body.speed[1], you can just do dx, dy = body.speed.
import tkinter as tk
class Space(tk.Frame):
def __init__(self, master, size, bg=None):
super().__init__(master)
frame = tk.Frame(master, border=5)
frame.pack()
self.width, self.height = size
self.canvas = tk.Canvas(frame,
width=self.width,
height=self.height,
borderwidth=0,
highlightthickness=0,
bg=bg)
self.canvas.pack()
def place_body(self, body):
x1, y1 = body.loc
x2, y2 = x1 + body.size, y1 + body.size
body.tk_tag = self.canvas.create_oval(x1, y1, x2, y2, fill=body.color)
def distance_step(self):
pass
def move_body(self, body):
# in stead of distance_step:
dx, dy = body.speed
dx, dy = dx/100, dy/100
self.canvas.move(body.tk_tag, dx, dy)
self.canvas.after(1, lambda: self.move_body(body))
class CelestialBody:
def __init__(self, name, size, mass, loc, speed, color="white"):
self.name = name
self.size = size
self.mass = mass
self.loc = loc
self.speed = speed
self.color = color
self.tk_tag = None
def __repr__(self):
return f"{self.name}"
class App:
def __init__(self):
x, y = 1000, 800
size = (x, y)
space = Space(root, size, bg='black')
sun1_size = 30
sun1_mass = 10
sun1_loc = (700, 450)
sun1_speed = (-200, 0)
sun2_size = 30
sun2_mass = 10
sun2_loc = (300, 350)
sun2_speed = (200, 0)
sun1 = CelestialBody("sun1", sun1_size, sun1_mass, sun1_loc, sun1_speed, color="yellow")
sun2 = CelestialBody("sun2", sun2_size, sun2_mass, sun2_loc, sun2_speed, color="yellow")
space.place_body(sun1)
space.place_body(sun2)
space.move_body(sun1)
space.move_body(sun2)
print(sun1, sun2)
root.mainloop()
root = tk.Tk()
root.title('UNIVERSE')
app = App()

Tkinter canvas doesn't show my "player" symbol

I am beginner in Python and want just to make a red square that will move by pressed keys on keyboard. But after I had run this, only green canvas showed up, no red square. Here is the code:
Imports:
try:
import Tkinter
except:
import tkinter as Tkinter
import time
Here just some constants
__author__ = "Brano"
print(__author__)
GAME_WIDTH = 800
GAME_HEIGHT = 600
GAME_BG = 'green'
MOVE_SPEED = 10
Main class with initialization:
class Game(Tkinter.Tk):
def __init__(self, *args, **kwargs):
Tkinter.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
Creating board:
def create_board(self):
self.board = Tkinter.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT,
bg=GAME_BG)
self.board.pack(padx=10, pady=10)
return
Creating red square:
def create_men(self):
self.men = self.board.create_rectangle(300, 300, 310, 310, fill='red')
return
Move square after pressing keys:
def move(self, event=None):
key = event.keysym
if key=='Left':
self.x = MOVE_SPEED
elif key=='Right':
self.x = -MOVE_SPEED
elif key=='Up':
self.y = MOVE_SPEED
elif key=='Down':
self.y = -MOVE_SPEED
else:
pass
return
Just tkinter updates:
def TkUpdate(self):
self.update()
self.update_idletasks()
return
My main move update:
def GameUpdate(self):
self.board.move(self.men, self.x, self.y)
return
Checking if it is imported:
if __name__ == '__main__':
root=Game(className=" Snake Game ")
while True:
root.TkUpdate()
root.GameUpdate()
time.sleep(0.09)
else :
print("U cannot import me !")
Here is the canvas I have
Here is the whole class:
class Game(Tkinter.Tk):
def __init__(self, *args, **kwargs):
Tkinter.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
def create_board(self):
self.board = Tkinter.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT, bg=GAME_BG)
self.board.pack(padx=10, pady=10)
return
def create_men(self):
self.men = self.board.create_rectangle(300, 300, 310, 310, fill='red')
return
def move(self, event=None):
key = event.keysym
if key=='Left':
self.x = MOVE_SPEED
elif key=='Right':
self.x = -MOVE_SPEED
elif key=='Up':
self.y = MOVE_SPEED
elif key=='Down':
self.y = -MOVE_SPEED
else:
pass
return
def TkUpdate(self):
self.update()
self.update_idletasks()
return
def GameUpdate(self):
self.board.move(self.men, self.x, self.y)
return
Avoid calling update and sleep. Instead use after and mainloop. Your code should schedule your gameloop using after and enter the mainloop after setting up everything. Then keep scheduling the gameloop with after calls.
Your actual problem is you have confused using self.x and self.y as a position in the setup but then use these as a relative move in the game loop. So when you first call GameUpdate you move the rectangle by half the canvas size and it immediately moves out of view. Below is a version that uses these as the 'man' position and asserts the position using coords each time around the game loop.
import tkinter as tk
GAME_WIDTH = 800
GAME_HEIGHT = 600
GAME_BG = 'green'
MOVE_SPEED = 10
MAN_SIZE = 20
class Game(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
def create_board(self):
self.board = tk.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT, bg=GAME_BG)
self.board.pack(padx=10, pady=10)
def create_men(self):
self.men = self.board.create_rectangle((self.x, self.y, self.x + MAN_SIZE, self.y + MAN_SIZE), fill='red', outline='black')
def move(self, event=None):
key = event.keysym
print(key)
if key=='Left':
self.x = self.x - MOVE_SPEED
elif key=='Right':
self.x = self.x + MOVE_SPEED
elif key=='Up':
self.y = self.y - MOVE_SPEED
elif key=='Down':
self.y = self.y + MOVE_SPEED
else:
pass
return
def game_loop(self):
self.board.coords(self.men, (self.x, self.y, self.x + MAN_SIZE, self.y + MAN_SIZE))
self.after(10, self.game_loop)
def main():
game = Game(className="Snake")
game.after(10, game.game_loop)
game.mainloop()
if __name__ == '__main__':
main()

How to detect if a key is being held down in Tkinter?

As a novice when it comes to Python, I've tried programming my own game to start, with the advice of a guidebook. However, for this game, I'm trying to detect when a key is held down consistently instead of just pressed. The current code I'm using doesn't make the character move, and without the halt(self, evt) code being implemented, causes the ship to speed up uncontrollably after the button is held down for long enough.
from tkinter import *
import random
import time
class Game:
def __init__(self):
self.tk = Tk()
self.tk.title("Shooter")
self.tk.resizable(0, 0)
self.tk.wm_attributes("-topmost", 1)
self.canvas = Canvas(self.tk, width=500, height=1000, highlightthickness=0)
self.canvas.pack()
self.tk.update()
self.canvas_height = 1000
self.canvas_width = 500
self.bg = PhotoImage(file="background.gif")
w = self.bg.width()
h = self.bg.height()
for x in range(0, 5):
for y in range(0, 10):
self.canvas.create_image(x * w, y * h, \
image=self.bg, anchor='nw')
self.sprites = []
self.running = True
def mainloop(self):
while 1:
if self.running == True:
for sprite in self.sprites:
sprite.move()
self.tk.update_idletasks()
self.tk.update()
time.sleep(0.01)
class Coords:
def __init__(self, x1=0, y1=0, x2=0, y2=0):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
class Sprite:
def __init__(self, game):
self.game = game
self.endgame = False
self.coordinates = None
def move(self):
pass
def coords(self):
return self.coordinates
class PlayerSprite(Sprite):
def __init__(self, game):
Sprite.__init__(self, game)
self.renderimage = [
PhotoImage(file="player_1.gif"),
PhotoImage(file="player_2.gif"),
PhotoImage(file="player_3.gif"),
PhotoImage(file="player_4.gif"),
]
self.image = game.canvas.create_image(225, 900, \
image=self.renderimage[0], anchor='nw')
self.x = 0
self.y = 0
self.velx = 0
self.current_image = 0
self.current_image_add = 1
self.shoot_timer = 0
self.last_time = time.time()
self.coordinates = Coords()
x_move = None
y_move = None
game.canvas.bind_all('<KeyPress-Left>', self.move_left)
game.canvas.bind_all('<KeyPress-Right>', self.move_right)
game.canvas.bind_all('<KeyPress-Up>', self.move_up)
game.canvas.bind_all('<KeyPress-Down>', self.move_down)
game.canvas.bind_all('<KeyPress-Left>', self.halt)
game.canvas.bind_all('<KeyPress-Right>', self.halt)
game.canvas.bind_all('<KeyPress-Up>', self.halt)
game.canvas.bind_all('<KeyPress-Down>', self.halt)
game.canvas.bind_all('<space>', self.shoot)
def move_left(self, evt):
x_move = self.x - 1.5
self.x = x_move
def move_right(self, evt):
x_move = self.x + 1.5
self.x = x_move
def move_up(self, evt):
y_move = self.y - 1.5
self.y = y_move
def move_down(self, evt):
y_move = self.y + 1.5
self.y = y_move
def halt(self, evt):
time.sleep(0.01)
if x_move < 0:
x_move = -1.5
elif x_move > 0:
x_move = 1.5
elif y_move < 0:
y_move = -1.5
elif y_move > 0:
y_move = 1.5
def shoot(self, evt):
print("Placeholder")
def move(self):
self.game.canvas.move(self.image, self.x, self.y)
def coords(self):
xy = self.game.canvas.coords(self.image)
self.coordinates.x1 = xy[0]
self.coordinates.y1 = xy[1]
self.coordinates.x2 = xy[0] + 24
self.coordinates.y2 = xy[1] + 32
return self.coordinates
g = Game()
sp = PlayerSprite(g)
g.sprites.append(sp)
g.mainloop()
My goal is to have my character move at a constant rate (as opposed to uncontrollably fast after a while) when the respective key is pressed.
The most straightforward solution to your question would be to avoid adding a value at every keypress, but rather set a constant value.
def move_left(self, evt):
x_move = -5
self.x = x_move
The movement would however lose its dynamic, but it will be constant. Otherwise, you could create a max value. Something like this:
def move_left(self, evt):
int max_val_left = -10
if( self.x < max_val_left):
x_move = self.x - 1.5
self.x = x_move
Thereby forcing self.x to remain capped and constant if it has reached the max_val.
Holding down a key is essentially the same as pressing that key repeatedly. What you're doing by adding to/subtracting from the self.x/self.y attributes in your move_* functions is you're increasing the amount that the canvas will move your player sprite in each function call (e.g. from 1.5 to 3 to 4.5 to 6, etc. as you hold down a direcitonal key).
Since the canvas will be moving your player by (self.x, self.y) units every time "move" is called under the "PlayerSprite" class, we want self.x and self.y to be either 0 or whatever speed you desire (1.5 in the following code). So instead of adding to self.x and self.y, we should assign it to a constant value:
def move_left(self, evt):
self.x = -1.5
def move_right(self, evt):
self.x = 1.5
def move_up(self, evt):
self.y = -1.5
def move_down(self, evt):
self.y = -1.5
Also, instead of using "halt", what you could do is include 'KeyRelease-*' bindings to stop your player once you've stopped holding down a directional key:
game.canvas.bind_all('KeyRelease-Left'>, self.stop_horz_move)
game.canvas.bind_all('KeyRelease-Right'>, self.stop_horz_move)
game.canvas.bind_all('KeyRelease-Up'>, self.stop_vert_move)
game.canvas.bind_all('KeyRelease-Down'>, self.stop_vert_move)
(I've generalized the left and right directions to horz as well as up and down to vert to save on the number of function definitions.)
Then you can create functions that assign your self.x value or self.y value to 0, so that your player doesn't move once "move" is called.
def stop_move_horz(self, evt):
self.x = 0
def stop_move_vert(self, evt):
self.y = 0

Redraw circle - python

I have this bit of code here:
from tkinter import *
class player():
def __init__(self, radius, xcoordinate = 0, ycoordinate = 0):
self.xcoordinate = xcoordinate
self.ycoordinate = ycoordinate
self.radius = radius
def moveRight(self, event):
self.xcoordinate += 25
self.draw()
print("Right key pressed")
print("x: " + str(self.xcoordinate))
def moveLeft(self, event):
self.ycoordinate += 25
self.draw()
print("Left key pressed")
print("y: " + str(self.ycoordinate))
def draw(self):
world = client()
world.title("World")
world.bind('<Right>', self.moveRight)
world.bind('<Left>', self.moveLeft)
canvas = Canvas(world, width=200, height=200, borderwidth=0,highlightthickness=0, bg="black")
canvas.grid()
canvas.draw_player(self.xcoordinate, self.ycoordinate, self.radius, fill="blue", width=4)
world.mainloop()
class client(Tk):
def __init__(self):
super().__init__()
def draw_player(self, x, y, r, **kwargs):
return self.create_oval(x-r, y-r, x+r, y+r, **kwargs)
Canvas.draw_player = draw_player
p1 = player(50)
p1.draw()
The problem is that whenever I press the right or left arrow keys, it calls the draw() method. The draw() method constructs a new client object and etc.
So you end up opening multiple windows each with a circle with different x and y coordinates. How do I make this such that when I call draw() it only edits the x and y coordinates and redraws the circle on the same window?
Please no suggestions to use pygame, my IDE gets errors when I try to import the module.
The code can be simplified by passing the move parameters to a single function.
from tkinter import *
from functools import partial
class player():
def __init__(self, master, radius, xcoordinate=100, ycoordinate=100):
self.master=master
self.xcoordinate = xcoordinate
self.ycoordinate = ycoordinate
self.radius = radius
self.master.title("World")
self.master.bind('<Right>', partial(self.move_oval, 25, 0))
self.master.bind('<Left>', partial(self.move_oval, -25, 0))
self.master.bind('<Up>', partial(self.move_oval, 0, -25))
self.master.bind('<Down>', partial(self.move_oval, 0, 25))
self.draw() ## called once
def move_oval(self, x, y, event):
self.canvas.move(self.oval_id, x, y)
print("key pressed", x, y)
def draw(self):
self.canvas = Canvas(self.master, width=200, height=200,
borderwidth=0,highlightthickness=0, bg="black")
self.canvas.grid()
self.oval_id=self.canvas.create_oval(self.xcoordinate-self.radius,
self.ycoordinate-self.radius,
self.xcoordinate+self.radius,
self.ycoordinate+self.radius,
fill="red")
master=Tk()
p1 = player(master, 50)
master.mainloop()
I assume that
redraws the circle on the same window
means moving the circle, and does not mean drawing a second circle in the same space. Use the move() function for a canvas object to do this http://effbot.org/tkinterbook/canvas.htm . Note that you have to save a reference to the object to be moved. Also your moveLeft() function doesn't.
class Player():
def __init__(self, master, radius, xcoordinate=100, ycoordinate=100):
self.master=master
self.xcoordinate = xcoordinate
self.ycoordinate = ycoordinate
self.radius = radius
self.master.title("World")
self.master.bind('<Right>', self.moveRight)
self.master.bind('<Left>', self.moveLeft)
self.draw() ## called once
def moveRight(self, event):
self.canvas.move(self.oval_id, 25, 0)
print("Right key pressed")
print("x: " + str(self.xcoordinate))
def moveLeft(self, event):
self.canvas.move(self.oval_id, 0, 25)
print("Left key pressed")
print("y: " + str(self.ycoordinate))
def draw(self):
self.canvas = Canvas(self.master, width=200, height=200,
borderwidth=0,highlightthickness=0, bg="black")
self.canvas.grid()
self.oval_id=self.canvas.create_oval(self.xcoordinate-self.radius,
self.ycoordinate-self.radius,
self.xcoordinate+self.radius,
self.ycoordinate+self.radius,
fill="red")
master=Tk()
p1 = Player(master, 50)
master.mainloop()

How to draw the "trail" in a maze solving application

Hello i have designed a maze and i want to draw a path between the cells as the 'person' moves from one cell to the next.
So each time i move the cell a line is drawn
Also i am using the graphics module
The graphics module is an object oriented library
Im importing
from graphics import*
from maze import*
my circle which is my cell
center = Point(15, 15)
c = Circle(center, 12)
c.setFill('blue')
c.setOutline('yellow')
c.draw(win)
p1 = Point(c.getCenter().getX(), c.getCenter().getY())
this is my loop
if mazez.blockedCount(cloc)> 2:
mazez.addDecoration(cloc, "grey")
mazez[cloc].deadend = True
c.move(-25, 0)
p2 = Point(p1.getX(), p1.getY())
line = graphics.Line(p1, p2)
cloc.col = cloc.col - 1
Now it says getX not defined every time i press a key is this because of p2???
This is the most important bits in the module for this part
def __init__(self, title="Graphics Window",
width=200, height=200, autoflush=True):
master = tk.Toplevel(_root)
master.protocol("WM_DELETE_WINDOW", self.close)
tk.Canvas.__init__(self, master, width=width, height=height)
self.master.title(title)
self.pack()
master.resizable(0,0)
self.foreground = "black"
self.items = []
self.mouseX = None
self.mouseY = None
self.bind("<Button-1>", self._onClick)
self.height = height
self.width = width
self.autoflush = autoflush
self._mouseCallback = None
self.trans = None
self.closed = False
master.lift()
if autoflush: _root.update()
def __checkOpen(self):
if self.closed:
raise GraphicsError("window is closed")
def setCoords(self, x1, y1, x2, y2):
"""Set coordinates of window to run from (x1,y1) in the
lower-left corner to (x2,y2) in the upper-right corner."""
self.trans = Transform(self.width, self.height, x1, y1, x2, y2)
def plot(self, x, y, color="black"):
"""Set pixel (x,y) to the given color"""
self.__checkOpen()
xs,ys = self.toScreen(x,y)
self.create_line(xs,ys,xs+1,ys, fill=color)
self.__autoflush()
def plotPixel(self, x, y, color="black"):
"""Set pixel raw (independent of window coordinates) pixel
(x,y) to color"""
self.__checkOpen()
self.create_line(x,y,x+1,y, fill=color)
self.__autoflush()
def draw(self, graphwin):
if self.canvas and not self.canvas.isClosed(): raise GraphicsError(OBJ_ALREADY_DRAWN)
if graphwin.isClosed(): raise GraphicsError("Can't draw to closed window")
self.canvas = graphwin
self.id = self._draw(graphwin, self.config)
if graphwin.autoflush:
_root.update()
def move(self, dx, dy):
"""move object dx units in x direction and dy units in y
direction"""
self._move(dx,dy)
canvas = self.canvas
if canvas and not canvas.isClosed():
trans = canvas.trans
if trans:
x = dx/ trans.xscale
y = -dy / trans.yscale
else:
x = dx
y = dy
self.canvas.move(self.id, x, y)
if canvas.autoflush:
_root.update()
class Point(GraphicsObject):
def __init__(self, x, y):
GraphicsObject.__init__(self, ["outline", "fill"])
self.setFill = self.setOutline
self.x = x
self.y = y
def _draw(self, canvas, options):
x,y = canvas.toScreen(self.x,self.y)
return canvas.create_rectangle(x,y,x+1,y+1,options)
def _move(self, dx, dy):
self.x = self.x + dx
self.y = self.y + dy
def clone(self):
other = Point(self.x,self.y)
other.config = self.config.copy()
return other
def getX(self): return self.x
def getY(self): return self.y
def __init__(self, p1, p2, options=["outline","width","fill"]):
GraphicsObject.__init__(self, options)
self.p1 = p1.clone()
self.p2 = p2.clone()
def _move(self, dx, dy):
self.p1.x = self.p1.x + dx
self.p1.y = self.p1.y + dy
self.p2.x = self.p2.x + dx
self.p2.y = self.p2.y + dy
def getP1(self): return self.p1.clone()
def getP2(self): return self.p2.clone()
def getCenter(self):
p1 = self.p1
p2 = self.p2
return Point((p1.x+p2.x)/2.0, (p1.y+p2.y)/2.0)
You might try this from an interactive Python shell:
>>> import graphics
>>> help(graphics.Circle)
That should tell you what attributes Circle does have.
You're trying to use getX() and getY() as free-standing FUNCTIONS:
p2 = Point(getX(), getY())
Note that you're calling them as bare names, not qualified names -- therefore, as functions, not as methods.
And yet the docs you quote say they're methods -- therefore, they must be called as part of qualified names ("after a dot"...!-) and before the dot must be an instance of Point.
Presumably, therefore, you need p1.getX() and p1.getY() instead of the bare names you're using. p1.getX is a qualified name (i.e., one with a dot) and it means "method or attribute getX of object p1.
This is really super-elementary Python, and I recommend you first study the official Python tutorial or other even simpler introductory documents before you try making or modifying applications in Python.
I don't know how maze solves the puzzle, so I am going to assume it works like a generator, yielding the next move for the circle to make. Something to this effect:
while not this_maze.solved():
next_position = this_maze.next()
my_circle.move(next_position)
Then all you need to do is keep track of the current circle position and the previous circle position.
prev_position = this_maze.starting_point
while not this_maze.solved():
next_position = this_maze.next()
my_circle.clear()
draw_trail(prev_position, next_position)
my_circle.draw_at(next_position)
prev_position = next_position
Obviously, changing this in something compatible with your framework is left up to you. dir(), help() and reading the libraries' source will all help you.

Categories