Easy-E
Easy-E

Reputation: 1

How do i move multiple objects at the same time but every object by different distance in tkinter python?

I have a game that generates multiple objects and which object comes to other side of canvas wins. When you press button every object moves a different random distance forward. The problem is that firts object moves the least and last object moves the most. So last object always wins. How do i made it that random object will win and not always the last one.

import tkinter
import random
canvas=tkinter.Canvas(width=400, height=400)
canvas.pack()

label=tkinter.Label(text='set amout of cars')
label.pack()

entry=tkinter.Entry()
entry.pack()

def car():
    global move
    move=0
    canvas.delete('all')
    p=int(entry.get())
    for i in range(p):
        canvas.create_rectangle(20,20+i*20,40,30+i*20, fill='coral')

move=0

def race():
    global move
    canvas.delete('all')
    p=int(entry.get())
    for i in range(p):
        rand=random.randint(5,20)
        move=move+rand
        canvas.create_rectangle(20+move,20+i*20,40+move,30+i*20, fill='coral')
    
    
        
button=tkinter.Button(text='start', command=car)
button.pack()
button2=tkinter.Button(text='forward', command=race)
button2.pack()

Upvotes: 0

Views: 713

Answers (2)

furas
furas

Reputation: 142804

All your objects use the same variable move - so in every execution of race they use the same position. But in every loop you add new values to move - so first object use distance move+rand1, second move+rand1+rand2, third move+rand1+rand2+rand3, etc - and this makes problem.

Every object should have own variable with position.

So it would need to use list with positions.


Or better create object only once and get ID

car_id = canvas.create_rectangle(...)

and later use ID to move this object

canvas.move(car_id, ...)

and this way every car will use own position.

And of course it also need to use list to keep all IDs


def restart():
    canvas.delete('all')
    all_cars.clear()

    number = int(entry.get())

    for i in range(number):
        car_id = canvas.create_rectangle(20, 20+i*20, 40, 30+i*20, fill='coral')
        all_cars.append( car_id )

def race():
    for car_id in all_cars:
        distance_x = random.randint(5,20)
        distance_y = 0
        canvas.move(car_id, distance_x, distance_y)

# --- main ---

all_cars = []

EDIT:

Full working code:

I also used

  • after(100, race) - so it automatically repeate function after 100ms and you don't have to click button race again and again.

  • canvas.corrds() to get current position and check if it end of race.

  • create_line to show finish line

import tkinter as tk
import random

# --- functions ---

def restart():
    canvas.delete('all')
    all_cars.clear()

    number = int(entry.get())

    for i in range(number):
        car_id = canvas.create_rectangle(20, 20+i*20, 40, 30+i*20, fill='coral')
        all_cars.append( car_id )

    # finish line
    canvas.create_line(360, 10, 360, 30+(number-1)*20 + 10, fill='red')
    
def race():
    winner = False
    
    for car_id in all_cars:
        distance_x = random.randint(5, 20)
        distance_y = 0
        canvas.move(car_id, distance_x, distance_y)

        x1, y1, x2, y2 = canvas.coords(car_id)
        
        if x1 >= 360:
            winner = True
            canvas.moveto(car_id, 360, y1-1)
            canvas.itemconfig(car_id, fill='green')

    if not winner:
        root.after(100, race)
    
# --- main ---

all_cars = []  # list for all IDs

root = tk.Tk()

canvas = tk.Canvas(root, width=400, height=400)
canvas.pack()

label = tk.Label(root, text='set amout of cars')
label.pack()

entry = tk.Entry(root)
entry.pack()

button = tk.Button(root, text='start', command=restart)
button.pack()

button2 = tk.Button(root, text='forward', command=race)
button2.pack()

root.mainloop()

enter image description here

Upvotes: 1

Bryan Oakley
Bryan Oakley

Reputation: 386220

As described in the comments, every object shares the same move variable, so each object starts where the last one stopped.

The better solution is to call the move method on the canvas for each of the objects. You can either save a list of objects or just ask the canvas to give you the objects. You can then use randint to decide how much to move each item.

The race function would look something like this:

def race():
    for car in canvas.find("all"):
        delta_x = random.randint(5,20)
        delta_y = 0
        canvas.move(car, delta_x, delta_y)

Upvotes: 2

Related Questions