Search code examples
pythontkinter

Invader distance increases even though it shouldn't


The distance between the Invader touching the left edge of the canvas increases even though it shouldn't. The Problem doesn't occur on the right side.

import tkinter
import timeit

tk = tkinter.Tk()
WIDTH = 1000
HEIGHT = 650
global canvas
canvas = tkinter.Canvas(tk, width=WIDTH, height=HEIGHT, bg="black")
canvas.pack()

class Invader():
    def __init__(self, canvas, play, x, y):
        self.canvas = canvas
        self.play = play
        self.x_coord = x
        self.y_coord = y
        self.shape = canvas.create_rectangle(self.x_coord, self.y_coord, self.x_coord + 50, self.y_coord + 50, fill='green')
        self.direction = 'left'

    def move(self):
        if self.direction == 'right':
            self.x_coord += 10
            if self.x_coord + 40 >= WIDTH:
                play.move_all_down()
        elif self.direction == 'left':
            self.x_coord -= 10
            if self.x_coord - 10 == 0:
                play.move_all_down()
        canvas.coords(self.shape, self.x_coord, self.y_coord, self.x_coord + 50, self.y_coord + 50)

class Play():
    def __init__(self, canvas):
        self.canvas = canvas
        self.invaderlist = []
        self.last_move_time = timeit.default_timer()
        self.move_delay = 0.3443434

    def move_invaders(self):
            current_time = timeit.default_timer()
            if current_time - self.last_move_time > self.move_delay:
                for invader in self.invaderlist:
                    invader.move()
                    self.last_move_time = current_time
    def move_all_down(self):
        for invader in self.invaderlist:
            invader.y_coord += 10
            canvas.coords(invader.shape, invader.x_coord, invader.y_coord, invader.x_coord + 50, invader.y_coord + 50)
            if invader.direction == 'left':
                invader.direction = 'right'
            elif invader.direction == 'right':
                invader.direction = 'left'


    def run_all(self):
        x_coords = [50, 120, 200, 270, 350, 420, 500, 570, 650, 720]
        y = 200
        for i in range(10):
            x = x_coords[i]
            invader = Invader(self.canvas, self, x, y)
            self.invaderlist.append(invader)
        while True:
            self.move_invaders()
            canvas.after(5)
            self.canvas.update()          

play = Play(canvas)
play.run_all()
tkinter.mainloop()

I tried outputting the coordinates when touching the left side plus added a line that printed the id of the invader and the coordinates, I also tried changing the distance that it checks for in line 26.


Solution

  • Your loop in Play.move_invaders() can tell each invader to move, except that any invader that moves beyond the limit left or right will cause all invaders to move down, and that switches the direction, which changes the test for the other invaders (if self.direction == 'right': etc) so not all invaders move the same direction.

    Your loop should first move all the invaders and then, if the limit was exceeded, should then call move_all_down():

    import tkinter
    import timeit
    
    tk = tkinter.Tk()
    WIDTH = 1000
    HEIGHT = 650
    global canvas
    canvas = tkinter.Canvas(tk, width=WIDTH, height=HEIGHT, bg="black")
    canvas.pack()
    
    class Invader():
        def __init__(self, canvas, play, x, y):
            self.canvas = canvas
            self.play = play
            self.x_coord = x
            self.y_coord = y
            self.shape = canvas.create_rectangle(self.x_coord, self.y_coord, self.x_coord + 50, self.y_coord + 50, fill='green')
            self.direction = 'left'
    
        def move(self):
            limit = False
            if self.direction == 'right':
                self.x_coord += 10
                if self.x_coord + 40 >= WIDTH:
                    limit = True
            elif self.direction == 'left':
                self.x_coord -= 10
                if self.x_coord - 10 <= 0:
                    limit = True
    
            canvas.coords(self.shape, self.x_coord, self.y_coord, self.x_coord + 50, self.y_coord + 50)
            return limit
    
    class Play():
        def __init__(self, canvas):
            self.canvas = canvas
            self.invaderlist = []
            self.last_move_time = timeit.default_timer()
            self.move_delay = 0.3443434
    
        def move_invaders(self):
                current_time = timeit.default_timer()
                if current_time - self.last_move_time > self.move_delay:
                    move_down = False
                    for invader in self.invaderlist:
                        limit = invader.move()
                        move_down = move_down or limit
                        self.last_move_time = current_time
                    if move_down:
                        self.move_all_down()
    
        def move_all_down(self):
            for invader in self.invaderlist:
                invader.y_coord += 10
                #canvas.coords(invader.shape, invader.x_coord, invader.y_coord, invader.x_coord + 50, invader.y_coord + 50)
                if invader.direction == 'left':
                    invader.direction = 'right'
                elif invader.direction == 'right':
                    invader.direction = 'left'
    
    
        def run_all(self):
            x_coords = [50, 120, 200, 270, 350, 420, 500, 570, 650, 720]
            y = 200
            for i in range(10):
                x = x_coords[i]
                invader = Invader(self.canvas, self, x, y)
                self.invaderlist.append(invader)
            while True:
                self.move_invaders()
                canvas.after(5)
                self.canvas.update()          
    
    play = Play(canvas)
    play.run_all()