Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Создаем шар. Завершаем проектСодержание книги
Поиск на нашем сайте
Модуль класса clsЛовец остается прежним. Приведу в окончательном виде все остальное, а именно: модуль класса clsШар, модуль кода и модуль (окно кода) формы. Модуль кода Public Const Число_шаров = 10 Public Const Размер_шара = 200 Public Const Размер_ловца = 500 Public Const Дальность = 200 'Это расстояние, на котором ловец достает шар Public Ловец As clsЛовец 'Объявляем объект Ловец класса clsЛовец Public Шар(1 To Число_шаров) As clsШар 'Объявляем массив объектов Шар класса clsШар Модуль формы Public intЧисло_пойманных_шаров As Integer
Private Sub Form_Load() 'Эта процедура выполняется один раз при запуске проекта Dim i As Integer Randomize 'Шары должны разлетаться со случайной скоростью и в случайном направлении 'Настраиваем размеры изображений шара и ловца: imgШар(1).Height = Размер_шара imgШар(1).Width = Размер_шара imgЛовец.Height = Размер_ловца imgЛовец.Width = Размер_ловца 'Порождаем массив изображений шара: For i = 2 To Число_шаров Load imgШар(i) imgШар(i).Visible = True Next i 'Порождаем объект Ловец и массив объектов-шаров: Set Ловец = New clsЛовец For i = 1 To Число_шаров Set Шар(i) = New clsШар Next i
Начальная_установка KeyPreview = True 'Чтобы форма реагировала на клавиатуру txtСчетчик_времени.Locked = True 'Чтобы в процессе игры нельзя было вручную менять показания счетчика End Sub
Private Sub cmd_Начинай_сначала_Click() 'Что происходит при нажатии кнопки НАЧИНАЙ СНАЧАЛА Начальная_установка txtСчетчик_времени.SetFocus 'Чтобы фокус ушел с кнопки, иначе первое нажатие на стрелки клавиатуры не вызывает движения ловца End Sub
Private Sub Начальная_установка() 'Все объекты встают в исходную позицию и настраиваются на новую игру Dim i As Integer txtСчетчик_времени.Text = 0 'Обнуляем счетчик времени intЧисло_пойманных_шаров = 0 'Обнуляем число пойманных шаров
Ловец.Начальная_установка 'Ловец встает в исходную позицию и настраивается на новую игру For i = 1 To Число_шаров 'Все шары встают в исходную позицию и настраиваются на новую игру Шар(i).Начальная_установка Next i End Sub
Private Sub Timer1_Timer() 'Главная_процедура игры, выполняется один раз на каждом импульсе таймера Dim i As Integer 'Действуют все шары: For i = 1 To Число_шаров Шар(i).Действие 'Сначала объект Шар вычисляет свои координаты, imgШар(i).Left = Шар(i).x 'Затем изображение шара сдвигается на вычисленные координаты imgШар(i).Top = Шар(i).y Next i 'Действует ловец: Ловец.Действие 'Сначала объект Ловец вычисляет свои координаты, imgЛовец.Left = Ловец.x 'Затем изображение Ловца сдвигается на вычисленные координаты imgЛовец.Top = Ловец.y 'Действует счетчик времени на форме, увеличивая свои показания на 1: If intЧисло_пойманных_шаров <> Число_шаров Then txtСчетчик_времени.Text = txtСчетчик_времени.Text + 1 End Sub 'Обработка события - нажатия клавиши на клавиатуре для управления ловцом: Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) Select Case KeyCode Case vbKeyUp Ловец.Руль = вверх Case vbKeyLeft Ловец.Руль = влево Case vbKeyDown Ловец.Руль = вниз Case vbKeyRight: Ловец.Руль = вправо Case vbKeyControl: Ловец.Руль = стоп End Select End Sub
Модуль clsШар Public x As Long 'Координаты шара Public y As Long Private dx As Long 'Шаг шара по горизонтали и вертикали между двумя импульсами таймера Private dy As Long Private Макс_шаг As Long 'Максимально возможное значение шага шара
Private Sub Class_Initialize() 'Процедура, выполняющаяся при рождении шара Макс_шаг = 100 End Sub
Public Sub Начальная_установка() 'Шар встает в исходную позицию и настраивается на новую игру 'Ставим шар на исходную позицию: x = f.shpБортик.Left + f.shpБортик.Width * 3 / 4 'Она отстоит по горизонтали на четверть ширины поля от правого его края y = f.shpБортик.Top + f.shpБортик.Height / 2 'Она по вертикали расположена посредине поля 'Вычисление шага: dx = Макс_шаг * (1 - 2 * Rnd) 'Шаг по горизонтали случаен и не превосходит Макс_шаг dy = Макс_шаг * (1 - 2 * Rnd) 'Шаг по вертикали случаен и не превосходит Макс_шаг End Sub
Public Sub Действие() 'Главная_процедура шара, выполняется один раз на каждом импульсе таймера If Поймали Then Выход_шара_из_игры 'Сначала шар определяет, не поймали ли его, Отскакивать_или_нет 'затем, если бортик рядом, реагирует на него, Шаг 'и наконец делает шаг End Sub
Private Sub Отскакивать_или_нет() 'Реакция на бортик If Шар_у_пола_или_потолка Then dy = -dy 'Отскок от пола или потолка ElseIf Шар_у_стен Then dx = -dx 'Отскок от стен End If End Sub
Private Sub Шаг() x = x + dx y = y + dy End Sub
Private Function Шар_у_пола_или_потолка() As Boolean If y < f.shpБортик.Top Or y + Размер_шара > f.shpБортик.Top + f.shpБортик.Height Then Шар_у_пола_или_потолка = True Else Шар_у_пола_или_потолка = False End If End Function
Private Function Шар_у_стен() As Boolean If x < f.shpБортик.Left Or x + Размер_шара > f.shpБортик.Left + f.shpБортик.Width Then Шар_у_стен = True Else Шар_у_стен = False End If End Function
Private Function Поймали() As Boolean 'ЕСЛИ расстояние по горизонтали между центрами шара и ловца меньше Дальности 'И если расстояние по вертикали между центрами шара и ловца меньше Дальности, ТО If Abs(x - Ловец.x - ((Размер_ловца - Размер_шара) / 2)) < Дальность _ And Abs(y - Ловец.y - ((Размер_ловца - Размер_шара) / 2)) < Дальность _ Then Поймали = True Else Поймали = False End If End Function
Private Sub Выход_шара_из_игры() x = -10000: y = -10000: dx = 0: dy = 0 'Убрать шар подальше с глаз долой и чтоб не двигался f.intЧисло_пойманных_шаров = f.intЧисло_пойманных_шаров + 1 End Sub
Запустите проект. Проверьте, правильно ли он работает. Поиграйте значениями шагов ловца и шара, их размерами, числом шаров и другими величинами, подберите наиболее удобные для себя. Пояснения. Обратите внимание, что в обоих классах много одноименных переменных и процедур. Как я уже говорил чуть выше, никакой путаницы здесь произойти не может. Иметь одинаковые имена для элементов одинакового смысла удобно и правильно. В модуле формы разберитесь самостоятельно. Я думаю, что комментариев достаточно. Поговорим подробнее о модуле шара. Совершенно аналогично модулю ловца здесь имеется два метода - Начальная_установка и Действие. Метод Действие главный, он определяет, что должен делать шар в каждое мгновение своего полета. Он должен знать, поймали его или нет, и пора ли отскакивать от бортика. Этому и посвящены первые две из трех строк процедуры Действие. Эти две строки вычисляют нужным образом dx и dy, а третья строка - Шаг - изменяет в соответствии с этими значениями координаты x и y. Все, больше ничего во время движения шара делать не нужно. Теперь посмотрим, что происходит при нажатии на кнопку "Начинай сначала". Выполняется процедура cmd_Начинай_сначала_Click и после пары прыжков по процедурам Visual Basic передает управление процедуре Начальная_установка каждого шара. Здесь трудности у вас может вызвать вычисление dx и dy. Поскольку значение Rnd есть случайное число в диапазоне от 0 до 1, то легко видеть, что как dx, так и dy будут случайными числами в диапазоне от -100 до 100. Этого достаточно, чтобы шар полетел со случайной скоростью в случайном направлении. Теперь насчет отскока. Возможно, тем, кто не очень силен в математике и физике, покажется удивительным, что для отскока от горизонтальной преграды достаточно выполнить оператор dy = -dy, то есть поменять вертикальную составляющую шага на ее противоположное значение. "Но это действительно так!" Аналогично, достаточно выполнить оператор dx = -dx для отскока от вертикальной преграды. Чтобы лучше понять этот факт, запустите пошаговый режим при Макс_шаг=1000 и Число_шаров=1. При этом проследите внимательно за dx и dy, x и y. Недоработки проекта Замеченные мной недоработки проекта вызваны нежеланием усложнять и увеличивать в объеме его код. Вот они: · Иногда шар, вместо того, чтобы отскочить от борта, начинает двигаться скачками вдоль него. Возьмем к примеру левый бортик. Почти наверняка это связано с неточностью обработки вещественных чисел в операторе x=x+dx, в результате чего после отскока опять выполняется условие x < f.shpБортик.Left и шарик опять выполняет оператор dx = -dx. Рискну посоветовать (сам не проверял): в момент отскока незначительно увеличьте абсоютное значение шага: dx = -(dx+0.001). · Я не знаю, как поведет себя шар, попавший точно в угол. По идее, он должен там застрять. Но у меня так ни разу не было. · Постоянными нажатиями на клавиши направления мы можем передвигать ловца за пределами стола. Ни к чему это. Надо бы запретить. Еще об объектах У вас могло создаться превратное впечатление, что объект - это обязательно что-то движущееся, причем в темпе, задаваемом таймером. Совсем нет. Вспомните элементы управления - список, флажок. Это все тоже объекты. Вы можете создать класс пользователя, представляющий собой набор процедур и функций для сложной обработки информации в текстовом поле. И таймера здесь никакого не нужно. Вы знаете, что у элементов управления есть свойства, методы и события. У объекта пользователя мы изучили только свойства и методы. А события? Они тоже есть, вернее, вы можете запрограммировать их. Но останавливаться на этом я не буду. Форма как объект Ревниво оберегая и инкапсулируя объекты пользователя, мы совсем забыли о форме. Ведь это тоже объект. И не годится оставлять его незащищенным извне, то есть со стороны модулей классов и кода. Надо инкапсулировать. Все, что можно, делать Private. Кстати, мы ведь можем во время работы проекта "штамповать" нашу форму, как "штамповали" объекты по их классу. Делается это так. Добавьте в форму нашей игры кнопку Command1 и запишите в окно кода формы такую процедуру: Private Sub Command1_Click() Dim f1 As New f 'Объявляется новая форма f1 как копия формы f f1.Show 'Форма f1 загружается и показывается на экране End Sub Запустите проект и в один из моментов игры нажмите кнопку Command1. Вы увидите, что игра идет уже на двух столах, причем одна и та же игра. Подвигайте ловца, понажимайте на кнопки. Поразмыслите сами, какие это сулит возможности в будущем. Свойства только для чтения Свойства только для чтения, как я уже говорил чуть раньше, нужны для того, чтобы обезопасить наш объект от вмешательства извне. Давайте сделаем свойством только для чтения свойство x ловца. Идея здесь такая. Объявим x, как Private. Проект сразу перестает работать, так как модулю формы для смещения изображения ловца нужно знать его координаты. Придумаем нашему свойству x "псевдоним", под которым он будет виден снаружи - Xл. Вся "фишка" в том, чтобы написать в классе clsЛовец глобальную функцию с именем Xл, все тело которой состоит из единственного оператора Xл=x: Public Function Xл() As Long Xл = x End Function Теперь заменим везде снаружи обращение Ловец.x на Ловец.Xл. Поскольку обращение к переменной и функции без параметров синтаксически неотличимо, то снаружи могут сколько угодно думать, что обращаются к переменной Xл, когда на самом деле это функция. Проект работает, проверьте. А где же здесь желанная цель "только для чтения"? А она достигнута. Потому что присваивать значение функции мы можем только в ее теле, а уж никак не из других модулей. Теперь сотрите эту функцию. Создадим ее другим, общепринятым путем. Visual Basic предлагает удобный интерфейс для создания процедур, функций, событий и свойств: Tools®Add Procedure® поставьте переключатели в положение Property (так как мы хотим создать свойство) и Public, дайте имя свойству - Xл ®OK. Перед нами появятся две заготовки: Public Property Get Xл() As Variant
End Property
Public Property Let Xл(ByVal vNewValue As Variant)
End Property Слова Property Get означают "Получи (узнай) значение свойства", а слова Property Let означают "Присвой значение свойству". Нижнюю заготовку стираем, так как она предлагает записать код, позволяющий менять значение Xл снаружи. А верхнюю можно использовать вместо старой функции, заменив для порядка Variant на Long: Public Property Get Xл() As Long Xл = x End Property Здесь открывается простор для контроля со стороны объекта над желающими снаружи видеть свойство и даже для введения их в заблуждение, так как в теле свойства мы можем писать какой угодно код, например: Public Property Get Xл() As Long Xл = x + 1000 If x > 5000 Then MsgBox ("Дальше замучаю сообщениями") End Property Наследование, полиморфизм Кроме инкапсуляции у классов объектов есть еще две замечательные черты: наследование и полиморфизм. Они важны в тех проектах, где имеются не один-два класса объектов, а целые их системы, иерархии. Понятие о наследовании и полиморфизме я дам вам на уровне аналогий. Вообразим, что мы создали простой класс Автомобиль, наделив его всего лишь двигателем, рулем и 4 колесами. И никаких подробностей. Полюбовавшись работой получившейся самоходной тележки, мы решили развивать проект дальше и создать еще три класса, более богатых и подробных: Амфибия, Грузовик и Автобус. У каждого из новых классов, как и у Автомобиля, есть двигатель, руль и 4 колеса, но вдобавок к ним и много подробностей, например, у Амфибии гребной винт, а у Грузовика - кузов. Как создавать эти 3 класса? Можно так же, как мы создавали clsШар, когда мы вручную записали весь код, причем скопировав часть кода из clsЛовец. В нашем случае нам можно было бы скопировать весь код Автомобиля в каждый из трех модулей, добавив затем в них для каждого свои процедуры и функции. Но есть гораздо более удобный и "правильный" способ - это наследование. Мы просто объявляем, что новый класс Грузовик является наследником класса Автомобиль. При этом Грузовик неявно (невидимо) приобретает весь код своего родителя - Автомобиля. Ничего не записав в код Грузовика, мы уже можем пользоваться им как Автомобилем. Чтобы снабдить Грузовик дополнительными чертами, мы пишем ему новые процедуры и функции. Аналогично поступаем с Амфибией и Автобусом. Самое интересное то, что если мы изменяем что-то в коде родителя (Автомобиль), то это изменение тут же сказывается на наследниках. Например, если мы в Автомобиле заменили двигатель внутреннего сгорания на электрический, то эта замена немедленно произойдет и в Амфибии, и в Грузовике, и в Автобусе. Это очень ценное и удобное качество. Полиморфизм в частном случае - это выполнение разных действий процедурами с одинаковыми именами. Так, метод Начальная_установка шар и ловец выполняют по-разному. При наследовании полиморфизм проявляется тогда, когда мы у наследника как-то изменяем процедуру родителя. Скажем, если для Автомобиля процедура Остановка это просто остановка, то для Автобуса это еще и объявление по громкоговорителю названия остановки. В заключение должен сказать, что Visual Basic версий 6.0 и более ранних не поддерживает настоящие полиморфизм и наследование. Впервые их поддержка осуществлена в Visual Basic.NET.
|
||||
Последнее изменение этой страницы: 2016-08-12; просмотров: 258; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.227.72.24 (0.009 с.) |