Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Создание компьютерных игр


Информационный Канал Subscribe.Ru

Cоздание компьютерных игр.
Рассылка Евгения Казеко.
Выпускается еженедельно по средам.

Выпуск 8. (от 7 мая 2003 года)
Функции и структуры.

--------------------------------------------------------------

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

Я очень надеялся, что в этом выпуске появится обещанный
оружейный магазин. Но возникло затруднение - чтобы реализовать
его, пришлось бы использовать указатели, что усложнит и
без того непростую программу. Так что магазин конечно появится, но
он будет пока что закрыт. Да и лекаря не будет дома. Зато
мы сможем передвигаться по игровому миру и стучаться к ним
в двери. Кроме того, появится простейшее игровое меню.

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

Для чего нужны функции? Они нужны для того, чтобы можно было
выполнять определенный набор действий несколько раз. Например,
нам нужно создать не одного, а трех персонажей. Можно конечно
переписать три раза соответствующий кусок программы, но что если
нам нужно сто персонажей? Переписывать одно и то же сто раз
просто неразумно. Есть правда еще такая вещь, как директивы
препроцессора, но функции помимо повторения набора действий
позволяют работать с параметрами, что очень важно.

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

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

Чем объяснять все "на пальцах", лучше показать все непосредственно
в программе, поэтому переходим к ее тексту.



Текст программы:

-----------------------------------------


// Функции и структуры

// Начинаем как всегда с подключения стандартного заголовочного файла.
#include <stdio.h>


/*      Что мы привыкли видеть в этом месте программы? Функцию main и
        объявление переменных. Но сегодня мы сделаем кое-что
        до функции main. Мы создадим структуру в которой будем
        хранить характеристики игрока, а также объявим наши функции.

        Структуру мы будем создавать определением нового типа данных.
        Вот как мы это сделаем.
*/


typedef struct _PLAYER
{
        char name[25];
        int player_class;
        int health, gold, attack, defence, magic;


} PLAYER;


/*      Узнаёте? Это характеристики нашего персонажа из предыдущего примера.
        Что же касается определения структуры, сейчас мы с ним разберемся.

        Начнем с определения типа. Мы можем задать любой тип данных,
        к примеру если мы хотим, чтобы у нас был тип с названием
        player_class, то мы можем записать typedef int player_class;
        после чего вместо int player = 0; писать player_class player = 0;
        То есть мы просто "переименовали" тип int и создали на его
        основе тип player_class.

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

        Как вы уже наверное поняли, можно объявить структуру и без объявления
        типа, вот так: struct _PLAYER {набор переменных}
        Но тогда нам пришлось бы при работе со структурой каждый раз
        указывать ключевое слово struct, что не очень удобно. Поэтому
        мы и определяем тип PLAYER. Название типа должно отличаться от
        имени структуры (которое, кстати, нам не понадобится).

        А что же собственно это такое - структура? Все очень просто.
        Это всего навсего переменная, в которой содержатся другие
        переменные. Можно сказать, что структура это контейнер для
        переменных.
*/


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



PLAYER CreatePlayer();

/*      Вот таким образом мы объявили функцию. Сперва записывается
        возвращаемый тип данных. Функция CreatePlayer будет нам
        нужна для создания персонажа, и поэтому она будет возвращать
        структуру с его характеристиками (структура, как вы помните,
        имеет тип PLAYER). Далее идет название функции (CreatePlayer),
        и в скобках указываются передаваемые в функцию параметры.
        Наша функция параметров не имеет, поэтому просто ставим
        две круглые скобки.

*/


void ShowPlayerInfo(PLAYER Player);

/*      С этой функцией все наоборот. Она ничего не возвращает,
        поэтому указываем тип void, но зато в функцию будет
        передаваться в качестве параметра структура типа PLAYER.
        Имя переменной в объявлении функции может быть произвольным,
        но в нашем случае оно будет совпадать с именем реальной
        структуры Player, которую мы создадим позже.
*/




/*     А теперь опишем наши функции - определим выполняемые ими
        действия. Сперва идет заголовок функции, а затем, в
        фигурных скобках - ее описание.
*/



// Функция для создания нового персонажа

