Reputation: 23
So I am trying to get 9 different balls to show up all with different color, size, and different movement. So far I have 9 balls, but they are sometimes the same color, all the same size, and all move almost the same trajectories. not sure what I should change
from tkinter import *
import time
import random
WIDTH = 800
HEIGHT = 500
SIZE = random.randrange(10,100,10)
tk = Tk()
canvas = Canvas(tk, width=WIDTH, height=HEIGHT, bg="grey")
canvas.pack()
colors = ['black', 'blue', 'yellow','orange','green','purple', 'maroon', 'teal', 'brown']
balls = []
for _ in range (10):
balls.append(canvas.create_oval(0, 0, SIZE, SIZE, fill=random.choice(colors)))
class Ball:
def __init__(self):
for self.shape in balls:
self.speedx = 9 # changed from 3 to 9
self.speedy = 9 # changed from 3 to 9
self.active = True
self.move_active()
def ball_update(self):
for self.shape in balls:
canvas.move(self.shape, self.speedx, self.speedy)
pos = canvas.coords(self.shape)
if pos[2] >= WIDTH or pos[0] <= 0:
self.speedx *= -1
if pos[3] >= HEIGHT or pos[1] <= 0:
self.speedy *= -1
def move_active(self):
if self.active:
self.ball_update()
tk.after(40, self.move_active) # changed from 10ms to 30ms
ball = Ball()
tk.mainloop()
Upvotes: 2
Views: 649
Reputation: 142744
If you get random value always from the same list then items can repeate. And sometimes you can randomly get the same color for all items. Better get colors from list one-by-one, not randomly.
for color in COLORS:
ball_id = canvas.create_oval(..., fill=color)
You select SIZE
only once - at start - and later you use the same value from SIZE
. You should select random size inside loop for _ in range (10)
Every ball starts in the same place (0,0)
and use the same speedx, speedy so it may move the same way. They should start in different places. And every ball should have own variable for speed.
for color in COLORS:
size = random.randrange(10, 50, 5)
x = random.randrange(0, WIDTH, 10)
y = random.randrange(0, HEIGHT, 10)
speedx = random.choice([-9, -6, -3, 3, 6, 9]) # skip `0`
speedy = random.choice([-9, -6, -3, 3, 6, 9]) # skip `0`
ball_id = canvas.create_oval(x, y, x+size, y+size, fill=color)
ball = [ball_id, speedx, speedy]
balls.append(ball)
from tkinter import *
import time
import random
# --- constants ---
WIDTH = 800
HEIGHT = 500
COLORS = ['black', 'blue', 'yellow','orange','green','purple', 'maroon', 'teal', 'brown']
# --- classes ---
class App:
def __init__(self, balls):
self.balls = balls
self.ball_update()
def ball_update(self):
for ball in self.balls:
#ball_id, speedx, speedy = ball
#canvas.move(ball_id, speedx, speedy)
canvas.move(ball[0], ball[1], ball[2])
pos = canvas.coords(ball[0])
if pos[2] >= WIDTH or pos[0] <= 0:
ball[1] *= -1
if pos[3] >= HEIGHT or pos[1] <= 0:
ball[2] *= -1
tk.after(50, self.ball_update) # changed from 10ms to 30ms
# --- functions ---
# empty
# --- main ---
tk = Tk()
canvas = Canvas(tk, width=WIDTH, height=HEIGHT, bg="grey")
canvas.pack()
balls = []
for color in COLORS:
size = random.randrange(10, 50, 5)
x = random.randrange(size, WIDTH-size, 10) # uses "size" to stop jamming the edge
y = random.randrange(size, HEIGHT-size, 10) # uses "size" to stop jamming the edge
speedx = random.choice([-9, -6, -3, 3, 6, 9]) # skip `0`
speedy = random.choice([-9, -6, -3, 3, 6, 9]) # skip `0`
ball_id = canvas.create_oval(x, y, x+size, y+size, fill=color)
ball = [ball_id, speedx, speedy]
balls.append(ball)
app = App(balls)
tk.mainloop()
EDIT: all in class App
import tkinter as tk # `import *` is not preferd
import time
import random
# --- constants ---
WIDTH = 800
HEIGHT = 500
COLORS = ['black', 'blue', 'yellow','orange','green','purple', 'maroon', 'teal', 'brown']
# --- classes ---
class App:
def __init__(self, root):
self.root = root
self.canvas = tk.Canvas(self.root, width=WIDTH, height=HEIGHT, bg="grey")
self.canvas.pack()
self.ball_create()
self.ball_update()
self.root.mainloop()
def ball_create(self):
self.balls = []
for color in COLORS:
size = random.randrange(10, 50, 5)
x = random.randrange(size, WIDTH-size, 10) # uses "size" to stop jamming the edge
y = random.randrange(size, HEIGHT-size, 10) # uses "size" to stop jamming the edge
speedx = random.choice([-9, -6, -3, 3, 6, 9]) # skip `0`
speedy = random.choice([-9, -6, -3, 3, 6, 9]) # skip `0`
ball_id = self.canvas.create_oval(x, y, x+size, y+size, fill=color)
ball = [ball_id, speedx, speedy]
self.balls.append(ball)
def ball_update(self):
for ball in self.balls:
#ball_id, speedx, speedy = ball
#self.canvas.move(ball_id, speedx, speedy)
self.canvas.move(ball[0], ball[1], ball[2])
pos = self.canvas.coords(ball[0])
if pos[2] >= WIDTH or pos[0] <= 0:
ball[1] *= -1
if pos[3] >= HEIGHT or pos[1] <= 0:
ball[2] *= -1
self.root.after(50, self.ball_update) # changed from 10ms to 30ms
# --- functions ---
# empty
# --- main ---
root = tk.Tk()
App(root)
root.mainloop()
BTW: class Ball
should keep information only about one ball and move only this ball. Your class Ball
worked rather like Application
so I changed its name.
import tkinter as tk # `import *` is not preferd
import time
import random
# --- constants ---
WIDTH = 800
HEIGHT = 500
COLORS = ['black', 'blue', 'yellow','orange','green','purple', 'maroon', 'teal', 'brown']
# --- classes ---
class Ball:
def __init__(self, canvas, color):
self.canvas = canvas
self.color = color
self.size = random.randrange(10, 50, 5)
self.x = random.randrange(self.size, WIDTH-self.size, 10) # uses "size" to stop jamming the edge
self.y = random.randrange(self.size, HEIGHT-self.size, 10) # uses "size" to stop jamming the edge
self.speedx = random.choice([-9, -6, -3, 3, 6, 9]) # skip `0`
self.speedy = random.choice([-9, -6, -3, 3, 6, 9]) # skip `0`
self.id = self.canvas.create_oval(self.x, self.y, self.x+self.size, self.y+self.size, fill=self.color)
def move(self):
self.canvas.move(self.id, self.speedx, self.speedy)
x1, y1, x2, y2 = self.canvas.coords(self.id)
if x1 <= 0 or x2 >= WIDTH:
self.speedx *= -1
if y1 <= 0 or y2 >= HEIGHT:
self.speedy *= -1
class App:
def __init__(self, root):
self.root = root
self.canvas = tk.Canvas(self.root, width=WIDTH, height=HEIGHT, bg="grey")
self.canvas.pack()
self.create()
self.move()
self.root.mainloop()
def create(self):
self.balls = []
for color in COLORS:
ball = Ball(self.canvas, color)
self.balls.append(ball)
def move(self):
for ball in self.balls:
ball.move()
self.root.after(50, self.move) # changed from 10ms to 30ms
# --- functions ---
# empty
# --- main ---
root = tk.Tk()
App(root)
root.mainloop()
Upvotes: 1