I am new to Python. I'm trying to create a space game where two space ships fight each other. The user controls one and the other will fly and fire randomly. The user has to protect their self and fire on the other ship. If either ship can sucessefully hit the other 10 times, then that ship wins.
Problem: I can not see both ships at the same time. When I control one turtle, then the other turtle does not show. Please help.
from turtle import *
import random
import pygame
class Application:
space_ship = Turtle()
window = Screen()
window_X = 640
window_Y = 640
ship_x = space_ship.xcor()
Clock = pygame.time.Clock()
def __init__(self):
self.game_config()
self.enemy_config()
def enemy_config(self):
enemy = Turtle()
enemy.penup()
enemy.speed(0)
enemy.shapesize(2)
enemy.setposition(0,-250)
while True:
self.Clock.tick(20)
enemy.fd(10)
if enemy.ycor() >= 340:
enemy.right(50)
enemy.sety(-320)
elif enemy.ycor() <= -340:
enemy.right(50)
enemy.sety(320)
elif enemy.xcor() >= 340:
enemy.right(50)
enemy.setx(-320)
elif enemy.xcor() <= -340:
enemy.right(50)
enemy.setx(320)
def movefd(self):
while True:
self.Clock.tick(20)
self.space_ship.fd(10)
if self.space_ship.ycor() >= 340:
self.space_ship.sety(-320)
elif self.space_ship.ycor() <= -340:
self.space_ship.sety(320)
elif self.space_ship.xcor() >= 340:
self.space_ship.setx(-320)
elif self.space_ship.xcor() <= -340:
self.space_ship.setx(320)
def moverg(self):
self.space_ship.right(15)
def movelf(self):
self.space_ship.left(15)
def game_config (self):
bgcolor("white")
self.space_ship.shapesize(2)
self.space_ship.speed(0)
self.space_ship.color("green")
self.window.setup(self.window_X,self.window_Y)
self.space_ship.left(90)
self.space_ship.penup()
onkeypress(self.moverg, "Right")
onkeypress(self.movelf, "Left")
onkeypress(self.movefd, "Up")
listen()
done()
if __name__ == '__main__':
Application()
Problem: can not see both ship same time. when use control one turtle
then another turtle does not show.
For me, the bigger problem is you've completely missed the point of object-oriented programming. Let's address both our problems with a complete rework of your code. But before we do, repeat over and over, "while True: has no business in an event-driven world like turtle."
from turtle import Screen, Turtle
class SpaceShip(Turtle):
def __init__(self):
super().__init__()
self.shapesize(2)
self.color("green")
self.speed('fastest')
self.penup()
self.setheading(90)
def movefd(self):
self.forward(10)
if self.ycor() >= 340:
self.sety(-320)
elif self.ycor() <= -340:
self.sety(320)
if self.xcor() >= 340:
self.setx(-320)
elif self.xcor() <= -340:
self.setx(320)
def moverg(self):
self.right(15)
def movelf(self):
self.left(15)
class EnemyShip(SpaceShip):
def __init__(self):
super().__init__()
self.hideturtle()
self.color("black")
self.setheading(-50)
self.sety(-250)
self.showturtle()
class Application:
SCREEN_X = 640
SCREEN_Y = 640
def __init__(self):
self.screen = Screen()
self.screen.setup(self.SCREEN_X, self.SCREEN_Y)
self.space_ship = SpaceShip()
self.enemy = EnemyShip()
self.screen.onkeypress(self.space_ship.moverg, "Right")
self.screen.onkeypress(self.space_ship.movelf, "Left")
self.screen.onkeypress(self.space_ship.movefd, "Up")
self.screen.listen()
self.movefd()
self.screen.mainloop()
def movefd(self):
self.enemy.movefd()
self.screen.ontimer(self.movefd, 100)
if __name__ == '__main__':
Application()
Related
I'm trying to make a program that is essentially an etchasketck, with some minor tweaks for my school project(the required use of a main function, wasd as movement controls, and q to quit the program and p to pick up or drop down the turtle pen). I was testing this code in trinket.io and it was working fine. You can see it working there with this link: https://trinket.io/python/99fd3ec305. However, when I go to run it from pycharm, cmd, or the python IDLE, it always leaves the turtle hanging and unresponsive. I get no errors, just the turtle to pop up for a few seconds, then it hangs, and I'm unable to do anything.
Here's my code:
import sys
import turtle
arg_len = len(sys.argv)
# store length of arguments
if arg_len < 3:
print("Too less arguments, using default values..")
WIDTH = 200
HEIGHT = 200
else:
WIDTH = int(sys.argv[1])
HEIGHT = int(sys.argv[2])
screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
# create a turtle instance
t = turtle.Turtle()
t.speed(0)
# slow down the turtle
# declare flags
move = False
exit_flag = False
def up():
global move
move = True
t.setheading(90)
def down():
global move
move = True
t.setheading(270)
def left():
global move
move = True
t.setheading(180)
def right():
global move
move = True
t.setheading(0)
# toggle pen up and down
def toggle_pen():
if t.isdown():
t.penup()
else:
t.pendown()
# set exit flag
def quit_program():
global exit_flag
exit_flag = True
def check_border():
if t.xcor() == WIDTH / 2:
t.penup()
t.setx(-WIDTH / 2)
elif t.xcor() == -WIDTH / 2:
t.penup()
t.setx(WIDTH / 2)
if t.ycor() == HEIGHT / 2:
t.penup()
t.sety(-HEIGHT / 2)
elif t.ycor() == -HEIGHT / 2:
t.penup()
t.sety(HEIGHT / 2)
def listen_keys():
screen.listen()
screen.onkey(up, "w")
screen.onkey(down, "s")
screen.onkey(left, "a")
screen.onkey(right, "d")
screen.onkey(toggle_pen, "p")
screen.onkey(quit_program, "q")
# main loop
def main():
listen_keys()
while not exit_flag:
global move
if move:
t.forward(0.5)
screen.update()
check_border()
else:
t.done()
main()
I'm using python 3.10, and I mainly use pycharm for the running.
I was trying to get the turtle to move indefinitly without user input after the first user input, I was going to achieve this with the while loop, but it just leaves my program unresponsive. Can anyone tell me what's wrong that I'm not seeing?
You've effectively put a while True: loop in an event-driven program where one should never be used. If I were writing this for the command line, with the constraints listed, I might go about it this way (dropping command line processing for example simplicity):
from turtle import Screen, Turtle
WIDTH, HEIGHT = 200, 200
def up():
turtle.setheading(90)
start_motion()
def down():
turtle.setheading(270)
start_motion()
def left():
turtle.setheading(180)
start_motion()
def right():
turtle.setheading(0)
start_motion()
def toggle_pen():
if turtle.isdown():
turtle.penup()
else:
turtle.pendown()
def quit_program():
screen.bye()
def check_border():
x, y = turtle.position()
if x >= WIDTH / 2:
turtle.penup()
turtle.setx(-WIDTH / 2)
elif x <= -WIDTH / 2:
turtle.penup()
turtle.setx(WIDTH / 2)
if y >= HEIGHT / 2:
turtle.penup()
turtle.sety(-HEIGHT / 2)
elif y <= -HEIGHT / 2:
turtle.penup()
turtle.sety(HEIGHT / 2)
def main():
screen.onkey(up, 'w')
screen.onkey(down, 's')
screen.onkey(left, 'a')
screen.onkey(right, 'd')
screen.onkey(toggle_pen, 'p')
screen.onkey(quit_program, 'q')
screen.listen()
screen.mainloop()
def move():
turtle.forward(1)
check_border()
screen.ontimer(move, 25)
moving = False
def start_motion():
global moving
if not moving:
moving = True
move()
screen = Screen()
screen.setup(WIDTH, HEIGHT)
turtle = Turtle()
turtle.speed('fastest')
main()
See if this still works with trinket.io, IDLE and PyCharm, or if it can be made to do so.
Trying to make a simple maze game in Python Turtle. Using the stamp method I have made the outline of the first level, and it loads perfectly. I want to add a second level and access it, but I don't know how. Any help will be appreciated.
P.S - I am quite new to stack overflow so idk how much code I should put here, but expecting help, I am posting the full code. Thank in advance
import turtle
import math
wn = turtle.Screen()
wn.bgcolor("black")
wn.title("A maze game")
wn.setup(700,700)
class Pen(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.shape("square")
self.color("white")
self.penup()
self.speed(0)
class Treasure(turtle.Turtle):
def __init__(self, x, y):
turtle.Turtle.__init__(self)
self.shape("square")
self.color(color_1)
self.penup()
self.speed(0)
self.gold = 100
self.goto(x, y)
def destroy(self):
self.goto(2000, 2000)
self.hideturtle()
def change_color(self):
self.color(color_2)
color_1 = ("white")
color_2 = ("gold")
class Player(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.shape("circle")
self.color("red")
self.penup()
self.speed(0)
self.gold = 0
def go_up(self):
move_to_x = player.xcor()
move_to_y = player.ycor() + 24
if (move_to_x, move_to_y) not in walls:
self.goto(move_to_x, move_to_y)
def go_down(self):
move_to_x = player.xcor()
move_to_y = player.ycor() - 24
if (move_to_x, move_to_y) not in walls:
self.goto(move_to_x, move_to_y)
def go_left(self):
move_to_x = player.xcor() - 24
move_to_y = player.ycor()
if (move_to_x, move_to_y) not in walls:
self.goto(move_to_x, move_to_y)
def go_right(self):
move_to_x = player.xcor() + 24
move_to_y = player.ycor()
if (move_to_x, move_to_y) not in walls:
self.goto(move_to_x, move_to_y)
def is_close_to(self, other):
a = self.xcor()-other.xcor()
b = self.ycor()-other.ycor()
distance = math.sqrt((a ** 2) + (b ** 2))
if distance < 50:
return True
else:
return False
levels = [""]
level_1 = [
"XXXXXXXXXXXXXXXXXXXXXXXXX",
"X P T X",
"XXXXXXXXXXXXXXXXXXXXXXXXX"
]
treasures = []
levels.append(level_1)
def setup_maze(level):
for y in range(len(level)):
for x in range(len(level[y])):
character = level[y][x]
screen_x = -288 + (x * 24)
screen_y = 288 - (y * 24)
if character == "X":
pen.goto(screen_x, screen_y)
pen.stamp()
walls.append((screen_x, screen_y))
if character == "P":
player.goto(screen_x, screen_y)
if character == "T":
treasures.append(Treasure(screen_x, screen_y))
pen = Pen()
player = Player()
walls = []
setup_maze(levels[1])
turtle.listen()
turtle.onkey(player.go_left,"Left")
turtle.onkey(player.go_right,"Right")
turtle.onkey(player.go_up,"Up")
turtle.onkey(player.go_down,"Down")
wn.tracer(0)
while True:
for treasure in treasures:
if player.is_close_to(treasure):
treasure.change_color()
wn.update()
To load a new level, you need to reset the current state of the world to a known base state, then setup the new level. You seem to have figured out the latter, and the former involves clearing the screen, re-initializing its properties, and clearing the game state.
First, you need to clear the window. As this answer tells us, this can be done by calling turtle.Screen().reset(), or in your case wm.reset().
After that's done, you need to reinitialize all the properties of the screen, like setting the bgcolor and title and other things like this. Right now these happen at the beginning of the file, but you'll need to do them multiple times through your program's lifecycle, so you should place them in a separate function, like init_screen, so that you can call it once you've reset it.
Finally, you need to reset the game state. In your case, this would be your treasures and walls lists, but as you add more features this may include any other data that does not need to persist between one level and the next. This data actually becomes invalid as soon as you call setup_maze, so it would make sense to first clear them and then setup the new level in the inner loops.
The Point of the game is to make all the circles disappear when they Collide but for some reason some circles aren't disappearing? - Thank you for your help in advance!
import turtle
import random
import math
import time
# Setting up the Screen
ms = turtle.Screen()
ms.bgcolor("red")
ms.title("Space Rocket Minigame #Rafa94")
# Using class functions/Methods
# subclass
class Border(turtle.Turtle):
def __init__(self): # class constrcutor
turtle.Turtle.__init__(self) # adding our Objects attributes all starting with "self"
self.penup()
self.hideturtle()
self.speed(0)
self.color("silver")
self.pensize(5)
def draw_border(self):
self.penup()# getting our pen to start drawing
self.goto(-300, -300)
self.pendown()
self.goto(-300, 300)
self.goto(300, 300)
self.goto(300, -300)
self.goto(-300, -300)
class Player(turtle.Turtle): # since it got inherited this class becomes a Superclass
def __init__(self): # self is our only argument here but it will have multiple attributes
turtle.Turtle.__init__(self) # since we are using the Turtle module, we are able to use it's built in functions
self.penup()# our attributes
self.speed(0)
self.shape("triangle")
self.color("black")
self.velocity = 0.1
def move(self):
self.forward(self.velocity)
# Border Checking
if self.xcor() > 290 or self.xcor() < -290: # Left side is -290 Right side is 290 we also want the coordinates x and y to be below 300 to not go over our border
self.left(60)
if self.ycor() > 290 or self.ycor() < -290:
self.left(60)
def turnleft(self):
self.left(30)
def turnright(self):
self.right(30)
def increasespeed(self):
self.velocity += 1
class Goal(turtle.Turtle): # Sub Class
def __init__(self):
# since we are using the Turtle module we are able to use it's built in functions
turtle.Turtle.__init__(self)
self.penup() # our attributes
self.speed(0)
self.shape("circle")
self.color("green")
self.velocity = 3 #xcor #ycor
self.goto(random.randint(-250, 250), random.randint(-250, 250)) # we are making our turtle "go to" X & Y coordinates by -250 and 250 only randomly. We also have our random module here aswell
self.setheading(random.randint(0, 360)) # setting the heading to see in which direction i want it to go
def jump(self): # Jump = Collidee
self.goto(random.randint(-250, 250), random.randint(-250, 250)) # "jump" stands for Collidee so if the circle "jumps" with player it will move to random postion by 250 and -25
self.setheading(random.randint(0, 360)) # from where it collidee's it goes 360 moves location 360 Right
def move(self): # we copyed the same method cause it will be doing the same movements as the player we want it to go "forward" with our set "speed" & also check for our borders we set
self.forward(self.velocity)
# Border Checking
if self.xcor() > 290 or self.xcor() < -290: # Left side is -290 Right side is 290 we also want the coordinates x and y to be below 300 to not go over our border
self.left(60)
if self.ycor() > 290 or self.ycor() < -290:
self.left(60)
# Collision checking function/Method
# Uses the Pythgorean Theorem to measure the distance between two objects
def isCollision(t1, t2): # t1 = turtle1 t2 = turtle also when a function starts with "is" isCollision most likely it will be a Boolean of True or False
a = t1.xcor()-t2.xcor() # xcor = Right -xcor = Left/ when they collide the xcor is 0
b = t1.ycor()-t2.ycor() # ycor = Right -ycor = Left/ when they collide the ycor is 0
distance = math.sqrt((a ** 2) + (b ** 2))
if distance < 30:
return True
else:
return False
# Create class instances
player = Player() # after creating a class must make instances to call it in other words make an Object of the class
border = Border() # sub class
#goal = Goal() #sub class
# Draw our border
border.draw_border()
#create multiple goals
goals = [] # Creating a list of goals
for count in range(6): # We are making the code repeat 6 times
goals.append(Goal()) # each time the code runs it puts a goal the end 6 times
# Set keyboard bindings
ms.listen()
ms.onkey(player.turnleft, "Left")
ms.onkey(player.turnright, "Right")
ms.onkey(player.increasespeed, "Up")
# speed game up
ms.tracer(0.1)
# main loop
while True:
ms.update()
player.move() # these two are class methods
#goal.move() # the reason we copyed like we said is cause it's gunna have the exact same movements as our player!
# we want the goal to be True to in our while loop in order for the code to be excuted
for goal in goals:
# Basically saying If there is a collision between the player and goal we the want the goal to "jump" / Function in our while True loop
goal.move()
if isCollision(player, goal):
goal.jump() # baiscally saying if the goal collide's move or "jump" to other location
time.sleep(0.005)
As far as I can tell, your circles (goals) disappear and reappear elsewhere as you designed them to do. One possibiliy is that since you move the circles to a random location, that location can be close to where they disappeared from, making it appear that nothing happened.
Generally, your code is a mess. Below is my rewrite of it to bring some structure and style to it. As well as take more advantage of what turtle offers:
from turtle import Screen, Turtle
from random import randint
WIDTH, HEIGHT = 600, 600
CURSOR_SIZE = 20
class Border(Turtle):
def __init__(self): # class initializer
super().__init__(visible=False)
self.penup()
self.color("silver")
self.pensize(5)
def draw_border(self):
self.goto(-WIDTH/2, -HEIGHT/2)
self.pendown()
for _ in range(2):
self.forward(WIDTH)
self.left(90)
self.forward(HEIGHT)
self.left(90)
class Player(Turtle):
def __init__(self):
super().__init__(shape="triangle")
self.color("black")
self.penup()
self.velocity = 0.1
def move(self):
self.forward(self.velocity)
if not (CURSOR_SIZE - WIDTH/2 < self.xcor() < WIDTH/2 - CURSOR_SIZE and CURSOR_SIZE - HEIGHT/2 < self.ycor() < HEIGHT/2 - CURSOR_SIZE):
self.undo() # undo forward motion
self.left(60)
self.forward(self.velocity) # redo forward motion in new heading
def turn_left(self):
self.left(30)
def turn_right(self):
self.right(30)
def increase_speed(self):
self.velocity += 1
class Goal(Turtle):
def __init__(self):
super().__init__(shape="circle")
self.color("green")
self.penup()
self.velocity = 3
self.jump()
def jump(self):
while self.distance(player) < CURSOR_SIZE * 10: # make sure we move far away from player
self.goto(randint(CURSOR_SIZE - WIDTH/2, WIDTH/2 - CURSOR_SIZE), randint(CURSOR_SIZE - HEIGHT/2, HEIGHT/2 - CURSOR_SIZE))
self.setheading(randint(0, 360))
def move(self):
self.forward(self.velocity)
if not (CURSOR_SIZE - WIDTH/2 < self.xcor() < WIDTH/2 - CURSOR_SIZE and CURSOR_SIZE - HEIGHT/2 < self.ycor() < HEIGHT/2 - CURSOR_SIZE):
self.undo() # undo forward motion
self.left(60)
self.forward(self.velocity) # redo forward motion in new heading
def isCollision(t1, t2):
return t1.distance(t2) < CURSOR_SIZE
def move():
player.move()
for goal in goals:
goal.move()
if isCollision(player, goal):
goal.jump()
screen.update()
screen.ontimer(move, 10)
# Setting up the Screen
screen = Screen()
screen.bgcolor("red")
screen.title("Space Rocket Minigame #cdlane")
screen.tracer(False)
# Create class instances
Border().draw_border()
player = Player()
# Create multiple goals
goals = [Goal() for _ in range(6)]
# Set keyboard bindings
screen.onkey(player.turn_left, "Left")
screen.onkey(player.turn_right, "Right")
screen.onkey(player.increase_speed, "Up")
screen.listen()
move()
screen.mainloop()
After weeks of trying, I have not come up with a solution to this issue, in which one turtle comes to a complete stop and the other goes 2x - 3x faster. How can I fix this? You must move them both around for a little bit to encounter the issue. Also this is on the site: repl.it
I have tried moving the wn.listen() command but that only switched which turtle stopped and which one didn't. I have unsuccessfully tried to switch the forward() command to goto() and I have tried to use direction specific movement (also unsuccessfully):
import turtle
import sys
player1 = turtle.Turtle()
player1.up()
player1.goto(0,350)
player1.right(90)
player1.down()
player2 = turtle.Turtle()
wn = turtle.Screen()
#preGame setup
player2.up()
player2.goto(0,-350)
player2.left(90)
player2.down()
player2.color("blue")
player1.color("red")
#main game loop
player1.speed(0)
player2.speed(0)
k = 0
def kr():
player1.left(90)
def kl():
player1.right(90)
wn.onkey(kr, "d")
wn.onkey(kl, "a")
def k1():
player2.right(90)
def k2():
player2.left(90)
wn.onkey(k1, "k")
wn.onkey(k2, "l")
wn.listen()
while True:
player1.forward(1)
player2.forward(1)
while player1.xcor() < (-350) or player1.xcor() > (350) or player1.ycor() > (350) or player1.ycor() < (-350):
player1.back(30)
while player2.xcor() < (-350) or player2.xcor() > (350) or player2.ycor() > (350) or player2.ycor() < (-350):
player2.back(30)
if player1.pos() == player2.pos():
print ("DONT CRASH INTO THE OTHER PLAYER")
sys.exit()
I expected them both to continue moving indefinitely, but one always stops, and the other is going 2x the speed.
Move the keylisteners outside your loop - having them inside the while loop will reattach them and redefine the functions all the time and confuse turtle.
You need to set them up once not every few milliseconds:
import turtle
player1 = turtle.Turtle()
player2 = turtle.Turtle()
player1.goto(350, 0)
player2.goto(-350, 0)
player1.right(180)
wn = turtle.Screen()
def kl():
player1.left(90)
def kr():
player1.right(90)
def k1():
player2.right(90)
def k2():
player2.left(90)
wn.onkey(kl, "d") # changed to lowercase
wn.onkey(kr, "a")
wn.onkey(k1, "j") # changed to other letters
wn.onkey(k2, "l")
wn.listen()
while True: # not changing k so just use while True
player1.forward(1) # changed speed
player2.forward(1)
Your nested while loop structure is working against you and isn't valid for an event-driven environment like turtle. Here's a rework of your program to fix this issue and clean up the code:
from turtle import Screen, Turtle
import sys
# preGame setup
player1 = Turtle()
player1.hideturtle()
player1.up()
player1.goto(0, 350)
player1.down()
player1.right(90)
player1.color('red')
player1.speed('fastest')
player1.showturtle()
def r1():
player1.left(90)
def l1():
player1.right(90)
player2 = Turtle()
player2.hideturtle()
player2.up()
player2.goto(0, -350)
player2.down()
player2.left(90)
player2.color('blue')
player2.speed('fastest')
player2.showturtle()
def r2():
player2.right(90)
def l2():
player2.left(90)
# main game loop
def move():
player1.forward(5)
if not (-350 < player1.xcor() < 350 and -350 < player1.ycor() < 350):
player1.backward(30)
player2.forward(5)
if not (-350 < player2.xcor() < 350 and -350 < player2.ycor() < 350):
player2.backward(30)
if player1.distance(player2) < 5:
print("DON'T CRASH INTO THE OTHER PLAYER!")
sys.exit()
screen.ontimer(move, 100)
screen = Screen()
screen.onkey(r1, 'd')
screen.onkey(l1, 'a')
screen.onkey(r2, 'k')
screen.onkey(l2, 'l')
screen.listen()
move()
screen.mainloop()
See if this behaves more like you expect/desire.
I am making a ping pong game with turtle. However, the assignment is that code must have multithreading. I could not apply multithreading properly.
The code shows no error in the editor, but it does not work. How can we fix this runtime error? It is so hard to find the error when there is no error in the editor.
import turtle
from threading import *
from time import sleep
wn = turtle.Screen()
wn.title("Ping pong by Cagatay em")
wn.bgcolor("blue")
wn.setup(width=900, height=600)
wn.tracer(0) #oyunu hizlandirir silersen cok yavaslar
class PaddleFirst(Thread):
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("square")
self.pen.shapesize(stretch_wid=5, stretch_len=1)
self.pen.penup()
self.pen.goto(-350, 0)
def run(self):
y = self.pen.ycor()
y += 20
self.pen.sety(y)
k = self.pen.ycor()
k -= 20
self.pen.sety(k)
class PaddleSecond(Thread):
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("square")
self.pen.shapesize(stretch_wid=5, stretch_len=1)
self.pen.penup()
self.pen.goto(350, 0)
def run(self):
y = self.pen.ycor()
y += 20
self.pen.sety(y)
k = self.pen.ycor()
k -= 20
self.pen.sety(k)
class Ball(Thread):
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("circle")
self.pen.color("red")
self.pen.penup()
self.pen.goto(0, 0)
self.pen.dx = 00.1
self.pen.dy = 00.1
def run(self):
self.pen.setx(self.pen.xcor() + self.pen.dx)
self.pen.sety(self.pen.ycor() + self.pen.dy)
if self.pen.ycor() > 290:
self.pen.sety(290)
self.pen.dy *= -1
if self.pen.ycor() < -290:
self.pen.sety(-290)
self.pen.dy *= -1
if self.pen.xcor() > 390:
self.pen.goto(0, 0)
self.pen.dx *= -1
if self.pen.xcor() < -390:
self.pen.goto(0, 0)
self.pen.dx *= -1
class Wall(Thread):
def run(self):
if ball.pen.xcor() > 340 and (ball.pen.ycor() < paddle2.pen.ycor() + 40 and ball.pen.ycor() > paddle2.pen.ycor() - 40):
ball.pen.dx *= -1
if ball.pen.xcor() < -340 and (ball.pen.ycor() < paddle1.pen.ycor() + 40 and ball.pen.ycor() > paddle1.pen.ycor() - 40):
ball.pen.dx *= -1
paddle1 = PaddleFirst()
paddle2 = PaddleSecond()
ball = Ball()
wall = Wall()
wn.listen()
wn.onkeypress(paddle1.run, "w")
wn.onkeypress(paddle1.run(), "s")
wn.onkeypress(paddle2.run(), "Up")
wn.onkeypress(paddle2.run, "Down")
while True:
wn.update() # everytime uptades the screen
ball.start()
sleep(0.2)
wall.start()
sleep(0.2)
paddle1.start()
sleep(0.2)
paddle2.start()
My guess is that the error message you got is due to you not calling the super class' __init__() method in your subclass of Thread.
It is so hard to find the error when there is no error in the editor.
You need to learn the art of debugging.
i could not apply multithreading properly.
I think there are two issues here. First, to use threading with turtle, which is built atop tkinter, you need to have all graphics commands routed throught the main thread -- secondary threads shouldn't try to modify the screen directly.
Second, your code is a mess. Aside from threading, it's not clear you understand object-programming as you have two identical classes, except for an X coordinate. This should be one class with an argument to it's initializer. It's not clear you undertand turtle as wn.onkeypress(paddle1.run(), "s") will never work. You probably shouldn't be messing with tracer() and update() until your code is working. And you shouldn't have a while True: on the main turtle thread.
I've taken your code apart and put it back together below. Only the ball is a separate thread, the (single) paddle class now inherits from Turtle. The main thread processes graphics commands from the ball thread as well as standard turtle events:
from turtle import Screen, Turtle
from threading import Thread, active_count
from queue import Queue
QUEUE_SIZE = 1
class Paddle(Turtle):
def __init__(self, xcor):
super().__init__(shape='square')
self.shapesize(stretch_wid=5, stretch_len=1)
self.speed('fastest')
self.penup()
self.setx(xcor)
self.dy = 10
def down(self):
y = self.ycor() - self.dy
if y > -250:
self.sety(y)
def up(self):
y = self.ycor() + self.dy
if y < 250:
self.sety(y)
class Ball(Thread):
def __init__(self):
super().__init__(daemon=True)
self.pen = Turtle('circle')
self.pen.speed('fastest')
self.pen.color('red')
self.pen.penup()
self.dx = 1
self.dy = 1
def run(self):
x, y = self.pen.position()
while True:
x += self.dx
y += self.dy
if x > 330 and (paddle2.ycor() - 60 < y < paddle2.ycor() + 60):
self.dx *= -1
elif x < -330 and (paddle1.ycor() - 60 < y < paddle1.ycor() + 60):
self.dx *= -1
if y > 290:
y = 290
self.dy *= -1
elif y < -290:
y = -290
self.dy *= -1
elif not -440 < x < 440:
x, y = 0, 0
self.dx *= -1
actions.put((self.pen.setposition, x, y))
def process_queue():
while not actions.empty():
action, *arguments = actions.get()
action(*arguments)
if active_count() > 1:
screen.ontimer(process_queue, 100)
screen = Screen()
screen.title("Ping pong rework by cdlane")
screen.bgcolor('blue')
screen.setup(width=900, height=600)
actions = Queue(QUEUE_SIZE)
paddle1 = Paddle(-350)
paddle2 = Paddle(350)
ball = Ball()
screen.onkeypress(paddle1.up, 'w')
screen.onkeypress(paddle1.down, 's')
screen.onkeypress(paddle2.up, 'Up')
screen.onkeypress(paddle2.down, 'Down')
screen.listen()
ball.start()
process_queue()
screen.mainloop()
The code is still incomplete and slightly buggy (e.g. doesn't shut down cleanly) -- things for you to work on. But it basically plays the game in a reasonable fashion.