pythonzelle-graphics

Zelle-graphics window — Cloning object instead of moving


I'm making a simulation of a traffic light and a car. When the light turns green, the car should move. (I'm aware that actual stoplights don't jump from green to red, or from red to yellow, but...just go with it). The program takes input from the user as to how long the stoplight should loop; it starts by remaining red for 3 seconds and then looping through the other colors.

So my problem is that when I try to move the car (represented by a Rectangle object here) and wheels (two Circle objects), the graphics window appears to be creating an entirely new rectangle, despite the fact that I haven't called the clone() method or anything anywhere in my program. Try running the program for 8+ seconds to see.

Why is the car rectangle making copies of itself instead of just moving the original?

Code below:

import sys
from graphics import *
import time

def drawCar(win):
    car = Rectangle(Point(0,510), Point(100,555))
    car.setFill(color_rgb(255,0,0))
    wheel1 = Circle(Point(15,565),10)
    wheel2 = Circle(Point(75,565),10)
    wheel1.setFill(color_rgb(0,0,0))
    wheel2.setFill(color_rgb(0,0,0))
    car.draw(win)
    wheel1.draw(win)
    wheel2.draw(win)

def drawTrack(win):
    rect = Rectangle(Point(0,575),Point(500,600))
    rect.setFill(color_rgb(0,0,0))
    rect.draw(win)
    drawCar(win)

def loop(x):
    # opens and titles a graphics window
    win = GraphWin("Traffic Light", 500,600)

    # creates 3 black circles for the window
    red = Circle(Point(250,100),80)
    yellow = Circle(Point(250,260),80)
    green = Circle(Point(250,420),80)

    # draw the car and track
    drawTrack(win)
    corner1 = Point(0,510)
    corner2 = Point(100,555)
    car = Rectangle(corner1,corner2)
    car.setFill(color_rgb(255,0,0))
    wheel1 = Circle(Point(15,565),10)
    wheel2 = Circle(Point(75,565),10)
    wheel1.setFill(color_rgb(0,0,0))
    wheel2.setFill(color_rgb(0,0,0))
    car.draw(win)
    wheel1.draw(win)
    wheel2.draw(win)

    # sets default colors of the circles
    red.setFill(color_rgb(255,0,0))
    yellow.setFill(color_rgb(0,0,0))
    green.setFill(color_rgb(0,0,0))
    red.draw(win)
    yellow.draw(win)
    green.draw(win)

    redCount = 1 # red light counter is automatically set to 1 because it starts with red by default
    yelCount = 0 # yellow and green light counters are set to 0
    greenCount = 0

    redSet = True
    yellowSet = False
    greenSet = False

    start = time.time()
    end = time.time() + x

    time.sleep(2) # wait 2 seconds while showing the red light (since the loop waits 1 additional second on the red), then begin the color-changing

    while (time.time() - start < end):
        if(time.time() + 1 > end): # if the time it will take to rest on the next light will make it go overtime
            break # then stop
        if redSet:
            print("Red, changing to yellow")
            red.setFill(color_rgb(0,0,0))
            yellow.setFill(color_rgb(255,255,0))
            yelCount += 1
            redSet = False
            yellowSet = True
            time.sleep(1) # hold the yellow light for 1 second
        elif yellowSet:
            yellow.setFill(color_rgb(0,0,0))
            green.setFill(color_rgb(0,255,0))
            greenCount += 1
            yellowSet = False
            greenSet = True
            time.sleep(1) # hold green light for 1 second
            #corner1.move(60,0)
            #corner2.move(60,0)
            car.move(60,0)
            wheel1.move(60,0)
            wheel2.move(60,0)
            print("Corners moved")
        elif greenSet:
            green.setFill(color_rgb(0,0,0))
            red.setFill(color_rgb(255,0,0))
            greenSet = False
            redSet = True
            time.sleep(1)
            redCount += 1
        else:
            break

    print("Red light hit ", redCount)
    print("Yellow light hit ", yelCount)
    print("Green light hit ", greenCount)

    # if the user clicks anywhere in the window
    win.getMouse()
    # then we close the window
    win.close()


def main():
    # prompts the user for a time limit
    x = float(input("How many seconds do you want the traffic light simulation to last? "))
    # prints confirmation
    print("Starting the loop for ", x, " seconds:")

    # begins the loop
    loop(x)


main()

Solution

  • The problem is because you're drawing the car (and wheels) twice.
    Fortunately the fix to prevent that is simple:

    def drawTrack(win):
        rect = Rectangle(Point(0,575),Point(500,600))
        rect.setFill(color_rgb(0,0,0))
        rect.draw(win)
    #    drawCar(win)  # Don't do this.
    

    Note: After doing this, there will be no calls at all the function drawCar() so you could remove it. Another alternative would be to leave it in and replace the lines of code in the initialization part of the loop() function that do the same thing with a call to it (thereby making the code more modular).