Tkinter canvas animation flicker - python

I wrote a Python program with Tkinter that makes a ball bounce around the screen. It works great, except for one problem: the outermost edges of the ball flicker as the ball moves.
I understand Tkinter automatically does double buffering, so I thought I shouldn't be having problems with tearing. I'm not sure where the error is coming from. Any ideas on how I can get rid of it?
Code is below. Here's the gist of it: class Ball extends Tk and gets created when the program is run. It sets up the game, encapsulating it in a GModel. GModel then runs the game with run() and just loops over and over, calling update().
import threading
from time import sleep, clock
from tkinter import *
from tkinter import ttk
SPEED = 150 # Pixels per second
WIDTH = 400
HEIGHT = 500
RAD = 25
PAUSE = 0 # Time added between frames. Slows things down if necessary
class GModel:
# Contains the game data.
def __init__(self, can):
# can is Canvas to draw on
self.can = can
self.circ = can.create_oval(0,0, 2*RAD, 2*RAD)
# Position and velocity of the ball
self.x, self.y = RAD, RAD
self.dx, self.dy = SPEED, SPEED
# Ball is moving?
self.is_running = True
def update(self, elapsed_time):
# Updates the dynamic game variables. elapsed_time is in seconds.
change_x = self.dx * elapsed_time
change_y = self.dy * elapsed_time
self.can.move(self.circ, change_x, change_y)
self.x += change_x
self.y += change_y
self.resolve_collisions()
def resolve_collisions(self):
# If the ball goes off the edge, put it back and reverse velocity
if self.x - RAD < 0:
self.x = RAD
self.dx = SPEED
elif self.x + RAD > WIDTH:
self.x = WIDTH - RAD
self.dx = -SPEED
if self.y - RAD < 0:
self.y = RAD
self.dy = SPEED
elif self.y + RAD > HEIGHT:
self.y = HEIGHT - RAD
self.dy = -SPEED
def end_game(self):
self.is_running = False
def run(self):
last_time = 0.0
while self.is_running:
# Get number of seconds since last iteration of this loop
this_time = clock()
elapsed_time = this_time - last_time
last_time = this_time
try: # Use this here in case the window gets X'd while t still runs
self.update(elapsed_time)
except:
self.is_running = False
if (PAUSE > 0):
sleep(PAUSE) # Slow things down if necessary
class Ball(Tk):
def __init__(self):
Tk.__init__(self)
self.can = Canvas(self, width=WIDTH, height=HEIGHT)
self.can.grid(row=0, column=0, sticky=(N, W, E, S))
self.gm = GModel(self.can)
def mainloop(self):
t = threading.Thread(target=self.gm.run, daemon=True)
t.start()
Tk.mainloop(self)
def main():
Ball().mainloop()
if __name__ == "__main__":
main()

Related

Hi, I need to build a platform game using only tkinter, cant use pygame, and Im having trouble moving two objects at the same time

