Рубрики
Без рубрики

ПОСЛЕДНЯЯ часть – научите своих детей создавать свою собственную игру с помощью Python.

учебник, который учит детей/начинающих разрабатывать знаменитую игру Space Invaders с Python.

Автор оригинала: Mustafa Anas.

Итак, без дальнейших объяснений, давайте начнем с того места, откуда мы ушли в прошлый раз. ((Нет, подожди! если вы этого не сделали, проверьте часть 1 и часть 2, а затем вернитесь сюда. Мы будем ждать!) До сих пор наш код создает главного игрока и позволяет нам перемещать его, создавать врагов и случайным образом размещать их на поле боя.

(хотите прыгнуть и увидеть окончательный результат этого урока? не стесняйтесь посетить оригинальное репо или перейти к концу этого)

Код к настоящему времени выглядит следующим образом:

import turtle

from random import randint

pen = turtle.Turtle()

turtle.register_shape("ship.gif")
turtle.register_shape("invador.gif")

pen.penup()
pen.setposition(-300,300)
pen.pendown() #this line puts the pen on the paper

for side in range(3): #see number three? its what reminds Python,  THREE times!
  pen.forward(600)
  pen.right(90)

pen.forward(600)
pen.hideturtle()

player = turtle.Turtle()
player.shape('ship.gif')
player.penup()

enemies = []
for i in range(10):
  enemies.append(turtle.Turtle())

for enemy in enemies:
  x = randint(-300, 300)
  y = randint(0, 300)
  enemy.penup()
  enemy.setposition(x, y)
  enemy.shape('invador.gif')

def moveRight():
  x = player.xcor()
  x += 10
  player.setx(x)


def moveLeft():
    x = player.xcor()
    x -= 10
    player.setx(x)  

def moveForward():
    print('something')
    y = player.ycor()
    y += 10
    player.sety(y)

def moveBackward():
    y = player.ycor()
    y -= 10
    player.sety(y)

wn = turtle.Screen()
wn.listen()

wn.onkey(moveRight, 'd')
wn.onkey(moveLeft, 'a')
wn.onkey(moveForward, 'w')
wn.onkey(moveBackward, 's')

wn.bgpic("bg.gif")

turtle.done() #this just keeps the window open until we close it.
turtle.close() #this just fixes issues related to closing the window

Здорово. А теперь давайте спланируем, что нам еще предстоит сделать, прежде чем двигаться дальше.

  • Продолжайте двигать врагов к нам до тех пор, пока они не мертвы
  • Разрешить игроку стрелять
  • Мы умрем, если враг коснется нас
  • Покажите наш счет на экране
  • Конечно же, враги умрут, если наша пуля попадет в них

Давайте разберемся с этим шаг за шагом. Сначала давайте поработаем над движением врагов. Вы можете планировать это по-разному, как пожелаете, но в этом уроке мы постараемся сделать все просто. Враги будут продолжать двигаться в правую сторону, пока не достигнут белой линии. Когда они достигнут белой линии, они спустятся к нам, снова начнут с левой стороны и двинутся к правой стороне. Каждый раз, когда враг достигает правой белой линии, он приближается к нам и начинает все сначала с левой стороны. Если он достигнет нижней части поля без того, чтобы мы его убили или он коснулся нас, он начнет все сначала с верхней части поля. Если нам удастся попасть в него пулей, мы заставим его начать все сначала с самого верха. Звучит неплохо? Давайте сделаем так, чтобы это произошло..

Переместите врагов Обратите внимание, что наша цель состоит в том, чтобы продолжать перемещать врагов в одном направлении, если они не попадут в белую линию, и в этом случае мы заставим ее снова начать с левой стороны. Итак, первый шаг состоит в том, чтобы продолжать перемещать врага. Это означает, что нам нужно написать фрагмент кода, который будет всегда выполняться. В коде мы называем это бесконечным циклом . Все, что находится внутри бесконечного цикла, продолжает работать, пока мы не скажем ему остановиться.

чтобы создать бесконечный цикл в Python, мы пишем:

while Ture:
    # this is the body of the loop

Нет, мы напишем код, который перемещает врагов в теле бесконечного цикла. Помните методы |/xcor() и ycor() мы использовали для перемещения нашего игрока? мы будем использовать те же методы для перемещения средств правовой защиты. Давайте определим скорость врагов и переместим их, написав тело цикла

enemy_speed = 30 # this is the speed of our enemies - You can change it to make them faster/slower

while True:
    for enemy in enemies: # go through the enemies one by one
        x = enemy.xcor() # get the current x location of the enemy
        x += enemy_speed # change the x location of the enemy by its speed which is 30
        enemy.setx(x) # move the enemy to its new x location

Теперь,если вы запустите этот код, вы увидите, что враги будут продолжать двигаться вправо, пока они не исчезнут с экрана. Это хорошо, но нам все равно нужно сказать врагу, что если вы попали в одну из белых линий, остановитесь, подойдите вплотную к игроку, а затем двигайтесь в противоположном направлении.

Для этого мы будем использовать оператор if . Это утверждение выполняется только в том случае, если выбранное нами условие является правильным. Наше условие – если враг ударит по одной из сторон . Как мы определяем такое условие в коде?

Легко.

Мы проверяем, что если текущее местоположение x ( xcor() ) противника равно 300 - enemy_speed . ПОДОЖДИТЕ … что?? Хорошо, давайте на секунду остановимся здесь.

Проверьте код, который вы написали ранее, чтобы нарисовать поле битвы. Видите ли вы pen.setposition(-300,300) ? это 300/-300-это x-расположение двух сторон поля. Причина, по которой мы вычитаем скорость врага, заключается в том, чтобы убедиться, что он остается на поле боя. Потому что, когда игрок находится на 270, он все равно будет двигаться на 30. Что составляет 300. ТОГДА мы сможем снова начать с другой стороны, но на шаг ближе к нам.

прежде чем мы исправим код. До сих пор мы говорили о x, чтобы переместить противника вправо. Но как мы двигаем его к себе? … Вы правы, мы должны уменьшить y, потому что мы находимся в отрицательном y, так как мы находимся в конце экрана

Теперь внутри цикла for (который находится внутри нашего бесконечного цикла) напишите это if заявление :

enemy_speed = 30 # this is the speed of our enemies - You can change it to make them faster/slower

while True:
    for enemy in enemies: 
        if enemy.xcor() > 270: # check if the enemy hit the white line
          y = enemy.ycor() # get the current y location of the enemy
          y -= 40 # change the y location of the enemy by 40
          enemy.sety(y) # move it closer to us by y which is 40
          enemy.speed(0) # this makes the transition seems instant
          enemy.setx(-270) # move the enemy to the left side again
        x = enemy.xcor() 
        x += enemy_speed 
        enemy.setx(x) 

ОТЛИЧНО! Теперь враги движутся в правильном направлении. Если вы запустите код и подождете, вы увидите, как они медленно движутся к нижней части поля боя. Но проблема в том, что они продолжают падать, пока не исчезнут с экрана. Поэтому нам нужно остановить их, когда они достигнут нижней белой линии, и заставить их снова начать с вершины. Нам нужен другой оператор if но для проверки местоположения y на этот раз:

enemy_speed = 30 # this is the speed of our enemies - You can change it to make them faster/slower

while True:
    for enemy in enemies: 
        if enemy.xcor() > 270:
            y = enemy.ycor() 
            y -= 40 
            enemy.sety(y) 
            enemy.speed(0) 
            enemy.setx(-270)

        if enemy.ycor() < -260: # check if the enemy hit the bottom white line
            y = 300  # set y to the new location at the top of the screen
            enemy.speed(0) # this makes the transition seems instant
            enemy.sety(y)  # move the enemy to the new location

        x = enemy.xcor() 
        x += enemy_speed 
        enemy.setx(x) 

Yaay 🎆 теперь наши враги двигаются идеально! Не стесняйтесь изменять значения x, y и enemy_speed, чтобы выбрать скорость, которая лучше всего подходит вам для игры.

Продолжайте двигать врагов к нам до тех пор, пока они не мертвы.

Теперь у нас все еще есть некоторая работа с врагами, так как мы хотим изменить их позицию, если в них попадет наша пуля, но это придется подождать, пока мы не заставим игрока стрелять. Так что давайте перейдем к этому сейчас.

Есть несколько вещей, которые нам нужно сделать:

  • Во-первых, поскольку все объекты в нашей игре на самом деле являются объектами черепахи, нам нужно будет создать черепаху-пулю и скрыть ее с экрана.

  • Во-вторых, мы создадим функцию, которая запускается при нажатии кнопки стрельбы (в данном случае пробел), которая отображает созданную нами пулю, переместит ее туда, где находится наш игрок, а затем заставит ее двигаться вперед.

  • В-третьих, мы создадим переменную оценки, отобразим ее на экране, а затем, если пуля коснется любого врага, мы увеличим счет на единицу, а затем переместим этого врага в верхний левый угол поля боя, чтобы начать все сначала. (Правда, наша игра заканчивается только в том случае, если мы умрем :] )

