简体   繁体   中英

How can I make this 9 different balls with different colors and sizes in python

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()

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM