Search code examples
pythonturtle-graphics2d-games

Caterpillars Eating Leaves Automatically in Caterpillar Game


I made a caterpillar game and now I'm trying to convert it into a two-player game. I made the second caterpillar and gave it the controls. When I ran it, the leaves automatically came to the caterpillars.

here is my code :

import random
import turtle as t

t.bgcolor('yellow')

caterpillar = t.Turtle()
caterpillar.shape('square')
caterpillar.color('red')
caterpillar.speed(0)
caterpillar.penup()
caterpillar.hideturtle()

caterpillar2 = t.Turtle()
caterpillar2.color('blue')
caterpillar2.shape('square')
caterpillar2.penup()
caterpillar2.speed(0)
caterpillar2.hideturtle()



leaf = t.Turtle()
leaf_shape = ((0, 0), (14, 2), (18, 6), (20, 20), (6, 18), (2, 14))
t.register_shape('leaf', leaf_shape)
leaf.shape('leaf')
leaf.color('green')
leaf.penup()
leaf.hideturtle()
leaf.speed(0)

game_started = False
text_turtle = t.Turtle()
text_turtle.write('Press SPACE to start' , align='center', font=('Arial', 50, 'bold' ))
text_turtle.hideturtle()

score_turtle = t.Turtle()
score_turtle.hideturtle()
score_turtle.speed(0)

def outside_window(caterpillar):
    left_wall = -t.window_width() / 2
    right_wall = t.window_width() / 2
    top_wall = t.window_height() / 2
    bottom_wall = -t.window_height() / 2
    (x, y) = caterpillar.pos()
    outside = \
        x<left_wall or \
        x>right_wall or \
        y<bottom_wall or \
        y>top_wall
    return outside

def game_over():
    caterpillar.color('yellow')
    caterpillar2.color('yellow')
    leaf.color('yellow')
    t.penup()
    t.hideturtle()
    t.write('GAME OVER!', align='center', font=('Arial', 30, 'normal'))

def display_score(current_score):
    score_turtle.clear()
    score_turtle.penup()
    x = (t.window_width() / 2) - 50
    y=(t.window_height() / 2) - 50
    score_turtle.setpos(x, y)
    score_turtle.write(str(current_score), align='right', font=('Arial', 40, 'bold'))

def place_leaf():
    leaf.ht()
    leaf.setx(random.randint(-200, 200))
    leaf.sety(random.randint(-200, 200))
    leaf.st()

def start_game():
    global game_started
    if game_started:
        return
    game_started=True

    score = 0
    text_turtle.clear()

    caterpillar_speed = 2
    caterpillar_length = 3
    caterpillar.shapesize(1, caterpillar_length, 1)
    caterpillar.showturtle()
    caterpillar2.shapesize(1, caterpillar_length, 1)
    caterpillar2.setheading(180)
    caterpillar2.showturtle()
    display_score(score)
    place_leaf()

    while True:
        caterpillar.forward(caterpillar_speed)
        caterpillar2.forward(caterpillar_speed)
        if caterpillar.distance(leaf) or leaf.distance(caterpillar2) < 20:
            place_leaf()
            caterpillar_length=caterpillar_length + 1
            caterpillar.shapesize(1, caterpillar_length, 1)
            caterpillar2.shapesize(1, caterpillar_length, 1)
            score = score + 10
            display_score(score)
        if outside_window(caterpillar) or outside_window(caterpillar2):
            game_over()
            break
def move_up():
    if caterpillar.heading() == 0 or caterpillar.heading() == 180 or caterpillar.heading() == 270:
        caterpillar.setheading(90)

def move_down():
    if caterpillar.heading() == 0 or caterpillar.heading() == 180 or caterpillar.heading() == 90:
        caterpillar.setheading(270)

def move_left():
    if caterpillar.heading() == 90 or caterpillar.heading() == 270 or caterpillar.heading() == 0:
        caterpillar.setheading(180)

def move_right():
    if caterpillar.heading() == 90 or caterpillar.heading() == 270 or caterpillar.heading() == 180:
        caterpillar.setheading(0)

def caterpillar2_move_up():
    if caterpillar2.heading() == 0 or caterpillar2.heading() == 180 or     caterpillar2.heading() == 270:
    caterpillar2.setheading(90)

def caterpillar2_move_down():
    if caterpillar2.heading() == 0 or caterpillar2.heading() == 180 or caterpillar2.heading() == 90:
        caterpillar2.setheading(270)

def caterpillar2_move_left():
    if caterpillar2.heading() == 90 or caterpillar2.heading() == 270 or caterpillar2.heading() == 0:
        caterpillar2.setheading(180)

def caterpillar2_move_right():
    if caterpillar2.heading() == 90 or caterpillar2.heading() == 270 or caterpillar2.heading() == 180:
        caterpillar2.setheading(0)


t.onkey(start_game, 'space')

t.onkey(move_up, 'Up')
t.onkey(move_right, 'Right')
t.onkey(move_down, 'Down')
t.onkey(move_left, 'Left')

t.onkey(caterpillar2_move_up, 'w')
t.onkey(caterpillar2_move_right, 'd')
t.onkey(caterpillar2_move_down, 's')
t.onkey(caterpillar2_move_left, 'a')

t.listen()
t. mainloop()

It gives me these errors :