PLAYER CreatePlayer()
{
        /*      Прежде всего нужно создать переменную - структуру,
                куда мы будем записывать характеристики игрока
                при его создании. Именно эту структуру и возвратит
                функция CreatePlayer после выполнения.

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

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

        PLAYER Player;

        /*      Мы только что создали структуру, точно также,
                как мы создаем любые другие переменные, и
                задали ей имя Player. А теперь вы увидите,
                как работать с переменными структуры.
        */

        Player.player_class = 0;

        /*      Мы присвоили переменной player_class в структуре
                Player значение 0. Как видите, все очень просто -
                мы получаем доступ к переменным в структуре, записывая
                сперва имя структуры, а затем, через точку,
                имя нужной нам переменной. Кстати, в Visual C++ 6,
                когда мы пишем имя структуры и ставим точку,
                выводится список всех переменных структуры.
                Это очень удобно.
        */

        // Вводим имя персонажа

        printf("Enter player's name: ");
        scanf("%s", &Player.name);


        printf("\n");

        // Определяем класс персонажа
        while ( (Player.player_class < 1) || (Player.player_class > 3) )
        {
                printf("Choose your class (1 - warrior, 2 - mage, 3 - thief): ");
                scanf("%d", &Player.player_class);

                // Если персонаж - воин
                if (Player.player_class == 1)
                {
                        Player.health = 40;
                        Player.gold = 20;
                        Player.attack = 3;
                        Player.defence = 3;
                        Player.magic = 1;
                }

                // Если персонаж - маг
                if (Player.player_class == 2)
                {
                        Player.health = 20;
                        Player.gold = 20;
                        Player.attack = 1;
                        Player.defence = 2;
                        Player.magic = 3;
                }

                // Если персонаж - вор
                if (Player.player_class == 3)
                {
                        Player.health = 20;
                        Player.gold = 40;
                        Player.attack = 2;
                        Player.defence = 2;
                        Player.magic = 2;
                }


                if ((Player.player_class < 1) || (Player.player_class > 3))
                        printf("Wrong class. Please choose again.\n\n" );

        }       // конец цикла while


        return Player;
        // После завершения работы функции, мы возвращаем структуру
        // Player.


} // конец функции CreatePlayer()



// Функция для вывода информации об игроке

void ShowPlayerInfo(PLAYER Player)
{
        printf("\n");
        printf("Name: %s\n", Player.name);
        switch(Player.player_class)
        {
                case 1:
                        printf("Class: Warrior\n");
                        break;
                case 2:
                        printf("Class: Mage\n");
                        break;
                case 3:
                        printf("Class: Thief\n");
                        break;
                default:
                        break;
        }

        printf("Health: %d\n", Player.health);
        printf("Gold: %d\n", Player.gold);
        printf("Attack: %d\n", Player.attack);
        printf("Defence: %d\n", Player.defence);
        printf("Magic: %d\n", Player.magic);


} // конец ShowPlayerInfo




/*      А вот наконец и main! После того, как мы описали все наши
        функции и определили структуру, мы можем приступить
        непосредственно к программе. Пожалуй, будет неплохо
        сделать игровое меню с пунктами "Новая игра" и "Выход".
        Пока что будет только два пункта, плюс нам понадобится
        реализовать перемещение по игровому миру.

        А также, наконец-то мы увидим, что такое игровой цикл.
        Впервые наша программа будет работать до тех пор,
        пока мы не захотим выйти из нее.
*/

void main()
{
        // Создаем переменную Player, с которой
        // будут работать наши функции

        PLAYER Player;

        // Эта переменная понадобится для работы игрового цикла
        // и будет определять, окончена ли игра
        int game_not_over = 1;

        // Переменная для работы с игровым меню
        int selection;

        // Вот и обещанный игровой цикл
        // Он будет работать до тех пор, пока значение
        // переменной game_not_over не станет равно 0,
        // что будет означать "игра окончена"
        // Помните, что любое выражение, отличное от нуля,
        // воспринимается как истинное.

        while (game_not_over)
        {
                printf("* Game menu * \n");
                printf("1 - New Game\n");
                printf("2 - Quit\n");
                printf("Choose a number: ");

                scanf("%d", &selection);

                if (selection == 1)
                {
                        // Здесь мы вызвали нашу функцию для создания игрока.
                        Player = CreatePlayer();

                        // Цикл, реализующий передвижение по игровому миру.
                        // Мы находимся на городской площади и имеем
                        // возможность посетить лекаря, оружейный магазин,
                        // посмотреть наши характеристики или выйти из игры.
                        while (game_not_over)
                        {
                                printf("\n");
                                printf("Town Square. You can do the following:\n");
                                printf("1 - View Player info\n");
                                printf("2 - Enter Healer's House\n");
                                printf("3 - Enter Weapon Shop\n");
                                printf("4 - Quit\n\n");
                                printf("Choose a number: ");

                                scanf("%d", &selection);


                                switch(selection)
                                {
                                case 1:
                                        // А здесь мы вызвали вторую функцию
                                        // Согласитесь, при использовании функций,
                                        // программу проще читать.
                                        ShowPlayerInfo(Player);
                                        break;
                                case 2:
                                        // Лекаря нет дома
                                        printf("Healer is not home. So you go back to the square.\n");
                                        break;
                                case 3:
                                        // Магазин закрыт - до следующего выпуска
                                        printf("The shop is closed. You return to the square.\n");
                                        break;
                                case 4:
                                        game_not_over = 0;
                                        break;
                                default:
                                        printf("Wrong choise\n");
                                        break;
                                }


                        }
                }

                else
                        game_not_over = 0;



        } // конец цикла while(game_not_over)

}       // Конец программы.



-----------------------------------------


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

И наконец, пробуйте экспериментировать и писать свои
программы. Мы уже узнали очень много, познакомились
практически со всеми основными понятиями. Так что,
тренируйтесь - только так можно научиться программировать.


--------------------------------------------------------------

Архив рассылки вы найдете по адресам http://subscribe.ru/catalog/comp.games.gamecoder
и http://www.gamecoder.nm.ru/subscribe.htm.


Евгений Казеко.
kazeko@list.ru
www.gamecoder.nm.ru
-----------------------------
Рассылка "Создание компьютерных игр", выпуск 8.
Выпускается еженедельно по средам.


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное