Error with the command onkey() - python

I'm trying to create a shooter-like game in Python turtle (it's basically a copy of the game Boom dots). But I'm having a lot of issues, because I'm kind of new to programming. This time the command onkey() doesn't work. I tried everything but nothing seems to be of help.
I don't get any traceback errors. It's just that defined command doesn't work when I press the button which is assigned to the command.
Part of code in which I suspect the problem is:
def cannon_left():
cannon_x = cannon_x - 10
cannon.goto(cannon_x, 0)
def cannon_right():
cannon_x = cannon_x + 10
cannon.goto(cannon_x, 0)
def reset1():
live_score = 0
The whole code:
import random
import turtle
#images
image_coconut = "Coconut.png"
image_banana = "Banana.png"
image_pineapple = "Pineapple.png"
image_cannon = "Cannon.png"
#definitions
live_score = 0
screen = turtle.Screen()
wn = turtle.Screen()
cannon = turtle.Turtle()
enemy = turtle.Turtle()
score = turtle.Turtle()
background = turtle.Turtle()
reset = turtle.Turtle()
bullet = turtle.Turtle()
enemy_x = enemy.xcor()
enemy_y = enemy.ycor()
cannon_x = 0
move_speed = 2
enemy1 = 0
def cannon_shooting(x, y):
bullet.showturtle()
bullet.forward(280)
if bullet.ycor() == enemy_y - 10:
if not bullet.xcor() == enemy_x - 10:
if live_score == 0:
live_score = 0
else:
live_score = live_score + 1
if bullet.xcor() == enemy_x - 10:
live_score = live_score + 1
enemy1 = random.randint(1, 3)
bullet.hideturtle()
#image adding
screen.addshape(image_coconut)
screen.addshape(image_banana)
screen.addshape(image_pineapple)
screen.addshape(image_cannon)
def cannon_left():
cannon_x = cannon_x - 10
cannon.goto(cannon_x, 0)
def cannon_right():
cannon_x = cannon_x + 10
cannon.goto(cannon_x, 0)
def reset1():
live_score = 0
#setup
bullet.hideturtle()
bullet.speed(50)
bullet.penup()
bullet.shape('circle')
bullet.goto(0, -140)
bullet.left(90)
enemy.speed(0)
enemy.penup()
enemy.hideturtle()
enemy.goto(0, 140)
screen.addshape(image_coconut)
enemy.shape(image_coconut)
enemy.showturtle()
cannon.speed(0)
cannon.penup()
cannon.hideturtle()
cannon.goto(0, -140)
screen.addshape(image_cannon)
cannon.shape(image_cannon)
cannon.showturtle()
cannon.left(90)
score.speed(0)
score.penup()
score.hideturtle()
score.goto(90, -190)
score.color('white')
score.write("Your score: %s" % live_score, font=(None, 11, "bold"))
reset.speed(0)
reset.penup()
reset.hideturtle()
reset.goto(-185, -190)
reset.color('white')
reset.write("Reset (R)", font=(None, 11, "bold"))
#movement
while True:
enemy.forward(move_speed)
if enemy.xcor() == 140:
enemy.left(180)
enemy.forward(move_speed)
if enemy.xcor() == -140:
enemy.right(180)
enemy.forward(move_speed)
if enemy1 == 1:
screen.addshape(image_banana)
enemy.shape(image_banana)
if enemy1 == 2:
screen.addshape(image_pineapple)
enemy.shape(image_pineapple)
if enemy1 == 3:
enemy.shape(image_coconut)
#key presses
wn.onkey(cannon_right, "D")
wn.onkey(cannon_left, "A")
wn.onkey(cannon_right, "Right")
wn.onkey(cannon_left, "Left")
wn.onkey(cannon_shooting, "SPACE")
wn.onkey(reset1, "R")
#others
wn.listen()
wn.mainloop()
Note: I'm creating the game in Trinket.io. Click here to go to the Trinket.io version.

Python is an imperative programming language. This means that order matters. What appears to be the main logic of your game is declared before the onkey initialization part as an infinite loop:
#movement
while True:
enemy.forward(move_speed)
...
As this loop runs forever, it means that will start executing and the code will never reach the part where you set up the key mapping.
You need the code that is in the loop put this code in a function, and decide when exactly it needs to be called by Turtle. You should not put the while True as part of the function, as there already exists a main loop managed by Turtle.