чтобы создать маркер, напишите следующий код прямо перед нашей функцией move Right() :

bullet = turtle.Turtle()
bullet.color('yellow')
bullet.penup()
bullet.speed(0)
bullet.setheading(90) #this just makes the triangular turtle head towards the top of the screen
bullet.shapesize(2, 2)
bullet.hideturtle()
bullet_speed = 50
bullet_state = 'ready' #???

Большинство приведенных выше кодов выглядят знакомыми, не так ли? Но почему именно мы добавили bullet_state? Поскольку за пулю отвечает не только одна функция, это помогает нам знать, когда мы можем стрелять, а когда нет. Цель состоит в том, чтобы стрелять по одной пуле каждый раз, когда мы попадаем в пробел. Поэтому мы изменим состояние bullet_state, как только мы попадем в бар, и изменим его снова, как только наша пуля достигнет конца поля боя. (Я понимаю, что сейчас это может не иметь большого смысла. Не беспокойтесь об этом. Вы поймете больше позже, когда мы будем использовать его)

Теперь, если вы запустите этот код, вы действительно не увидите ничего нового. Это потому, что наша пуля спрятана, и мы ее еще не показали. Давайте создадим функцию, которая срабатывает.

Прямо под нашей функцией moveBackward() добавьте это:

def fire_bullet():
    # the global word makes bullet_state accessible from whitin the function. If you remove it, the code breaks
    global bullet_state 
    if bullet_state == 'ready':
        bullet_state = 'fire'
        x = player.xcor() # get the x location of the player
        y = player.ycor() + 10 # get the y location of the player
        bullet.setposition(x, y) # move the bullet to where the player is
        bullet.showturtle() # show the bullet

Здорово. Функция теперь готова, но она не запускается. Нам нужно сказать Python, чтобы он запускался, когда мы нажимаем пробел. Ты знаешь, как это сделать правильно? Добавьте этот удар своим wn.onkey друзьям.

wn.onkey(fire_bullet, 'space')

Вот как сейчас выглядит наш игровой код:

import turtle

from random import randint

pen = turtle.Turtle()

turtle.register_shape("ship.gif")
turtle.register_shape("invador.gif")

pen.penup()
pen.setposition(-300,300)
pen.pendown() #this line puts the pen on the paper

for side in range(3): #see number three? its what reminds Python,  THREE times!
  pen.forward(600)
  pen.right(90)

pen.forward(600)
pen.hideturtle()

player = turtle.Turtle()
player.shape('ship.gif')
player.penup()

enemies = []
for i in range(10):
  enemies.append(turtle.Turtle())

for enemy in enemies:
  x = randint(-300, 300)
  y = randint(0, 300)
  enemy.penup()
  enemy.setposition(x, y)
  enemy.shape('invador.gif')

bullet = turtle.Turtle()
bullet.color('yellow')
bullet.penup()
bullet.speed(0)
bullet.setheading(90) #this just makes the triangular turtle head towards the top of the screen
bullet.shapesize(2, 2)
bullet.hideturtle()
bullet_speed = 50
bullet_state = 'ready' #???

def moveRight():
  x = player.xcor()
  x += 10
  player.setx(x)


def moveLeft():
    x = player.xcor()
    x -= 10
    player.setx(x)  

def moveForward():
    print('something')
    y = player.ycor()
    y += 10
    player.sety(y)

def moveBackward():
    y = player.ycor()
    y -= 10
    player.sety(y)

def fire_bullet():
    # the global word makes bullet_state accessible from whitin the function. If you remove it, the code breaks
    global bullet_state 
    if bullet_state == 'ready':
        bullet_state = 'fire'
        x = player.xcor() # get the x location of the player
        y = player.ycor() + 10 # get the y location of the player
        bullet.setposition(x, y) # move the bullet to where the player is
        bullet.showturtle() # show the bullet

wn = turtle.Screen()
wn.listen()

wn.onkey(moveRight, 'd')
wn.onkey(moveLeft, 'a')
wn.onkey(moveForward, 'w')
wn.onkey(moveBackward, 's')
wn.onkey(fire_bullet, 'space')

wn.bgpic("bg.gif")

enemy_speed = 30 # this is the speed of our enemies - You can change it to make them faster/slower

while True:
    for enemy in enemies: # go through the enemies one by one
        if enemy.xcor() > 270: # check if the enemy hit the white line
          y = enemy.ycor() # get the current y location of the enemy
          y -= 40 # change the y location of the enemy by 40
          enemy.sety(y) # move it closer to us by y which is 40
          enemy.speed(0) # this makes the transition seems instant
          enemy.setx(-270) # move the enemy to the left side again

        if enemy.ycor() < -260: # check if the enemy hit the bottom white line
            y = 300  # set y to the new location at the top of the screen
            enemy.speed(0) # this makes the transition seems instant
            enemy.sety(y)  # move the enemy to the new location
        
        x = enemy.xcor() # get the current x location of the enemy
        x += enemy_speed # change the x location of the enemy by its speed which is 30
        enemy.setx(x) # move the enemy to its new x location

turtle.done() #this just keeps the window open until we close it.
turtle.close() #this just fixes issues related to closing the window

Попробуйте запустить код и нажать пробел. Что же происходит? Видишь желтую пулю? он движется?

Если вы думаете, что мы что-то пропустили или сделали что-то не так, тогда повторите это снова 😉 Эта функция не должна отвечать за перемещение пули. Он стреляет только пулей. Вот почему у нас есть переменная bullet_state . Когда мы нажимаем пробел и запускаем пулю, мы меняем ее состояние с “готово” на “огонь”. Но перемещение должно происходить в бесконечном цикле (бесконечный цикл отвечает за перемещение материала. Помните перемещение врагов?).

Теперь мы хотим сделать следующее: если состояние пули-огонь, переместите пулю наверх. Продолжайте перемещать пулю вверх, пока она не попадет либо в верхнюю белую линию, либо в одного из врагов. Если это так, измените его состояние на “готово” и снова спрячьте.

Поэтому нам нужны два новых оператора if в теле бесконечного цикла while. один, который перемещает пулю, если состояние готово, и другой, который изменяет состояние на “готово”, если пуля попадает в верхнюю белую линию (пока не беспокойтесь о попадании во врагов. Для этого мы создадим новую функцию).

Измените цикл while на этот:

while True:
    for enemy in enemies: 
        if enemy.xcor() > 270: 
          y = enemy.ycor() 
          y -= 40 
          enemy.sety(y) 
          enemy.speed(0) 
          enemy.setx(-270) 

        if enemy.ycor() < -260: 
            y = 300  
            enemy.speed(0)
            enemy.sety(y)  

        if bullet_state == 'fire': #chech if the state of the bullet is fire
            y = bullet.ycor() # get the y location of the bullet
            y += bullet_speed # increase the y location of the bullet by its speed
            bullet.sety(y) # move the bullet to the new location

        if bullet.ycor() > 275: # check if the bullet hit the top white line
            bullet.hideturtle() # hide the billet
            bullet_state = 'ready' # change its state to ready to enable the player to fire again
        
        x = enemy.xcor() 
        x += enemy_speed 
        enemy.setx(x) 

Ура, теперь мы действительно можем стрелять! Давайте теперь повредим наших врагов 😠 если пуля попадет во врага, мы хотим переместить врага обратно на вершину и увеличить счет. Чтобы узнать, произошло ли столкновение между пулей и врагом, мы создадим функцию с именем is Collision() и запустим ее в бесконечном цикле. Добавьте функцию ниже прямо над этой строкой: wn.Screen()

def isCollosion(t1, t2):
    distance = math.sqrt(math.pow(t1.xcor() - t2.xcor(), 2) + math.pow(t1.ycor() - t2.ycor(), 2))
    if distance < 35:
        return True
    else:
        return False

Приведенная выше функция немного сложна. Ожидается, что вы не поймете, как именно это работает, но вы можете спросить об этом своего родителя, если вы увлекаетесь математикой 😄 Короче говоря, функция создает круг с определенными размерами. Затем он проверяет, является ли расстояние между t1 и t2 (когда мы вызываем функцию, мы можем сделать t1 пулей, а t2 врагом) меньше 35. Если это так, значит, они достаточно близки и поэтому соприкоснулись. Кроме того, поскольку это математические вещи, нам нужно сказать Python, чтобы он принес математические инструменты (вы знаете калькуляторы и прочее), поэтому в верхней части вашего кода добавьте import math (вы что-то заметили? изменение 35 на меньшее число затрудняет попадание во врага, так как вам нужно быть более точным, а увеличение числа облегчает убийство)

Теперь пришло время запустить функцию внутри бесконечного цикла. Где-то в теле цикла for, который находится внутри цикла while, напишите это:

while True:
    for enemy in enemies: # go through the enemies one by one
        if isCollosion(bullet, enemy):
          bullet.hideturtle()
          bullet_state = 'ready' #make the state ready to allow firing again
          enemy.setposition(-300, 300)

ВСЕ РАБОТАЕТ ДЕЙСТВИТЕЛЬНО ИДЕАЛЬНО 🙌

Позвольте игроку стрелять ° Конечно, враги умрут, если наша пуля попадет в них °

Вы намного ближе к тому, чтобы стать настоящим разработчиком игр! Осталось совсем немного вещей. Нам нужно где-то показать, сколько врагов мы убили, и нам нужно остановить игру, если враг нападет на нас. Давайте начнем с первого

В верхней части нашего кода давайте создадим переменную с именем score и сделаем ее равной нулю (никаких врагов, убитых в начале!) оценка

В начале игры давайте создадим черепаху, которая записывает счет на экран:

turtle.color("white")
turtle.penup()
turtle.setposition(-300, 250)
turtle.write("Your score is: {}".format(score), move=False, align="left", font=("Arial", 18, "normal"))
turtle.hideturtle()

Здорово. Теперь нам нужно увеличивать счет каждый раз, когда происходит столкновение между пулей и врагом. Для этого нам нужно будет очистить то, что мы написали, увеличить счет и снова записать счет на экран. Итак, давайте обновим функцию is Collision() в бесконечном цикле до следующего:

if isCollosion(bullet, enemy):
    bullet.hideturtle()
    bullet_state = 'ready' #make the state ready to allow firing again
    enemy.setposition(-300, 300)
    score += 1
    turtle.clear()
    turtle.color("white")
    turtle.penup()
    turtle.setposition(-300, 250)
    turtle.write("Your score is: {}".format(score), move=False, align="left", font=("Arial", 18, "normal"))
    turtle.hideturtle()

Удивительно! теперь мы видим, сколько врагов мы уже убили. Мы почти на месте!

Покажите наш счет на экране ✔

Наш код в настоящее время выглядит следующим образом:

import turtle
import math

from random import randint

score = 0
pen = turtle.Turtle()

turtle.register_shape("ship.gif")
turtle.register_shape("invador.gif")

pen.penup()
pen.setposition(-300,300)
pen.pendown() #this line puts the pen on the paper

for side in range(3): #see number three? its what reminds Python,  THREE times!
  pen.forward(600)
  pen.right(90)

pen.forward(600)
pen.hideturtle()

player = turtle.Turtle()
player.shape('ship.gif')
player.penup()

enemies = []
for i in range(10):
  enemies.append(turtle.Turtle())

for enemy in enemies:
  x = randint(-300, 300)
  y = randint(0, 300)
  enemy.penup()
  enemy.setposition(x, y)
  enemy.shape('invador.gif')

bullet = turtle.Turtle()
bullet.color('yellow')
bullet.penup()
bullet.speed(0)
bullet.setheading(90) #this just makes the triangular turtle head towards the top of the screen
bullet.shapesize(2, 2)
bullet.hideturtle()
bullet_speed = 50
bullet_state = 'ready' #???

turtle.color("white")
turtle.penup()
turtle.setposition(-300, 250)
turtle.write("Your score is: {}".format(score), move=False, align="left", font=("Arial", 18, "normal"))
turtle.hideturtle()

def moveRight():
  x = player.xcor()
  x += 10
  player.setx(x)


def moveLeft():
    x = player.xcor()
    x -= 10
    player.setx(x)  

def moveForward():
    y = player.ycor()
    y += 10
    player.sety(y)

def moveBackward():
    y = player.ycor()
    y -= 10
    player.sety(y)

def fire_bullet():
    # the global word makes bullet_state accessible from whitin the function. If you remove it, the code breaks
    global bullet_state 
    if bullet_state == 'ready':
        bullet_state = 'fire'
        x = player.xcor() # get the x location of the player
        y = player.ycor() + 10 # get the y location of the player
        bullet.setposition(x, y) # move the bullet to where the player is
        bullet.showturtle() # show the bullet

def isCollosion(t1, t2):
    distance = math.sqrt(math.pow(t1.xcor() - t2.xcor(), 2) + math.pow(t1.ycor() - t2.ycor(), 2))
    if distance < 35:
        return True
    else:
        return False

wn = turtle.Screen()
wn.listen()

wn.onkey(moveRight, 'd')
wn.onkey(moveLeft, 'a')
wn.onkey(moveForward, 'w')
wn.onkey(moveBackward, 's')
wn.onkey(fire_bullet, 'space')

wn.bgpic("bg.gif")

enemy_speed = 30 # this is the speed of our enemies - You can change it to make them faster/slower

while True:
    for enemy in enemies: # go through the enemies one by one

        if isCollosion(bullet, enemy):
          bullet.hideturtle()
          bullet_state = 'ready' #make the state ready to allow firing again
          enemy.setposition(-300, 300)
          score += 1
          turtle.clear()
          turtle.color("white")
          turtle.penup()
          turtle.setposition(-300, 250)
          turtle.write("Your score is: {}".format(score), move=False, align="left", font=("Arial", 18, "normal"))
          turtle.hideturtle()

        if enemy.xcor() > 270: # check if the enemy hit the white line
          y = enemy.ycor() # get the current y location of the enemy
          y -= 40 # change the y location of the enemy by 40
          enemy.sety(y) # move it closer to us by y which is 40
          enemy.speed(0) # this makes the transition seems instant
          enemy.setx(-270) # move the enemy to the left side again

        if enemy.ycor() < -260: # check if the enemy hit the bottom white line
            y = 300  # set y to the new location at the top of the screen
            enemy.speed(0) # this makes the transition seems instant
            enemy.sety(y)  # move the enemy to the new location

        if bullet_state == 'fire': # check if the state of the bullet is fire
            y = bullet.ycor() # get the y location of the bullet
            y += bullet_speed # increase the y location of the bullet by its speed
            bullet.sety(y) # move the bullet to the new location

        if bullet.ycor() > 275: # check if the bullet hit the top white line
            bullet.hideturtle() # hide the billet
            bullet_state = 'ready' # change its state to ready to enable the player to fire again
        
        x = enemy.xcor() # get the current x location of the enemy
        x += enemy_speed # change the x location of the enemy by its speed which is 30
        enemy.setx(x) # move the enemy to its new x location

turtle.done() #this just keeps the window open until we close it.
turtle.close() #this just fixes issues related to closing the window

Мы всего в шаге от завершения этой игры! Нам нужно убедиться, что если кто-то из врагов коснется нас, мы остановим игру и распечатаем окончательный счет. Можете ли вы догадаться, как мы узнаем, коснулись ли мы врага?? Ах да, мы будем использовать функцию is Collision () ! Давайте вставим эту функцию в цикл for в нашем бесконечном цикле:

if isCollosion(player, enemy):
  player.hideturtle()  #hide player from the arena
  turtle.color('red')
  turtle.penup()
  turtle.setposition(0, 0)
  turtle.write("Game Over!", move=False, align="center", font=("Arial", 35, "normal"))
  turtle.setposition(0, -50) #Go to a new line      
  turtle.write("Your score is: {}".format(score), move=False, align="center", font=("Arial", 35, "normal"))
  turtle.done()  #Stop Game
  break

И это был наш последний штрих 🙋 давайте рассмотрим весь код в последний раз:

import turtle
import math

from random import randint

score = 0
pen = turtle.Turtle()

turtle.register_shape("ship.gif")
turtle.register_shape("invador.gif")

pen.penup()
pen.setposition(-300,300)
pen.pendown() #this line puts the pen on the paper

for side in range(3): #see number three? its what reminds Python,  THREE times!
  pen.forward(600)
  pen.right(90)

pen.forward(600)
pen.hideturtle()

player = turtle.Turtle()
player.shape('ship.gif')
player.penup()

enemies = []
for i in range(10):
  enemies.append(turtle.Turtle())

for enemy in enemies:
  x = randint(-300, 300)
  y = randint(0, 300)
  enemy.penup()
  enemy.setposition(x, y)
  enemy.shape('invador.gif')

bullet = turtle.Turtle()
bullet.color('yellow')
bullet.penup()
bullet.speed(0)
bullet.setheading(90) #this just makes the triangular turtle head towards the top of the screen
bullet.shapesize(2, 2)
bullet.hideturtle()
bullet_speed = 50
bullet_state = 'ready' #???

turtle.color("white")
turtle.penup()
turtle.setposition(-300, 250)
turtle.write("Your score is: {}".format(score), move=False, align="left", font=("Arial", 18, "normal"))
turtle.hideturtle()

def moveRight():
  x = player.xcor()
  x += 10
  player.setx(x)


def moveLeft():
    x = player.xcor()
    x -= 10
    player.setx(x)  

def moveForward():
    y = player.ycor()
    y += 10
    player.sety(y)

def moveBackward():
    y = player.ycor()
    y -= 10
    player.sety(y)

def fire_bullet():
    # the global word makes bullet_state accessible from whitin the function. If you remove it, the code breaks
    global bullet_state 
    if bullet_state == 'ready':
        bullet_state = 'fire'
        x = player.xcor() # get the x location of the player
        y = player.ycor() + 10 # get the y location of the player
        bullet.setposition(x, y) # move the bullet to where the player is
        bullet.showturtle() # show the bullet

