Найти в Дзене
Реверс игры

Части игры

Несмотря на то, что игры являются приложениями, они сложны и состоят из нескольких частей. Некоторые из них включают в себя: Из-за сложности каждой части большинство игр используют внешние функции для этих частей. Эти внешние функции объединяются в то, что называется библиотекой. Затем библиотеки используются другими программами для уменьшения объема написанного кода. Например, чтобы нарисовать изображения и фигуры на экране, большинство игр используют библиотеку DirectX или OpenGL. Для некоторых типов "hcks" важно определить используемые библиотеки. Стена «hcks» — это тип «hcks», который позволяет «hcks» видеть других игроков сквозь сплошные стены. Одним из методов программирования wall"hcks" является модификация графической библиотеки игры. И OpenGL, и DirectX уязвимы к этому типу «hcks», но каждый из них требует своего подхода. Для большинства "hcks" мы будем модифицировать логику игры. Это раздел инструкции, отвечающий за то, как проходит игра. Например, логика игры будет контролир
Оглавление

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

  • Графика
  • Звуки
  • Ввод
  • Физика
  • Игровая логика

Из-за сложности каждой части большинство игр используют внешние функции для этих частей. Эти внешние функции объединяются в то, что называется библиотекой. Затем библиотеки используются другими программами для уменьшения объема написанного кода. Например, чтобы нарисовать изображения и фигуры на экране, большинство игр используют библиотеку DirectX или OpenGL.

Для некоторых типов "hcks" важно определить используемые библиотеки. Стена «hcks» — это тип «hcks», который позволяет «hcks» видеть других игроков сквозь сплошные стены. Одним из методов программирования wall"hcks" является модификация графической библиотеки игры. И OpenGL, и DirectX уязвимы к этому типу «hcks», но каждый из них требует своего подхода.

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

Структура игры

Игровая логика состоит из инструкций, как и весь компьютерный код. Из-за сложности игр их часто пишут на языке высокого уровня и компилируют. Понимание общей структуры исходного кода часто требуется для более сложных "hcks".

Большинство игр имеют две основные функции:

  • Настройка
  • Основной цикл

Функция настройки выполняется при первом запуске игры. Он отвечает за загрузку изображений, звуков и других больших файлов с жесткого диска и размещение их в оперативной памяти. Основной цикл — это особый тип функции, который выполняется вечно, пока игрок не выйдет. Он отвечает за обработку ввода, воспроизведение звуков и обновление экрана, среди прочего. Пример основного цикла может выглядеть следующим образом:

function main_loop() {
handle_input();
update_score();
play_sound_effects();
draw_screen();
}

Все эти функции, в свою очередь, вызывают другие функции. Например, функция handle_input может выглядеть следующим образом:

function handle_input() {
if( keydown == LEFT ) {
update_player_position(GO_LEFT);
}
else if( keydown == RIGHT ) {
update_player_position(GO_RIGHT);
}
}

Каждая игра запрограммирована по-своему. В некоторых играх обновление графики может быть отдано приоритетом перед обработкой ввода. Тем не менее, во всех играх есть своего рода основной цикл.

Данные и классы

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

int money = 0;

Этот код объявляет переменную money как целое число. Как мы узнали на предыдущем уроке, целочисленные значения в C — это целые числа (например, 1, 2 или 3). Представьте, если бы нам нужно было отслеживать деньги нескольких игроков. Одним из способов сделать это может быть наличие нескольких объявлений, например:

int money1 = 0;
int money2 = 0;
int money3 = 0;
int money4 = 0;

Одним из недостатков этого подхода является то, что его трудно поддерживать, поскольку игра становится больше и сложнее. Например, чтобы написать код, увеличивающий деньги каждого игрока на 1, нам пришлось бы вручную обновить каждую переменную:

function increase_money() {
деньги1 = деньги1 + 1;
деньги2 = деньги2 + 1;
...
}

Если бы мы добавили еще одного игрока, нам пришлось бы обновлять каждый раздел кода, который изменял деньги игроков. Лучшим подходом является объявление этих значений в виде списка. Затем мы можем использовать инструкцию, известную как цикл, для перебора каждого элемента в списке. Это называется итерацией. В C списки обычно реализуются с помощью так называемого массива. Для наших целей вы можете предположить, что списки и массивы являются синонимами. Один из типов циклов в C известен как цикл for. Циклы for разделены на три сегмента: начальное значение, конечное значение и способы обновления значения после каждой итерации. Пример предыдущего кода может быть написан следующим образом:

class Player {
int money;
string name;

function increase_money() {
money = money + 1;
}
}

Теперь нам нужно будет только обновить переменную current_players, чтобы добавить поддержку другого игрока.

Чтобы упростить разработку сложных приложений, разработчики часто используют модель программирования, известную как объектно-ориентированное программирование или ООП. В ООП переменные и функции группируются в коллекции, называемые классами. Классы обычно самодостаточны. Например, во многих играх будет класс «Игрок». Этот класс будет содержать несколько переменных, таких как позиция игрока, имя или деньги. Эти переменные внутри класса называются членами. Классы также будут содержать функции для изменения этих членов. Один из примеров класса Player может выглядеть следующим образом:

class Player {
int деньги;
имя строки;
function increase_money() {
деньги = деньги + 1;
}
}

Игры часто содержат списки классов. Например, в игре Quake 3 есть массив всех игроков, которые в данный момент подключены к серверу. У каждого игрока есть свой класс игрока в игре. Чтобы рассчитать экран счета, игра пройдется по каждому игроку в списке и посмотрит на количество убийств, которые они совершили.

Память

В играх много больших ресурсов, как изображения, так и звуки. Они должны быть загружены с жесткого диска, обычно на этапе настройки игры. После загрузки они помещаются в оперативную память вместе с кодом и данными игры. Поскольку игры настолько большие, они должны постоянно загружать различные данные из оперативной памяти в регистры для работы. Эта загрузка обычно выполняется с помощью команды mov. Эта команда переместит раздел памяти в регистр. Наш increase_money пример функции, выполняемой процессором, может выглядеть следующим образом:

Функция increase_money:
mov eax, 0x12345678
Добавить EAX, 1
Mov 0x12345678, EAX

В данном примере мы используем 0x12345678 в качестве местоположения в оперативной памяти денег игрока. Большинство игр будут иметь эту структуру, но другую локацию. Для более сложных игр эти локации будут основываться на других локациях. Если бы в нашей игре был класс Player, то increase_money код, выполняемый процессором, должен был бы использовать местоположение класса Player для получения денег.

Функция increase_money:
MOV EBX, 0x12345670
МОВ ЕАК, ЭБХ + 8
Добавить EAX, 1
MOV EBX+8, EAX

В этом случае процессор должен был компенсировать расположение денег в зависимости от местоположения класса Player.

Многопользовательские клиенты

Многопользовательские игры позволяют нескольким игрокам взаимодействовать друг с другом. Для этого в многопользовательских играх используются клиенты и серверы. Пример модели клиент-сервер показан ниже:

-2

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

Информация также может быть отправлена ​​в обоих направлениях. Примером этого является перемещение игрока. Один клиент сообщит серверу, что игрок изменил свою позицию. Затем сервер сообщит всем остальным клиентам обновить свои связанные позиции для перемещенного клиента.

Многопользовательские серверы

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

Основы многопользовательской игры мы обсудим подробнее в следующем уроке.