Related

Time and keypress events with Python's Turtle

I am trying to create a simple game with turtle:
A turtle controlled by the user can shoot bullets when space is pressed
An enemy turtle is created at a random position
If the enemy is hit by the bullet, the enemy is destroyed and moves to a new position.
If the bullet leaves the screen, it disappears.
While the bullet is moving, the player should still be able to move.
If the enemy is not destroyed in 20 seconds, the player looses.
Therefore, I need some events to be controlled with the keyboard and others that get triggered after a certain time. I cannot think about a way of doing this without a loop inside which I check the distance between the bullet and the enemy, but if I do it like that, I cannot control the main turtle during the loop.
import turtle as trtl
from random import randint
import time
class Game():
def __init__(self):
self.scr = trtl.Screen()
self.scr.update()
self.player = trtl.Turtle()
self.player.shape('turtle')
self.player.penup()
trtl.onkeypress(self.forward,'w')
trtl.onkeypress(self.backwards,'s')
trtl.onkeypress(self.left,'a')
trtl.onkeypress(self.right,'d')
trtl.onkeypress(self.shoot,'space')
trtl.listen()
self.enemy = trtl.Turtle()
self.enemy.shape('square')
self.enemy.penup()
self.enemy.speed(0)
self.move_enemy()
self.bullet = trtl.Turtle()
self.bullet.penup()
self.bullet.hideturtle()
self.bulletShot = False
def forward(self):
self.player.forward(5)
def backwards(self):
self.player.back(5)
def left(self):
self.player.left(6)
def right(self):
self.player.right(6)
def shoot(self):
if self.bulletShot == False:
self.bullet.speed(0)
self.bullet.goto(self.player.pos())
self.bullet.seth(self.player.heading())
self.bullet.showturtle()
self.bulletShot = True
def move_enemy(self):
x = randint(-300,300)
y = randint(-300,300)
self.enemy.hideturtle()
self.enemy.goto(x,y)
self.enemy.showturtle()
def play(self):
startTime = time.time()
print(time.time() - startTime)
while time.time() - startTime < 20:
if self.bulletShot:
self.bullet.forward(1)
collision = self.bullet.distance(self.enemy.pos()) < 10
isIn = (self.bullet.pos()[0] <= 300 and
self.bullet.pos()[0] >= -300 and
self.bullet.pos()[1] <= 300 and
self.bullet.pos()[1] >= -300)
if not(isIn):
self.bullet.hideturtle()
self.bulletShot = False
elif collision:
self.bullet.hideturtle()
self.bulletShot = False
self.move_enemy()
startTime = time.time()
self.player.write('You loose')
self.scr.exitonclick()
game = Game()
game.play()
I tried a simpler version in which one turtle moves automatically in a loop and another turtle is controlled with the keyboard, and it works well.
import turtle as trtl
def up():
jane.sety(jane.pos()[1] + 10)
def down():
jane.sety(jane.pos()[1] - 10)
scr = trtl.Screen()
scr.update()
bob = trtl.Turtle()
bob.penup()
bob.seth(180)
bob.setx(300)
bob.speed(1)
jane = trtl.Turtle()
jane.penup()
trtl.onkeypress(up,'w')
trtl.onkeypress(down,'s')
trtl.listen()
while True:
if bob.pos()[0] > -300:
bob.forward(10)
else:
break
scr.exitonclick()
Is there a way of fixing this with turtle?
Let's redesign the game to work with turtle's event system by using a timer event to control the action while still using your timer to limit play time:
from turtle import Screen, Turtle
from random import randint
import time
class Game():
def __init__(self):
self.startTime = -1
self.screen = Screen()
self.screen.tracer(False)
self.player = Turtle()
self.player.shape('turtle')
self.player.penup()
self.enemy = Turtle()
self.enemy.shape('square')
self.enemy.penup()
self.move_enemy()
self.bullet = Turtle()
self.bullet.hideturtle()
self.bullet.penup()
self.bulletShot = False
self.screen.onkeypress(self.forward, 'w')
self.screen.onkeypress(self.backwards, 's')
self.screen.onkeypress(self.left, 'a')
self.screen.onkeypress(self.right, 'd')
self.screen.onkeypress(self.shoot, 'space')
self.screen.listen()
def forward(self):
self.player.forward(5)
self.screen.update()
def backwards(self):
self.player.back(5)
self.screen.update()
def left(self):
self.player.left(6)
self.screen.update()
def right(self):
self.player.right(6)
self.screen.update()
def shoot(self):
if not self.bulletShot:
self.bullet.setposition(self.player.position())
self.bullet.setheading(self.player.heading())
self.bullet.showturtle()
self.bulletShot = True
self.screen.update()
def move_enemy(self):
x = randint(-300, 300)
y = randint(-300, 300)
self.enemy.goto(x, y)
self.screen.update()
def play(self):
if self.startTime == -1:
self.startTime = time.time()
if self.bulletShot:
self.bullet.forward(1)
x, y = self.bullet.position()
if not(-300 <= x <= 300 and -300 <= y <= 300):
self.bullet.hideturtle()
self.bulletShot = False
elif self.bullet.distance(self.enemy.pos()) < 10:
self.bullet.hideturtle()
self.bulletShot = False
self.move_enemy()
self.startTime = time.time()
self.screen.update()
if time.time() - self.startTime > 20:
self.player.write('You loose!')
self.screen.update()
else:
self.screen.ontimer(self.play, 10)
screen = Screen()
game = Game()
game.play()
screen.mainloop()
Still bit crude but should be playable. You had a self.scr.update() call in your original code but without an initial call to tracer(), it does nothing. Here we're using tracer() and update() to speed up and smooth out the motion by manually controlling all screen updates.
I managed to solve it without changing much the code and without making the function play() recursive. The problem was that if the if inside de while needs an else, otherwise, the key press is not recorded. So I gave it something to do and now it works as I want.
while time.time() - startTime < 20:
if self.bulletShot:
self.bullet.forward(3)
...
else:
self.scr.update()

