Search code examples
pythonpython-3.xturtle-graphicspython-turtle

When I press a key, all the other previously moving elements stop moving in python turtle


So I'm making a 2 player tron game in turtle, and my code seemed to be working fine (except the border that's why I commented it out). The only thing is that when I tried to play the game by myself to test it out, whenever I moved the "other" tron bike, the one that I just had clicked to make move stops moving. How can I fix this?

Here is my code:

def tron():
    #Drawing the starting turtles
    blueplayer = turtle.Turtle()
    redplayer = turtle.Turtle()
    screen = turtle.Screen()
    screen.setup(width, height)
    screen.bgpic('TronBg.png')
    screen.bgcolor('black')
    screen.addshape('BlueBike.gif')
    screen.addshape('RedBike.gif')
    blueplayer.shape('BlueBike.gif')
    redplayer.shape('RedBike.gif')
    redplayer.pencolor("red")
    redplayer.pensize(3)
    blueplayer.pencolor("blue")
    blueplayer.pensize(3)
    redplayer.pu()
    blueplayer.pu()
    redplayer.goto(width/2, height/8)
    blueplayer.goto(-1*(width)/2, height/8)
    redplayer.pd()
    blueplayer.pd()

    #Border
    #box = Turtle()
    #box.ht()
    #box.color('purple')
    #box.speed('fastest')
    #box.pensize(10)

   # box.pu()
   # box.goto(-1*height, -1*width)
   # box.pd()

   # for i in range(4):
   #   box.forward(height)
   #   box.left(90)
   #   box.forward(width)
   #   box.left(90)
      
    #Player movements
    def RedUp():
      while True:
        blueplayer.setheading(90)
        blueplayer.forward(3)
    def BlueUp():
      while True:
        redplayer.setheading(90)
        redplayer.forward(3)

    def RedDown():
      while True:
        blueplayer.setheading(270)
        blueplayer.forward(3)
    def BlueDown():
      while True:
        redplayer.setheading(270)
        redplayer.forward(3)

    def RedLeft():
      while True:
        blueplayer.setheading(180)
        blueplayer.forward(3)
    def BlueLeft():
      while True:
        redplayer.setheading(180)
        redplayer.forward(3)

    def RedRight():
      while True:
        blueplayer.setheading(0)
        blueplayer.forward(3)
    def BlueRight():
      while True:
        redplayer.setheading(0)
        redplayer.forward(3)

    for x in range(10):
      turtle.color('white')
      style = ('Arial', 25, 'italic')
      turtle.write(10-x, font=style, align='center') 
      time.sleep(1)
      turtle.undo()
  
    screen.listen()

    screen.onkey(RedUp, "w")
    screen.onkey(RedDown, "s")
    screen.onkey(RedLeft, "a")
    screen.onkey(RedRight, "d")

    screen.onkey(BlueUp, "Up")
    screen.onkey(BlueDown, "Down")
    screen.onkey(BlueLeft, "Left")
    screen.onkey(BlueRight, "Right")
    
    screen.mainloop()

tron()

Solution

  • Using while True can be the problem - it runs endless loop which may block previous function and this may stop previous player.

    Keys should set global variables with player direction - and timer should repeate code which checks directions for both players and update they positions.


    Minimal working code - without images - so everyone can simply copy and run.

    import turtle
    import time
    
    width = 600
    height = 600
    
    red_direction = None
    blue_direction = None
    
    # blue player movements   # PEP8: one space after `#`
    def blue_up():   # PEP8: `lower_case_names` for functions
        global blue_direction
        blue_direction = 'up'
    
    def blue_down():
        global blue_direction
        blue_direction = 'down'
    
    def blue_left():
        global blue_direction
        blue_direction = 'left'
    
    def blue_right():
        global blue_direction
        blue_direction = 'right'
    
    # blue player movements   # PEP8: one space after `#`
    def red_up():   # PEP8: `lower_case_names` for functions
        global red_direction
        red_direction = 'up'
    
    def red_down():
        global red_direction
        red_direction = 'down'
    
    def red_left():
        global red_direction
        red_direction = 'left'
    
    def red_right():
        global red_direction
        red_direction = 'right'
    
    # movements   # PEP8: one space after `#`
    def move_player(player, direction):
        if direction == 'up':
            player.setheading(90)
            player.forward(5)
        elif direction == 'down':
            player.setheading(270)
            player.forward(5)
        elif direction == 'left':
            player.setheading(180)
            player.forward(5)
        elif direction == 'right':
            player.setheading(0)
            player.forward(5)
    
    def gameloop():
        move_player(red_player, red_direction)
        move_player(blue_player, blue_direction)
    
        # repeate after 40ms (0.04s) (1000ms/20ms = 25 FPS [Frames Per Second])
        screen.ontimer(gameloop, 40)
    
    def tron():
        global screen
        global blue_player
        global red_player
    
        screen = turtle.Screen()
        screen.setup(width, height)
        screen.bgcolor('black')
        
        blue_player = turtle.Turtle()
        blue_player.pencolor("blue")
        blue_player.pensize(3)
        blue_player.pu()
        blue_player.goto(-1*(width)/3, height/8)
        blue_player.pd()
        
        red_player = turtle.Turtle()
        red_player.pencolor("red")
        red_player.pensize(3)
        red_player.pu()
        red_player.goto(width/3, height/8)
        red_player.pd()
    
        style = ('Arial', 25, 'italic')
        turtle.color('white')
        for x in range(10):  # PEP8: 4 spaces indention
            turtle.write(10-x, font=style, align='center') 
            time.sleep(0.5)
            turtle.undo()
      
        screen.listen()
    
        screen.onkey(red_up, "w")
        screen.onkey(red_down, "s")
        screen.onkey(red_left, "a")
        screen.onkey(red_right, "d")
    
        screen.onkey(blue_up, "Up")
        screen.onkey(blue_down, "Down")
        screen.onkey(blue_left, "Left")
        screen.onkey(blue_right, "Right")
        
        screen.ontimer(gameloop, 250)
        screen.mainloop()
    
    tron()
    

    PEP 8 -- Style Guide for Python Code