i recently start learning about python, and made simple source of 2 balls in canvas which are moving with 2d vector rule. i want multiply the number of balls with list in python. here is source of that.
import time
import random
from tkinter import *
import numpy as np
import math
window = Tk()
canvas = Canvas(window,width=600,height=400)
canvas.pack()
canvas.create_rectangle(50,50,550,350)
R = 15
x1 = random.randrange(50+R,550-R)
y1 = random.randrange(50+R,350-R)
x2 = random.randrange(50+R,550-R)
y2 = random.randrange(50+R,350-R)
vx1 = random.randrange(1 , 10)
vy1 = random.randrange(1 , 10)
vx2 = random.randrange(1 , 10)
vy2 = random.randrange(1 , 10)
ntime = 100000
dt = .1
for iter in range(ntime):
x1 += vx1*dt
y1 += vy1*dt
x2 += vx2*dt
y2 += vy2*dt
c1 = canvas.create_oval(x1-R,y1-R,x1+R,y1+R,fill="red")
c2 = canvas.create_oval(x2-R,y2-R,x2+R,y2+R,fill="blue")
if (x1 > 550-R):
vx1 = -vx1
if (x1 < 50+R ):
vx1 = -vx1
if (x2 > 550-R):
vx2 = -vx2
if (x2 < 50+R ):
vx2 = -vx2
if (y1 > 350-R) or (y1 < 50+R):
vy1 = -vy1
if (y2 > 350-R) or (y2 < 50+R):
vy2 = -vy2
if (x2-x1)**2 + (y2-y1)**2 <= 4*R*R:
vector1 = np.array([x1,y1])
vector2 = np.array([x2,y2])
vvector1 = np.array([vx1,vy1])
vvector2 = np.array([vx2,vy2])
nvector = np.array([x2-x1,y2-y1])
un = (nvector)/((sum(nvector*nvector))**(1/2))
tvector = np.array([y1-y2,x2-x1])
ut = tvector/((sum(nvector*nvector))**(1/2))
vector1midn = sum(vvector1*un)
vector2midn = sum(vvector2*un)
vector1midt = sum(vvector1*ut)
vector2midt = sum(vvector2*ut)
vector1after = vector2midn*un + vector1midt*ut
vector2after = vector1midn*un + vector2midt*ut
vx1 = vector1after[0]
vy1 = vector1after[1]
vx2 = vector2after[0]
vy2 = vector2after[1]
txt = canvas.create_text(100,30,text=str(iter),font=('consolas', '20',
'bold'))
window.update()
time.sleep(0.002)
if iter == ntime-1 : break
canvas.delete(c1)
canvas.delete(c2)
canvas.delete(txt)
window.mainloop()
exact question is, how do i change c1,c2 , above there , into many of them without simply typing every single ball.
Question: How do i change these two balls into many of them?
Create a class object
for each Ball or pair of Balls.
This results in, all Balls using the same rules.
Note: I show only one Ball per class object
, not a pair of Balls and without collision detection!
class Ball:
R = 15
def __init__(self, parent=None, color=None):
self.parent = parent
# Define shortcuts
radius = self.R
# Random bbox Ellipse coordinates of the ball.
x = random.randrange(50 + radius, 550 - radius)
y = random.randrange(50 + radius, 350 - radius)
coord1 = (x - radius, y - radius, x + radius, y + radius)
# Random direction
x = random.randrange(1, 10)
y = random.randrange(1, 10)
self.direction = (x, y)
# Save the bbox coordinate of the ball
self.coord1 = self.bbox(coord1, self.direction)
def bbox(self, coord1=None, direction=None):
# Return if NO move
if coord1 is None:
return self.coord1
return (coord1[0] + direction[0],
coord1[1] + direction[1],
coord1[2] + direction[0],
coord1[3] + direction[1]
)
def vector_rule(self):
# Get the estimated new bbox coordinate of the Ball
coord1 = self.bbox(self.coord1, self.direction)
# Define shortcuts
R = self.R
x1 = coord1[0]
y1 = coord1[1]
vx1 = self.direction[0]
vy1 = self.direction[1]
# Boundary check
if (x1 > 530 - R):
vx1 = -vx1
if (x1 < 35 + R):
vx1 = -vx1
if (y1 > 330 - R) or (y1 < 35 + R):
vy1 = -vy1
# Save the new direction - could be the same as before
self.direction = (vx1, vy1)
# Save the new bbox coordinate of the Ball
self.coord1 = self.bbox(self.coord1, self.direction)
# Return the move offsets
return self.direction
Usage:
Create a class BallCanvas
, in .create_balls(...
loop to create class Ball
objects and Canvas create_oval(...
objects.
Accumulate both in a list
, loop this list
to move the Balls using canvas.move(...
, according the result of Ball.vector_rules(...
.
class BallCanvas(tk.Canvas):
def __init__(self, parent, width, height):
self.parent = parent
super().__init__(parent, width=width, height=height)
self.create_rectangle(50, 50, 550, 350)
self.grid(row=1)
self.balls = []
self.create_balls()
def create_balls(self):
for n in range(5):
for color in ['red', 'blue']:
ball = Ball()
self.balls.append((self.create_oval(ball.bbox(), fill=color, tags='ball'), ball))
def move_balls(self):
for id, ball in self.balls:
new_x, new_y = ball.vector_rule()
self.move(id, new_x, new_y)
Main Application:
Move the Ball objects
using Tkinter .after(150, ...
.
This means. all Ball objects
moved every 150ms.
class App(tk.Tk):
def __init__(self):
super().__init__()
self.geometry("610x430+650+280")
self.canvas = BallCanvas(self, width=600, height=400)
self.count = 200
self.after(500, self.move)
def move(self):
self.count -= 1
self.canvas.move_balls()
if self.count > 0:
self.after(150, self.move)
if __name__ == "__main__":
App().mainloop()
Tested with Python: 3.5
you can start by initializing the variables as random arrays with the same length. Example with length 10:
x = np.random.randint(50+R,550-R, size=10)
Do this for all variables. Inside your current loop you can loop through all variables.