My python game is not responding when I run it

so I have been trying to make this game in python using only standard libraries because I don't know how to link libraries (I am an absolute beginner) but whenever I run the program, it doesn't respond. This is the code:
import turtle
import random
import math
import time
import os
play = True
#window
window = turtle.Screen()
window.bgcolor("#4287f5")
window.title("Box Grab!")
#border
outer = turtle.Turtle()
outer.speed(0)
outer.color("#000000","#000000")
outer.up()
outer.goto(250, 250)
outer.down
outer.begin_fill()
for i in range(4):
outer.rt(90)
outer.fd(500)
outer.ht()
#boxes
box1 = turtle.Turtle()
box2 = turtle.Turtle()
box3 = turtle.Turtle()
box4 = turtle.Turtle()
box5 = turtle.Turtle()
box6 = turtle.Turtle()
box1n = 2
box2n = 2
box3n = 2
box4n = 2
box5n = 2
box6n = 2
box1.penup()
box1.speed(0)
box1.color("darkorange")
box1.shape("square")
box2.penup()
box2.speed(0)
box2.color("darkorange")
box2.shape("square")
box3.penup()
box3.speed(0)
box3.color("darkorange")
box3.shape("square")
box4.penup()
box4.speed(0)
box4.color("darkorange")
box4.shape("square")
box5.penup()
box5.speed(0)
box5.color("darkorange")
box5.shape("square")
box6.penup()
box6.speed(0)
box6.color("darkorange")
box6.shape("square")
box1.setpos(random.randint(-250, 250), random.randint(-250, 250))
box2.setpos(random.randint(-250, 250), random.randint(-250, 250))
box3.setpos(random.randint(-250, 250), random.randint(-250, 250))
box4.setpos(random.randint(-250, 250), random.randint(-250, 250))
box5.setpos(random.randint(-250, 250), random.randint(-250, 250))
box6.setpos(random.randint(-250, 250), random.randint(-250, 250))
#player
player = turtle.Turtle()
player.penup()
player.color("blue")
player.shape("circle")
#defining movement
def down():
player.setheading(270)
player.forward(20)
def right():
player.setheading(0)
player.forward(20)
def left():
player.setheading(180)
player.forward(20)
def up():
player.setheading(90)
player.forward(20)
#collision
def isCollision(t1, t2):
d = math.sqrt(math.pow(t1.xcor()-t2.xcor(),2) + math.pow(t1.ycor()-t2.ycor(),2))
if d < 20:
return True
else:
return False
if isCollision(player, box1):
box1.hideturtle()
box1n - 1
if isCollision(player, box2):
box2.hideturtle()
box2n - 1
if isCollision(player, box3):
box3.hideturtle()
box3n - 1
if isCollision(player, box4):
box4.hideturtle()
box4n - 1
if isCollision(player, box5):
box5.hideturtle()
box5n - 1
if isCollision(player, box6):
box6.hideturtle()
box6n - 1
#movement
turtle.listen()
turtle.onkey(up,"w")
turtle.onkey(down,"s")
turtle.onkey(right,"d")
turtle.onkey(left,"a")
#time
def mainTime():
x = 60
for i in range(60 + 1):
time.sleep(1)
print(formatTime(x))
x -= 1
def formatTime(x):
minutes = int(x / 60)
seconds_rem = int(x % 60)
if (seconds_rem < 10):
return(str(minutes) + ":0" + str(seconds_rem))
else:
return(str(minutes) + ":" + str(seconds_rem))
if x == 0:
play = false
mainTime()
#score
def score():
score = 0
for s in range(60):
t = 60
time.sleep(1)
t -= 1
if box1 or box2 or box3 or box4 or box5 or box6 == 1:
score = score + (seconds_rem * 100)
score()
#game over
if play == false:
print("GAME OVER. ")
restart = input("RESTART? Y/N")
if restart == "y":
os.system('python "C:\\Users\\lyons\\AppData\\Local\\Programs\\Python\\Python37-32\\Projects\\failing to make a game.py"')
Also, when it used to work, the boxes wouldn't dissapear after the player hit them. How do I fix this?

How to fix bug where my enemies don't disappear?

I want to make a Space Invaders game but my enemies don't disappear if they get hit. Does anyone know how to fix it?
I already tried a for loop (as you will see) but it doesnt work:
import turtle as tr
wn = tr.Screen()
wn.tracer(0)
bullet = tr.Turtle()
player = tr.Turtle()
enimis = []
y = -250
def shoot():
player.direction = "up"
wn.onkey(shoot,"space")
while True:
if len(enimis) == 0:
for u in range(-210,210,60):
for o in range(100,260,60):
enimi = tr.Turtle()
enimi.setpos(u,o)
enimis.append(enimi)
if player.direction == "up":
bullet.penup()
x = player.xcor()
bullet.setpos(x,y)
bullet.pendown()
for p in range(550):
bullet.setpos(x,y+p)
for k in enimis:
if bullet.distance(k) < 25:
score += 10
if score > highscore:
highscored = True
else:
highscored = False
del k
hit = True
break
else:
hit = False
wn.update()
There aren't any error messages, the enemies just don't disappear.
I don't see why you're stuck on making dead enemies disappear when the code doesn't run at all due to this error:
if player.direction == "up":
AttributeError: 'Turtle' object has no attribute 'direction'
Nor could you hit an enemy since your player and enemies can't move and the player isn't pointing at an enemy to start with. Too much magical thinking and not enough code.
To answer your question, this can't work:
for k in enimis:
if bullet.distance(k) < 25:
# ...
del k
# ...
break
It either needs to be:
for k in enimis:
if bullet.distance(k) < 25:
# ...
enimis.remove(k) # remove by value
# ...
break
or:
for k in range(len(enimis)):
if bullet.distance(enimis[k]) < 25:
# ...
del enimis[k] # remove by index
# ...
break
Below is my complete rewrite of your code to get it to basically play: player can move left and right; bullets fire, hit enemies, score points, and enemies disappear; the score is shown on the screen; etc.
from turtle import Screen, Turtle
BASELINE = -250
FONT = ('Arial', 18, 'bold')
def left():
player.setx(player.xcor() - 5)
def right():
player.setx(player.xcor() + 5)
def shoot():
global firing
firing = True
firing = False
enemies = []
score = 0
bullet = Turtle('triangle')
bullet.hideturtle()
bullet.speed('fastest')
bullet.shapesize(0.5)
bullet.setheading(90)
bullet.penup()
player = Turtle('turtle')
player.hideturtle()
player.speed('fastest')
player.color('green')
player.setheading(90)
player.penup()
player.sety(BASELINE)
player.showturtle()
marker = Turtle()
marker.hideturtle()
marker.penup()
marker.goto(-300, 300)
marker.write("Score: {}".format(score), align='center', font=FONT)
def play():
global firing, score
if not enemies:
screen.tracer(False)
for x in range(-210, 210, 60):
for y in range(100, 260, 60):
enemy = Turtle('turtle')
enemy.color('red')
enemy.setheading(270)
enemy.penup()
enemy.setpos(x, y)
enemies.append(enemy)
screen.tracer(True)
if firing:
bullet.setx(player.xcor())
bullet.sety(BASELINE)
bullet.showturtle()
for p in range(0, 550, 5):
bullet.sety(BASELINE + p)
for enemy in enemies:
if bullet.distance(enemy) < 20:
score += 10
marker.undo()
marker.write("Score: {}".format(score), align='center', font=FONT)
enemy.clear()
enemy.hideturtle()
enemies.remove(enemy)
break
else: # no break
continue
break
bullet.clear()
bullet.hideturtle()
firing = False
screen.ontimer(play, 100)
screen = Screen()
screen.onkey(shoot, 'space')
screen.onkey(left, 'Left')
screen.onkey(right, 'Right')
screen.listen()
play()
screen.mainloop()
Still needed: moving enemies left, right and down; making bullet firing and player/enemy movement happen at the same time; add back highscore; etc.

How to launch a turtle program with a tkinter messagebox?

I am trying to launch a turtle game stored in one file with a message box from tkinter stored in another py file but both in the same directory. However, I receive a
_tkinter.TclError: image "pyimage2" doesn't exist error.
I have a function inside the game code that is called upon in the launcher code. This function runs all of the code inside the main game program apart from importing modules which I have included in the function but makes no difference.
Sorry for showing all but as I don't know what the problem is I thought this was best(removed as much code irrelevant to problem as I could(Assume anything unnamed that is called is deleted as irrelevant code)
def start():
import turtle
import math
import time
counter = 0
wn = turtle.Screen()
wn.setup(800, 600)
wn.bgcolor("black")
wn.title("Trooper shooter")
wn.bgpic("background1.png")
wn.update()
turtle.register_shape("invader.gif")
turtle.register_shape("plane.gif")
turtle.register_shape("troop.gif")
turtle.register_shape("player1.gif")
turtle.register_shape("player2.gif")
turtle.register_shape("bomb.gif")
turtle.register_shape("boom.gif")
#player
soldier = turtle.Turtle()
soldier.color("blue")
soldier.shape("player1.gif")
soldier.penup()
soldier.speed(0)
soldier.setposition(0,-200)
soldier.setheading(90)
soldierspd = 20
#Bomb
Numbombs = 2
bombs = []
for i in range(Numbombs):
bombs.append(turtle.Turtle())
for bomb in bombs:
bomb.shape("bomb.gif")
bomb.penup()
bomb.speed(0)
bomb.ht()
x = -1700
y = 2700
bomb.setposition(x+30,y)
bomb.setheading(270)
bombspeed = 10
#Plane
plane = turtle.Turtle()
plane.color("red")
plane.shape("plane.gif")
plane.penup()
plane.speed(0)
plane.setposition(-270,200)
plane.setheading(360)
planespd = 20
#Plane2
plane2 = turtle.Turtle()
plane2.ht()
plane2.color("red")
plane2.shape("plane.gif")
plane2.penup()
plane2.speed(0)
plane2.setposition(-270,200)
plane2.setheading(360)
planespd2 = 20
#ParaTroopers
num = 5
Troopers = []
for i in range(num):
Troopers.append(turtle.Turtle())
for Troop in Troopers:
Troop.color("Purple")
Troop.shape("troop.gif")
Troop.penup()
Troop.speed(0)
Troop.ht()
x = -170
y = 270
Troop.setposition(x+30,y)
Troop.setheading(270)
Troopspeed = 3
#Bullet
bullet = turtle.Turtle()
bullet.color("yellow")
bullet.shape("triangle")
bullet.penup()
bullet.speed(0)
bullet.setheading(90)
bullet.shapesize(0.5, 0.5)
bullet.ht()
bulletspeed = 30
#Define bullet state
#ready = ready to fire
#fire = bullet is firing
state = "ready"
#Move player left
def Left():
x = soldier.xcor()
x -= soldierspd
soldier.setx(x)
soldier.shape("player1.gif")
if x < -280:
x = -280
soldier.setx(x)
#Move player right
def Right():
x = soldier.xcor()
x += soldierspd
soldier.setx(x)
soldier.shape("player2.gif")
if x > 280:
x = 280
soldier.setx(x)
#Shoot bullet
def Shoot():
#Declare bullet state as global
global state
if state == "ready":
state = "fire"
#Move bullet above player
x = soldier.xcor()
y = soldier.ycor()
bullet.setposition(x, y +10)
bullet.showturtle()
#HitBoxes
def checkCollision(A,B):
distance = math.sqrt(math.pow(A.xcor() - B.xcor(), 2) +
math.pow(A.ycor() - B.ycor(), 2))
if distance < 30:
return True
else:
return False
#Move plane
def MovePlane():
x = plane.xcor()
x += planespd
plane.speed(1)
plane.setx(x)
if plane.xcor() > 280:
plane.ht()
turtle.listen()
turtle.onkey(Left,"Left")
turtle.onkey(Right,"Right")
turtle.onkey(Shoot,"space")
while True:
#Move Plane
MovePlane()
#Move count
incCount()
#Show Paratrooper
x = -200
for Troop in Troopers:
if plane.xcor() > x+50:
x += 80
Troop.setx(x)
Troop.showturtle()
y = Troop.ycor()
y -= Troopspeed
Troop.sety(y)
if y < -280:
Troop.ht()
if checkCollision(bullet, Troop):
# Reset bullet
bullet.ht()
state = "ready"
bullet.setposition(0, -400)
Troop.shape("boom.gif")
# Update Scoreboard
score += 10
scorestring = "Score: %s" % score
score_pen.clear()
score_pen.write(scorestring, False, align="left", font=("Arial", 14, "normal"))
time.sleep(0.1)
Troop.setposition(1000, 1000)
#update background
if counter == 30:
wn.bgpic("background2.png")
wn.update()
if counter == 60:
wn.bgpic("background3.png")
wn.update()
if counter == 90:
wn.bgpic("background4.png")
wn.update()
if counter == 120:
wn.bgpic("background5.png")
wn.update()
if counter == 150:
wn.bgpic("background6.png")
wn.update()
wn.mainloop()
from tkinter import *
from tkinter import messagebox
import TrooperShooter
root = Tk()
launch = messagebox.askquestion("launcher","Play game?")
if launch == "yes":
TrooperShooter.start()
When the launcher is run a messagebox should appear saying do you wish to play
and when "yes" is clicked the function to start the game is launched. However I receive the error:
Traceback (most recent call last):
File "C:/Users/marco/Desktop/Trooper shooter/launcher.py", line 10, in <module>
TrooperShooter.start()
File "C:\Users\marco\Desktop\Trooper shooter\TrooperShooter.py", line 18, in start
wn.bgpic("background1.png")
File "C:\Program Files (x86)\Python37-32\lib\turtle.py", line 1482, in bgpic
self._setbgpic(self._bgpic, self._bgpics[picname])
File "C:\Program Files (x86)\Python37-32\lib\turtle.py", line 738, in _setbgpic
self.cv.itemconfig(item, image=image)
File "<string>", line 1, in itemconfig
File "C:\Program Files (x86)\Python37-32\lib\tkinter\__init__.py", line 2578, in itemconfigure
return self._configure(('itemconfigure', tagOrId), cnf, kw)
File "C:\Program Files (x86)\Python37-32\lib\tkinter\__init__.py", line 1476, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: image "pyimage2" doesn't exist
Process finished with exit code 1
My first suggestion is that you use the turtle textinput() method (new in Python 3) instead of dragging tkinter and messagebox into the picture.
But if you're going to combine tkinter and turtle, you need to do it correctly. Turtle is designed to run either standalone with its own Tk window or embedded in an existing tkinter window. You're attempting to run it standalone, embedded in a tkinter window. I.e. instead of the standalone Turtle & Screen interface, you should be working with the embedded TurtleScreen, RawTurtle and ScrolledCanvas interface.
Besides this issue, your code is generally buggy. You've lots of unfinished code. Your use of global has to become nonlocal when you move the entire program inside the start() function. You're missing pieces of code necessary to run. Finally, you have a while True: loop which has no business being in an event-driven environment like turtle. I've repaced it with a timer event.
I've reworked your code below to run as you intended. I've tossed incomplete and/or broken features to simplify the example. The startup code:
from tkinter import Tk
from tkinter import messagebox
import TrooperShooter
root = Tk()
launch = messagebox.askquestion("launcher", "Play game?")
if launch == "yes":
TrooperShooter.start(root)
TrooperShooter.py
import tkinter as tk
from turtle import TurtleScreen, ScrolledCanvas, RawTurtle
def start(root):
# Move player left
def Left():
soldier.shape("player1.gif")
x = soldier.xcor() - soldierspd
soldier.setx(x)
if x < -280:
soldier.setx(-280)
# Move player right
def Right():
soldier.shape("player2.gif")
x = soldier.xcor() + soldierspd
soldier.setx(x)
if x > 280:
soldier.setx(280)
# Shoot bullet
def Shoot():
# Declare bullet state as global
nonlocal state
if state == "ready":
state = "fire"
# Move bullet above player
x, y = soldier.position()
bullet.setposition(x, y + 10)
bullet.showturtle()
# HitBoxes
def checkCollision(a, b):
return a.distance(b) < 30
# Move plane
def MovePlane():
x = plane.xcor() + plane_speed
plane.setx(x)
if plane.xcor() > 280:
plane.hideturtle()
def action():
nonlocal state, score
# Move Plane
MovePlane()
# Show Paratrooper
x = -200
for troop in troopers:
if plane.xcor() > x + 50:
x += 80
troop.setx(x)
troop.showturtle()
y = troop.ycor() - troop_speed
troop.sety(y)
if y < -280:
troop.hideturtle()
if checkCollision(bullet, troop):
# Reset bullet
bullet.hideturtle()
state = "ready"
bullet.setposition(0, -400)
troop.shape("boom.gif")
# Update Scoreboard
score += 10
scorestring = "Score: %s" % score
score_pen.clear()
score_pen.write(scorestring, align="left", font=("Arial", 14, "normal"))
troop.setposition(1000, 1000)
if state == "fire":
y = bullet.ycor()
if y > 300:
state = 'ready'
bullet.hideturtle()
else:
bullet.sety(y+ bullet_speed)
screen.ontimer(action, 100)
score = 0
# Define bullet state
# ready = ready to fire
# fire = bullet is firing
state = "ready"
root.geometry("800x600")
root.title("Trooper shooter")
canvas = ScrolledCanvas(root)
canvas.pack(fill=tk.BOTH, expand=tk.YES)
screen = TurtleScreen(canvas)
screen.bgcolor("black")
screen.bgpic("background1.png")
screen.register_shape("invader.gif")
screen.register_shape("plane.gif")
screen.register_shape("troop.gif")
screen.register_shape("player1.gif")
screen.register_shape("player2.gif")
screen.register_shape("boom.gif")
# Player
soldier = RawTurtle(screen)
soldier.color("blue")
soldier.shape("player1.gif")
soldier.penup()
soldier.speed('fastest')
soldier.setposition(0, -200)
soldier.setheading(90)
soldierspd = 20
# Score
score_pen = RawTurtle(screen)
score_pen.speed('fastest')
score_pen.hideturtle()
# Plane
plane = RawTurtle(screen)
plane.color("red")
plane.shape("plane.gif")
plane.penup()
plane.speed('fastest')
plane.setposition(-270, 200)
plane.setheading(360)
plane_speed = 20
# ParaTroopers
number_troops = 5
troopers = []
for _ in range(number_troops):
troop = RawTurtle(screen)
troop.color("Purple")
troop.shape("troop.gif")
troop.penup()
troop.speed('fastest')
troop.hideturtle()
x, y = -170, 270
troop.setposition(x + 30, y)
troop.setheading(270)
troopers.append(troop)
troop_speed = 3
# Bullet
bullet = RawTurtle(screen)
bullet.color("yellow")
bullet.shape("triangle")
bullet.penup()
bullet.speed('fastest')
bullet.setheading(90)
bullet.shapesize(0.5)
bullet.hideturtle()
bullet_speed = 30
screen.onkey(Left, "Left")
screen.onkey(Right, "Right")
screen.onkey(Shoot, "space")
screen.listen()
action()
screen.mainloop()

