Мегаобучалка Главная | О нас | Обратная связь


Использование массивов при программировании игр



2015-11-11 1247 Обсуждений (0)
Использование массивов при программировании игр 0.00 из 5.00 0 оценок




Идеология. Есть ли польза от массивов при программировании игр? Вопрос праздный. Массивы необходимы и для шахмат, и для шашек, и для морского боя, и для крестиков-ноликов, и для многих других игр, в особенности для тех, где игра проходит на прямоугольном поле, расчерченном на квадраты. Возьмем для примера игру против компьютера в крестики-нолики на поле размером 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 обращений к этой процедуре. Дальше думайте сами. Все это совсем не просто.

Массивы как объекты

Оказывается, массив – это объект. Объект класса Arrayпространства имен System. Как?! – скажете вы, – мы до сих пор прекрасно работали с массивами и, как говорится, «ни сном, ни духом»! Мы нигде не писали New, не пользовались свойствами и методами массивов. – Что ж, верно, многим программистам вполне можно работать с массивами и не подозревать, что это объекты. Авторы VB замаскировали этот факт (как мне кажется), чтобы не пугать программистов, переходящих с Visual Basic 6.0 на VB. Массивы-объекты рождаются в вашей программе «нечувствительно» для вас безо всякого New.

И все же, вот как можно создать массив при помощи New:

Dim a() As Integer = New Integer() {8, 1, 4, 3}

Нам будут полезны некоторые свойства и методы массивов (см. процедуру):

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

Dim a() As Integer = {80, 60, 50, 90, 40, 20, 50, 70}

Dim t(,) As Integer = {{99, 99, 99, 99, 99}, {99, -8, -14, -19, -18}, {99, 25, 28, 26, 20}, {99, 11, 18, 20, 25}}

Debug.WriteLine(a.Length) 'Длина массива a (число элементов) = 8

Debug.WriteLine(t.Length) 'Длина массива t (число элементов) = 20

Debug.WriteLine(t.GetUpperBound(0)) 'Число строк (макс. индекс первого измерения) - 1 = 3

Debug.WriteLine(t.GetUpperBound(1)) 'Число столбцов (макс. индекс второго измерения) - 1 = 4

'Ищется первое вхождение числа 50 в одномерный массив a и находится его индекс (2):

Debug.WriteLine(Array.IndexOf(a, 50))

'Ищется последнее вхождение числа 50 в одномерный массив a и находится его индекс (6):

Debug.WriteLine(Array.LastIndexOf(a, 50))

Debug.WriteLine(Array.IndexOf(a, 55)) 'Ищется число 55 в массиве a и не находится (-1)

Array.Reverse(a) 'Все элементы массива a меняют порядок на обратный = {70, 50, 20, 40, 90, 50, 60, 80}

Array.Sort(a) 'Все элементы массива a сортируются по возрастанию = {20, 40, 50, 50, 60, 70, 80, 90}

Array.Clear(a, 4, 3) 'Обнуляется 3 элемента массива a, начиная с индекса 4= {20, 40, 50, 50, 0, 0, 0, 90}

End Sub

Из приведенных методов некоторые имеют несколько вариантов, которые я здесь не привожу.

Замечание. Учитывая, что массив – это объект, я призываю вас до поры не присваивать массив массиву целиком, без индексов, например, вот так:

Dim a() As Integer = {8, 1, 5, 2}

Dim b() As Integer

b = a

Присвоение, конечно, состоится, но совсем не такое, как вы ждали. Оно может привести к неожиданным для начинающих последствиям. Вот к каким, например. Продолжу фрагмент:

a(2) = 99

Debug.WriteLine(b(2))

Напечатается 99, а не 5, потому что массив – это объект. Почему? Расскажу позднее, в 27.2.

Массивы как параметры

До этого момента параметр процедуры или функции был для нас каким-то одним данным: это или одно число, или одна строка, или один объект. Но параметр может быть и массивом.

Задача: Имеется два массива, по три числа в каждом. Напечатать сумму элементов каждого массива. Использовать функцию sum, единственным параметром которой является суммируемый массив.

Программа:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim a() As Integer = {4, 10, 20}

Dim b() As Integer = {100, 40, 50}

Debug.WriteLine(sum(a))

Debug.WriteLine(sum(b))

End Sub

 

Function sum(ByVal c() As Integer) As Integer

sum = c(0) + c(1) + c(2)

End Function

Выполните программу в пошаговом режиме, глядя в окно Locals. Понаблюдайте, как массив c принимает в себя значения элементов массивов a и b.

Задание 105.

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

Указание: Создать функции Минимум(c), Максимум(c) и Разница(c).

Задание 106.

На двух метеостанциях (A и B) в течение года измерялась температура. Соответственно созданы два массива чисел длиной 365. Затем оказалось, что на обеих станциях термометры были испорчены: на станции A термометр все время показывал температуру на 2 градуса выше настоящей, а на станции B – на 3 градуса ниже. Написать процедуру с двумя параметрами, которая исправляет один произвольный массив и с ее помощью исправить оба массива. Один параметр процедуры – величина поправки, другой – массив температур.



2015-11-11 1247 Обсуждений (0)
Использование массивов при программировании игр 0.00 из 5.00 0 оценок









Обсуждение в статье: Использование массивов при программировании игр

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

Популярное:
Как распознать напряжение: Говоря о мышечном напряжении, мы в первую очередь имеем в виду мускулы, прикрепленные к костям ...
Модели организации как закрытой, открытой, частично открытой системы: Закрытая система имеет жесткие фиксированные границы, ее действия относительно независимы...



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (1247)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.008 сек.)