I have gotten an issue where an enemy turtle stops when I shoot. I am relatively new to python so I know that my code is pretty bad. I cant seem to spot why this happens but I'm assuming its got something to do with the while loop.
here is the code:
(i have added notes so it is easy to skip to important parts of it)
import turtle
import os
#wn is window
#bp = border
bullet = 'ready'
#screen setup
wn = turtle.Screen()
wn.bgcolor('black')
wn.title('SPACE.INVADERS')
#border
bp = turtle.Turtle()
bp.speed(0)
bp.color('green')
bp.penup()
bp.setposition(-300,-300)
bp.pendown()
count=0
while count != 5:
count= (count+1)
bp.fd(600)
bp.lt(90)
bp.hideturtle()
#player
p = turtle.Turtle()
p.color('red')
p.shape('triangle')
p.penup()
p.speed(0)
p.setposition(0,-250)
p.setheading(90)
#enemy
e = turtle.Turtle()
e.penup()
e.speed(0)
e.shape('square')
e.shapesize(1.25,1.25)
e.color('orange')
e.setpos(-250,250)
e.speed(1)
#p = player
#ps = player speed
ps = 15
#moving left and right
def left_mov():
x = p.xcor()
x -= ps
p.setx(x)
def right_mov():
x = p.xcor()
x += ps
p.setx(x)
#shooting
def shoot():
global bullet
if bullet == 'ready':
bullet = 'fire'
shot= turtle.Turtle()
shot.penup()
shot.speed(0)
shot.goto(p.pos())
shot.color('white')
shot.shape('triangle')
shot.shapesize(0.5)
shot.lt(90)
shot.speed(1)
shot.fd(550)
bullet = 'ready'
#bindings
turtle.listen()
turtle.onkey(left_mov, 'Left')
turtle.onkey(right_mov, 'Right')
turtle.onkey(shoot, 'space')
#enemy movement
while True:
e.fd(500)
e.rt(90)
e.fd(25)
e.rt(90)
e.fd(500)
e.lt(90)
e.fd(25)
e.lt(90)
I'm assuming its got something to do with the while loop
Yes, it shouldn't be there! In an event-driven world like turtle, there should never be a while True: loop. Instead, we need a timer event that fires off on regular intervals that does incremental updates of the objects in motion (enemy and bullet) so they appear to move at the same time. Below is my rework of your code using a timer event:
from turtle import Screen, Turtle
# moving left and right
def left_move():
player.setx(player.xcor() - player_speed)
def right_move():
player.setx(player.xcor() + player_speed)
# screen setup
screen = Screen()
screen.bgcolor('black')
screen.title('SPACE.INVADERS')
# border
border = Turtle(visible=False)
border.speed('fastest')
border.color('green')
border.penup()
border.setposition(-300, -300)
border.pendown()
for _ in range(4):
border.forward(600)
border.left(90)
# player
player = Turtle('triangle')
player.speed('fastest')
player.color('red')
player.penup()
player.setposition(0, -250)
player.setheading(90)
player_speed = 15
# enemy
enemy = Turtle('square')
enemy.speed('fast')
enemy.shapesize(1.25)
enemy.color('orange')
enemy.penup()
enemy.setpos(-250, 250)
enemy_speed = 6 # enemy speed
enemy_direction = 1 # enemy direction
# bullet
bullet = Turtle('triangle', visible=False)
bullet.speed('fastest')
bullet.color('white')
bullet.shapesize(0.5)
bullet.penup()
bullet.left(90)
bullet_speed = 9 # bullet speed
# shooting
def shoot():
if not bullet.isvisible():
bullet.goto(player.position())
bullet.showturtle()
def move():
global enemy_direction
if bullet.isvisible():
if bullet.ycor() > 275:
bullet.hideturtle()
else:
bullet.forward(bullet_speed)
# enemy movement
enemy.forward(enemy_direction * enemy_speed)
enemy.settiltangle(enemy.tiltangle() + 3) # just for fun
x, y = enemy.position()
if x > 250 or x < -250:
enemy_direction *= -1
enemy.sety(y - 25)
screen.ontimer(move, 50)
# bindings
screen.onkey(left_move, 'Left')
screen.onkey(right_move, 'Right')
screen.onkey(shoot, 'space')
screen.listen()
move()
screen.mainloop()
This should give you the basic functionality you need to move forward and add collision detection (bullet to enemy, enemy to player, player to wall) and scoring.
Also note that turtles are global entities so creating a new bullet every time you need one is a bad idea. Even if you evenually allow overlapping bullets, keep a reusable set of bullets for that purpose.
Related
When I try to run my code, my python turtle window just hangs; I can't move also. I've tried removing the win_pen and it worked, but I don't know what inside the win_pen is making it hang.
It also gives me the spinning wheel since I am on Mac, and I am not sure if that is the problem for this. I'm on Big Sur 11.1 by the way.
edit: The indents are right on my screen, just a copy and paste problem
Code:
import turtle
import os
import math
import random
from random import randint
score = 0
# Set Up Screen
wn = turtle.Screen()
wn.bgcolor("black")
wn.title("test")
# Draw border
border_pen = turtle.Turtle()
border_pen.speed(0)
border_pen.color("white")
border_pen.penup()
border_pen.setposition(-300,-300)
border_pen.pendown()
border_pen.hideturtle()
border_pen.pensize(3)
for side in range(4):
border_pen.fd(600)
border_pen.lt(90)
# Draw Winning Area
win_pen = turtle.Turtle()
win_pen.hideturtle()
win_pen.shape("square")
win_pen.penup()
win_pen.setposition(0,267.7)
win_pen.shapesize(3,29.8)
# Show Score on Screen
score_pen = turtle.Turtle()
score_pen.speed(0)
score_pen.color("white")
score_pen.penup()
score_pen.setposition(-290, 303)
scorestring = "Score: %s" %score
score_pen.write(scorestring, False, align="left", font=("Ubuntu", 14, "normal"))
score_pen.hideturtle()
# Set up Player 1
player1 = turtle.Turtle()
player1.color("blue")
player1.shape("triangle")
player1.penup()
player1.speed(0)
player1.setposition(0, -250)
player1.setheading(90)
player1speed = 15
# Set Up Enemies
en = 8
enemies = []
for i in range(en):
enemies.append(turtle.Turtle())
for enemy in enemies:
enemy.color("red")
enemy.shape("square")
enemy.penup()
enemy.speed(0)
enemy.goto(randint(-280,280),randint(-280,280))
enemy.shapesize(2,2)
enemyspeed = 2
# Draw Winning Area
win_pen = turtle.Turtle()
win_pen.hideturtle()
win_pen.shape("square")
win_pen.penup()
win_pen.setposition(0,267.7)
win_pen.shapesize(3,29.8)
#Define bullet state
#ready - ready to fire
#fire - bullet is firing
bulletstate = "ready"
def left():
x = player1.xcor()
player1.setheading(180)
player1.forward(player1speed)
if x < -280:
x = - 280
player1.setx(x)
def right():
x = player1.xcor()
player1.setheading(0)
player1.forward(player1speed)
if x > 280:
x = 280
player1.setx(x)
def up():
y = player1.ycor()
player1.setheading(90)
player1.forward(player1speed)
if y > 280:
y = 280
player1.sety(y)
def down():
y = player1.ycor()
player1.setheading(270)
player1.forward(player1speed)
if y < -280:
y = 280
player1.sety(y)
def isCollision(t1, t2):
distance = math.sqrt(math.pow(t1.xcor()-t2.xcor(),2)+math.pow(t1.ycor()-t2.ycor(),2))
if distance < 15:
return True
else:
return False
turtle.listen()
turtle.onkey(left, "a")
turtle.onkey(right, "d")
turtle.onkey(up, "w")
turtle.onkey(down, "s")
# Main Game Loop
while True:
if isCollision(player1, win_pen):
player1.setposition(0, -250)
player1.setheading(90)
There are several problems with your code: don't use while True: in an event-driven world like turtle -- let the event handler do its job; your collision logic is incorrect as it measures from the center of the turtles whereas we're really only concerned with the y position of the two turtles; you seem to be resetting the player in the wrong direction; you implement the winning area twice.
I've rewritten, and simplified, your code below incorporating the above changes and some other tweaks:
from turtle import Screen, Turtle
from random import randint
ENEMY_COUNT = 8
PLAYER_SPEED = 15
def left():
player.setheading(180)
player.setx(max(-280, player.xcor() - PLAYER_SPEED))
check_collision(player, win_pen)
def right():
player.setheading(0)
player.setx(min(280, player.xcor() + PLAYER_SPEED))
check_collision(player, win_pen)
def up():
player.setheading(90)
player.sety(min(280, player.ycor() + PLAYER_SPEED))
check_collision(player, win_pen)
def down():
player.setheading(270)
player.sety(max(-280, player.ycor() - PLAYER_SPEED))
check_collision(player, win_pen)
def check_collision(player, win_pen):
if abs(player.ycor() - win_pen.ycor()) < 15:
player.sety(-250)
player.setheading(90)
score = 0
# Set Up Screen
screen = Screen()
screen.bgcolor('black')
# Draw border
border_pen = Turtle()
border_pen.hideturtle()
border_pen.pensize(3)
border_pen.color('white')
border_pen.speed('fastest')
border_pen.penup()
border_pen.setposition(-300, -300)
border_pen.pendown()
for _ in range(4):
border_pen.forward(600)
border_pen.left(90)
# Draw Winning Area
win_pen = Turtle()
win_pen.shape('square')
win_pen.shapesize(3, 29.8)
win_pen.color('gray')
win_pen.penup()
win_pen.sety(267.7)
# Show Score on Screen
score_pen = Turtle()
score_pen.hideturtle()
score_pen.color('white')
score_pen.penup()
score_pen.setposition(-290, 303)
scorestring = "Score: %s" %score
score_pen.write(scorestring, False, align='left', font=('Ubuntu', 14, 'normal'))
# Set up Player
player = Turtle()
player.shape('triangle')
player.color('blue')
player.speed('fastest')
player.setheading(90)
player.penup()
player.setx(-250)
# Set Up Enemies
enemies = []
for _ in range(ENEMY_COUNT):
enemy = Turtle()
enemy.color('red')
enemy.shape('square')
enemy.shapesize(2)
enemy.speed('fastest')
enemy.penup()
enemy.goto(randint(-280, 280), randint(-280, 280))
enemies.append(enemy)
screen.onkey(left, 'a')
screen.onkey(right, 'd')
screen.onkey(up, 'w')
screen.onkey(down, 's')
screen.listen()
screen.mainloop()
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.
I am trying to make a game where I can press space to shoot my bullet. There is a lot of lag. I am trying to figure out how to make the bullet disappear after it exits the screen. There is also a lot of lag. I am pretty sure the lag is from the bullet not resetting the screen after reaching the end. I imported time but I just can't seem to figure out how to use time.
This is what I tried:
# Importing GUI library
import turtle
import time
bullets = []
bullets2 = []
# Set speed, GUI, creates new turtle
t_speed = 5
bullet_speed = 50000
screen = turtle.Screen()
t = turtle.Turtle()
t2=turtle.Turtle()
screen.setup(700, 400)
# Arrow Keys as turtle movement
def forward():
t.forward(t_speed)
def left():
t.left(t_speed)
def right():
t.right(t_speed)
def back():
t.back(t_speed)
def forward2():
t2.forward(t_speed)
def left2():
t2.left(t_speed)
def right2():
t2.right(t_speed)
def back2():
t2.back(t_speed)
# Shoot a turtle from a turtle
def shoot():
# sets position of bullet at x and y of t
# spawn turtle at x and y
bullet = turtle.Turtle()
bullet.ht()
bullet.penup()
# Launch him
screen.addshape("uparrow.png")
bullet.shape("uparrow.png")
bullet.setheading(t.heading())
bullet.setposition(t.xcor(), t.ycor())
bullet.st()
bullet.forward(700)
bullet.speed(bullet_speed)
#TODO: Make less laggy by deleting bullet object after x seconds
def shoot2():
# set a timer
current = time.localtime().tm_sec
# sets position of bullet at x and y of t
# spawn turtle at x and y
bullet = turtle.Turtle()
bullets2.append(bullet)
bullet.ht()
bullet.penup()
# Launch him
screen.addshape("uparrow.png")
bullet.shape("uparrow.png")
bullet.setheading(t2.heading())
bullet.setposition(t2.xcor(), t2.ycor())
bullet.st()
bullet.forward(700)
bullet.speed(bullet_speed)
#TODO: Make less laggy by deleting bullet object after x seconds
#new = time.localtime().tm_sec
#if new > current + 3:
#bullets2.
def playGame():
# TODO: Health Bar
# TODO: Characters
t.penup()
t.setheading(5)
t2.penup()
# TODO
still_alive = True
# Movement
screen.onkey(back, "Down")
screen.onkey(left, "Left")
screen.onkey(right, "Right")
screen.onkey(shoot, "space")
screen.onkey(forward, "Up")
screen.onkey(back2, "S")
screen.onkey(left2, "A")
screen.onkey(right2, "D")
screen.onkey(shoot2, "Z")
screen.onkey(forward2, "W")
# Game Engine
screen.listen()
t.mainloop()
def gameStart():
# Title
print("Welcome to my game!")
# Menu; press Q to quit, Press p to play
startGame = True
while startGame == True:
inp = raw_input("Press p to play or Press q to quit")
if inp == "q":
exit()
elif inp == "p":
playGame()
startGame = False
else:
print("Incorrect prompt")
# Instructions
print("Use Arrow Keys to move. Press space to shoot")
def main():
gameStart()
if __name__ == "__main__":
main()
The object should disappear after some time.
Your progam appears to be a collection of misconceptions glued together with bad code management. Your bullet not only has lag, but it locks out all other action while it's in motion! Let's toss the time module idea and instead take advantage of turtle's own timer events to really let the bullets fly:
from turtle import Screen, Turtle
# Arrow Keys as turtle movement
def forward_1():
player_1.forward(player_speed)
def back_1():
player_1.back(player_speed)
def left_1():
player_1.left(player_speed)
def right_1():
player_1.right(player_speed)
def shoot_1():
screen.onkey(None, "space") # disable handler inside handler!
shoot(player_1)
screen.onkey(shoot_1, "space")
def forward_2():
player_2.forward(player_speed)
def left_2():
player_2.left(player_speed)
def right_2():
player_2.right(player_speed)
def back_2():
player_2.back(player_speed)
def shoot_2():
screen.onkey(None, "z")
shoot(player_2)
screen.onkey(shoot_2, "z")
def travel(bullet, milliseconds):
bullet.forward(bullet_speed)
if milliseconds:
screen.ontimer(lambda b=bullet, s=milliseconds - 100: travel(b, s), 100)
else:
bullet.hideturtle()
bullets.append(bullet)
# Shoot a bullet from a player
def shoot(player):
# sets position of bullet at x and y of player
# spawn turtle at x and y
if bullets:
bullet = bullets.pop(0)
else:
bullet = Turtle(visible=False)
# bullet.shape("uparrow.png")
bullet.shape('arrow')
bullet.speed('fastest')
bullet.penup()
# Launch him
bullet.color(player.fillcolor())
bullet.setheading(player.heading())
bullet.setposition(player.position())
bullet.showturtle()
travel(bullet, 2000)
bullets = []
# Set speed, GUI, creates new turtle
player_speed = 10
bullet_speed = 15
screen = Screen()
screen.setup(700, 400)
# screen.addshape("uparrow.png")
player_1 = Turtle('triangle')
player_1.speed('fastest')
player_1.color('red', 'pink')
player_1.penup()
player_1.setheading(90)
player_2 = Turtle('triangle')
player_2.speed('fastest')
player_2.color('blue', 'cyan')
player_2.penup()
player_2.setheading(270)
# Movement
screen.onkey(forward_1, "Up")
screen.onkey(back_1, "Down")
screen.onkey(left_1, "Left")
screen.onkey(right_1, "Right")
screen.onkey(shoot_1, "space")
screen.onkey(forward_2, "w")
screen.onkey(back_2, "s")
screen.onkey(left_2, "a")
screen.onkey(right_2, "d")
screen.onkey(shoot_2, "z")
# Game Engine
screen.listen()
screen.mainloop()
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()
I am trying to make a space invaders game using turtle, and in order to move the bullet up the screen I am trying to update the y coordinate of the bullet every 0.5 seconds. I tried to do this with a while loop and the time.sleep() function, but everytime I try to fire a bullet, the program crashes. Is there any way I can stop it from doing this? Or why is it not working? Is there an equally effective method that will not crash my program?
import turtle
import time
userx = 0
x = 0
y = -300
enemies = [(300,50, "left"), (400,50, "left"), (350, -50, "right")]
bullets = []
gameover = False
def frame():
pass
ship = turtle.Turtle()
ship.pu()
ship.ht()
ship.setpos(userx, -300)
ship.pd()
ship.circle(5)
bullet = turtle.Turtle()
bullet.pu()
bullet.ht()
bullet.setpos(x, y)
bullet.pd()
bullet.circle(2)
def key_left():
global userx
pass
userx += -10
print(userx)
def key_right():
global userx
pass
userx += 10
print(userx)
def key_space():
pass # your code here
global x
global y
global bullets
x = userx
while y <= 300:
time.sleep(0.5)
y += 4
else: y = 0
bullets += (x,y)
def physics():
global bullets
global enemies
pass
def ai():
global enemies
global gameover
pass
def reset():
global enemies
global bullets
global userx
global gameover
pass
def main():
turtle.tracer(0,0)
turtle.hideturtle()
turtle.onkey(key_left, "Left")
turtle.onkey(key_right, "Right")
turtle.onkey(key_space, "space")
turtle.listen()
reset()
while not gameover:
turtle.clear()
physics()
ai()
frame()
turtle.update()
time.sleep(0.05)
main()
It is not ideal but it starts working.
In key_space you only add new bullet to list.
In while not gameover you run function which will move all bullets.
In frame you draw all bullets.
import turtle
import time
userx = 0
x = 0
y = -300
enemies = [(300,50, "left"), (400,50, "left"), (350, -50, "right")]
bullets = []
gameover = False
def frame():
pass
ship = turtle.Turtle()
ship.pu()
ship.ht()
ship.setpos(userx, -300)
ship.pd()
ship.circle(5)
# redraw bullets
for x, y in bullets:
bullet = turtle.Turtle()
bullet.pu()
bullet.ht()
bullet.setpos(x, y)
bullet.pd()
bullet.circle(2)
def key_left():
global userx
pass
userx += -10
print(userx)
def key_right():
global userx
pass
userx += 10
print(userx)
def key_space():
pass # your code here
global x
global y
global bullets
x = userx
# add bullet to list
bullets.append([x, -300])
def move_bullets():
global bullets
live_bullets = []
# move every bullet and check if should still live
for x, y in bullets:
y += 4
# keep only some bullets and other forget (kill/remove)
if y <= 300:
live_bullets.append([x, y])
bullets = live_bullets
def physics():
global bullets
global enemies
pass
def ai():
global enemies
global gameover
pass
def reset():
global enemies
global bullets
global userx
global gameover
pass
def main():
turtle.tracer(0,0)
turtle.hideturtle()
turtle.onkey(key_left, "Left")
turtle.onkey(key_right, "Right")
turtle.onkey(key_space, "space")
turtle.listen()
reset()
while not gameover:
turtle.clear()
physics()
ai()
move_bullets() # <-- move bullets (or maybe before physics)
frame()
turtle.update()
time.sleep(0.05)
main()
I would:
def key_space():
# simply spawn a new bullet and put it into your bullets list
def advance_bullet(): # call this after paintnig all bullets in frame
# iterate over all bullets inside bullets, advance the Y position by 3
def frame():
# add code to paint all bullets inside bullets - and call advance_bullets()
In the code that checks for collision with enemies:
# remove a bullet from bullets when its outside your screen (or passed all enemies max y coord) - no need to track that bullet anymore
if you ned to advance the bullets slower then your main loops intervall, make a "framespassed" counter and see if framespassed % something == 0 and only then advance your bullets.
Adapted to what you already have
You need to change these parts:
def frame():
global bullets
pass
ship = turtle.Turtle()
ship.pu()
ship.ht()
ship.setpos(userx, -300)
ship.pd()
ship.circle(5)
# debugging all bullets:
# print(bullets) # remove this
for idx in range(0,len(bullets)): # paint ALL bullets in the bullets list
bulletTurtle = turtle.Turtle()
b = bullets[idx] # current bullet we are painting
bulletTurtle.pu()
bulletTurtle.ht()
bulletTurtle.setpos(b[0], b[1])
bulletTurtle.pd()
bulletTurtle.circle(2)
b[1] += 13 # quick and dirty approach, move bulltet after painting
# to save another complete bullets-foreach-loop
# quick n dirty bullet removal for out of screen bullets
# normally I would do this probably in your "check if enemy hit"
# method as you are going over bullets there as well and can remove
# them as soon as they passed all enemies
bullets = [x for x in bullets if x[1] < 500]
def key_space():
global x
global y
global bullets
bullets.append([userx,-300]) # start a new bullet at current player position
Edit:
You might want to take a look at turtle.shape, turtle.size and turtle.stamp - by using a "circle" shape and a size that fits, you might be able to "stamp" this shape down. Advantage: you can simply delete the stamped shape - by its integer-id. I haven*t worked with turtle ever - consider yourself if that would be a way to easily redraw your players position and/or bullets