- •6.1. Объекты – экземпляры класса 11
- •6.2. Графические объекты. Рисуем и пишем. 22
- •Глава 7. Разветвляющиеся программы 45
- •Глава 8. Циклические программы 94
- •Глава 9. Отладка программы 133
- •Глава 10. Типичные приемы программирования 144
- •10.3.1. Пример 154
- •Глава 11. Процедуры и функции 167
- •11.3. Области видимости переменных 208
- •11.4. Функции 222
- •11.5. Переменные и параметры объектного типа 239
- •Глава 12. Графика – 2 259
- •Глава 13. Работа с таймером, временем, датами 320
- •Глава 14. Работа с мышью и клавиатурой 392
- •Глава 15. Массивы, рекурсия, сортировка 440
- •Глава 16. Разные звери в одном ковчеге 479
- •Объекты – экземпляры класса
- •Понятие объекта, как экземпляра класса
- •Создаем объекты из класса
- •Невидимый код в окне кода – Windows Form Designer generated code
- •Удобство визуального программирования
- •Класс – это программа
- •Невидимые объекты
- •Графические объекты. Рисуем и пишем.
- •Класс Graphics
- •Первая нарисованная линия
- •Рисуем отрезки, прямоугольники, круги, эллипсы
- •Рисуем дуги, сектора и закрашенные фигуры
- •Рисуем на нескольких элементах управления
- •Переменные и выражения вместо чисел
- •Методы, «придирчивые» к типу параметров
- •Разветвляющиеся программы
- •Что такое выбор (ветвление)
- •Условный оператор If или как компьютер делает выбор
- •Разбираем оператор If на примерах
- •Правила записи однострочного оператора If
- •Еще примеры и задания
- •Случайные величины
- •Функции Rnd и Randomize
- •Проект «Звездное небо».
- •Многострочный If
- •Разбираем многострочный If на примерах
- •Правила записи многострочного If
- •If условие Then операторы ElseIf операторы
- •Ступенчатая запись программы
- •Вложенные операторы If. Логические операции и выражения
- •Вложенные операторы If
- •Логические операции And, Or, Not
- •Логические выражения
- •Логический тип данных Boolean
- •Оператор варианта Select Case
- •Улучшаем калькулятор
- •Проверка ввода чисел в текстовое поле
- •Запрет деления на ноль
- •Ставим пароль на калькулятор
- •Функция MsgBox
- •Циклические программы
- •Оператор перехода GoTo. Цикл. Метки
- •Цикл с GoTo. Метки
- •Зацикливание
- •Примеры
- •Движение объектов по экрану
- •Выход из цикла с помощью If
- •Операторы цикла Do
- •Оператор Do …. Loop
- •Оператор Do …. Loop While
- •Оператор Do …. Loop Until
- •Оператор Do While …. Loop
- •Оператор Do Until …. Loop
- •Разница между вариантами операторов Do
- •Примеры и задания
- •Оператор Exit Do
- •Оператор цикла While …End While
- •Оператор цикла For
- •Объясняю For на примерах
- •Шаг цикла
- •Синтаксис и работа оператора For
- •Оператор Exit For
- •«Мыльные пузыри» и другие шалости
- •Используем в рисовании переменные величины
- •Отладка программы
- •Типичные приемы программирования
- •Вычисления в цикле
- •Роль ошибок в программе
- •Счетчики и сумматоры
- •Счетчики
- •Сумматоры
- •Вложенные операторы
- •Вложенные циклы – «Таблица умножения»
- •Вложенные циклы – «Небоскреб»
- •Поиск максимума и минимума
- •Процедуры и функции
- •Процедуры
- •Понятие о процедурах пользователя
- •Пример процедуры пользователя
- •Понятие о процедурах с параметрами
- •Пример процедуры с параметрами
- •Вызов процедур из процедуры пользователя
- •Операторы Stop, End и Exit Sub
- •Проект «Парк под луной»
- •Задание на проект
- •От чисел – к переменным
- •От переменных – к параметрам
- •Делим задачу на части
- •Программируем части по-отдельности
- •Серп молодого месяца или «в час по чайной ложке»
- •Земля, пруд, три дерева и два фонаря
- •Ряд деревьев
- •Ряд фонарей и аллея
- •Два способа программирования
- •Области видимости переменных
- •Создание, инициализация и уничтожение переменных
- •Области видимости переменных
- •Зачем нужны разные области видимости
- •Область видимости – блок
- •Статические переменные
- •Функции
- •Передача параметров по ссылке и по значению
- •Из чего состоит тело процедуры. Выражения
- •Функции
- •Константы
- •Переменные и параметры объектного типа
- •Переменные объектного типа
- •Параметры объектного типа
- •Соответствие типов
- •Соответствие объектных типов
- •Неопределенные параметры, произвольное число параметров
- •Что такое методы
- •Пользуемся подсказкой, чтобы узнать объектные типы
- •Параметры методов
- •Графика – 2
- •Точки и прямоугольники
- •Прямоугольник
- •Использование Точки и Прямоугольника в графических методах
- •Собственные перья, кисти и шрифты
- •Создаем собственные перья. Конструктор
- •Создаем собственные кисти
- •Работа с картинками
- •Картинка, как свойство Image элемента управления
- •Растровая и векторная графика
- •Рисуем картинки
- •Размер и разрешение картинок
- •Метод DrawImage и его варианты
- •Метод RotateFlip объекта Bitmap
- •Метод Save объекта Bitmap
- •Рисуем в памяти
- •Перерисовка картинок, фигур и текста
- •Текстурная кисть
- •Работа с цветом
- •Системные цвета
- •Функция FromArgb
- •Прозрачность
- •Как узнать цвет точки на фотографии
- •Преобразования системы координат
- •Встроенный графический редактор vb
- •Работа с таймером, временем, датами
- •Тип данных DateTime (Date)
- •Переменные и литералы типа DateTime
- •Свойства и методы структуры DateTime
- •Свойства и методы модуля DateAndTime
- •Значения строкового параметра для функций работы с датами:
- •Форматирование даты и времени
- •Перечисления
- •Рамка (GroupBox), панель (Panel) и вкладка (TabControl)
- •Рамка (GroupBox)
- •Панель (Panel)
- •Вкладка (TabControl)
- •Проект «Будильник-секундомер»
- •Постановка задачи
- •Делим проект на части
- •Делаем часы
- •Занимаемся датой
- •Занимаемся днем недели
- •Делаем будильник
- •Делаем секундомер
- •Рисуем бордюры вокруг рамок
- •Полный текст программы «Будильник-секундомер»
- •Недоработки проекта
- •Таймер и моделирование
- •Анимация
- •Суть анимации
- •Движем объекты
- •«Движем» свойства объектов
- •Мультфильм «Летающая тарелка»
- •Мультфильм «Человечек»
- •Работа с мышью и клавиатурой
- •Фокус у элементов управления
- •Работа с мышью
- •Основные события, связанные с мышью
- •Подробности событий мыши. Класс MouseEventArgs
- •Две задачи: Глаз-ватерпас и Мышка-карандаш
- •Работа с клавиатурой
- •Событие KeyPress. Класс KeyPressEventArgs. Структура Char
- •События KeyDown и KeyUp. Класс KeyEventArgs
- •Проект – Гонки (игра)
- •Постановка задачи
- •Делим проект на части
- •Первая часть – рисуем поле для гонки
- •Вторая часть – управляем машиной
- •Третья часть – Поведение машины, организация счетчиков и пр.
- •Недоработки проекта
- •Гонки двух автомобилей
- •Задания на проекты
- •Часть III. Программирование на vb – второй уровень
- •Массивы, рекурсия, сортировка
- •Переменные с индексами
- •Одномерные массивы
- •Основы работы с одномерными массивами
- •Мощь одномерных массивов
- •Двумерные массивы
- •Какие бывают массивы
- •Использование массивов при программировании игр
- •Массивы как объекты
- •Массивы как параметры
- •Массивы элементов управления
- •Индукция. Рекурсия
- •Сортировка
- •Простая сортировка
- •Метод пузырька
- •Разные звери в одном ковчеге
- •Коллекции
- •Создание коллекции, методы коллекции
- •Оператор цикла For Each
- •Коллекции, принадлежащие контейнерам
- •Структуры
- •Оператор With
- •Алфавитный указатель
- •Специально для http://all-ebooks.Com
Какие бывают массивы
Массивы бывают не только числовые, но и строковые и типа Date и многие прочие. Например:
Dim s(50) As String
Это означает, что в каждой из 51 ячеек должно находиться не число, а произвольная строка. А объявление
Dim DT(10) As Date
означает, что в каждой из 11 ячеек должна находиться дата.
Пример. Вот элементарный пример использования строкового массива:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim s(50) As String
s(21) = "Привет"
s(22) = s(21) + " всем!!!"
Debug.WriteLine(s(22))
Debug.WriteLine(Len(s(21)))
End Sub
Вот что напечатает эта программа:
Привет всем!!!
6
Пример. Вот пример работы с массивами других типов:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim b(30, 6) As Boolean
Dim DT(10) As Date
b(2, 3) = False
b(5, 0) = Not b(2, 3)
Debug.WriteLine (b(5, 0))
DT(2) = #1/15/2003 11:59:42 PM#
DT(0) = DT(2).AddDays(10)
If b(5, 0) Then Debug.WriteLine (DT(0))
End Sub
Вот что напечатает эта программа:
True
25.01.2003 23:59:42
Еще пример:
Enum типРуль
вверх
влево
вниз
вправо
End Enum
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim Руль(300) As типРуль
Руль(200) = типРуль.влево
Руль(220) = Руль(200) + 1
Debug.WriteLine(Руль(220))
End Sub
Вот что напечатает эта программа:
вниз
Бывают массивы, состоящие из структур, объектов, но о них мы поговорим позже.
Многомерные массивы. Массивы могут быть одномерные, двумерные, трехмерные, четырехмерные и т.д.:
Dim a (10) As Integer |
-одномерный массив |
11 ячеек |
Dim a (10, 5) As Integer |
-двумерный массив |
66 ячеек (11*6) |
Dim a (9, 4, 1) As Integer |
-трехмерный массив |
100 ячеек (10*5*2) |
Dim a (9, 4, 1, 2) As Integer |
-четырехмерный массив |
300 ячеек (10*5*2*3) |
Использование массивов при программировании игр
Идеология. Есть ли польза от массивов при программировании игр? Вопрос праздный. Массивы необходимы и для шахмат, и для шашек, и для морского боя, и для крестиков-ноликов, и для многих других игр, в особенности для тех, где игра проходит на прямоугольном поле, расчерченном на квадраты. Возьмем для примера игру против компьютера в крестики-нолики на поле размером 3 на 3. Компьютеру приходится здесь рисовать на экране большие клетки, а в них – нолики (кружочки) после ваших ходов и крестики (пересекающиеся косые линии) после своих. Но этого умения недостаточно. Компьютеру ведь еще надо соображать, куда ставить крестики. А для этого нужно как минимум знать, где уже стоят крестики и нолики. А откуда он это знает? Если знание об этом хранится только на экране, то это очень неудобно, так как анализировать информацию о пикселях экрана трудно. Гораздо разумнее заранее организовать массив Dim a (3, 3) As Integer и записывать туда в нужные места нолики после ходов человека и, скажем, единички после ходов компьютера. Сразу же после записи в элемент массива нуля или единицы программа должна рисовать в соответствующем месте экрана кружок или крестик. Мыслить компьютер мог бы при помощи примерно таких операторов –
If a(1,1)=0 And a(1,2)=0 Then a(1,3)=1
Это очевидный защитный ход компьютера – на два кружочка в ряду он ставит в тот же ряд крестик.
Итак, сделаем вывод, что массив в памяти компьютера и поле для игры на экране в любой момент времени соответствуют друг другу, но компьютеру удобнее глядеть не на экран, а в память.
Проиллюстрируем идею использования массивов в играх подробнее, на специально придуманном примитивном примере (типа морского боя, но гораздо проще).
З адание на создание игры: Играют друг против друга два человека на квадратном поле размером 2 на 2:
Компьютер в игре участвует только как судья, а не как игрок.
Правила: Сначала первый игрок тайком от второго сообщает компьютеру, в каких двух клетках находятся его одноклеточные корабли (например, в правой верхней и правой нижней). Затем второй сообщает компьютеру, в какие клетки он производит два выстрела (тоже, конечно, наугад – например, в левую верхнюю и правую нижнюю). Если подбиты оба корабля – он выиграл, если подбит один – ничья, если ни одного – выиграл первый игрок.
Сначала запрограммируем эту игру без графики, а потом с графикой.
Поле боя должно быть показано на экране только один раз – после двух выстрелов, причем, если без графики, то в виде распечатки из 4 букв:
м к
о х
Здесь я использовал такие обозначения:
о - корабля здесь нет и сюда не стреляли
к - неподбитый корабль
х - подбитый корабль
м - мимо (стреляли и промахнулись)
Других вариантов быть не может. Вы видите, что приведенная распечатка отражает результат расстановки кораблей и выстрелов, описанных мной в качестве примера.
Вот программа без графики:
Dim a(2, 2) As String 'Поле боя
Dim i, j, Подбито As Integer
'Главная процедура:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
a(1, 1) = "о" : a(1, 2) = "о" 'Поначалу на поле боя кораблей нет
a(2, 1) = "о" : a(2, 2) = "о"
Устанавливаем_корабль(1)
Устанавливаем_корабль(2)
Подбито = 0 'Пока не стреляли
Выстрел(1)
Выстрел(2)
Показываем_поле_боя()
Debug.WriteLine(Подбито) 'Показываем исход битвы - количество подбитых кораблей
End Sub
Sub Устанавливаем_корабль(ByVal Номер_корабля As Integer)
i = InputBox("Первый игрок, назовите номер строки для корабля " & Номер_корабля)
j = InputBox("Первый игрок, назовите номер столбца для корабля " & Номер_корабля)
a(i, j) = "к"
End Sub
Sub Выстрел(ByVal Номер_выстрела As Integer)
i = InputBox("Второй игрок, назовите номер строки для выстрела " & Номер_выстрела)
j = InputBox("Второй игрок, назовите номер столбца для выстрела " & Номер_выстрела)
If a(i, j) = "к" Then 'Если попал, то
a(i, j) = "х" 'ставим крестик
Подбито = Подбито + 1 'и увеличиваем счетчик подбитых кораблей
ElseIf a(i, j) = "о" Then 'иначе если промахнулся, то
a(i, j) = "м" 'ставим м
End If
End Sub
Sub Показываем_поле_боя()
For i = 1 To 2
For j = 1 To 2
Debug.Write(a(i, j))
Next j
Debug.WriteLine("")
Next i
End Sub
Пояснения: Вы видите, что в качестве массива, представляющего поле для игры, я выбрал строковый массив
Dim a(2, 2) As String 'Поле боя
Теперь прочтите главную процедуру. Убедитесь, что она правильно отражает основной порядок действий в процессе игры. Затем разберитесь в процедурах Устанавливаем_корабль и Выстрел. Они с параметрами. Наконец, разберитесь в процедуре Показываем_поле_боя.
Программа не объявляет итогов боя, а всего лишь печатает количество подбитых кораблей. Определение и объявление победителя оставляю вам.
Обратите внимание, что игра мгновенно переделывается из игры на поле 2 на 2 в игру на поле, скажем, 30 на 30, простой заменой числа 2 в тексте программы на число 30. Этой возможностью мы наслаждаемся только благодаря использованию массива! В этом случае, конечно, придется в цикле записать во все клеточки поля букву «о». А если мы хотим при этом иметь больше двух кораблей и двух выстрелов, нам придется в главной процедуре обратиться в цикле к процедуре Устанавливаем_корабль и в цикле к процедуре Выстрел, что очень просто.
Если бы мы пренебрегли секретностью, то могли бы показывать поле боя после каждого хода игроков. Для этого достаточно в конец процедур Устанавливаем_корабль и Выстрел включить строку
Показываем_поле_боя()
Программа с графикой. Придумаем для простоты такую графику. Поле состоит из 4 цветных квадратов. Вот возможные цвета:
Голубой квадрат - корабля здесь нет и сюда не стреляли
Серый квадрат - неподбитый корабль
Красный квадрат - подбитый корабль
Зеленый квадрат - мимо (стреляли и промахнулись)
Замечательно, что от добавлении графики программа абсолютно не изменится за исключением единственной процедуры Показываем_поле_боя. Причем и в ней-то вся структура цикла останется неизменной. По большому счету выкинем только строку
Debug.WriteLine("")
как нужную только для текстового вывода, а строку, печатающую очередную букву из четырех:
Debug.Write(a(i, j))
заменим фрагментом, рисующим очередной квадрат из четырех. Вот новая процедура Показываем_поле_боя:
Sub Показываем_поле_боя()
Dim Размер As Integer = 100 'Размер квадрата
Dim Гр As Graphics = Me.CreateGraphics
Dim Кисть_для_воды As New SolidBrush(Color.LightBlue)
Dim Кисть_для_корабля As New SolidBrush(Color.Gray)
Dim Кисть_для_попадания As New SolidBrush(Color.Red)
Dim Кисть_для_промаха As New SolidBrush(Color.Green)
Dim Кисть As SolidBrush 'Текущая кисть для квадрата
Гр.Clear(Color.White) 'Стираем поле, нарисованное после предыдущего хода
For i = 1 To 2
For j = 1 To 2
Select Case a(i, j) 'Выбираем кисть для очередного квадрата
Case "о" : Кисть = Кисть_для_воды
Case "к" : Кисть = Кисть_для_корабля
Case "х" : Кисть = Кисть_для_попадания
Case "м" : Кисть = Кисть_для_промаха
End Select 'Рисуем очередной квадрат:
Гр.FillRectangle(Кисть, Размер * j, Размер * i, Размер, Размер)
Next j
Next i
End Sub
Пояснения: Предположим, наша процедура работает после каждого хода игроков. Мы могли бы написать ее так, чтобы после каждого очередного хода (поставили корабль или выстрелили) компьютер перерисовывал только тот квадрат, о котором шла речь. Остальные ведь остались неизменными – чего их перерисовывать? В этом случае компьютеру пришлось бы «меньше трудиться». Но я пошел по более простому и универсальному пути – после каждого хода все поле со всеми квадратами стирается и рисуется заново согласно содержимому массива a.
Кстати, строка
Гр.Clear(Color.White) 'Стираем поле, нарисованное после предыдущего хода
в нашем случае излишня. Ведь мы все равно заново перерисовываем все квадраты поля, поэтому предварительно стирать их не имеет смысла.
Крестики-нолики 3х3 – советы. В принципе вы уже готовы к программированию игры против компьютера в обычные крестики-нолики 3х3. Всю техническую сторону дела мы прошли. Остается логика, то есть объяснение компьютеру, куда ставить крестики. И вот с логикой-то у нас будет проблема. Вы скажете: Какая проблема? – ведь клеточек всего 9 штук! Один из возможных операторов уже написан:
If a(1,1)=0 And a(1,2)=0 Then a(1,3)=1
Напишу еще пару десятков подобных операторов – и дело с концом! – А пару сотен не хотите?! Вы только попробуйте перебрать все возможные варианты расстановки крестиков, ноликов и пустых клеток! Их вообще несколько тысяч. В этом случае, чтобы сократить программу, нужно применять в качестве индексов переменные величины и ломать голову над тем, какие писать процедуры, ветвления и циклы.
Поэтому любителям игр рекомендую для тренировки запрограммировать крестики-нолики не против компьютера, а как игру человека с человеком, где компьютер – лишь судья. Если получится, вот тогда можно замахнуться и на большее. Но и здесь идите постепенно. Рекомендую написать большую процедуру для правильной простановки крестика в произвольном одномерном массиве из трех клеток. У этой процедуры будет три параметра – по числу клеток. Затем заметьте, что в реальной игре 3х3 вас интересует только 8 рядов: 3 по горизонтали, 3 по вертикали и 2 по диагонали. Значит у вас будет 8 обращений к этой процедуре. Дальше думайте сами. Все это совсем не просто.