"/Users/arkumar/user python/bin/python"             /Users/arkumar/PycharmProjects/caterpillar/.idea/caterpillar.py
Exception in Tkinter callback
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1536, in __call__
    return self.func(*args)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/turtle.py", line 710, in eventfun
    fun()
  File "/Users/arkumar/PycharmProjects/caterpillar/.idea/caterpillar.py", line 98, in start_game
    place_leaf()
  File "/Users/arkumar/PycharmProjects/caterpillar/.idea/caterpillar.py", line 70, in place_leaf
    leaf.ht()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/turtle.py", line 2236, in hideturtle
    self.pen(shown=False)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/turtle.py", line 2363, in pen
    self._update()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/turtle.py", line 2564, in _update
    self._update_data()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/turtle.py", line 2550, in _update_data
    self.screen._incrementudc()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/turtle.py", line 1239, in _incrementudc
    raise Terminator
Terminator

And yet it gives me an exit code 0:

Process finished with exit code 0

Could you please help me with this code?

Thank You, Aditya


Solution

  • I've reworked your code into a playable game below. I can't say what caused your specific error, it may be related to PyCharm, but logic-wise, the biggest problem I saw was this line:

    if caterpillar.distance(leaf) or leaf.distance(caterpillar2) < 20:
    

    I've seen other beginners try to do this and it just doesn't work, what you need to say is:

    if caterpillar.distance(leaf) < 20 or leaf.distance(caterpillar2) < 20:
    

    As the or doesn't distribute the conditional.

    import random
    from turtle import Turtle, Screen, mainloop
    
    TEXT_FONT = ('Arial', 50, 'bold')
    SCORE_FONT = ('Arial', 40, 'bold')
    
    def outside_window(caterpillar):
        left_wall, right_wall = -window_width / 2, window_width / 2
        top_wall, bottom_wall = window_height / 2, -window_height / 2
    
        x, y = caterpillar.pos()
    
        inside = left_wall < x < right_wall and  bottom_wall < y < top_wall
        return not inside
    
    def game_over():
        caterpillar1.hideturtle()
        caterpillar2. hideturtle()
        leaf.hideturtle()
        text_turtle.write('GAME OVER!', align='center', font=TEXT_FONT)
    
    def display_score(current_score):
        score_turtle.undo()
        score_turtle.write(current_score, align='right', font=SCORE_FONT)
    
    def place_leaf():
        leaf.hideturtle()
        leaf.setposition(random.randint(-200, 200), random.randint(-200, 200))
        leaf.showturtle()
    
    def start_game():
        screen.onkey(None, 'space')  # can't restart currently
    
        text_turtle.clear()
    
        score = 0
    
        caterpillar_speed = 2
        caterpillar_length = 3
    
        caterpillar1.shapesize(1, caterpillar_length, 1)
        caterpillar1.showturtle()
        caterpillar2.shapesize(1, caterpillar_length, 1)
        caterpillar2.setheading(180)
        caterpillar2.showturtle()
    
        display_score(score)
        place_leaf()
    
        while True:
            caterpillar1.forward(caterpillar_speed)
            caterpillar2.forward(caterpillar_speed)
    
            if caterpillar1.distance(leaf) < 20 or caterpillar2.distance(leaf) < 20:
                place_leaf()
                caterpillar_length += 1
                caterpillar1.shapesize(1, caterpillar_length, 1)
                caterpillar2.shapesize(1, caterpillar_length, 1)
                score = score + 10
                display_score(score)
    
            if outside_window(caterpillar1) or outside_window(caterpillar2):
                game_over()
                break
    
    def caterpillar1_move_up():
        caterpillar1.setheading(90)
    
    def caterpillar1_move_down():
        caterpillar1.setheading(270)
    
    def caterpillar1_move_left():
        caterpillar1.setheading(180)
    
    def caterpillar1_move_right():
        caterpillar1.setheading(0)
    
    def caterpillar2_move_up():
        caterpillar2.setheading(90)
    
    def caterpillar2_move_down():
        caterpillar2.setheading(270)
    
    def caterpillar2_move_left():
        caterpillar2.setheading(180)
    
    def caterpillar2_move_right():
        caterpillar2.setheading(0)
    
    screen = Screen()
    screen.bgcolor('yellow')
    window_width, window_height = screen.window_width(), screen.window_height()
    
    caterpillar1 = Turtle('square')
    caterpillar1.color('red')
    caterpillar1.speed('fastest')
    caterpillar1.penup()
    caterpillar1.hideturtle()
    
    caterpillar2 = Turtle('square')
    caterpillar2.color('blue')
    caterpillar2.speed('fastest')
    caterpillar2.penup()
    caterpillar2.hideturtle()
    
    leaf_shape = ((0, 0), (14, 2), (18, 6), (20, 20), (6, 18), (2, 14))
    screen.register_shape('leaf', leaf_shape)
    leaf = Turtle('leaf', visible=False)
    leaf.speed('fastest')
    leaf.color('green')
    leaf.penup()
    
    text_turtle = Turtle(visible=False)
    text_turtle.write('Press SPACE to start', align='center', font=TEXT_FONT)
    
    score_turtle = Turtle(visible=False)
    score_turtle.speed('fastest')
    score_turtle.penup()
    score_turtle.setpos(window_width / 2 - 50, window_height / 2 - 50)
    score_turtle.write(0, align='right', font=SCORE_FONT)
    
    screen.onkey(start_game, 'space')
    
    screen.onkey(caterpillar1_move_up, 'Up')
    screen.onkey(caterpillar1_move_right, 'Right')
    screen.onkey(caterpillar1_move_down, 'Down')
    screen.onkey(caterpillar1_move_left, 'Left')
    
    screen.onkey(caterpillar2_move_up, 'w')
    screen.onkey(caterpillar2_move_right, 'd')
    screen.onkey(caterpillar2_move_down, 's')
    screen.onkey(caterpillar2_move_left, 'a')
    
    screen.listen()
    
    mainloop()
    

    enter image description here

    One problem with my reworked code is it retains the while True: loop which really shouldn't happen in turtle's event driven environment. It should be replaced with screen.ontimer() events.