import time,random,math,ctypes # Aron Seifert 2017 from tkinter import * user32 = ctypes.windll.user32 screensize=user32.GetSystemMetrics(0),user32.GetSystemMetrics(1) main={ #settings box: makes it easier to change things later 'balls': 25, #amount of balls 'width': 1200, 'height': 720, 'fullscreen': 1, #makes window fullscreen 0|1 -> if fullscreen is 1 window size adjusts automatically 'fps': 1} #adds a fps counter in the bottom left corner 0|1 if main['fullscreen']==1: #makes sure windows size~displaysize in fullscreen, had to add two variables. wheight= screensize[1] wwidth= screensize[0] else: wheight=main['height'] wwidth=main['width'] master = Tk( ) master.wm_title("Bouncing Balls") w = Canvas(master, width=wwidth, height=wheight, bg='#1b1104') if main['fullscreen']==1:master.attributes("-fullscreen", True) w.pack() def startup(): #to do one time only, draws the background -> useless but pretty w.create_rectangle(20, 20, wwidth-20, wheight-20, fill='#5b3207', outline='#ffd700') w.create_oval(-25, -25, 125, 125, fill="#5b3207", outline="#ffd700") w.create_oval(wwidth-125, -25, wwidth+25, 125, fill="#5b3207", outline="#ffd700") w.create_oval(-25, wheight-125, 125, wheight+25, fill="#5b3207", outline="#ffd700") w.create_oval(wwidth-125, wheight-125, wwidth+25, wheight+25, fill="#5b3207", outline="#ffd700") w.create_rectangle(50, 50, wwidth-55, wheight-55, fill="#0A2E00", outline="black") w.create_rectangle(57, 57, wwidth-62, wheight-62, fill="#154B07", outline="#154B07") w.create_oval(0, 0, 100, 100, fill="black", outline="black") w.create_oval(wwidth-100, 0, wwidth, 100, fill="black", outline="black") w.create_oval(0, wheight-100, 100, wheight, fill="black", outline="black") w.create_oval(wwidth-100, wheight-100, wwidth, wheight, fill="black", outline="black") def colormaker(): #makes randomized colors for the balls, converting 0-255 in hexa and making it into a string. e.g.: #FF1300 saver=random.randint(1,9) #with this Im trying to make sure the colors arent grey-ish-> clear colors (with black tones as exception) if not(saver== 1 or saver== 2 or saver== 3 or saver== 4 or saver== 5): r=(str(hex(int(random.randint(127,255)))).replace("0x","")) if len(r)==1:r="0"+r else: r="00" if not(saver == 3 or saver== 4 or saver== 5 or saver== 6 or saver== 7): g=(str(hex(int(random.randint(127,255)))).replace("0x","")) if len(g)==1:g="0"+g else: g="00" if not(saver == 5 or saver== 6 or saver== 7 or saver== 8 or saver== 9): b=(str(hex(int(random.randint(127,255)))).replace("0x","")) if len(b)==1:b="0"+b else: b="00" return "#"+r+g+b class ball: def __init__(self,color,number,x,y): #following splits up the given color string, in order tp make it lighter, for an other oval imitating reflactions r=int(color[1]+color[2], 16)+120 g=int(color[3]+color[4], 16)+120 b=int(color[5]+color[6], 16)+120 if r >= 255:r=255 if g >= 255:g=255 if b >= 255:b=255 #saving variables for later usage self.light="#"+str(hex(r)).replace("0x", "").replace("-", "")+str(hex(g)).replace("0x", "").replace("-", "")+str(hex(b).replace("0x", "")).replace("-", "") self.color=color self.number=number self.x=x self.y=y #making sure velocity of balls isnt 0 self.xv=0 while self.xv==0:self.xv=2*(random.random()-0.5) self.yv=0 while self.yv==0:self.yv=2*(random.random()-0.5) #draws ball for the first time to make sure the variables exist, so that they can be used later self.oval=w.create_oval(x-50,y-50,x+50,y+50, fill=self.color, outline=self.color) self.ovallight=w.create_oval(x-5,y+5,x+35,y-35, fill=self.light, outline=self.light) self.ovalwhite=w.create_oval(x-20,y+20,x+20,y-20, fill="white", outline="black") self.text=w.create_text(x, y, font=("Arial", 24),text=number) w.update() def update(self): #all physics related stuff happens here #makes ball move self.x = self.x + self.xv self.y = self.y + self.yv #checks if ball is colliding with other ones for a in range (0,main['balls']): otherx=elemente[a].coords()[0] othery=elemente[a].coords()[1] otherxv=elemente[a].coords()[2] otheryv=elemente[a].coords()[3] if otherx != self.x and othery != self.y: dsqrd = (othery-self.y) * (othery-self.y) + (otherx-self.x) * (otherx-self.x); if (dsqrd < (50+50)*(50+50)): #if ball is colliding -> go back self.xv = -self.xv self.yv = -self.yv self.x = self.x + self.xv self.y = self.y + self.yv #makes balls go the opposite way when hitting others -> if this isnt added, balls get stuck "in each other" #if ball is hitting the wall, go back if self.y<=102 or self.y>=wheight-102: self.yv = self.yv * (-1) if self.x<=102 or self.x>=wwidth-102: self.xv = self.xv * (-1) self.draw() def draw(self): #deletes old ball and draws new one w.delete(self.oval,self.ovallight,self.ovalwhite,self.text) self.oval=w.create_oval(self.x-50,self.y-50,self.x+50,self.y+50, fill=self.color, outline=self.color) self.ovallight=w.create_oval(self.x-5,self.y+5,self.x+35,self.y-35, fill=self.light, outline=self.light) self.ovalwhite=w.create_oval(self.x-20,self.y+20,self.x+20,self.y-20, fill="white", outline="black") self.text=w.create_text(self.x, self.y, font=("Arial", 24),text=self.number) w.update() def coords(self): #returns coordinates of element return self.x,self.y,self.xv,self.yv startup() #spawning balls, making sure they dont overlap elemente=[] for a in range (1,main['balls']+1): if elemente!=[]: errors=0 while errors !=-1: errors=0 x=random.randint(103,wwidth-103) y=random.randint(103,wheight-103) for b in range (0,len(elemente)): dsqrd=0 otherx=elemente[b].coords()[0] othery=elemente[b].coords()[1] dsqrd = (othery-y) * (othery-y) + (otherx-x) * (otherx-x); if dsqrd < 12000:errors +=1 if errors==0:errors=-1 else: x=random.randint(103,wwidth-103) y=random.randint(103,wheight-103) b=ball(colormaker(),str(a),x,y) elemente.append(b) if main['fps'] == 1: #initializes fps counter variables fpsmsg=w.create_text(150,wheight-40,font=("Arial", 12),fill="#ffd700",text="0") fps=0 t0 = time.time() while True: #mainloop, runs physics on all balls if main['fps'] == 1:fps += 1 #fps counter if time.time() - t0 >=1 and main['fps'] == 1: t0 = time.time() w.delete(fpsmsg) fpsmsg=w.create_text(150,wheight-40,font=("Arial", 12),fill="#ffd700",text=fps*1) fps=0 for a in range (0,main['balls']): #physics on balls elemente[a].update()