Главная страница
Навигация по странице:

  • Глава Как раздавить жука14 278Таблица 14.1. Значения переменных xStep и yStepЛевый верхний Левый нижний Правый

  • Глава Как раздавить жука14

  • Тапком по виртуальному жуку

  • Глава Как раздавить жука14 282Figure.xFigure.y xPos yPos Рис.

  • Несколько вопросов... 1. Можно ли управлять жуком с помощью мыши и клавиа- туры2. С помощью какого модуля ты можешь получить доступ к разным математическим функциям...и задача

  • Шуман Х. - Python для детей - 2019. # Startwerte festlegen Red (255,0,0)


    Скачать 5.95 Mb.
    Название# Startwerte festlegen Red (255,0,0)
    Дата10.03.2023
    Размер5.95 Mb.
    Формат файлаpdf
    Имя файлаШуман Х. - Python для детей - 2019.pdf
    ТипДокументы
    #977830
    страница19 из 22
    1   ...   14   15   16   17   18   19   20   21   22
    Глава
    Как раздавить жука
    14
    276
    # Класс Player class Player(pg.sprite.Sprite) :
    def __init__(self, xPos=0, yPos=0) :
    super().__init__()
    self.image = pg.image.load("Bilder\Insekt1.png")
    self.x, self.y = xPos, yPos self.Bild = self.image def rotate(self, degree) :
    self.Bild = pg.transform.rotate(self.image, degree)
    def move(self, distance, xx, yy) :
    self.x += xx self.y += yy distance -= 1
    return distance
    # Установка начальных значений
    Green = (0,255,0)
    xMax, yMax = 600, 400
    distance = 0
    degree = 0
    # Запуск Pygame, создание игрового поля и персонажа pg.init()
    pg.key.set_repeat(20,20)
    Window = pg.display.set_mode((xMax, yMax))
    Figure = Player(xMax/2-50, yMax/2-50)
    # Цикл событий running = True while running :
    for event in pg.event.get() :
    if event.type == pg.QUIT :
    running = False
    # Запрос мыши if event.type == pg.MOUSEBUTTONDOWN :
    (xPos, yPos) = pg.mouse.get_pos()
    ##­­
    xDiff = xPos - Figure.x - 50
    yDiff = yPos - Figure.y - 50
    distance = sqrt(xDiff*xDiff + yDiff*yDiff)
    degree = atan2(-yDiff, xDiff)
    degree = degrees(degree) - 90
    xDiff /= distance yDiff /= distance
    Figure.rotate(degree)
    # Задержка движения if distance > 5 :
    distance = Figure.move(distance, xDiff, yDiff)
    pg.time.delay(5)

    Свободное ползание
    277
    # Положение спрайта в окне (новое)
    Window.fill(Green)
    Window.blit(Figure.Bild, (Figure.x, Figure.y))
    pg.display.update()
    # Завершение Pygame pg.quit()
    ¾
    Доработай свою программу и запусти ее. Теперь жук начнет ползать.
    На мой взгляд, получилось неплохо. Но было бы лучше, если бы жук всегда оставался полностью видимым на поле.
    И ты сможешь решить эту проблему ближе к концу главы.
    Свободное ползание
    Сейчас мы предоставим немного свободы нашей програм- ме. Как только программа запустится, жук начнет ползать самостоятельно.
    Теперь вы умеете перемещать жука, но всегда в одном на- правлении. А как насчет генерации случайных чисел?
    Давай попробуем. Начнем с импорта модуля Random:
    import random
    Ниже, непосредственно перед циклом while, мы сгенериру- ем два случайных значения переменных xStep и yStep:
    xStep = random.randint(0,2)
    yStep = random.randint(0,2)
    С помощью метода random.randint() мы получаем число в диапазоне от 0 до 1. Но если мы оставим все так, как есть, жук будет либо всегда ползти в одном направлении, либо стоять на месте. Поэтому мы должны сделать, чтобы нули становились реальными значениями шага:
    if xStep == 0 :
    xStep = ­1
    if yStep == 0 :
    yStep = ­1
    Теперь переменные xStep и yStep могут иметь четыре ком- бинации для направлений, показанные в табл. 14.1 и на рис. 14.5.

    Глава
    Как раздавить жука
    14
    278
    Таблица 14.1. Значения переменных xStep и yStep
    Левый
    верхний
    Левый
    нижний
    Правый
    верхний
    Правый
    нижний
    xStep
    –1
    –1
    +1
    +1
    yStep
    –1
    +1
    –1
    +1
    Рис. 14.5.Значения переменных xStep и yStep
    Прежде чем мы позволим жуку ползти, мы должны уста- новить пределы его движения. Как это работает, ты узнал из прошлой главы. Но здесь код выглядит по-другому (⇒
    buggy6.py):
    if (Figure.x < 0) or (Figure.x > xMax-110) :
    xStep = ­xStep if (Figure.y < 0) or (Figure.y > yMax-110) :
    yStep = ­yStep
    На первый взгляд сложно.

    Если из-за шага жук уходит слишком далеко влево или вправо, меняем размер шага по оси x.

    Если из-за шага жук уходит слишком далеко вверх или вниз, меняем размер шага по оси y.
    «Слишком далеко» означает математически меньше (<) либо больше (>). А изменение шага означает, что жук по- ворачивается и ползет обратно к границе поля. Как только жук выходит на границу поля, он просто меняет свое на- правление (рис. 14.6).

    Свободное ползание
    279
    Рис. 14.6.Схема вычислений движений жука
    Изменение направления xStep и для yStep всегда должно выполняться в двух случаях, поэтому есть два условия, свя- занных оператором or (ИЛИ). Ты уже видел его в главе 3.
    В табл. 14.2 напомню, в чем заключается разница между операторами И (and) и ИЛИ (or).
    Таблица 14.2. Разница между операторами И (and) и ИЛИ (or)
    Условие1 or Условие2
    Одно из условий должно быть выполнено
    Условие1 and Условие2 Все условия должны быть выполнены
    Теперь значения могут быть переданы методу move. Но по- скольку мы не располагаем расстоянием в виде параметра
    (и нам это не нужно), я использую метод с другим именем
    (который, разумеется, мне еще нужно определить):
    Figure.step(xStep, yStep)
    pg.time.delay(5)
    Ниже показано определение метода step (⇒ buggy6.py):
    def step(self, xx, yy) :
    self.x += xx self.y += yy

    Глава
    Как раздавить жука
    14
    280
    Перед нами, так сказать, уменьшенная версия метода move.
    Конечно, мы также сохраним это в классе Player, на всякий случай.
    Если ты сейчас запустишь программу, будет казаться, что перемещаемый жук всегда смотрит только в одном направ- лении. Поэтому мы должны задействовать поворот. Для это- го сначала определим угол, на этот раз с помощью значений переменных xStep и yStep, затем повернем (⇒ buggy6.py):
    degree = atan2(-yStep, xStep)
    degree = degrees(degree) - 90
    Figure.rotate(degree)
    Итак, эта версия программы завершена.
    ¾
    Удали все под событием мыши, где вычисляются рас- стояние и угол. Затем добавь изученный исходный код
    (⇒ buggy6.py) (рис. 14.7).
    Рис. 14.7.Новый код
    ¾
    Запусти программу и проверь ее. Ты не можешь влиять на жука. Если повороты тебя не устраивают, измени их.

    Тапком по виртуальному жуку
    281
    Тапком по виртуальному жуку
    Наблюдая за бегающим жуком, не хотел бы ты наступить на него? Более жестко: нет ли желания поймать и раздавить насекомое?
    Конечно, живого жука нам жалко, и нужно найти другое на- секомое. Я выбрал виртуального жука, которого легко най- ти и раздавить.
    В моей коллекции насекомых (которую ты можешь скачать с сай- та dmkpress.com
    ) есть файл insect2.png. Это версия нераздавлен- ного жука. Также возьми файл insect2x.png, который демонстри- рует результат «сдавливания» (рис. 14.8). (Оба они расположены в папке bilder.)
    Рис. 14.8. Файлы insect2.png и insect2x.png
    Но ты также можешь найти любых уродливых паразитов в интер- нете, если захочешь.
    Чтобы заменить жука на другого, не нужно делать сложных манипуляций. Но, помимо этого, нам понадобится еще один рисунок. Мы займемся им позже. Во-первых, давай вернемся в игру, и на этот раз насекомое не должно авто- матически бежать туда, где ты щелкнешь мышью, потому что на этот раз это будет опасно для его маленькой жизни.
    Как проверить, попала ли мышь в жука? В игре известно положение указателя мыши и жука, и их координаты долж- ны быть идентичны (рис. 14.9).

    Глава
    Как раздавить жука
    14
    282
    Figure.x
    Figure.y xPos yPos
    Рис. 14.9.Координаты жука и указателя мыши
    В частности, речь идет о проверке того, что указатель мыши находится внутри прямоугольника, где находится жук.
    Итак, нам нужны четыре условия:
    if event.type == pg.MOUSEBUTTONDOWN :
    (xPos, yPos) = pg.mouse.get_pos()
    if (xPos > Figure.x) and (xPos < Figure.x + 100) \
    and (yPos > Figure.y) and (yPos < Figure.y + 100) :
    print ("тык!")
    (Обязательно распредели длинные условия для конструк- ции if на несколько строк!)
    Я специально написал здесь инструкцию print, чтобы ты мог видеть слово «тык!» в окне, когда щелкаешь мышью по жуку.
    Все условия связаны оператором И (and). Он используется пото- му, что только когда все условия выполнены, жук раздавливается
    (рис. 14.10). В этом случае еще говорят об обнаружении столкно-
    вений, поэтому конструкцию if можно назвать монитором столк- новений. (Подробнее об этом в следующей главе.)
    Figure.x
    Figure.y
    Figure.x
    + 100
    Figure.y
    +
    100
    Рис. 14.10.Только при соблюдении
    всех условий инструкции
    в конструкции выполняются

    Управление классами
    283
    Теперь нам нужен метод Player для гибели раздавленного насекомого. Он может выглядеть так (⇒ buggy7.py):
    def destroy(self) :
    self.image = pg.image.load("Bilder\Insekt2X.png")
    self.Bild = self.image self.isKilled = True
    Сначала загружается изображение раздавленного насеко- мого, которое затем становится атрибутом Bild (для после- дующего отображения). И наконец, мне нужна еще одна переменная, isKilled = True. В методе init ей должно при- сваиваться значение false (⇒ buggy7.py):
    def __init__(self, xPos=0, yPos=0) :
    super().__init__()
    self.image = pg.image.load("Bilder\Insekt2.png")
    self.x, self.y = xPos, yPos self.Bild = self.image self.isKilled = False
    Последнее изменение влияет на область, в которой вызы- вается метод step. Таким образом мы не позволяем мерт- вому насекомому продолжать передвигаться:
    if not Figure.isKilled :
    Figure.step(xStep, yStep)
    pg.time.delay(5)
    Управление классами
    На самом деле ты уже можешь обновить свою програм- му. Но я хотел бы сделать еще одно изменение, которое не повлияет на ее работу, но позволит улучшить ее. В конце концов, возможно, что ты захочешь расширить класс Play­
    er
    , добавив некоторые атрибуты и методы. Потому что игра с жуками явно может дорабатываться.
    Кроме того, ты можешь использовать этого персонажа в других подобных играх. Это хорошая идея – поместить его код в отдельный файл, листинг которого выглядит сле- дующим образом (⇒ bplayer.py):
    import pygame as pg
    # Класс Player class Player(pg.sprite.Sprite) :

    Глава
    Как раздавить жука
    14
    284
    def __init__(self, xPos=0, yPos=0) :
    super().__init__()
    self.image = pg.image.load("Bilder\Insekt2.png")
    self.x, self.y = xPos, yPos self.Bild = self.image self.isKilled = False def rotate(self, degree) :
    self.Bild = pg.transform.rotate(self.image, degree)
    def move(self, distance, xx, yy) :
    self.x += xx self.y += yy distance -= 1
    return distance def step(self, xx, yy) :
    self.x += xx self.y += yy def destroy(self) :
    self.image = pg.image.load("Bilder\Insekt2X.png")
    self.Bild = self.image self.isKilled = True
    ¾
    Создай новый файл и скопируй в него все определения класса последней версии программы. Затем сохрани оба файла. (Если ты хочешь, то также можешь скачать этот файл на сайте dmkpress.com
    .)
    Мы не первый раз создаем отдельный файл класса. Вероятно, ты помнишь файл mplayer.py, в котором мы ранее поместили класс Player. Однако та программа была основана на библиотеке tkinter
    , поэтому тот класс нельзя использовать с Pygame. Отмечу, что может быть очень много классов для игры – так же, как су- щест вует множество разных игровых персонажей.
    Теперь основной файл стал немного «худее». Приведу так- же полный листинг для основной части программы (⇒ bug­
    gy8.py):
    import pygame as pg import random from math import *
    from bplayer import *
    # Установка начальных значений
    Green = (0,255,0)
    xMax, yMax = 600, 400
    degree = 0

    Управление классами
    285
    # Запуск Pygame, создание игрового поля и персонажа pg.init()
    pg.key.set_repeat(20,20)
    pg.display.set_caption("Моя игра")
    Window = pg.display.set_mode((xMax, yMax))
    Figure = Player(xMax/2-50, yMax/2-50)
    # Случайное направление xStep = random.randint(0,2)
    if xStep == 0 :
    xStep = ­1
    yStep = random.randint(0,2)
    if yStep == 0 :
    yStep = ­1
    # Цикл событий running = True while running :
    for event in pg.event.get() :
    if event.type == pg.QUIT :
    running = False
    # Запрос мыши if event.type == pg.MOUSEBUTTONDOWN :
    (xPos, yPos) = pg.mouse.get_pos()
    if (xPos > Figure.x) and (xPos < Figure.x + 100) \
    and (yPos > Figure.y) and (yPos < Figure.y + 100) :
    Figure.destroy()
    # Ограничение управления if (Figure.x < 0) or (Figure.x > xMax-110) :
    xStep = ­xStep if (Figure.y < 0) or (Figure.y > yMax-110) :
    yStep = ­yStep
    # Определение направления движения degree = atan2(-yStep, xStep)
    degree = degrees(degree) - 90
    Figure.rotate(degree)
    # Задержка движения if not Figure.isKilled :
    Figure.step(xStep, yStep)
    pg.time.delay(5)
    # Положение спрайта в окне (новое)
    Window.fill(Green)
    Window.blit(Figure.Bild, (Figure.x, Figure.y))
    pg.display.update()
    # Завершение Pygame pg.quit()

    Глава
    Как раздавить жука
    14
    286
    ¾
    Измени свою предыдущую программу (или используй файлы с сайта dmkpress.com
    ). Затем запусти программу и попробуй прихлопнуть жука. Если скорость высоко- вата, измени значение в функции delay() (рис. 14.11).
    Рис. 14.11.Виртуальный паразит пойман!
    В самом конце в код было добавлено нечто новое, о чем, конечно, я должен был упомянуть раньше. Но я не вижу особой необходимости присваивать окну определенный заголовок. Вот как я это сделал:
    pg.display.set_caption("Моя игра")
    Метод set_caption() берет указанный тобой текст и поме- щает его в строку заголовка окна.
    Подведение итогов
    Теперь у нас наконец есть (опять) игра. Графика, правда, не крутая, и процесс примитивен, но зато с проектом, с кото- рым можно экспериментировать и который можно расши- рить. Вот что ты узнал новенького о Pygame:

    ...и задача
    287
    set_caption()
    Устанавливает заголовок окна
    Mouse.get_pos()
    Определяет позицию указателя мыши time
    Модуль времени Pygame delay()
    Приостанавливает игру на указанное время
    Также ты познакомился с новым модулем Python и некото- рыми его методами:
    Math
    Модуль для математических формул и вычислений atan2()
    Определяет угол между двумя фрагментами пути degrees()
    Преобразует значения из радиан в градусы sqrt()
    Извлекает квадратный корень из числа
    Несколько вопросов...
    1. Можно ли управлять жуком с помощью мыши и клавиа- туры?
    2. С помощью какого модуля ты можешь получить доступ к разным математическим функциям?
    ...и задача
    1. Сделай так, чтобы жук, управляемый мышью, оставался в пределах игрового поля.

    288
    15
    Уклониться
    или проиграть
    Как насчет нового игрового проекта? Для него мы можем взять и адаптировать класс Player из последней главы.
    Смысл игры отличается от предыдущего проекта, и поэто- му нам понадобится в некоторых местах изменить класс
    Player
    На самом деле здесь есть два персонажа: один пытается поймать другого. Пока другой успевает уклоняться, игра продолжается. Поскольку оба они преследуют разные зада- чи, мы должны определить здесь два класса.
    Итак, в этой главе ты узнаешь:
    
    как написать новую игру и новый класс;
    
    как использовать две разные фигуры;
    
    кое-что об обнаружении столкновений.
    Новый персонаж
    Начнем с сюжета игры: персонаж стоит в одном месте на поле, объекты летают или катятся к нему, и он должен укло- няться, приседая или подпрыгивая (рис. 15.1). После столк- новения игра заканчивается.

    Новый персонаж
    289
    Я использовал для этого проекта название Dodger, потому что с английского это слово переводится как «Ловкач».
    Рис. 15.1.Интерфейс игры «Ловкач»
    На этот раз ты видишь игру не сверху, а сбоку. Таким обра- зом, здесь игровое поле является скорее фоном. Я оформил его так же просто, как в предыдущем проекте, используя только один сплошной цвет.
    У меня игрок находится слева (это персонаж, которым нуж- но управлять), а мяч справа перемещается к игроку. Для этого я определил две «высоты»: одна выше и одна ниже центральной линии (рис. 15.2).
    Рис. 15.2.Две «высоты» в игре
    Стоящая фигура окружена невидимым прямоугольни- ком, который должен иметь такую высоту, чтобы позже

    Глава
    Уклониться или проиграть
    15
    290
    в него вписалась фигура в прыжке. В общем, я создал три изобра жения для моего игрового объекта, как показано на рис. 15.3.
    Рис. 15.3.Три изображения игрового персонажа
    Ты можешь взять эти рисунки, если загрузишь примеры с сайта dmkpress.com
    (они также находятся в папке Bilder). Или если ты прирожденный художник, то можешь нарисовать собственные фигуры. Они должны иметь прозрачный фон и быть сохранены в формате PNG.
    Преимущество этих трех изображений: персонажу в реаль- ности не нужно двигаться, спрайт должен лишь сменить изображение. Это означает, что только мяч перемещается в этой игре. И мы посвятим новый ему класс чуть позже.
    Опять же, если ты хочешь избежать написания большого коли- чества исходного кода, то можешь загрузить файлы из предыду- щего проекта.
    Эта игра отличается, потому что есть разница между пол- зающими и односторонними жуками и фигурой, которая должна избегать препятствий. И класс Player здесь тоже сильно отличается для адаптации к типу игры.
    Взгляни на мой первый вариант класса Player (⇒ dplayer.py):
    class Player(pg.sprite.Sprite) :
    image = []
    def __init__(self, xPos=0, yPos=0) :
    super().__init__()

    Новый персонаж
    291
    self.image.append(pg.image.load("Bilder\DoStand.png"))
    self.image.append(pg.image.load("Bilder\DoDuck.png"))
    self.image.append(pg.image.load("Bilder\DoJump.png"))
    self.x, self.y = xPos, yPos self.Bild = self.image[0]
    self.isHit = False self.Status = 0
    Загрузи файл bplayer.py и сохрани его под именем dplayer.
    py. Затем добавь изображения и скорректируй определение метода init.
    Некоторые моменты знакомы, а другие совсем нет. Я пол- ностью опустил другие методы здесь (но они находятся в листинге dplayer.py). Давай подробнее рассмотрим код класса.
    Сначала создается пустой список изображений:
    image = []
    В методе init три файла изображений загружаются и встав- ляются в список:
    self.image.append(pg.image.load("Bilder\DoStand.png"))
    self.image.append(pg.image.load("Bilder\DoDuck.png"))
    self.image.append(pg.image.load("Bilder\DoJump.png"))
    Я присвоил имена трем изображениям, которые ты видел ранее в этой главе.
    Здесь, как и в прошлом проекте, я непосредственно указываю имена файлов изображений. Ты также можешь использовать име- на в списке параметров, если в дальнейшем планируешь исполь- зовать класс Player для разных игровых персонажей.
    Затем определяется положение фигуры и переменной Bild присваивается первое изображение:
    self.x, self.y = xPos, yPos self.Bild = self.image[0]
    Далее появляются два новых атрибута. Один из них – пе- ременная переключения, которая определяет, попал ли в персонажа объект (например, мяч). Исходное значение, конечно, False:

    1   ...   14   15   16   17   18   19   20   21   22


    написать администратору сайта