I am writing the Space Invaders game from Christian Thompson
I have problem exactly in line 188 where the player and enemy hide when a collision is detected. My player turtle is hiding but the enemy turtle doesn't "want" to hide. Here is the code:
import turtle
import os
import math
import random
import winsound
#Set up the screen
wn = turtle.Screen()
wn.bgcolor("black")
wn.title("Space Invaders")
wn.bgpic("space_invaders_background.gif")
#Register the shapes
turtle.register_shape("invader.gif")
turtle.register_shape("player.gif")
#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.pensize(3)
for side in range(4):
border_pen.fd(600)
border_pen.lt(90)
border_pen.hideturtle()
#Set the score to 0
score = 0
#Draw score
score_pen = turtle.Turtle()
score_pen.speed(0)
score_pen.color("white")
score_pen.penup()
score_pen.setposition(-290, 280)
scorestring = "Score: %s" %score
score_pen.write(scorestring, False, align="left", font=("Arial", 14, "normal"))
score_pen.hideturtle()
#Game Over
game_over = turtle.Turtle()
game_over.speed(0)
game_over.color("red")
game_over.penup()
game_over.setposition(0, 0)
gameOverMsg = "Game Over!"
game_over.hideturtle()
#Create player
player = turtle.Turtle()
player.color("blue")
player.shape("player.gif")
player.penup()
player.speed(0)
player.setposition(0,-230)
player.setheading(90)
playerspeed = 15
#Choose a number of enemies
number_of_enemies = 20
#Create empty list of enemies
enemies = []
#Add enemies to list
for i in range(number_of_enemies):
# Create the enemy
enemies.append(turtle.Turtle())
for enemy in enemies:
enemy.color("red")
enemy.shape("invader.gif")
enemy.penup()
enemy.speed(0)
x = random.randint(-200, 200)
y = random.randint(100, 250)
enemy.setposition(x, y)
enemyspeed = number_of_enemies * 0.5
#Create the player's 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.hideturtle()
bulletspeed = 20
def laser():
winsound.PlaySound("laser.wav", winsound.SND_ASYNC)
def explosion():
winsound.PlaySound("explosion.wav", winsound.SND_ASYNC)
#Move the player left and right
def move_left():
x = player.xcor()
x -= playerspeed
if x < -280:
x = -280
player.setx(x)
def move_right():
x = player.xcor()
x += playerspeed
if x > 280:
x = 280
player.setx(x)
def fire_bullet():
if not bullet.isvisible():
laser()
#Move the bullet to the just above the player
x = player.xcor()
y = player.ycor() + 10
bullet.setposition(x, y)
bullet.showturtle()
#Checking collision between enemy and bullet
def isCollision(t1, t2) :
distance = math.sqrt(math.pow(t1.xcor()-t2.xcor(),2)+math.pow(t1.ycor()-t2.ycor(),2))
if distance < 20:
return True
else:
return False
#Create keyboard bindings
turtle.listen()
turtle.onkeypress(move_left, "Left")
turtle.onkeypress(move_right, "Right")
turtle.onkeypress(fire_bullet, "space")
#Main game loop
while True:
for enemy in enemies:
#Move the enemy
x = enemy.xcor()
x += enemyspeed
enemy.setx(x)
#Move the enemy back and down
if enemy.xcor() > 280:
#Move all enemies down
for e in enemies:
y = e.ycor()
y -= 40
e.sety(y)
#Change enemy direction
enemyspeed *= -1
if enemy.xcor() < -280:
#Move all enemies down
for e in enemies:
y = e.ycor()
y -= 40
e.sety(y)
#Change enemy direction
enemyspeed *= -1
# Check for a collision between the bullet and the enemy
if isCollision(bullet, enemy):
explosion()
# Reset the bullet
bullet.hideturtle()
bullet.setposition(0, -400)
# Reset the enemy
x = random.randint(-200, 200)
y = random.randint(100, 250)
enemy.setposition(x, y)
#Update the score
score += 10
scorestring = "Score: %s" %score
score_pen.clear()
score_pen.write(scorestring, False, align="left", font=("Arial", 14, "normal"))
if isCollision(player, enemy):
explosion()
player.hideturtle()
enemy.hideturtle()
game_over.write(gameOverMsg, False, align="center", font=("Arial", 60, "normal"))
break
#Move the bullet
if bullet.isvisible():
y = bullet.ycor()
y += bulletspeed
bullet.sety(y)
#Check border collision
if bullet.ycor() > 290:
bullet.hideturtle()
wn.mainloop()
I wasn't able to reproduce your problem. I've reworked your code below: I've dropped the images and sound so anyone can run it and help you debug it; I tossed your isCollision() code and substituted turtle's own distance() method; I replaced the while True: loop, which has no place in an event-driven world like turtle, with a timer event; I've streamlined the code where I could:
from turtle import Screen, Turtle
from random import randint
PLAYER_SPEED = 15
BULLET_SPEED = 20
# Choose a number of enemies
NUMBER_OF_ENEMIES = 20
SMALL_FONT = ('Arial', 14, 'normal')
LARGE_FONT = ('Arial', 60, 'normal')
# Move the player left and right
def move_left():
x = player.xcor() - PLAYER_SPEED
if x < -280:
x = -280
player.setx(x)
def move_right():
x = player.xcor() + PLAYER_SPEED
if x > 280:
x = 280
player.setx(x)
def fire_bullet():
if not bullet.isvisible():
# Move the bullet to the just above the player
x, y = player.position()
bullet.setposition(x, y + 10)
bullet.showturtle()
# Check collision between enemy and bullet
def isCollision(t1, t2):
return t1.distance(t2) < 20
# Set up the screen
wn = Screen()
wn.bgcolor('black')
wn.title("Space Invaders")
# Draw border
border_pen = Turtle(visible=False)
border_pen.speed('fastest')
border_pen.color('white')
border_pen.pensize(3)
border_pen.penup()
border_pen.setposition(-300, -300)
border_pen.pendown()
for _ in range(4):
border_pen.fd(600)
border_pen.lt(90)
# Set the score to 0
score = 0
# Draw score
score_pen = Turtle(visible=False)
score_pen.speed('fastest')
score_pen.color('white')
score_pen.penup()
score_pen.setposition(-290, 280)
scorestring = "Score: %s" % score
score_pen.write(scorestring, False, align='left', font=SMALL_FONT)
# Game Over
game_over = Turtle(visible=False)
game_over.speed('fastest')
game_over.color('red')
game_over.penup()
gameOverMsg = "Game Over!"
# Create player
player = Turtle('turtle')
player.speed('fastest')
player.color('blue')
player.penup()
player.setposition(0, -230)
player.setheading(90)
# Create empty list of enemies
enemies = []
# Add enemies to list
for _ in range(NUMBER_OF_ENEMIES):
# Create the enemy
enemy = Turtle('turtle', visible=False)
enemy.settiltangle(270) # for non GIF version of game
enemy.speed('fastest')
enemy.color('red')
enemy.penup()
enemy.setposition(randint(-200, 200), randint(100, 250))
enemies.append(enemy)
for enemy in enemies:
enemy.showturtle()
# Create the player's bullet
bullet = Turtle('triangle', visible=False)
bullet.color('yellow')
bullet.penup()
bullet.speed('fastest')
bullet.setheading(90)
bullet.shapesize(0.5)
# Create keyboard bindings
wn.onkeypress(move_left, 'Left')
wn.onkeypress(move_right, 'Right')
wn.onkeypress(fire_bullet, 'space')
wn.listen()
enemy_speed = NUMBER_OF_ENEMIES * 0.5
# Main game loop
def move():
global score, enemy_speed
collision = False
for enemy in enemies:
# Move the enemy
enemy.forward(enemy_speed)
# Check for a collision between the bullet and the enemy
if isCollision(bullet, enemy):
# Reset the bullet
bullet.hideturtle()
# Reset the enemy
enemy.setposition(randint(-200, 200), randint(100, 250))
# Update the score
score += 10
scorestring = "Score: %s" % score
score_pen.clear()
score_pen.write(scorestring, False, align='left', font=SMALL_FONT)
if isCollision(player, enemy):
player.hideturtle()
enemy.hideturtle()
game_over.write(gameOverMsg, False, align='center', font=LARGE_FONT)
collision = True
break
if any(enemy.xcor() < -280 or enemy.xcor() > 280 for enemy in enemies):
# Move all enemies down
for enemy in enemies:
enemy.sety(enemy.ycor() - 40)
# Change enemy direction
enemy_speed *= -1
# Move the bullet
if bullet.isvisible():
bullet.forward(BULLET_SPEED)
# Check border collision
if bullet.ycor() > 290:
bullet.hideturtle()
if not collision:
wn.ontimer(move, 50)
move()
wn.mainloop()
This program is déjà vu for me with respect to this question so see my answer to it for more ideas. Also, see this answer to another space invaders game in turtle to see what you can learn from it to polish your game.
Related
I'm trying to get my game to restart once the user clicks on the screen. I've tried wrapping the whole thing in a while loop, but that gave me errors about variables not being defined.
I've also tried wrapping the code in a function but that also gives me errors on variables.
Here's the code.
import turtle
import math
import random
import pygame
pygame.init()
pygame.mixer.init()
# MUSIC AND SOUND SETUP
pygame.mixer.music.load("Sounds/music.mp3")
pygame.mixer.music.play(loops=-1)
I'm using pygame just to add music into my game.
bubblefiredsound = pygame.mixer.Sound("Sounds/bubblefired.mp3")
enemyhitsound = pygame.mixer.Sound("Sounds/enemyhit.mp3")
# SCREEN SETUP
screen = turtle.Screen()
screen.bgcolor("black")
screen.title("Space Invaders")
screen.bgpic("TurtleInvadersBackground.png")
# CUSTOM SHAPES
turtle.register_shape("Enemy.gif")
turtle.register_shape("Turtle.gif")
turtle.register_shape("Bubble.gif")
# BORDERS
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.pensize(3)
for side in range(4):
border_pen.fd(600)
border_pen.lt(90)
border_pen.hideturtle()
# SCORE
score = 0
score_pen = turtle.Turtle()
score_pen.speed(0)
score_pen.color("white")
score_pen.penup()
score_pen.setposition(-290, 270)
scorestring = "Score: %s" % score
score_pen.write(scorestring, False, align="left", font=("Bubble3D", 20, "normal"))
score_pen.hideturtle()
# MAIN TURTLE
MajorTom = turtle.Turtle()
MajorTom.color("blue")
MajorTom.shape("Turtle.gif")
MajorTom.penup()
MajorTom.speed(0)
MajorTom.setposition(0, -250)
MajorTom.setheading(90)
playerspeed = 0
# NUMBER OF ENEMIES
number_of_enemies = 5
# PLACEHOLDER FOR ENEMIES
enemies = []
# ADD ENEMIES TO THE PLACEHOLDER
for i in range(number_of_enemies):
# CREATE ENEMIES
enemies.append(turtle.Turtle())
for enemy in enemies:
enemy.color("red")
enemy.shape("Enemy.gif")
enemy.penup()
enemy.speed(0)
x = random.randint(-200, 200)
y = random.randint(100, 250)
enemy.setposition(x, y)
enemyspeed = 5
# CREATE THE PROJECTILE BUBBLE
bubble = turtle.Turtle()
bubble.color("blue")
bubble.shape("Bubble.gif")
bubble.penup()
bubble.speed(0)
bubble.setheading(90)
bubble.hideturtle()
bubble.setpos(0, -300)
bubblespeed = 20
# BUBBLE STATE, READY = READY TO FIRE, FIRE = FIRING
bubblestate = "ready"
# MOVEMENT (LEFT AND RIGHT)
def move_left():
global playerspeed
playerspeed = -7
def move_right():
global playerspeed
playerspeed = 7
def stop_player():
global playerspeed
playerspeed = 0
def fire_bubble():
global bubblestate
if bubblestate == "ready":
bubblestate = "fire"
# MOVE BUBBLE TO MAJOR TOM
x = MajorTom.xcor()
y = MajorTom.ycor() + 10
bubble.setposition(x, y)
bubble.showturtle()
if bubblestate == "fire":
bubblefiredsound.play()
def CollisionDetection(t1, t2):
distance = math.sqrt(math.pow(t1.xcor() - t2.xcor(), 2) + math.pow(t1.ycor() - t2.ycor(), 2))
if distance < 32:
return True
else:
return False
# KEYBINDINGS
screen.listen()
screen.onkeypress(move_left, "a")
screen.onkeypress(move_right, "d")
screen.onkeyrelease(stop_player, "a")
screen.onkeyrelease(stop_player, "d")
screen.onkey(fire_bubble, "space")
This is the main loop, most of the code is put together here.
# GAME LOOP
while True:
# MOVE PLAYER
MajorTom.setx(MajorTom.xcor() + playerspeed)
# BORDER CONTROL
if MajorTom.xcor() > 285:
MajorTom.setx(285)
playerspeed = 0
elif MajorTom.xcor() < -285:
MajorTom.setx(-285)
playerspeed = 0
for enemy in enemies:
# ENEMY MOVEMENT
x = enemy.xcor()
x += enemyspeed
enemy.setx(x)
# MOVE THE ENEMY BACK AND DOWN
if enemy.xcor() > 280 or enemy.xcor() < -280:
# MOVE ALL ENEMIES DOWN
for e in enemies:
y = e.ycor()
y -= 40
e.sety(y)
# CHANGE ENEMY DIRECTION
enemyspeed *= -1
# BUBBLE HITS ENEMY
if CollisionDetection(bubble, enemy):
# PLAY BUBBLE BURST SOUND
enemyhitsound.play()
# RESET BUBBLE POSITION
bubble.hideturtle()
bubblestate = "ready"
bubble.setposition(0, -400)
# RESET ENEMY POSITION "SPAWN NEW ENEMY"
x = random.randint(-200, 200)
y = random.randint(100, 250)
enemy.setposition(x, y)
# ADD SCORE IF PLAYER HITS BUBBLE
score += 10
scorestring = "Score: %s" % score
score_pen.clear()
score_pen.write(scorestring, False, align="left", font=("Bubble3D", 20, "normal"))
if CollisionDetection(MajorTom, enemy) or enemy.ycor() < -300:
MajorTom.hideturtle()
enemy.hideturtle()
print("Game Over")
GameOverPen = turtle.Turtle()
GameOverPen.hideturtle()
GameOverPen.penup()
GameOverPen.goto(0,0)
GameOverPen.speed(0)
GameOverPen.color("pink")
GameOverPen.write("GAME OVER!", align="center", font=("Bubble3D", 90, "normal"))
GameOverPen.goto(0, -20)
GameOverPen.write("\nClick to try again!", align="center", font=("Arial", 20, "normal"))
break
# BUBBLE MOVEMENT
if bubblestate == "fire":
y = bubble.ycor()
y += bubblespeed
bubble.sety(y)
# CHECK TO SEE IF BUBBLE HAS HIT THE CEILING
if bubble.ycor() > 275:
bubble.hideturtle()
bubblestate = "ready"
you are looking for the turtle.onscreenclick function.
this function is called with the current x and y coordinates of the mouse when the screen is clicked.
def reset(x_pos, y_pos):
# reset the game
turtle.onscreenclick(reset)
Okay, so I'm trying to make a meteor game where you have to dodge the meteors. But I don't only want 1 meteor I want multiple. So how do I copy my first meteor into more?
Ive tried using a function to make more. But it gives me an error. Ive tried to use a while loop so it runs the meteor code 10 times but that didn't work
import turtle
import random
# meteorgame by Daniel99oslo
wn = turtle.Screen()
wn.title("Meteor")
wn.bgcolor("black")
wn.setup(width=500, height=600)
wn.tracer(0)
#Player
Player = turtle.Turtle()
Player.speed(0)
Player.shape("square")
Player.color("Blue")
Player.shapesize(stretch_wid=1, stretch_len=1)
Player.penup()
Player.goto(0, -100)
#Meteor
Meteor = turtle.Turtle()
Meteor.speed(0)
Meteor.shape("square")
Meteor.color("red")
Meteor.shapesize(stretch_wid=1, stretch_len=1)
Meteor.penup()
Meteor.goto(0, 290)
y1 = (random.randint(500,600))
y2 = Meteor.ycor()
Meteor.sety(y1)
# left/right
def Player_Left():
x = Player.xcor()
x -= 5
Player.setx(x)
def Player_Right():
x = Player.xcor()
x += 5
Player.setx(x)
# Keyboard binds a/d
wn.listen()
wn.onkeypress(Player_Left, "a")
wn.onkeypress(Player_Right, "d")
# Main game loop
while True:
wn.update()
#Meteor respawn/location
x1 = (random.randint(-230,230))
y = Meteor.ycor()
y -= 0.1
Meteor.sety(y)
if Meteor.ycor() <-300:
Meteor.sety(290)
x = Meteor.xcor()
Meteor.setx(x1)
#Meteor hit player detection
if Player.distance(Meteor) < 25:
#Code that will kill player add here
pass
If you just loop through the meteor code you have 10 times you still only get one result because the variable just gets overwritten each time you loop through it. An easy way to handle this would be to create a list and store the meteors in there.
meteors = []
for i in range(10):
Meteor = turtle.Turtle()
...
meteors.append(Meteor)
#code:
import turtle
import random
import time
# meteorgame by Daniel99oslo
wn = turtle.Screen()
wn.title("Meteor")
wn.bgcolor("black")
wn.setup(width=500, height=600)
wn.tracer(0)
# Pen
score = 0
highscore = 0
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 260)
#Player
Player = turtle.Turtle()
Player.speed(0)
Player.shape("square")
Player.color("Blue")
Player.shapesize(stretch_wid=1, stretch_len=1)
Player.penup()
Player.goto(0, -100)
#Number of meteors
number_of_meteors = 10
#Meteor
meteors = []
for i in range(number_of_meteors):
Meteor = turtle.Turtle()
Meteor.speed(0)
Meteor.shape("square")
Meteor.color("red")
Meteor.shapesize(stretch_wid=1, stretch_len=1)
Meteor.penup()
Meteor.setposition(0, 290)
meteors.append(Meteor)
def restart():
for Meteor in meteors:
y1 = (random.randint(500,2000))
y2 = Meteor.ycor()
Meteor.sety(y1)
# left/right
def Player_Left():
x = Player.xcor()
x -= 5
Player.setx(x)
def Player_Right():
x = Player.xcor()
x += 5
Player.setx(x)
# Keyboard binds a/d
wn.listen()
wn.onkeypress(Player_Left, "a")
wn.onkeypress(Player_Right, "d")
#Timer
Timer = turtle.Turtle()
Timer.speed(0)
Timer.shape("square")
Timer.color("orange")
Timer.shapesize(stretch_wid=1, stretch_len=1)
Timer.penup()
Timer.goto(-240, 290)
restart()
# Main game loop
while True:
wn.update()
#scoreadjust
time = 0.2
#Timerfaller
y = Timer.ycor()
y -= time
Timer.sety(y)
if Timer.ycor() <-300:
Timer.goto(-240, 290)
pen.clear()
score += 10
pen.write("Score: {} Highscore: {}".format(score, highscore), align="center", font=("Courier", 24, "normal"))
#Meteor respawn/location
for Meteor in meteors:
x1 = (random.randint(-230,230))
y = Meteor.ycor()
y -= 0.1
Meteor.sety(y)
if Meteor.ycor() <-300:
Meteor.sety(290)
x = Meteor.xcor()
Meteor.setx(x1)
#Meteor hit player detection
for Meteor in meteors:
if Player.distance(Meteor) < 25:
#Restart
restart()
#Score if tests
if score == highscore:
score -= score
if score > highscore:
highscore -= highscore
if highscore > score:
score -= score
highscore += score
score -= score
pen.clear()
pen.write("Score: {} Highscore: {}".format(score, highscore), align="center", font=("Courier", 24, "normal"))
pass
Another approach is to initialize one prototype meteor and then use its .clone() method to fill out your array of meteors:
from turtle import Screen, Turtle
from random import randint
# ...
# Meteors
prototype_meteor = Turtle()
prototype_meteor.shape('square')
prototype_meteor.speed('fastest')
prototype_meteor.color('red')
prototype_meteor.penup()
prototype_meteor.setposition(randint(-230, 230), randint(250, 300))
meteors = [prototype_meteor]
for i in range(9):
meteor = prototype_meteor.clone()
meteor.setposition(randint(-230, 230), randint(250, 300))
meteors.append(meteor)
Complete code:
from turtle import Screen, Turtle
from random import randint
WIDTH, HEIGHT = 500, 600
FONT_SIZE = 24
FONT = ('Courier', FONT_SIZE, 'normal')
TURTLE_SIZE = 20
# left/right
def player_left():
x = player.xcor() - 5
player.setx(x)
def player_right():
x = player.xcor() + 5
player.setx(x)
def random_horizontal():
return randint(TURTLE_SIZE - WIDTH/2, WIDTH/2 - TURTLE_SIZE)
def random_vertical():
return randint(HEIGHT / 3, HEIGHT/2 - TURTLE_SIZE)
def restart():
for meteor in meteors:
meteor.setposition(random_horizontal(), random_vertical())
screen = Screen()
screen.title("Meteor")
screen.bgcolor('black')
screen.setup(width=WIDTH, height=HEIGHT)
screen.tracer(0)
# Pen
score = 0
highscore = 0
pen = Turtle()
pen.hideturtle()
pen.color("white")
pen.penup()
pen.sety(260)
pen.write("Score: {} Highscore: {}".format(score, highscore), align="center", font=FONT)
# Timer
timer = Turtle()
timer.shape('square')
timer.speed('fastest')
timer.color('orange')
timer.penup()
timer.goto(TURTLE_SIZE/2 - WIDTH/2, HEIGHT/2 - TURTLE_SIZE)
# Player
player = Turtle()
player.shape('square')
player.speed('fastest')
player.color('blue')
player.penup()
player.sety(-HEIGHT / 3)
# Meteors
number_of_meteors = 10
prototype_meteor = Turtle()
prototype_meteor.shape('square')
prototype_meteor.speed('fastest')
prototype_meteor.color('red')
prototype_meteor.penup()
meteors = [prototype_meteor] + [prototype_meteor.clone() for i in range(number_of_meteors - 1)]
restart()
# Keyboard binds a/d
screen.onkeypress(player_left, 'a')
screen.onkeypress(player_right, 'd')
screen.listen()
# Main game loop
while True:
timer.sety(timer.ycor() - 0.2)
if timer.ycor() < TURTLE_SIZE - HEIGHT/2:
timer.goto(TURTLE_SIZE/2 - WIDTH/2, HEIGHT/2 - TURTLE_SIZE)
score += 10
for meteor in meteors:
# Meteor respawn/location
y = meteor.ycor() - 1
if y < TURTLE_SIZE - HEIGHT/2:
meteor.setposition(random_horizontal(), random_vertical())
else:
meteor.sety(y)
# Meteor hit player detection
if player.distance(meteor) < TURTLE_SIZE:
score -= 20
restart()
break
if score > highscore:
highscore = score
pen.clear()
pen.write("Score: {} Highscore: {}".format(score, highscore), align="center", font=FONT)
screen.update()
I've created simple penalty game and all works fine but I want to improve it a bit. Goal moves on sides itself and want I want to do is speeding it up when scored. I understand when dx is negative it must be += 1 and if dx is positive it must be opposite so += -1. I thought about for loop for dx in range(-270, 0, -270) and the second one for prositive variables. I'm beginner in python and programming itself, so I appreciate any advice. I want to speed up SL, SP and P. Those objects create the goal.
import turtle
import time
sd = 0.1
wn = turtle.Screen()
wn.bgcolor("black")
wn.title("karne")
wn.setup(width=800, height=600)
wn.tracer(0)
#pilka
ball = turtle.Turtle()
ball.shape("circle")
ball.color("green")
ball.speed(0)
ball.penup()
ball.goto(0, -275)
ball.direction = "stop"
score = 0
miss = 0
#scoring
pen = turtle.Turtle()
pen.speed(0)
pen.shape("square")
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 0)
#slupek lewy
sl = turtle.Turtle()
sl.shape("square")
sl.color("white")
sl.shapesize(stretch_wid=3, stretch_len=1)
sl.speed(0)
sl.penup()
sl.goto(-80, 270)
sl.dx = sd
#slupek prawy
sp = turtle.Turtle()
sp.shape("square")
sp.color("white")
sp.shapesize(stretch_wid=3, stretch_len=1)
sp.speed(0)
sp.penup()
sp.goto(80, 270)
sp.dx = sd
#poprzeczka
p = turtle.Turtle()
p.shape("square")
p.color("white")
p.shapesize(stretch_wid=7, stretch_len=1)
p.speed(0)
p.seth(90)
p.penup()
p.goto(0, 290)
p.dx = sd
score = 0
miss = 0
#function
def right():
x = ball.xcor()
x +=20
ball.setx(x)
def left():
x = ball.xcor()
x -=20
ball.setx(x)
def shoot():
ball.direction = "up"
def shoot2():
ball.direction = "stop"
def shoot1():
if ball.direction == "up":
y = ball.ycor()
ball.sety(y+0.5)
#binds
wn.listen()
wn.onkeypress(right, "d")
wn.onkeypress(left, "a")
wn.onkeypress(shoot, "space")
while True:
#goal moving
sl.setx(sl.xcor() + sl.dx)
sp.setx(sp.xcor() + sp.dx)
p.setx(p.xcor() + p.dx)
#goal borders check
if sl.xcor() > 250:
sl.setx(250)
sl.dx *= -1
if sl.xcor() < -390:
sl.setx(-390)
sl.dx *= -1
if sp.xcor() > 390:
sp.setx(390)
sp.dx *= -1
if sp.xcor() < -250:
sp.setx(-250)
sp.dx *= -1
if p.xcor() > 320:
p.setx(320)
p.dx *= -1
if p.xcor() < -320:
p.setx(-320)
p.dx *= -1
#ball and goal check
if (ball.ycor() > 270 and ball.ycor() < 280) and (ball.xcor() < p.xcor() + 50 and ball.xcor() > p.xcor() -40):
score += 1
pen.clear()
pen.write("Score:{} Miss:{} ".format(score, miss), align="center", font=("Courier", 24, "normal"))
shoot2()
ball.goto(0, -275)
if ball.ycor() > 295:
miss += 1
ball.goto(0, -275)
score = 0
pen.clear()
pen.write("Score:{} Miss:{} ".format(score, miss), align="center", font=("Courier", 24, "normal"))
shoot2()
shoot1()
wn.update()
With a program like this, the fewer objects you try to move in real time, the better. Your goal is three pieces that have to be be moved in unison. The primary fix below is to define the goal as a turtle shape so the goal is only one piece that needs to be manipulated. The secondary fix below is to replace while True:, which has no place in an event-driven world, with a timed event:
from turtle import Screen, Turtle
sd = 1.0
FONT = ("Courier", 24, "normal")
def right():
ball.forward(20)
def left():
ball.backward(20)
def shoot():
ball.direction = "up"
def shoot2():
ball.direction = "stop"
def shoot1():
if ball.direction == "up":
ball.sety(ball.ycor() + sd * 2)
wn = Screen()
wn.bgcolor("black")
wn.title("karne")
wn.setup(width=800, height=600)
wn.tracer(False)
wn.register_shape("goal", ((-90, 30), (90, 30), (90, -30), (70, -30), (70, 10), (-70, 10), (-70, -30), (-90, -30)))
# pilka
ball = Turtle("circle")
ball.color("green")
ball.speed('fastest')
ball.penup()
ball.sety(-275)
ball.direction = "stop"
# scoring
pen = Turtle(visible=False)
pen.speed('fastest')
pen.color("white")
pen.penup()
# poprzeczka
p = Turtle("goal")
p.color("white")
p.speed('fastest')
p.seth(90)
p.penup()
p.sety(270)
p.dx = sd
score = 0
miss = 0
# binds
wn.onkeypress(right, "d")
wn.onkeypress(left, "a")
wn.onkeypress(shoot, "space")
wn.listen()
def move():
global score, miss
# goal moving
p.setx(p.xcor() + p.dx)
# goal borders check
if p.xcor() > 330:
p.setx(330)
p.dx *= -1
elif p.xcor() < -330:
p.setx(-330)
p.dx *= -1
# ball and goal check
if 270 < ball.ycor() < 280 and ball.distance(p) < 50:
score += 1
pen.clear()
pen.write("Score:{} Miss:{} ".format(score, miss), align="center", font=FONT)
shoot2()
ball.goto(0, -275)
elif ball.ycor() > 295:
miss += 1
score = 0
pen.clear()
pen.write("Score:{} Miss:{} ".format(score, miss), align="center", font=FONT)
shoot2()
ball.goto(0, -275)
shoot1()
wn.update()
wn.ontimer(move, 25)
move()
wn.tracer(True)
wn.mainloop()
Plus lots of other little fixes to streamline the code.
I'm very new to turtle and python in general, so I apologize if my code seems messy.
I'm currently coding a turtle version of space invaders and I can't figure out why my invaders aren't dying when they hit the turtles. The code seems to be the same as all the other space invader turtle programs I can find. Any help would be greatly appreciated.
import turtle
import random
import math
#### Player ####
player1 = turtle.Turtle()
player1.shape("arrow")
player1.color("white")
player1.speed(0)
player1.penup()
player1.setheading(90)
player1.setposition(0, -175)
player1.speed(4)
def move_right():
x = player1.xcor()
x += playerspeed
if x > 210:
x = 210
player1.setx(x)
def move_left():
x = player1.xcor()
x -= playerspeed
if x < -210:
x = -210
player1.setx(x)
bulletlist = []
def fire():
if len(bulletlist) < 5:
bulletlist.append(Bullet())
#### Window ####
win = turtle.Screen()
win.bgcolor("black")
win.tracer(2)
border_pen = turtle.Turtle()
border_pen.speed(0)
border_pen.color("white")
border_pen.penup()
border_pen.setposition(-225, -225)
border_pen.pensize(3)
border_pen.pendown()
for side in range(4):
border_pen.fd(450)
border_pen.lt(90)
border_pen.hideturtle()
### Invader ###
class Invader(turtle.Turtle):
def __init__(self, xcor, ycor):
turtle.Turtle.__init__(self)
self.color("red")
self.shape("turtle")
self.penup()
self.speed(0)
self.setposition(xcor, ycor)
self.setheading(270)
self.speed(1)
self.hit = 0
### Bullet ###
bulletstate = 1
class Bullet(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.color("yellow")
self.shape("arrow")
self.shapesize(.5, 1)
self.penup()
self.speed(0)
self.setheading(90)
self.hideturtle()
self.bulletspeed = 20
fire()
def bullet_movement():
global firedb
firedb = bulletlist[-1]
firedb.speed(0)
ybul = firedb.ycor()
ybul += 10
firedb.sety(ybul)
if ybul > 195:
firedb.hideturtle()
def fire_bullet():
print("fire!")
firedb = bulletlist[-1]
firedb.hideturtle()
x = player1.xcor()
y = player1.ycor() + 20
firedb.setpos(x, y)
firedb.showturtle()
if firedb.ycor() > 200:
firedb.hideturtle()
bulletlist.remove(firedb)
def bulletmake():
bulletfire = Bullet()
def bulletmechanics():
fire()
fire_bullet()
win.listen()
win.onkey(move_left, "Left")
win.onkey(move_right, "Right")
win.onkey(fire_bullet, "space")
enemies = []
xx = -175
xxxx = -175
for invader in range(19):
if invader <= 9:
enemies.append(Invader(xx, 200))
xx += 30
if invader >= 9:
enemies.append(Invader(xxxx, 175))
xxxx += 30
playerspeed = 7
enemyspeed = 8
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
dead = []
while True:
global firedb
firedb = bulletlist[-1]
fire()
bullet_movement()
for Invader in enemies:
bullet_movement()
# if Invader.distance(firedb.xcor()+200, firedb.ycor()+200) < 1:
if isCollision(bulletlist[-1], Invader) == True:
print("AAAAAAAAGH")
isCollision(firedb, Invader)
Invader.hit += 1
if Invader.hit == 1:
Invader.color("orange")
if Invader.hit == 2:
Invader.color("yellow")
if Invader.hit == 3:
Invader.speed(0)
Invader.setpos(1000, 1000)
dead.append(Invader)
Invader.hideturtle()
for invader in enemies:
bullet_movement()
xpos = invader.xcor()
invader.speed(0)
xpos += enemyspeed
invader.setx(xpos)
if invader.xcor() > 200:
for invader in enemies:
ypos = invader.ycor()
ypos -= 40
invader.sety(ypos)
enemyspeed *= -1
if invader.xcor() < -200:
for invader in enemies:
y = invader.ycor()
y -= 40
invader.sety(y)
enemyspeed *= -1
I belive your problem is the way you interlace bullet movements with invader movements. In your while True: loop (which shouldn't exist in an event-driven world like turtle) you call bullet_movement() at the top level, then in a for loop and again within a nested for loop. So where you see the bullet and where it is relative to invaders aren't necessarily the same.
I've reworked your code, and for example purposes, simplified it in places. Along with the above issues, I've also modified the code to use turtle tilt which is perfect for this sort of game where the turtles face in one direction but move in another. And I've completely trashed your isCollision() function as turtles already know how to compute their distance from another turtle.
from turtle import Screen, Turtle
class Invader(Turtle):
def __init__(self, xcor, ycor):
super().__init__(shape="turtle")
self.color("red")
self.penup()
self.setposition(xcor, ycor)
self.tilt(-90)
self.speed('slow')
self.hit = 0
class Bullet(Turtle):
def __init__(self):
super().__init__(shape="arrow", visible=False)
self.shapesize(.5, 1)
self.color("yellow")
self.penup()
self.setheading(90)
self.speed('fastest')
self.bulletspeed = 20
def move_right():
if player.xcor() + playerspeed < 210:
player.forward(playerspeed)
def move_left():
if player.xcor() - playerspeed > -210:
player.backward(playerspeed)
def bullet_movement():
firedb.forward(10)
if firedb.ycor() > 195:
firedb.hideturtle()
def fire_bullet():
if not firedb.isvisible():
x, y = player.position()
firedb.setposition(x, y + 20)
firedb.showturtle()
def isCollision(t1, t2):
return t1.distance(t2) < 20
def move():
global enemyspeed
if firedb.isvisible():
bullet_movement()
for invader in enemies:
if firedb.isvisible() and isCollision(firedb, invader):
invader.hit += 1
if invader.hit == 1:
invader.color("orange")
elif invader.hit == 2:
invader.color("yellow")
elif invader.hit == 3:
invader.hideturtle()
enemies.remove(invader)
firedb.hideturtle() # only one hit per bullet!
invader.forward(enemyspeed)
if invader.xcor() < -200 or invader.xcor() > 200:
for invader in enemies:
y = invader.ycor() - 40
invader.sety(y)
enemyspeed *= -1
win.update()
win.ontimer(move, 50)
#### Player ####
player = Turtle("arrow")
player.color("white")
player.penup()
player.tilt(90)
player.sety(-175)
player.speed('fast')
#### Window ####
win = Screen()
win.bgcolor("black")
win.tracer(False)
border_pen = Turtle(visible=False)
border_pen.speed('fastest')
border_pen.color("white")
border_pen.pensize(3)
border_pen.penup()
border_pen.setposition(-225, -225)
border_pen.pendown()
for _ in range(4):
border_pen.forward(450)
border_pen.left(90)
### Bullet ###
firedb = Bullet()
enemies = []
xx = -175
xxxx = -190
for invader_count in range(19):
if invader_count < 9:
enemies.append(Invader(xx, 200))
xx += 30
else:
enemies.append(Invader(xxxx, 175))
xxxx += 30
playerspeed = 7
enemyspeed = 2
win.onkey(move_left, "Left")
win.onkey(move_right, "Right")
win.onkey(fire_bullet, "space")
win.listen()
move()
win.mainloop()
Finally, be careful with Python global and turtle tracer() which are routinely misunderstood.
I've created a Space Invaders clone in Python using the PyGame modules but I'm running into some difficulty getting them to move down together when reaching the edge of the game screen.
How would I make it so when the aliens reach the edge of the game screen they all simultaneously change direction and drop down a level?
import pygame
import random
class spaceInvader(pygame.sprite.Sprite):
def __init__(self):
self.image = pygame.image.load("spaceInvader.png")
self.x = 200
self.y = 390
self.shots = []
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 5
if key[pygame.K_RIGHT]:
self.x+=dist
elif key[pygame.K_LEFT]:
self.x-=dist
def draw(self, surface):
surface.blit(self.image,(self.x,self.y))
for s in self.shots:
s.draw(screen)
class Alien(pygame.sprite.Sprite):
def __init__(self,x,y,direction,alienType):
pygame.sprite.Sprite.__init__(self)
self.AlienType = alienType
self.Direction = direction
if alienType == 1:
alienImage = pygame.image.load("alien1.png")
self.Speed = 1
self.Score = 5
if alienType == 2:
alienImage = pygame.image.load("alien2.png")
self.Score = 15
self.Speed = 1
if alienType == 3:
alienImage = pygame.image.load("alien3.png")
self.Score = 10
self.Speed = 1
if alienType == 4:
alienImage = pygame.image.load("alien4.png")
self.Score = 20
self.Speed = 1
if alienType == 5:
alienImage = pygame.image.load("alien5.png")
self.Score = 25
self.Speed = 1
self.image = pygame.Surface([26, 50])
self.image.set_colorkey(black)
self.image.blit(alienImage,(0,0))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def moveAliens(self):
if self.Direction == "right":
self.rect.x += self.Speed
if self.Direction == "left":
self.rect.x -= self.Speed
pygame.init()
pygame.mouse.set_visible(False)
screen = pygame.display.set_mode([400,400])
allAliens = pygame.sprite.Group()
spaceInvader = spaceInvader()
pygame.display.set_caption("Space Attack")
background_image = pygame.image.load("Galaxy.png").convert()
pygame.mouse.set_visible(True)
done = False
clock = pygame.time.Clock()
black =( 0, 0, 0)
white =( 255,255,255)
red = (255, 0, 0)
score = 0
enemies = []
#For X coords
spawnPositions = [50,100,150,200,250,300,350]
yCoord = 10
for n in range(5):
for i in range(len(spawnPositions)):
xCoord = spawnPositions[i]
alienType = random.randint(1,5)
alien = Alien(xCoord, yCoord,"right", alienType)
allAliens.add(alien)
yCoord = yCoord + 15
loop = 0
while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
for alien in (allAliens.sprites()):
if alien.rect.x < 0:
alien.rect.y = alien.rect.y + 15
alien.Direction = "right"
if alien.rect.x > 395:
alien.rect.y = alien.rect.y + 15
alien.Direction = "left"
loop =+1
for alien in (allAliens.sprites()):
alien.moveAliens()
spaceInvader.handle_keys()
screen.blit(background_image,[0,0])
spaceInvader.draw(screen)
allAliens.draw(screen)
pygame.display.flip()
clock.tick(20)
pygame.quit()
Thanks.
Your problem lies here:
for alien in (allAliens.sprites()):
if alien.rect.x < 0:
alien.rect.y = alien.rect.y + 15
alien.Direction = "right"
if alien.rect.x > 395:
alien.rect.y = alien.rect.y + 15
alien.Direction = "left"
loop =+1
I assume the aliens are currently individually dropping down?
You need to change this so that when one alien triggers these if statements, all alien's y and direction are appropriately set, not just the one hitting the side.
# Space Invader
import turtle
import os
import random
import math
# Set up the screen.
wn = turtle.Screen()
wn.setup(700,700)
wn.bgcolor("lightblue")
wn.title("Space Invaders")
# Draw border
border = turtle.Turtle()
border.speed("fastest")
border.color("white")
border.penup()
border.setposition(-300,-270)
border.pendown()
border.pensize(3)
for side in range(4):
border.forward(560)
border.left(90)
border.hideturtle()
# Set the score to 0.
score = 0
# Draw the score.
score_pen = turtle.Turtle()
score_pen.speed("fastest")
score_pen.color("white")
score_pen.penup()
score_pen.setposition(-290,260)
scorestring = "Score: %s" %score
score_pen.write(scorestring, False, align="left", font = ("Arial",14,"normal"))
score_pen.hideturtle()
# Create the player turtle
player = turtle.Turtle()
player.color("black")
player.speed("fastest")
player.shape("triangle")
player.penup()
player.setposition(0,-265)
player.setheading(90)
playerspeed = 15
# Create enemy
#enemy = turtle.Turtle()
#enemy.shape("circle")
#enemy.color("red")
#enemy.penup()
#enemy.speed(2)
#enemy.setposition(-200,250)
#enemyspeed = 2
# Choose number of enemies.
number_of_enemies = 5
# Create an empty list of enemies.
enemies = []
# Add enemies to list.
for i in range(number_of_enemies):
# Create enemy
enemies.append(turtle.Turtle())
for enemy in enemies:
enemy.shape("circle")
enemy.color("red")
enemy.penup()
enemy.speed(2)
x = random.randint(-200,200)
y = random.randint(100,250)
enemy.setposition(x,y)
enemyspeed = 2
# Create the player's bullet.
bullet = turtle.Turtle()
bullet.color("yellow")
bullet.shape("triangle")
bullet.penup()
bullet.speed("fastest")
bullet.setheading(90)
bullet.shapesize(.5,.5)
bullet.hideturtle()
bulletspeed = 20
# Define bullet state
# ready - ready to fire
# fire - bullet is firing
bulletstate = "ready"
# Move the player left and right.
def move_left():
x = player.xcor()
x -= playerspeed
if x < -280:
x = -280
player.setx(x)
def move_right():
x = player.xcor()
x += playerspeed
if x >250:
x = 250
player.setx(x)
def fire_bullet():
# Declare the bulletstate as a global if it needs changed.
global bulletstate
if bulletstate == "ready":
bulletstate = "fire"
# Move the bullet just above the player.
x = player.xcor()
y = player.ycor() + 10
bullet.setposition(x,y)
bullet.showturtle()
def isCollision(t1,t2):
dx = t1.xcor() - t2.xcor()
dy = t1.ycor()- t2.ycor()
distance = dx**2 + dy**2
distance1 = math.sqrt(distance)
if distance1 < 15:
return True
else:
return False
# Create keyboard bindings
wn.onkey(move_left, "Left")
wn.onkey(move_right,"Right")
wn.onkey(fire_bullet,"space")
wn.listen()
# Main game loop
while True:
for enemy in enemies:
# Move enemy
x = enemy.xcor()
x += enemyspeed
enemy.setx(x)
# Move the enemy back and down
if enemy.xcor()>250:
# Move all the enemies down
for e in enemies:
y = e.ycor()
y -= 40
e.sety(y)
# Change the enemy direction
enemyspeed *= -1
if enemy.xcor()< -280:
# Move all the enemies down
for e in enemies:
y = e.ycor()
y -= 40
e.sety(y)
# change the enemy direction
enemyspeed *= -1
# Check for the collision between bullet and the enemy.
if isCollision(bullet ,enemy):
# Reset the bullet
bullet.hideturtle()
bulletstate = "ready"
bullet.setposition(0,-400)
# Reset the enemy
x = random.randint(-200,200)
y = random.randint(100,250)
enemy.setposition(x,y)
# Update the score.
score += 1
scorestring = "Score: %s" %score
score_pen.clear()
score_pen.write(scorestring, False, align = "left",font = ("Arial",14, "normal"))
if isCollision(player,enemy):
player.hideturtle()
enemy.hideturtle()
print("Game Over")
break
# Move the bullet.
if bulletstate == "fire":
y = bullet.ycor()
y += bulletspeed
bullet.sety(y)
# Check to see if the bullet has gone to the top.
if bullet.ycor() > 275:
bullet.hideturtle()
bulletstate = "ready"
turtle.mainloop()