Making snake in Python, can't get bodies to follow head etc

I wanted to make a snake game in turtle but I can't seem to get the tail segments to follow the leader. As if to say I can't get the first body part to follow the head, and then the second body part to follow the first body, etc.
I tried using what maths I have but I can't seem to get it to calculate where the head just was or where the body in front of it just was.
here is my code:
#libraries
import turtle
import random
import math
#screen
the_screen = turtle.Screen()
the_screen.bgcolor("lightgreen")
the_screen.title("Catapillar")
#border
border_writer = turtle.Turtle()
border_writer.speed(0)
border_writer.color("green")
border_writer.penup()
border_writer.setposition(-275, -275)
border_writer.pendown()
border_writer.pensize(7)
for side in range(4):
border_writer.fd(550)
border_writer.lt(90)
border_writer.hideturtle()
#player
player = turtle.Turtle()
player.color("yellow")
player.shape("circle")
player.penup()
player.speed(0)
player.setposition(0,0)
player.setheading(0)
playerspeed = 2
#fruit
fruit = 1
fruit = turtle.Turtle()
fruit.color("red")
fruit.shape("circle")
fruit.penup()
fruit.speed(0)
fruit.shapesize(0.6, 0.6)
x = random.randint(-200, 200)
y = random.randint(100, 250)
fruit.setposition(x, y)
#moving and collision checker
def turnleft():
player.left(24.5)
def turnright():
player.right(24.5)
def increasespeed():
global playerspeed
playerspeed += 1
def isCollision(t1, t2):
distance = math.sqrt(math.pow(t1.xcor()-t2.xcor(), 2) + math.pow(t1.ycor()-t2.ycor(), 2))
if distance < 24:
return True
else:
return False
#making the tail(s) and hiding them
tail1 = turtle.Turtle()
tail1.hideturtle()
tail1.color("yellow")
tail1.shape("circle")
tail1.penup()
tail1.speed(0)
tail1.setposition(+700,700)
tail1.shapesize(0.6, 0.6)
tail1state = 'off'
#key presses
turtle.listen()
turtle.onkeypress(turnleft, "Left")
turtle.onkeypress(turnright, "Right")
turtle.onkeypress(increasespeed, "Up")
#main loop player always moves forward, out of bound set, reset fruit
#randomly when collided, create tail1...
while True:
player.forward(playerspeed)
#gameovers'
if (player.xcor() > 275) or (player.xcor() < -275):
playerspeed += 7
print("GAME OVER")
if (player.ycor() > 275) or (player.ycor() < -275):
playerspeed += 7
print("GAME OVER")
#collision check between fruit and head
if isCollision(player, fruit):
#resets the fruit, moves it randomly
fruit.hideturtle()
if tail1state == 'off':
uuu = player.xcor()
vvv = player.ycor()
tail1.setposition(uuu,vvv)
tail1.showturtle()
tail1state = 'on'
#reset the fruit
x = random.randint(-200, 200)
y = random.randint(-100, 250)
fruit.setposition(x, y)
fruit.showturtle()
#playerspeed +=1
If you have any idea on how you think I should approach it, please let me know what you think.
Thank you.
Since this comes up over and over (but effort to effect it is rarely shown) here's my minimal, generic, slithering around a screen effect that you should be able to adapt for your own purposes:
from turtle import Turtle, Screen
SNAKE_LENGTH = 10
SNAKE_SIZE = 15
WIDTH, HEIGHT = 375, 375
CURSOR_SIZE = 20
def slither():
segment = snake[-1].clone() if len(snake) < SNAKE_LENGTH else snake.pop(0)
screen.tracer(False) # segment.hideturtle()
segment.setposition(snake[-1].position())
segment.setheading(snake[-1].heading())
segment.forward(SNAKE_SIZE)
while not -WIDTH/2 < segment.xcor() < WIDTH/2 or not -HEIGHT/2 < segment.ycor() < HEIGHT/2:
segment.undo()
segment.right(95)
segment.forward(SNAKE_SIZE)
screen.tracer(True) # segment.showturtle()
snake.append(segment)
screen.ontimer(slither, 100)
boundary = Turtle(shape='square', visible=False)
boundary.shapesize(HEIGHT / CURSOR_SIZE, WIDTH / CURSOR_SIZE)
boundary.fillcolor("white")
boundary.stamp()
head = Turtle("circle")
head.shapesize(SNAKE_SIZE / CURSOR_SIZE)
head.penup()
snake = [head]
screen = Screen()
slither()
screen.exitonclick()

Categories