cant move the character at the same time the obstacle is moving, pirincipal is the name of the image that works as the player
def move():
def left(event):
x = -5
y = 0
canvasGame.update()
edgeReached()
canvasGame.move(principal,x, y)
collision()
def right(event):
x = 5
y = 0
canvasGame.update()
edgeReached()
canvasGame.move(principal,x, y)
collision()
canvasGame.bind_all("<Left>", left)
canvasGame.bind_all("<Right>", right
move()
class Barrel:
def __init__(self, canvas):
self.canvas = canvas
self.obs = canvasGame.create_image(125, 500, image=nuevoObs, anchor=tk.NW)
self.x = 16
self.y = 0
def movement(self):
while True:
coords = canvasGame.coords(self.obs)
if (coords[0] >= 1000):
self.x = -10
self.y = 0
elif (coords[0] < 0):
self.x = 10
self.y = 0
self.canvas.move(self.obs, self.x,self.y)
canvasGame.update()
time.sleep(0.05)
def createBarrel():
barrel = Barrel(canvasGame)
circle_thread = Thread(target=barrel.movement())
circle_thread.daemon = True
circle_thread.start()
createBarrel()
def plzmove():
moveplz = Thread(target=move())
moveplz.daemon = True
moveplz.start()
plzmove()
I tried creating threads but the problem continues, if there is a barrel moving, the player cant move (if there is nothing else moving, the player can move with freedom), also, the player movement is just an image being moved, any tip is appreciated, much love.

How do I make the enemy float around randomly?

I have pretty much everything done for this little game except I can't seem to get the enemy to just aimlessly float around. They spawn at the top of the window but it's rather bland having them stand in line Civil War style. I'm pretty sure it's something to do with class Enemy, but not sure. Any tips on how to get the player and aliens moving around would be appreciated!
import sys, logging, os, random, math, open_color, arcade
#check to make sure we are running the right version of Python
version = (3,7)
assert sys.version_info >= version, "This script requires at least Python {0}.{1}".format(version[0],version[1])
#turn on logging, in case we have to leave ourselves debugging messages
logging.basicConfig(format='[%(filename)s:%(lineno)d] %(message)s', level=logging.DEBUG)
logger = logging.getLogger(__name__)
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
MARGIN = 30
SCREEN_TITLE = "Intergalactic slam"
NUM_ENEMIES = 5
STARTING_LOCATION = (400,100)
BULLET_DAMAGE = 10
ENEMY_HP = 10
HIT_SCORE = 10
KILL_SCORE = 100
PLAYER_HP = 100
class Bullet(arcade.Sprite):
def __init__(self, position, velocity, damage):
'''
initializes the bullet
Parameters: position: (x,y) tuple
velocity: (dx, dy) tuple
damage: int (or float)
'''
super().__init__("assets/Player/PNG/Sprites/Missiles/spaceMissiles_012.png", 0.5)
(self.center_x, self.center_y) = position
(self.dx, self.dy) = velocity
self.damage = damage
def update(self):
'''
Moves the bullet
'''
self.center_x += self.dx
self.center_y += self.dy
class Enemy_Bullet(arcade.Sprite):
def __init__(self, position, velocity, damage):
super().__init__("PNG/laserGreen1.png", 0.5)
(self.center_x, self.center_y) = position
(self.dx, self.dy) = velocity
self.damage = damage
def update(self):
self.center_x += self.dx
self.center_y += self.dy
class Player(arcade.Sprite):
def __init__(self):
super().__init__("assets/Player/PNG/Sprites/Ships/spaceShips_005.png", 0.5)
(self.center_x, self.center_y) = STARTING_LOCATION
self.hp = PLAYER_HP
class Enemy(arcade.Sprite):
def __init__(self, position):
'''
initializes an alien enemy
Parameter: position: (x,y) tuple
'''
super().__init__("PNG/shipGreen_manned.png", 0.5)
self.hp = ENEMY_HP
(self.center_x, self.center_y) = position
class Window(arcade.Window):
def __init__(self, width, height, title):
super().__init__(width, height, title)
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
self.set_mouse_visible(True)
arcade.set_background_color(open_color.black)
self.bullet_list = arcade.SpriteList()
self.enemy_list = arcade.SpriteList()
self.enemy_bullet_list = arcade.SpriteList()
self.player = Player()
self.score = 0
self.win = False
self.lose = False
def setup(self):
'''
Set up enemies
'''
for i in range(NUM_ENEMIES):
x = 120 * (i+1) + 40
y = 500
enemy = Enemy((x,y))
self.enemy_list.append(enemy)
def update(self, delta_time):
self.bullet_list.update()
self.enemy_bullet_list.update()
if (not (self.win or self.lose)):
for e in self.enemy_list:
for b in self.bullet_list:
if (abs(b.center_x - e.center_x) <= e.width / 2 and abs(b.center_y - e.center_y) <= e.height / 2):
self.score += HIT_SCORE
e.hp -= b.damage
b.kill()
if (e.hp <= 0):
e.kill()
self.score += KILL_SCORE
if (len(self.enemy_list) == 0):
self.win = True
if (random.randint(1, 75) == 1):
self.enemy_bullet_list.append(Enemy_Bullet((e.center_x, e.center_y - 15), (0, -10), BULLET_DAMAGE))
for b in self.enemy_bullet_list:
if (abs(b.center_x - self.player.center_x) <= self.player.width / 2 and abs(b.center_y - self.player.center_y) <= self.player.height / 2):
self.player.hp -= b.damage
b.kill()
if (self.player.hp <= 0):
self.lose = True
def on_draw(self):
arcade.start_render()
arcade.draw_text(str(self.score), 20, SCREEN_HEIGHT - 40, open_color.white, 16)
arcade.draw_text("HP: {}".format(self.player.hp), 20, 40, open_color.white, 16)
if (self.player.hp > 0):
self.player.draw()
self.bullet_list.draw()
self.enemy_bullet_list.draw()
self.enemy_list.draw()
if (self.lose):
self.draw_game_loss()
elif (self.win):
self.draw_game_won()
def draw_game_loss(self):
arcade.draw_text(str("LOSER!"), SCREEN_WIDTH / 2 - 90, SCREEN_HEIGHT / 2 - 10, open_color.white, 30)
def draw_game_won(self):
arcade.draw_text(str("WINNER!"), SCREEN_WIDTH / 2 - 90, SCREEN_HEIGHT / 2 - 10, open_color.white, 30)
def on_mouse_motion(self, x, y, dx, dy):
'''
The player moves left and right with the mouse
'''
self.player.center_x = x
def on_mouse_press(self, x, y, button, modifiers):
if button == arcade.MOUSE_BUTTON_LEFT:
x = self.player.center_x
y = self.player.center_y + 15
bullet = Bullet((x,y),(0,10),BULLET_DAMAGE)
self.bullet_list.append(bullet)
def main():
window = Window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
window.setup()
arcade.run()
if __name__ == "__main__":
main()
You'd want to change the self.center_x and self.center_y of each Enemy on every update, like you're already doing for each Bullet, but make the dx and dy values random in some way. For example:
class Enemy(arcade.Sprite):
def __init__(self, position):
...
(self.center_x, self.center_y) = position
(self.dx, self.dy) = (0, 0)
def update(self):
self.dx += random.random() - 0.5
self.dy += random.random() - 0.5
self.center_x += self.dx
self.center_y += self.dy
Now, this may look more like "twitching wildly" than "floating": many times a second, the thing potentially changes course completely. That's technically random movement, but it's not something a spaceship would do.
If it's too twitchy, make it so that dx and dy change more slowly, for example by dividing the random.random() - 0.5 by a fixed number. If it's too floaty, make it so that every update changes it more.
If you want the enemy to prefer moving down, or towards the player, get out the trigonometry and adjust dx and dy to match.

How to limit the times you press a key in Python

i am trying to make a game where you can shoot bullets to kill emojis. However, i can't manage to figure out how to stop spamming the space key to shoot bullets. If you keep on spamming, the game would be too easy. I am not exactly sure if I should use the sleep command or something else.Please help! thanks!
Here is my code:
# import everything from turtle
from turtle import *
import random
import math
#create a link to the object (creates the environment)
screen = Screen()
speed1 = 1.3
ht()
amountOfEmojis = 11
#set a boundary for screen, if touches end, goes to the other side
screenMinX = -screen.window_width()/2
screenMinY = -screen.window_height()/2
screenMaxX = screen.window_width()/2
screenMaxY = screen.window_height()/2
#establish important data for screen environment
screen.setworldcoordinates(screenMinX,screenMinY,screenMaxX,screenMaxY)
screen.bgcolor("black")
#turtle setup
penup()
ht()
speed(0)
goto(0, screenMaxY - 50)
color('white')
write("Welcome to Emoji Run!", align="center", font=("Courier New",26))
goto(0, screenMaxY - 70)
write("Use the arrow keys to move and space to fire. The point of the game is to kill the emojis", align="center")
goto(0, 0)
color("red")
emojis = ["Poop_Emoji_7b204f05-eec6-4496-91b1-351acc03d2c7_grande.png", "1200px-Noto_Emoji_KitKat_263a.svg.png",
"annoyningface.png", "Emoji_Icon_-_Sunglasses_cool_emoji_large.png"]
class Bullet(Turtle):
#constructor, object for a class, pass in information
def __init__(self,screen,x,y,heading):
#create a bullet
Turtle.__init__(self)#clones bullet
self.speed(0)
self.penup()
self.goto(x,y)
self.seth(heading)#pointing to itself
self.screen = screen
self.color('yellow')
self.max_distance = 500
self.distance = 0
self.delta = 20
self.shape("bullet")
#logic to move bullet
def move(self):
self.distance = self.distance + self.delta#how fast it's going to move
self.forward(self.delta)
if self.done():
self.reset()
def getRadius(self):
return 4#collision detection helper function
def blowUp(self):
self.goto(-300,0)#function that makes something go off the screen
def done(self):
return self.distance >= self.max_distance # append to list
class Asteroid(Turtle):
def __init__(self,screen,dx,dy,x,y,size,emoji):#spawn asteroid randomly
Turtle.__init__(self)#clone itself
self.speed(0)
self.penup()
self.goto(x,y)
self.color('lightgrey')
self.size = size
self.screen = screen
self.dx = dx
self.dy = dy
r = random.randint(0, len(emoji) - 1)
screen.addshape(emojis[r])
self.shape(emojis[r])
#self.shape("rock" + str(size)) #sets size and shape for asteroid
def getSize(self):#part of collision detection
return self.size
#getter and setter functions
def getDX(self):
return self.dx
def getDY(self):
return self.dy
def setDX(self,dx):
self.dx = dx
def setDY(self,dy):
self.dy = dy
def move(self):
x = self.xcor()
y = self.ycor()
#if on edge of screen. go to opposite side
x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY
self.goto(x,y)
def blowUp(self):
self.goto(-300,0)#function that makes something go off the screen
def getRadius(self):
return self.size * 10 - 5
class SpaceShip(Turtle):
def __init__(self,screen,dx,dy,x,y):
Turtle.__init__(self)
self.speed(0)
self.penup()
self.color("white")
self.goto(x,y)
self.dx = dx
self.dy = dy
self.screen = screen
self.bullets = []
self.shape("turtle")
def move(self):
x = self.xcor()
y = self.ycor()
x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY
self.goto(x,y)
#logic for collision
def powPow(self, asteroids):
dasBullets = []
for bullet in self.bullets:
bullet.move()
hit = False
for asteroid in asteroids:
if intersect(asteroid, bullet):#counts every asteroid to see if it hits
asteroids.remove(asteroid)
asteroid.blowUp()
bullet.blowUp()
hit = True
if (not bullet.done() and not hit):
dasBullets.append(bullet)
self.bullets = dasBullets
def fireBullet(self):
self.bullets.append(Bullet(self.screen, self.xcor(), self.ycor(), self.heading()))
def fireEngine(self):#how turtle moves
angle = self.heading()
x = math.cos(math.radians(angle))
y = math.sin(math.radians(angle))
self.dx = self.dx + x#how it rotates
self.dy = self.dy + y
self.dx = self.dx / speed1
self.dy = self.dy / speed1
#extra function
def turnTowards(self,x,y):
if x < self.xcor():
self.left(7)
if x > self.xcor():
self.right(7)
def getRadius(self):
return 10
def getDX(self):
return self.dx
def getDY(self):
return self.dy
#collision detection
def intersect(object1,object2):
dist = math.sqrt((object1.xcor() - object2.xcor())**2 + (object1.ycor() - object2.ycor())**2)
radius1 = object1.getRadius()
radius2 = object2.getRadius()
# The following if statement could be written as
# return dist <= radius1+radius2
if dist <= radius1+radius2:
return True
else:
return False
#adds object to screen
screen.register_shape("rock3",((-20, -16),(-21, 0), (-20,18),(0,27),(17,15),(25,0),(16,-15),(0,-21)))
screen.register_shape("rock2",((-15, -10),(-16, 0), (-13,12),(0,19),(12,10),(20,0),(12,-10),(0,-13)))
screen.register_shape("rock1",((-10,-5),(-12,0),(-8,8),(0,13),(8,6),(14,0),(12,0),(8,-6),(0,-7)))
screen.register_shape("ship",((-10,-10),(0,-5),(10,-10),(0,10)))
screen.register_shape("bullet",((-2,-4),(-2,4),(2,4),(2,-4)))
#ship spawn exactly the middle everytime
ship = SpaceShip(screen,0,0,(screenMaxX-screenMinX)/2+screenMinX,(screenMaxY-screenMinY)/2 + screenMinY)
#randomize where they spawn
asteroids = []
for k in range(amountOfEmojis):
dx = random.random() * 6 - 3
dy = random.random() * 6 - 3
x = random.randrange(10) * (screenMaxX - screenMinX) + screenMinX
y = random.random() * (screenMaxY - screenMinY) + screenMinY
asteroid = Asteroid(screen,dx,dy,x,y,random.randint(1,3), emojis)
asteroids.append(asteroid)
def play():
# Tell all the elements of the game to move
ship.move()
gameover = False
for asteroid in asteroids:
r = random.randint(0, 1)
if r == 1:
asteroid.right(50)
else:
asteroid.left(20)
asteroid.move()
if intersect(ship,asteroid):
write("You Got Killed :(",font=("Verdana",25),align="center")
gameover = True
ship.powPow(asteroids)
screen.update()
if not asteroids:
color('green')
write("You Killed the Emojis!!",font=("Arial",30),align="center")
ht()
if not gameover:
screen.ontimer(play, 30)
bullets = []
#controls
def turnLeft():
ship.left(7)
def turnRight():
ship.right(7)
def go():
ship.fireEngine()
def fire():
ship.fireBullet()
ht()
screen.tracer(0);
screen.onkey(turnLeft, 'left')
screen.onkey(turnRight, 'right')
screen.onkey(go, 'up')
screen.onkey(fire, 'space')
screen.listen()
play()
Thanks!
You could try something like this:
import time
FIRE_DELAY = 0.1 # number of seconds between bullets
LAST_FIRE = 0
def fire():
t = time.time()
if t - LAST_FIRE > FIRE_DELAY:
LAST_FIRE = t
ship.fireBullet()

Python Threading: "RuntimeError: thread.__init__() not called"

I am making a ping pong game with turtle. However, the assignment is that code must have multithreading. I could not apply multithreading properly.
The code shows no error in the editor, but it does not work. How can we fix this runtime error? It is so hard to find the error when there is no error in the editor.
import turtle
from threading import *
from time import sleep
wn = turtle.Screen()
wn.title("Ping pong by Cagatay em")
wn.bgcolor("blue")
wn.setup(width=900, height=600)
wn.tracer(0) #oyunu hizlandirir silersen cok yavaslar
class PaddleFirst(Thread):
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("square")
self.pen.shapesize(stretch_wid=5, stretch_len=1)
self.pen.penup()
self.pen.goto(-350, 0)
def run(self):
y = self.pen.ycor()
y += 20
self.pen.sety(y)
k = self.pen.ycor()
k -= 20
self.pen.sety(k)
class PaddleSecond(Thread):
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("square")
self.pen.shapesize(stretch_wid=5, stretch_len=1)
self.pen.penup()
self.pen.goto(350, 0)
def run(self):
y = self.pen.ycor()
y += 20
self.pen.sety(y)
k = self.pen.ycor()
k -= 20
self.pen.sety(k)
class Ball(Thread):
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("circle")
self.pen.color("red")
self.pen.penup()
self.pen.goto(0, 0)
self.pen.dx = 00.1
self.pen.dy = 00.1
def run(self):
self.pen.setx(self.pen.xcor() + self.pen.dx)
self.pen.sety(self.pen.ycor() + self.pen.dy)
if self.pen.ycor() > 290:
self.pen.sety(290)
self.pen.dy *= -1
if self.pen.ycor() < -290:
self.pen.sety(-290)
self.pen.dy *= -1
if self.pen.xcor() > 390:
self.pen.goto(0, 0)
self.pen.dx *= -1
if self.pen.xcor() < -390:
self.pen.goto(0, 0)
self.pen.dx *= -1
class Wall(Thread):
def run(self):
if ball.pen.xcor() > 340 and (ball.pen.ycor() < paddle2.pen.ycor() + 40 and ball.pen.ycor() > paddle2.pen.ycor() - 40):
ball.pen.dx *= -1
if ball.pen.xcor() < -340 and (ball.pen.ycor() < paddle1.pen.ycor() + 40 and ball.pen.ycor() > paddle1.pen.ycor() - 40):
ball.pen.dx *= -1
paddle1 = PaddleFirst()
paddle2 = PaddleSecond()
ball = Ball()
wall = Wall()
wn.listen()
wn.onkeypress(paddle1.run, "w")
wn.onkeypress(paddle1.run(), "s")
wn.onkeypress(paddle2.run(), "Up")
wn.onkeypress(paddle2.run, "Down")
while True:
wn.update() # everytime uptades the screen
ball.start()
sleep(0.2)
wall.start()
sleep(0.2)
paddle1.start()
sleep(0.2)
paddle2.start()
My guess is that the error message you got is due to you not calling the super class' __init__() method in your subclass of Thread.
It is so hard to find the error when there is no error in the editor.
You need to learn the art of debugging.
i could not apply multithreading properly.
I think there are two issues here. First, to use threading with turtle, which is built atop tkinter, you need to have all graphics commands routed throught the main thread -- secondary threads shouldn't try to modify the screen directly.
Second, your code is a mess. Aside from threading, it's not clear you understand object-programming as you have two identical classes, except for an X coordinate. This should be one class with an argument to it's initializer. It's not clear you undertand turtle as wn.onkeypress(paddle1.run(), "s") will never work. You probably shouldn't be messing with tracer() and update() until your code is working. And you shouldn't have a while True: on the main turtle thread.
I've taken your code apart and put it back together below. Only the ball is a separate thread, the (single) paddle class now inherits from Turtle. The main thread processes graphics commands from the ball thread as well as standard turtle events:
from turtle import Screen, Turtle
from threading import Thread, active_count
from queue import Queue
QUEUE_SIZE = 1
class Paddle(Turtle):
def __init__(self, xcor):
super().__init__(shape='square')
self.shapesize(stretch_wid=5, stretch_len=1)
self.speed('fastest')
self.penup()
self.setx(xcor)
self.dy = 10
def down(self):
y = self.ycor() - self.dy
if y > -250:
self.sety(y)
def up(self):
y = self.ycor() + self.dy
if y < 250:
self.sety(y)
class Ball(Thread):
def __init__(self):
super().__init__(daemon=True)
self.pen = Turtle('circle')
self.pen.speed('fastest')
self.pen.color('red')
self.pen.penup()
self.dx = 1
self.dy = 1
def run(self):
x, y = self.pen.position()
while True:
x += self.dx
y += self.dy
if x > 330 and (paddle2.ycor() - 60 < y < paddle2.ycor() + 60):
self.dx *= -1
elif x < -330 and (paddle1.ycor() - 60 < y < paddle1.ycor() + 60):
self.dx *= -1
if y > 290:
y = 290
self.dy *= -1
elif y < -290:
y = -290
self.dy *= -1
elif not -440 < x < 440:
x, y = 0, 0
self.dx *= -1
actions.put((self.pen.setposition, x, y))
def process_queue():
while not actions.empty():
action, *arguments = actions.get()
action(*arguments)
if active_count() > 1:
screen.ontimer(process_queue, 100)
screen = Screen()
screen.title("Ping pong rework by cdlane")
screen.bgcolor('blue')
screen.setup(width=900, height=600)
actions = Queue(QUEUE_SIZE)
paddle1 = Paddle(-350)
paddle2 = Paddle(350)
ball = Ball()
screen.onkeypress(paddle1.up, 'w')
screen.onkeypress(paddle1.down, 's')
screen.onkeypress(paddle2.up, 'Up')
screen.onkeypress(paddle2.down, 'Down')
screen.listen()
ball.start()
process_queue()
screen.mainloop()
The code is still incomplete and slightly buggy (e.g. doesn't shut down cleanly) -- things for you to work on. But it basically plays the game in a reasonable fashion.

Doing traces behind balls with Tkinter

So i've this code who create moving balls :
from Tkinter import *
from random import randrange
from threading import Thread
Matrice = (600*400)*[0]
class Ball(Frame):
def __init__(self, can, posx, posy, name):
self.can = can
self.largeur_can = int(self.can.cget("width"))
self.hauteur_can = int(self.can.cget("height"))
self.posx = posx
self.posy = posy
self.name = name
self.ball1 = self.can.create_oval(self.posy, self.posx, self.posy+10, self.posx+10, outline="red", fill=self.name, width=2)
self.nx = randrange(-10,10,1)
self.nx /= 2.0
self.ny = randrange(-10,10,1)
self.ny /= 2.0
self.move()
def move(self):
global Matrice
self.pos_ball = self.can.coords(self.ball1)
self.posx_ball = self.pos_ball[0]
self.posy_ball = self.pos_ball[1]
if self.posx_ball < 0 or (self.posx_ball + 10) > self.largeur_can:
self.nx = -self.nx
if self.posy_ball < 0 or (self.posy_ball + 10) > self.hauteur_can:
self.ny = -self.ny
self.can.move(self.ball1, self.nx, self.ny)
Matrice[int(self.posy_ball)*600 + int(self.posx_ball)] += 100
self.can.after(10, self.move)
root=Tk()
can=Canvas(root,width=600,height=400,bg="black")
for x in range(10):
x=Ball(can,100,400, "blue")
x=Ball(can,100,400, "green")
can.pack()
root.mainloop()
And i would create traces behind balls, i created a matrix Matrice where I recorded where each ball is passed and now i want to show it un the background but i don't know how.
Nota : values in the matrix could decrease or be changed somewhere other than in move.
So anyone have an idea how i could do that ?
This is an inefficient way of doing it, but it's the simplest. Every time you move a ball just draw a line from where it used to be to where it currently is.
self.can.move(self.ball1, self.nx, self.ny)
new_pos = self.can.coords(self.ball1)
self.can.create_line(self.posx_ball, self.posy_ball, new_pos[0], new_pos[1], fill='red')
self.can.after(10, self.move)
Note that this line will follow the top left of the sprite - you can adjust the coordinates if you want it to follow the middle of the sprite.

Categories

Resources