I am writing a mario-like game (non-commercial, I'm just trying to brush up on coding) and I need to follow one of two players. Messing with canvas.move doesn't work for my needs, I was wondering if there was some way to actually control what position it renders from (such as one player offscreen and the camera moves to make him onscreen). My code:
from tkinter import *
import math,time
## Declare your many GAME CLASSES here
class Camera:
def __init__(self,game):
self.cnv=game.canvas
self.tracker=None
def track(self,player):
self.tracker=player
def run(self):
cords=self.cnv.coords(self.tracker.id)
self.cnv.move(ALL,250-cords[0],250-cords[1])
class Human:
def __init__(self,game):
game.tk.bind_all("<KeyPress>",self.press)
game.tk.bind_all("<KeyRelease>",self.release)
self.left=False
self.right=False
self.jump=False
def run(self,player):
if self.left:
player.left()
if self.right:
player.right()
if self.jump:
player.jump()
self.jump=False
def press(self,event):
if event.keysym=="Left":
self.left=True
if event.keysym=="Right":
self.right=True
if event.keysym=="Up":
self.jump=True
def release(self,event):
if event.keysym=="Left":
self.left=False
if event.keysym=="Right":
self.right=False
def hitx(self):
pass
def hity(self):
pass
class Computer:
def __init__(self):
self.direction=1
def run(self,player):
if player.onground:
if self.direction==1:
player.right()
if self.direction==-1:
player.left()
def hitx(self):
self.direction*=-1
def hity(self):
pass
class Player:
def __init__(self,startx,starty,game,controller):
self.id=game.canvas.create_image(250+startx,250+starty,anchor=CENTER,image=game.player_images[0])
self.game=game
self.xv=0
self.yv=0
self.controller=controller
self.speed=4
self.face=0
self.side=0
self.onground=False
def left(self):
self.xv-=self.speed
self.side=1
self.face=tick%2
def right(self):
self.xv+=self.speed
self.side=0
self.face=tick%2
def jump(self):
if self.onground:
self.yv=math.sqrt(self.speed)*-10
def look(self):
bricks=[]
for x in self.game.tileset:
coords=self.game.canvas.coords(x[0])
playercoords=self.game.canvas.coords(self.id)
xdifference=abs(coords[0]-playercoords[0])
ydifference=abs(coords[1]-playercoords[1])
if xdifference<250 and ydifference<250:
bricks.append(coords)
def run_slf(self):
if not self.onground:
self.face=2
self.set_face()
self.face=0
self.onground=False
self.game.canvas.move(self.id,self.xv,0)
## Work in progress: Do the X COLLISIONS FOR THE PLAYER
bounds=self.getbounds()
if len(self.game.canvas.find_overlapping(*bounds))>1:
while len(self.game.canvas.find_overlapping(*bounds))>1:
self.game.canvas.move(self.id,abs(self.xv)/self.xv*-1,0)
bounds=self.getbounds()
self.xv=0
self.controller.hitx()
self.game.canvas.move(self.id,0,self.yv)
## Work in progress: Do the Y COLLISIONS FOR THE PLAYER
bounds=self.getbounds()
if len(self.game.canvas.find_overlapping(*bounds))>1:
while len(self.game.canvas.find_overlapping(*bounds))>1:
self.game.canvas.move(self.id,0,abs(self.yv)/self.yv*-1)
bounds=self.getbounds()
self.yv=0
self.onground=True
self.controller.hity()
self.controller.run(self)
self.xv*=0.8
self.yv+=1
def set_face(self):
self.game.canvas.itemconfig(self.id,image=game.player_images[self.face+(self.side*3)])
def getbounds(self):
width=25
height=45
cords=self.game.canvas.coords(self.id)
return [cords[0]-width,cords[1]-height,cords[0]+width,cords[1]+height]
class Game:
def __init__(self,width,height):
self.tileset=[]
self.players=[]
self.tk=Tk()
self.brick_types={"regular":[False,PhotoImage(file="blocks/brick_basic.png")]}
self.tk.resizable(0,0)
self.canvas=Canvas(self.tk,width=width,height=height,background="white")
self.canvas.pack()
self.player_images=[PhotoImage(file="marioAnim/face.png"),PhotoImage(file="marioAnim/walk.png"),PhotoImage(file="marioAnim/jump.png"),PhotoImage(file="marioAnim/face-2.png"),PhotoImage(file="marioAnim/walk-2.png"),PhotoImage(file="marioAnim/jump-2.png")]
def run(self):
self.tk.update_idletasks()
self.tk.update()
for x in self.players:
x.run_slf()
def addbrick(self,x,y,tp):
self.tileset.append([self.canvas.create_image(x*50+250,y*50+250,anchor="nw",image=self.brick_types[tp][1]),self.brick_types[tp][0]])
def addline(self,x,y,xd,yd,length,tp):
for i in range(0,length):
self.addbrick(x+xd*i,y+yd*i,tp)
def addplayer(self,player):
self.players.append(player)
## Declare your GLOBAL VARIABLES here.
game=Game(500,500)
human=Human(game)
computer=Computer()
cplayer=Player(-50,0,game,computer)
hplayer=Player(50,0,game,human)
tick=0
camera=Camera(game)
camera.track(cplayer)
## BUILD TILESET
game.addline(-8,4,1,0,16,'regular')
game.addbrick(-5,3,'regular')
game.addbrick(4,3,'regular')
## ADD PLAYERS
game.addplayer(cplayer)
game.addplayer(hplayer)
while 1:
tick+=1
camera.run()
game.run()
time.sleep(0.02)
I am using python 3.7 with Tkinter.
You are asking how to programatically scroll the canvas. The xview and yview methods of the canvas control what portion of the full drawable area is visible at the current time: xview, xview_moveto, xview_scroll, yview, yview_moveto, and yview_scroll.
The xview_scroll and yview_scroll methods accept an integer amount, and then the string "units" or "pages". "units" refers to the distance defined by the xscrollincrement and yscrollincrement attributes. "pages" causes the window to scroll in increments of 9/10ths of the window width or height.
For example, if you want to be able to scroll by single pixels you can set xscrollincrement to 1, and the use xview_scroll to move left or right.
canvas.configure(xscrollincrement=1)
...
canvas.xview_scroll(1, "units")
Related
I have to generate two turtle windows and draw in each one, so I'm using tkinter to create and show the windows. My code currently opens the right screen and draws in it, but the turtle is really slow so I want to set the turtle tracer to false to use the update function, but I can't figure out how to.
This is my turtle_interpreter.py file, which has all the functions I use to draw the L-system:
import turtle
from tkinter import *
class Window(Tk):
def __init__(self, title, geometry):
super().__init__()
self.running = True
self.geometry(geometry)
self.title(title)
self.protocol("WM_DELETE_WINDOW", self.destroy_window)
self.canvas = Canvas(self)
self.canvas.pack(side=LEFT, expand=True, fill=BOTH)
self.turtle = turtle.RawTurtle(turtle.TurtleScreen(self.canvas))
def update_window(self):
'''
sets window to update
'''
if self.running:
self.update()
def destroy_window(self):
'''
sets window to close
'''
self.running = False
self.destroy()
def drawString(turt, dstring, distance, angle):
'''Interpret the characters in string dstring as a series
of turtle commands. Distance specifies the distance
to travel for each forward command. Angle specifies the
angle (in degrees) for each right or left command. The list
of turtle supported turtle commands is:
F : forward
- : turn right
+ : turn left
'''
for char in dstring:
if char == 'F':
turt.forward(distance)
elif char == '-':
turt.right(angle)
elif char == '+':
turt.left(angle)
def place(turt, xpos, ypos, angle=None):
'''
places turtle at given coordinates and angle
'''
turt.penup()
turt.goto(xpos, ypos)
if angle != None:
turt.setheading(angle)
turt.pendown()
def goto(turt, xpos, ypos):
'''
moves turtle to given coordinates
'''
turt.penup()
turt.goto(xpos, ypos)
turt.pendown()
def setColor(turt, color):
'''
sets turtle color
'''
turt.color(color)
And this is the file where the functions get called. Running it draws the L-system.
import turtle_interpreter as turt_int
import lsystem_scene_three as lsystem
def turtle_scene_two():
'''
generates scene two
'''
# create window
win_two = turt_int.Window('Turtle Scene 2', '640x480+650+0')
# assign turtle
turt2 = win_two.turtle
# lsystem setup
lsystemFile = lsystem.Lsystem('lsystem_scene_two.txt')
tstr = lsystemFile.buildString(4)
# draw stuff
turt_int.setColor(turt2, (0, 0, 0))
turt_int.place(turt2, 0, -200, 90)
turt_int.drawString(turt2, tstr, 4, 90)
# update window (loop)
while win_two.running:
win_two.update_window()
turtle_scene_two()
Hope this makes sense. Let me know if it doesn't.
Appreciate your help!
Tried a few things but nothing was promising. Calling turtle generates another screen (which I don't want).
Since you didn't provide all your code, I can't test this, so I'm guessing a good start would be changing this:
self.turtle = turtle.RawTurtle(turtle.TurtleScreen(self.canvas))
to something like:
screen = turtle.TurtleScreen(self.canvas)
screen.tracer(False)
self.turtle = turtle.RawTurtle(screen)
I want to create multiple small games in pygame zero, with a main window on which you have buttons to click - when clicking a button it would start a new window and a new subgame (coded on its own in another file). The secondary games should be able to return if the game was won or lost. Is this possible using pygame-zero? I am thinking the subgame should be encapsulated in some function to be able to give a return value, but I am not sure if this is doable in pygame-zero since it calls some functions itself... any idea?
Or am I better off adding some kind of game state in the main program and do everything there like this?
def update():
if state == 'game1':
#all of the game1 update code here
elif state == 'game2':
#all of the game2 update code here
#etc
def draw():
if state == 'game1':
#all of the game1 draw code here
elif state == 'game2':
#all of the game2 draw code here
#etc
I think you are definitely better off by implementing a game state. I'd use an object-oriented approach like:
class GameState:
def update():
pass
def draw():
pass
class Game1(GameState):
def update():
# ...
def draw():
# ...
class GameChooser(GameState):
def update():
# choose game here
global state
if ...:
state = Game1()
def draw():
# ...
state = GameChooser()
def update():
state.update()
def draw():
state.draw()
Attempted to do simple movement in tkinter:
import tkinter as tk
class GameApp(object):
"""
An object for the game window.
Attributes:
master: Main window tied to the application
canvas: The canvas of this window
"""
def __init__(self, master):
"""
Initialize the window and canvas of the game.
"""
self.master = master
self.master.title = "Game"
self.master.geometry('{}x{}'.format(500, 500))
self.canvas = tk.Canvas(self.master)
self.canvas.pack(side="top", fill="both", expand=True)
self.start_game()
#----------------------------------------------#
def start_game(self):
"""
Actual loading of the game.
"""
player = Player(self)
#----------------------------------------------#
#----------------------------------------------#
class Player(object):
"""
The player of the game.
Attributes:
color: color of sprite (string)
dimensions: dimensions of the sprite (array)
canvas: the canvas of this sprite (object)
window: the actual game window object (object)
momentum: how fast the object is moving (array)
"""
def __init__(self, window):
self.color = ""
self.dimensions = [225, 225, 275, 275]
self.window = window
self.properties()
#----------------------------------------------#
def properties(self):
"""
Establish the properties of the player.
"""
self.color = "blue"
self.momentum = [5, 0]
self.draw()
self.mom_calc()
#----------------------------------------------#
def draw(self):
"""
Draw the sprite.
"""
self.sprite = self.window.canvas.create_rectangle(*self.dimensions, fill=self.color, outline=self.color)
#----------------------------------------------#
def mom_calc(self):
"""
Calculate the actual momentum of the thing
"""
self.window.canvas.move(self.sprite, *self.momentum)
self.window.master.after(2, self.mom_calc)
#----------------------------------------------#
#----------------------------------------------#
root = tk.Tk()
game_window = GameApp(root)
Where self.momentum is an array containing 2 integers: one for the x movement, and another for the y movement. However, the actual movement of the rectangle is really slow (about 5 movements per second), with the self.window.master.after() time not seeming to have an effect.
Previously on another tkinter project I had managed to get really responsive tkinter movement, so I'm just wondering if there is a way I can minimize that movement updating time in this case, by either using a different style of OOP, or just different code altogether.
UPDATE: Turns out the time in the .after() method does matter, and it actually stacks onto the real time of the method. After using timeit to time calling the method, I got this output:
>>> print(timeit.timeit("(self.window.master.after(2, self.mom_calc))", number=10000, globals={"self":self}))
0.5395521819053108
So I guess the real question is: Why is that .after() method taking so long?
UPDATE 2: Tested on multiple computers, movement is still slow on any platform.
"The default Windows timer resolution is ~15ms. Trying to fire a timer every 1ms is not likely to work the way you want, and for a game is probably quite unnecessary (a display running a 60FPS updates only every ~16ms). See Why are .NET timers limited to 15 ms resolution?"
Found the solution at Python - tkinter call to after is too slow where Andrew Medico gave a good answer (in a comment).
I don't see the problem you report on Windows 10 using Python 3.6 at least. I tested the program as shown and had to add a root.mainloop() at the end. This showed no rectangle because the object has moved off the canvas too fast to see.
So I modified this to bounce between the walls and added a counter to print the number of mom_calc calls per second. With the after timeout set at 20ms I get 50 motion calls per second, as expected. Setting this to 2ms as in your post I get around 425 per second so there is a little error here and its taking about 2.3 or 2.4 ms per call. This is a bit variable as other processes can take up some of the time at this granularity.
Here is the (slightly) modified code:
import tkinter as tk
class GameApp(object):
"""
An object for the game window.
Attributes:
master: Main window tied to the application
canvas: The canvas of this window
"""
def __init__(self, master):
"""
Initialize the window and canvas of the game.
"""
self.master = master
self.master.title = "Game"
self.master.geometry('{}x{}'.format(500, 500))
self.canvas = tk.Canvas(self.master, background="white")
self.canvas.pack(side="top", fill="both", expand=True)
self.start_game()
#----------------------------------------------#
def start_game(self):
"""
Actual loading of the game.
"""
player = Player(self)
#----------------------------------------------#
#----------------------------------------------#
class Player(object):
"""
The player of the game.
Attributes:
color: color of sprite (string)
dimensions: dimensions of the sprite (array)
canvas: the canvas of this sprite (object)
window: the actual game window object (object)
momentum: how fast the object is moving (array)
"""
def __init__(self, window):
self.color = ""
self.dimensions = [225, 225, 275, 275]
self.window = window
self.movement = 0
self.movement_last = 0
self.properties()
#----------------------------------------------#
def properties(self):
"""
Establish the properties of the player.
"""
self.color = "blue"
self.momentum = [5, 0]
self.draw()
self.mom_calc()
self.velocity()
#----------------------------------------------#
def draw(self):
"""
Draw the sprite.
"""
self.sprite = self.window.canvas.create_rectangle(*self.dimensions, fill=self.color, outline=self.color)
#----------------------------------------------#
def mom_calc(self):
"""
Calculate the actual momentum of the thing
"""
pos = self.window.canvas.coords(self.sprite)
if pos[2] > 500:
self.momentum = [-5, 0]
elif pos[0] < 2:
self.momentum = [5, 0]
self.window.canvas.move(self.sprite, *self.momentum)
self.window.master.after(2, self.mom_calc)
self.movement = self.movement + 1
def velocity(self):
print(self.movement - self.movement_last)
self.movement_last = self.movement
self.aid_velocity = self.window.master.after(1000, self.velocity)
#----------------------------------------------#
#----------------------------------------------#
if __name__ == '__main__':
root = tk.Tk()
game_window = GameApp(root)
root.mainloop()
I am working on a gui to animate coin flips one at a time continuously.
I have two classes cointoss.py and flipbell.py.
Cointoss class generates the value change for coins and flipbell is used to animate the process.
As if now I have the code working to animate one coin at a time but not all the coins at a time.
When I say all coins this is the logic: first one coin comes down according to the value change, next another one comes down but the first coin value also gets updated accordingly and so on.
I need help how to move forward with what I have tried so far. I have used for loops to animate the process and I was thinking of using recursive method to have the logic part.
Any help with existing code or ideas to move forward would be great.
flipbell.py
from tkinter import Tk, Canvas, Button, W, E
import random
from math import pi, sin, cos
from cointoss import *
class FlipBell(object):
"""
GUI to simulate cointoss.
"""
def __init__(self, wdw, dimension, increment, delay):
"""
Determines the layout of the GUI.
wdw : top level widget, the main window,
dimension : determines the size of the canvas,
increment : step size for a billiard move,
delay : time between updates of canvas.
"""
wdw.title('Coin flips and Bell Curve')
self.dim = dimension # dimension of the canvas
self.inc = increment
self.dly = delay
self.togo = False # state of animation
# initial coordinates of the ball
self.xpt = self.dim/2
self.ypt = 0
self.cnv = Canvas(wdw, width=self.dim,\
height=self.dim, bg='white')
self.cnv.grid(row=0, column=0, columnspan=2)
self.bt0 = Button(wdw, text='start',\
command=self.start)
self.bt0.grid(row=1, column=0, sticky=W+E)
self.bt1 = Button(wdw, text='stop',\
command=self.stop)
self.bt1.grid(row=1, column=1, sticky=W+E)
def map2table(self, pnt):
"""
Keeps the ball on the canvas table.
"""
if pnt < 0:
(quo, rest) = divmod(-pnt, self.dim)
else:
(quo, rest) = divmod(pnt, self.dim)
return rest
def placecoin(self, xpt, ypt):
self.cnv.create_oval(xpt-1, ypt-1, xpt+1, ypt+1,\
width=2, outline='red', fill='red', tags='coin')
def drawball(self):
"""
Draws the ball on the canvas.
"""
xpt = self.map2table(self.xpt)
ypt = self.map2table(self.ypt)
self.cnv.delete('dot')
self.cnv.create_oval(xpt-1, ypt-1, xpt+1, ypt+1,\
width=1, outline='black', fill='red', tags='dot')
def animate(self):
"""
Performs the animation.
"""
self.drawball()
val = []
for k in range(400):
val1 = CoinToss.cointoss(3,k,self.dim//2)
val.append(val1)
points = {}
for i in range(1,401):
points[i] = 0
for i in range(0,400):
for j in range(0,400):
(xpt, ypt) = (self.xpt, self.ypt)
self.xpt = val[i][1][j]
# print("x %d",self.xpt)
self.ypt = ypt + 1
# print("y %d",self.ypt)
self.cnv.after(self.dly)
self.drawball()
self.cnv.update()
#Puts the coin on top each other
if self.ypt == 400:
if points[self.xpt]>=1:
self.placecoin(val[i][1][-1],400-points[self.xpt])
else:
self.placecoin(val[i][1][-1],400)
points[self.xpt]+=3
self.ypt = 0
def start(self):
"""
Starts the animation.
"""
self.togo = True
self.animate()
def stop(self):
"""
Stops the animation.
"""
self.togo = False
def main():
"""
Defines the dimensions of the canvas
and launches the main event loop.
"""
top = Tk()
dimension = 400 # dimension of canvas
increment = 10 # increment for coordinates
delay = 1 # how much sleep before update
num_flips = 3
num_value = dimension//2
FlipBell(top, dimension, increment, delay)
top.mainloop()
if __name__ == "__main__":
main()
cointoss.py
from random import randint
import random
class CoinToss:
coin = 0
def __init__(self, value,num_flip):
# self.id = 1
self.v = value
self.state = 1
self.flip = num_flip
CoinToss.coin += 1
def cointoss(self,coin,value):
print('The ball at the start: ball: %d, state: %d, value: %d' % (coin, self, value))
value_change = value
coin_change = []
for i in range(1,400+1):
value = value_change
value_change = CoinToss.flip(value)
print('after flip %d, ball: %d, state: %d, value: %d' % (i,coin, i, value_change))
coin_change.append(value_change)
return([coin,coin_change])
def flip(self):
rand_value = randint(0, 1)
if rand_value == 1:
self +=1
else:
self -=1
return self
You have named both a function and a variable "flip" in CoinToss which is confusing. Also, you use the "tags" keyword and it should be "tag". There is more than one way to code this. The code below is not a complete solution but a simple example that shows how to use the CoinToss class to create and move an individual ball (doesn't check for move off of canvas). The FlipBell class stores each CoinToss instance in a list and calls the "flip" function for each class each time a ball is created. You could also use "after" within the CoinToss class to have the flip function call itself repeatedly.
from tkinter import *
from random import randint
class FlipBell(object):
"""
GUI to simulate cointoss.
"""
def __init__(self, wdw, dimension, delay):
"""
Determines the layout of the GUI.
wdw : top level widget, the main window,
dimension : determines the size of the canvas,
increment : step size for a billiard move,
delay : time between updates of canvas.
"""
wdw.title('Coin flips and Bell Curve')
self.cnv = Canvas(wdw, width=dimension,
height=dimension, bg='white')
self.cnv.grid()
self.ct_instances=[]
self.colors=["blue", "red", "yellow", "gray", "green"]
self.delay=delay
self.offset=0
self.create_next()
def create_next(self):
""" create one ball for each color in self.colors
and call each existing ball's flip function to
move it a random amount
"""
x=5
y=5
incr=10*self.offset
CT=CoinToss(self.cnv, x+incr, y+incr, self.colors[self.offset])
##save each CoinToss (ball) instance in a list
self.ct_instances.append(CT)
self.offset += 1
## call flip (move ball) for each instance
for instance in self.ct_instances:
instance.flip()
if self.offset < len(self.colors):
self.cnv.after(self.delay, self.create_next)
class CoinToss:
def __init__(self, canvas, start_x, start_y, color):
self.cnv=canvas
self.cointoss(start_x, start_y, color)
def cointoss(self, start_x, start_y, color):
self.this_ball=self.cnv.create_oval(start_x-5, start_y-5, start_x+5, start_y+5,
outline='black', fill=color, tag="dot")
def flip(self):
""" move the ball created for this class instance by a random amount
"""
rand_value = randint(10, 50)
self.cnv.move(self.this_ball, rand_value, rand_value)
if __name__ == "__main__":
top = Tk()
dimension = 400 # dimension of canvas
delay = 500 # how much sleep before update --> 1/2 second
num_flips = 3
FP=FlipBell(top, dimension, delay)
top.mainloop()
I have a program where the user controls a block and navigates through pipes, similar to the game flappy bird. I want to know if tkinter has a way of telling me if one rectangle touches or hits another. I know there is a find_overlapping method for the canvas, but when i use find_overlapping on the pipe's rectangle it gives me the id of the pipe! I want to know if canvas items have a way of knowing if another canvas item is touching it!
Thanks
Here is my code:
from Tkinter import *
from random import *
root=Tk()
c=Canvas(root,width=600,height=600)
speed=20
num=1
first=True
b=0
pipes=[]
done=False
class Pipe():
def __init__(self,canvas,pipes,length,width=75,color="Green",position=600,speed=5):
self.speed=speed
self.canvas=canvas
self.length=length
self.width=width
self.color=color
self.position=position
self.current1=self.canvas.create_rectangle((self.position,0,self.position+self.width,self.length),outline=self.color,fill=self.color)
self.current2=self.canvas.create_rectangle((self.position,600,self.position+self.width,self.length+150),outline=self.color,fill=self.color)
self.pipes=pipes
self.pipes.append(self.current1)
self.pipes.append(self.current2)
def move(self):
global done
if (len(self.canvas.find_overlapping(self.position,0,self.position+self.width,self.length))==1 and len(self.canvas.find_overlapping(self.position,600,self.position+self.width,self.length+150))==1) and not done:
self.position-=3
self.canvas.coords(self.current1,(self.position,0,self.position+self.width,self.length))
self.canvas.coords(self.current2,(self.position,600,self.position+self.width,self.length+150))
if self.position>-75:
self.canvas.after(self.speed,self.move)
else:
self.pipes.remove(self.current1)
self.pipes.remove(self.current2)
self.canvas.delete(self.current1)
self.canvas.delete(self.current2)
else:
print self.canvas.find_overlapping(self.position,0,self.position+self.width,self.length)
print
print self.canvas.find_overlapping(self.position,600,self.position+self.width,self.length+150)
done=True
class Player():
def __init__(self,canvas,x=150,y=300,size=40):
self.size=size
self.faller=True
self.x=x
self.y=y
self.fell=5
self.canvas=canvas
#For now
self.current=self.canvas.create_rectangle((self.x-20,self.y-20,self.x+20,self.y+20),tags="user",outline="Blue",fill="Blue")
self.canvas.after(100,self.fall)
self.canvas.bind("<1>",self.jump)
def fall(self):
global done
if self.faller and not done:
self.y+=self.fell
self.fell*=1.001
self.canvas.coords(self.current,(self.x-20,self.y-20,self.x+20,self.y+20))
self.canvas.after(30,self.fall)
elif done:
a=600-self.y+20
a/=50
while self.y<580:
self.y+=a
self.canvas.coords(self.current,(self.x-20,self.y-20,self.x+20,self.y+20))
def jump(self,e):
if not done:
self.faller=False
for x in range(10):
self.canvas.after(100,self.move)
self.faller=True
self.fell=5
def move(self):
self.y-=7.5
self.canvas.coords(self.current,(self.x-20,self.y-20,self.x+20,self.y+20))
def changey(self,a):
self.y=a
def run():
global b,first,done
if not done:
if first:
b=randint(5,450)
first=False
else:
if b<225:
b=randint(5,b+225)
if b>225:
b=randint(b-225,450)
else:
b=randint(0,600)
a=Pipe(c,pipes,b)
a.move()
c.after(2000,run)
else:
return
root.focus_set()
user=Player(c)
c.after(2000,run)
c.pack()
root.mainloop()
Canvas.find_overlapping return a tuple with all the ids of shapes in the bbox. If only your id is returned it might be because it is the sole one.
You can use it with the bbox of another shape like this : canvas.find_overlapping(*canvas.bbox(aShape)).
Note that overlapping works on rectangle and might be erroneous for instance on circles.