0
\$\begingroup\$

How do I add collision between two player controlled turtles? I asked the question before but misunderstood my own groundings on the plan. I cannot figure out how to make two player controlled turtles in the game to hit each other and end the game. This is what I have so far:

import turtle
import pygame
import math
import string




wn = turtle.Screen()
wn.bgcolor("black")

#Write Tron

text=turtle.Pen()
text.pencolor("aqua")
text.hideturtle()
text.penup()
text.setposition(150, 300)
text.write("TRON", font=("system", 30))

#Draw border
mypen = turtle.Turtle()
mypen.penup()
mypen.pencolor('white')
mypen.setposition(-300,-300)
mypen.pendown()
mypen.pensize(3)
for side in range (4):
    mypen.forward(600)
    mypen.left(90)
mypen.hideturtle()


pygame.display.update
#Create player 1
player = turtle.Turtle()
player.setposition(240,240)
player.setheading(180)
player.color("red")
player.shape("triangle")

player.speed(0)

#Create player 2
player2 = turtle.Turtle()
player2.setposition(-240,-240)
player2.color("aqua")
player2.shape("triangle")
player2.position()
player2.speed(0)

#Set speed variable
speed = 3

#Define functions
def turnleft():
    player.left(30)

def turnright():
    player.right(30)

def increasespeed():
    global speed
    speed += 3

#Set keyboard bindings for p1ayer 1
    
turtle.listen()
turtle.onkey(turnleft,"Left")
turtle.onkey(turnright,"Right")

#Define player 2 functions

def turnleft():
    player2.left(30)

def turnright():
    player2.right(30)

def increasespeed():
    global speed
    speed += 3

#Set keyboard bindings for player 2
turtle.listen()
turtle.onkey(turnleft,"a")
turtle.onkey(turnright,"d")
turtle.onkey(turnleft,"A")
turtle.onkey(turnright,"D")

#turtle.onkey(increasespeed,"Up")

while True:
    player.forward(speed)
    player2.forward(speed)

    #Bouandary
    if player.xcor() > 300 or player.xcor() < -300:
        print("GAME OVER")
        quit()
    #Boundary
    if player.ycor() > 300 or player.ycor() < -300:
        print("GAME OVER")
        quit()
    #Bouandary2
    if player2.xcor() > 300 or player2.xcor() < -300:
        print("GAME OVER")
        quit()
    #Boundary2
    if player2.ycor() > 300 or player2.ycor() < -300:
        print("GAME OVER")
        quit()
        
    #Collision
while True:
  if player.setposition(player.ycor()+10, player.xcor()+10) and player2.setposition(player2.xcor()+10, player2.ycor()+10):
      quit 
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

The code formatting for your answer has mostly broken down, it would be a lot easier to help you if you fixed it.

What does it mean for turtles to collide? It means that they occupy the same space, so the easiest thing to do is:

if player.position() == player2.position():
    print("GAME OVER")
    quit()

however, this doesn't quite work because turtle keeps the position as a floating point, so the turtles could be separated by a distance of 0.00000001 and count as not colliding, when anyone would think they would do. One way to get around this is to use math.is_close. A minimal example of this is:

import turtle
import math
import time

player_1 = turtle.Turtle()
player_1.setposition((-100, 0))

player_2 = turtle.Turtle()
player_2.setposition((100, 0))
player_2.left(180)

while True:
    player_1.forward(1)
    player_2.forward(1)

    if(math.isclose(player_1.xcor(), player_2.xcor(), abs_tol=1e-10) and
       math.isclose(player_1.ycor(), player_2.ycor(), abs_tol=1e-10)):
        print("CRASH!")
        print("GAME OVER")
        break

    if player_1.xcor() > 300 or player_1.xcor() < -300:
        print("GAME OVER")
        break

    if player_1.ycor() > 300 or player_1.ycor() < -300:
        print("GAME OVER")
        break

    if player_2.xcor() > 300 or player_2.xcor() < -300:
        print("GAME OVER")
        break

    if player_2.ycor() > 300 or player_2.ycor() < -300:
        print("GAME OVER")
        break

print("Thanks for playing!")
time.sleep(2)

Note that if you increase the argument in forward() then this doesn't work. That's because the turtles then "jump" from one position to the other and collisions are only checked in between jumps. It should not be complicated to modify the basic idea here to make that work however.

\$\endgroup\$
0
\$\begingroup\$

The existing answer neglects the builtin turtle .distance() method which trivializes this:

while True:
    player.forward(speed)
    player2.forward(speed)

    if player.distance(player2) < 30:
        print("collision")
        quit()

That's it! If the distance between the turtles is less than 30 (pick a number to taste), quit the game.

Here's a quick rewrite:

import math
from turtle import Screen, Turtle

wn = Screen()
wn.bgcolor("black")
wn.tracer(False)

# Write Tron
text = Turtle()
text.pencolor("aqua")
text.hideturtle()
text.penup()
text.setposition(150, 300)
text.write("TRON", font=("system", 30))

# Draw border
pen = Turtle()
pen.penup()
pen.pencolor("white")
pen.setposition(-300, -300)
pen.pendown()
pen.pensize(3)
for side in range(4):
    pen.forward(600)
    pen.left(90)
pen.hideturtle()

# Create player 1
player = Turtle()
player.setposition(240, 240)
player.setheading(180)
player.color("red")
player.shape("triangle")
player.speed(0)

# Create player 2
player2 = Turtle()
player2.setposition(-240, -240)
player2.color("aqua")
player2.shape("triangle")
player2.position()
player2.speed(0)

# Set turtle movement speed
speed = 3

# Set keyboard bindings for p1ayer 1
wn.listen()
wn.onkeypress(lambda: player.left(30), "Left")
wn.onkeypress(lambda: player.right(30), "Right")

# Set keyboard bindings for player 2
wn.onkeypress(lambda: player2.left(30), "a")
wn.onkeypress(lambda: player2.right(30), "d")
wn.onkeypress(lambda: player2.left(30), "A")
wn.onkeypress(lambda: player2.right(30), "D")
wn.tracer(True)

while True:
    player.forward(speed)
    player2.forward(speed)

    if player.distance(player2) < 30:
        print("collision")
        quit()

    # Check border collisions
    if (
        player.xcor() > 300 or player.xcor() < -300 or
        player.ycor() > 300 or player.ycor() < -300 or
        player2.xcor() > 300 or player2.xcor() < -300 or
        player2.ycor() > 300 or player2.ycor() < -300
    ):
        print("GAME OVER")
        quit()

This can be improved further to turn magic numbers like 300 into global constants, and avoiding repetition in player creation and collision checks, left as an exercise.

Note that onkey is actually onkeyrelease, and that your game is subject to the operating system's keyboard retrigger timing. This leads to a poor experience. Following this post, you can decouple movement and key presses, leading to smooth movement:

# ...

# Set turtle movement speed
speed = 3
turn_speed = 15

# Set keyboard bindings for p1ayer 1
keys = set()
wn.listen()
wn.onkeypress(lambda: keys.add("Left"), "Left")
wn.onkeypress(lambda: keys.add("Right"), "Right")
wn.onkeyrelease(lambda: keys.remove("Left"), "Left")
wn.onkeyrelease(lambda: keys.remove("Right"), "Right")

# Set keyboard bindings for player 2
wn.onkeypress(lambda: keys.add("a"), "a")
wn.onkeypress(lambda: keys.add("d"), "d")
wn.onkeyrelease(lambda: keys.remove("a"), "a")
wn.onkeyrelease(lambda: keys.remove("d"), "d")
wn.tracer(True)

while True:
    if "Left" in keys:
        player.left(turn_speed)
    if "Right" in keys:
        player.right(turn_speed)
    if "a" in keys:
        player2.left(turn_speed)
    if "d" in keys:
        player2.right(turn_speed)

    player.forward(speed)
    player2.forward(speed)
    # ...

Here's a more abstracted version of the same thing, based on this answer:

# ...
# Set turtle movement speed
speed = 3
turn_speed = 15

def bind(key):
    wn.onkeypress(lambda: keys.add(key), key)
    wn.onkeyrelease(lambda: keys.remove(key), key)

keys = set()
actions = {
    "Left": lambda: player.left(turn_speed),
    "Right": lambda: player.right(turn_speed),
    "a": lambda: player2.left(turn_speed),
    "d": lambda: player2.right(turn_speed),
}

for key in actions.keys():
    bind(key)

wn.listen()
wn.tracer(True)

while True:
    for key in [*keys]:
        actions[key]()

    player.forward(speed)
    player2.forward(speed)
    # ...
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.