def isCollosion(t1, t2):
    distance = math.sqrt(math.pow(t1.xcor() - t2.xcor(), 2) + math.pow(t1.ycor() - t2.ycor(), 2))
    if distance < 35:
        return True
    else:
        return False

wn = turtle.Screen()
wn.listen()

wn.onkey(moveRight, 'd')
wn.onkey(moveLeft, 'a')
wn.onkey(moveForward, 'w')
wn.onkey(moveBackward, 's')
wn.onkey(fire_bullet, 'space')

wn.bgpic("bg.gif")

enemy_speed = 30 # this is the speed of our enemies - You can change it to make them faster/slower

while True:
    for enemy in enemies: # go through the enemies one by one
        if isCollosion(player, enemy):
          player.hideturtle()  #hide player from the arena
          turtle.color('red')
          turtle.penup()
          turtle.setposition(0, 0)
          turtle.write("Game Over!", move=False, align="center", font=("Arial", 35, "normal"))
          turtle.setposition(0, -50) #Go to a new line      
          turtle.write("Your score is: {}".format(score), move=False, align="center", font=("Arial", 35, "normal"))
          turtle.done()  #Stop Game
          break

        if isCollosion(bullet, enemy):
          bullet.hideturtle()
          bullet_state = 'ready' #make the state ready to allow firing again
          enemy.setposition(-300, 300)
          score += 1
          turtle.clear()
          turtle.color("white")
          turtle.penup()
          turtle.setposition(-300, 250)
          turtle.write("Your score is: {}".format(score), move=False, align="left", font=("Arial", 18, "normal"))
          turtle.hideturtle()

        if enemy.xcor() > 270: # check if the enemy hit the white line
          y = enemy.ycor() # get the current y location of the enemy
          y -= 40 # change the y location of the enemy by 40
          enemy.sety(y) # move it closer to us by y which is 40
          enemy.speed(0) # this makes the transition seems instant
          enemy.setx(-270) # move the enemy to the left side again

        if enemy.ycor() < -260: # check if the enemy hit the bottom white line
            y = 300  # set y to the new location at the top of the screen
            enemy.speed(0) # this makes the transition seems instant
            enemy.sety(y)  # move the enemy to the new location

        if bullet_state == 'fire': # check if the state of the bullet is fire
            y = bullet.ycor() # get the y location of the bullet
            y += bullet_speed # increase the y location of the bullet by its speed
            bullet.sety(y) # move the bullet to the new location

        if bullet.ycor() > 275: # check if the bullet hit the top white line
            bullet.hideturtle() # hide the billet
            bullet_state = 'ready' # change its state to ready to enable the player to fire again

        x = enemy.xcor() # get the current x location of the enemy
        x += enemy_speed # change the x location of the enemy by its speed which is 30
        enemy.setx(x) # move the enemy to its new x location

turtle.done() #this just keeps the window open until we close it.
turtle.close() #this just fixes issues related to closing the window

Продолжайте двигать врагов к нам до тех пор, пока они не мертвы ✔ Позвольте игроку стрелять ✔ Мы умрем, если враг коснется нас ✔ Отобразите наш счет на экране ✔ Конечно, эмени умирают, если наша пуля попадет в них ✔

МИССИЯ ВЫПОЛНЕНА, теперь вы просто запустите ее и наслаждайтесь 🎆 🎆 🎆 !!!

На протяжении всей этой серии я получал много сообщений о поддержке от родителей, и я очень ценю, что смог заинтересовать любого ребенка. Если есть какие-либо предложения/запросы, которые вы хотите от/для меня, пожалуйста, не стесняйтесь обращаться ко мне.

Я нахожусь на пожизненной миссии, чтобы как можно больше поддерживать и вносить свой вклад в общие знания сообщества разработчиков. Некоторые из моих работ могут показаться слишком глупыми или слишком сложными, но никакое знание никогда не бывает бесполезным. Я призываю вас сделать то же самое и попытаться вернуть свое сообщество по-своему 😄 ❤️