Python using tkinter Figure on top of another

2

Hi, I am new to this page and programming, I have a project where I have to make a bubble collection program, either circles or images of these, where I must click and generate a fractal figure for each click.

The fractal has to be generated from a distance in which it is not generated above the previous figure, that is, the fractal, and that the distance that can be clicked and generated is not so far away. When the program starts, these bubbles are generated and the fractal is generated in the lower part of the screen, when you click create a line of figures until you reach a bubble, and if the figure touches the bubble it disappears and you begin to add the points. These figures disappear and return to the original position to collect the bubbles that remain and that's how this game works.

With this I generate the bubbles:

from tkinter import  *
import random

ventana = Tk ()
ventana.title ("Ventana")

label1 = Label (ventana,text=" Jugador 1 ")
label1.grid()
label1  =  Label (ventana,text ="Puntuacion:  ")
label1.grid()

canvas=Canvas (ventana, width=1500, height=900, borderwidth=0,
               highlightthickness=0, bg= "orange")
canvas.grid()


def _create_circle (self, x, y, r, **kwargs):
    return self.create_oval (x-r, y-r, x+r, y+r, **kwargs)

Canvas.create_circle = _create_circle

colores=["red", "blue", "orange", "yellow", "purple", "green",  "black", 
"white", "#5E00FF"]

for i in range (0,10):        
      n= random.randint (10,1000)         
      n2 = random.randint (20,700)          
      canvas.create_circle (n,  n2,  20,  fill=colores [1])

ventana.mainloop ()

I need help so that it does not go over one another, that's my problem now, please help me and thank you in advance,

    
asked by Alejandro Rodriguez 29.06.2017 в 08:37
source

1 answer

1

The most common way to solve this problem is to check if the circumferences overlap. To see if two circles overlap, you only need to know their radius and center (which is what you use to create them). Bearing this, it is enough to calculate the distance between both, which is not more than the calculation of the hypotenuse of a right triangle (Pythagorean Theorem):

With what the formula to calculate the distance is:

Taking the above into account, it suffices to create a function in Python that returns if two circumferences overlap or not and for each new circumference created randomly we check if it overlaps with any of the esxistentes. To do this we keep each circumference in a set ( set ) as a tuple of the form (x, y, radio) and we use any to do the check for each new circle to create. We can also add a third condition so that the new circles not only do not overlap, but are at a certain minimum distance from the rest:

def solapamiento(cir1, cir2, esp = 0):
    # cir1 y cir2 son tuplas de la forma (x, y, radio)
    # esp es la separación mínima que ha de haber entre circunferencias
    distancia = ((cir2[0] - cir1[0])**2 + (cir2[1] - cir1[1])**2)**0.5
    return (cir1[2] + cir2[2] + esp) > abs(distancia)


circulos = set()
espaciamiento = 10
n = 10
while len(circulos) < n:
    x= random.randint (10,1000)         
    y = random.randint (20,700)
    r = 20
    cir = (x, y, r)
    if not any(solapamiento(cir, c, espaciamiento) for c in circulos):
        circulos.add(cir)

Logically, you have to be careful with the parameters. A greater radius or greater separation less circles can be created and more difficult is that random of with an accepted circle. You can adapt the while so that if you do not find all the circles in i iterations, leave and draw the ones you have, avoiding that if we ask you to create more circles than possible for the available space, you can iterate infinitely .

Your code would look like this:

import random
import tkinter as tk

class MyCanvas(tk.Canvas):
    def __init__(self, parent, *args, **kwargs):
        tk.Canvas.__init__(self, parent, *args, **kwargs)

    def create_circle (self, x, y, r, **kwargs):
        return self.create_oval (x-r, y-r, x+r, y+r, **kwargs)

colores=["red", "blue", "yellow", "purple", "green",  "black", 
"white", "#5E00FF"]

ventana = tk.Tk ()
ventana.title ("Ventana")

label1 = tk.Label (ventana,text=" Jugador 1 ")
label1.grid()
label1  =  tk.Label (ventana,text ="Puntuacion:  ")
label1.grid()

canvas = MyCanvas(ventana, width=1500, height=900, borderwidth=0,
                  highlightthickness=0, bg= "orange")
canvas.grid()

def solapamiento(cir1, cir2, esp = 0):
    # cir1 y cir2 son tuplas de la forma (x, y, radio)
    # esp es la separación mínima que ha de haber entre circunsferencias
    distancia = ((cir2[0] - cir1[0])**2 + (cir2[1] - cir1[1])**2)**0.5
    return (cir1[2] + cir2[2] + esp) > abs(distancia)


circulos = set()
espaciamiento = 10
n = 10
while len(circulos) < n:
    x= random.randint(10,1000)         
    y = random.randint(20,700)
    r = random.randint(15,40)
    color = random.choice(colores)
    cir = (x, y, r)
    if not any(solapamiento(cir, c, espaciamiento) for c in circulos):
        circulos.add(cir)
        canvas.create_circle (x,  y,  r,  fill = color)

ventana.mainloop ()

I have modified some things, in addition to the above:

  • You should not use the way to import from módulo import * in Python. It is a bad practice, dangerous in complex and extensive codes, very inefficient with memory and makes reading by third parties difficult. Remember the zen of Python: "Explicit better than implicit". The common way is to use import tkinter as tk , you can also use import tkinter or from tkinter import Canvas, Label, ... .

  • The way you create your create_circle method is a bit confusing and not very appropriate. It is better and safer to create a class that inherits Canvas instead. In this case MyCanvas (call it what you want) has your method create_circle but the class tkinter.Canvas is left intact. Modifying the latter directly can have unexpected consequences, for example if another widget uses the original class.

  • Finally, in the previous code the radius and the color are also random. You can eliminate the behavior by changing the variables by radio = 20 and color = colores[0] , for example.

An example of how it is:

    
answered by 29.06.2017 в 16:19