Придумал игру Radio Attack

Скриншот, сделанный вручную

Скриншот, сделанный вручную

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

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

Давным давно я вынашивал план создать 3d игру, где программист то ли на космической станции, то ли на дне океана на станции, ходит с отладчиком и взламывает устройства, и возможно за ним ещё монстр охотиться, и надо в страхе побыстрее что-то сделать и спрятаться в шкаф. :)

Начитавшись некоторых книг, у меня начал немного проясняться сюжет игры. Сначала я хотел сделать игру про 80-е в Америке. Для этого я задумал сделать свою операционную систему, компилятор и разные программы. Уже насоздавал некоторые модели в blender, скачал документацию по i386, распечатал, и начал изучать. В этой документации ещё предлагалось почитать руководство по системному программированию для i386. Я скачал, сходил в салон, мне сделали книгу-брошуру.

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

Читая документацию по i386, я вновь вспомнил о таких понятиях как задача, что есть специальный транслятор виртуальной памяти, который для программиста прозрачен (если я правильно помню). И только читая неделю, я понял, что мне не нужно сразу делать такой сложный эмулятор процессора, я просто сломаюсь. Нужно брать что-то попроще и делать. И так пришло решение делать свою архитектуру процессора, немного поглядывая на 8086 и процессор, который использовался в NES, 8-битный.

Я вдохновился! Сделаю более простую архитектуру эмулятора, я смогу сделать более быстрый эмулятор, так как будет требоваться меньше работы. Читая про операционные системы, я узнал, что раньше вместо ОС были так называемые мониторы. Я подумал, что может быть даже сделаю тоже монитор, а не ОС, посмотрим.

Также купив книгу по операционным системам, я также купил книгу crafting interpreters, но английский в ней для меня чуть более сложноват оказался, я понимаю только некоторые формулировки, которых вроде бы достаточно. В данный момент я не читаю ни по ОС, ни по компиляторам.

Когда я только прочитал первую и вторую главу по компиляторам, я подумал, что попробую сначала сам сделать компилятор ассемблера. Если не получиться, то буду читать.

Первая версия получилась неудобной и невозможной для поддерживания, я удалил код. Подумав над ошибками, я сделал более лучший вариант компилятора, который до сих пор делаю. Он умеет работать с метками, понимает команды, требует указывать размер для [BX + SI]. У меня свой байткод. Я решил не делать как в i386 некоторые двухбайтные операнды, каждый операнд один байт имеет плюс его разновидность. На всякий случай оставил один байт для расширения как это делается в i386, в i386 байт 0×66 служит тому, что вместо AX будет EAX. Так называемый префикс байт (если я правильно выражаюсь).

Сначала я делал компилятор вместе с эмулятором, но в последнии дни я занимаюсь только компилятором. У меня был ужасный код, я его привёл чуточку в порядок. Я понимаю, что хакеры компиляторов на многие годы усовершенствовали свой код так, что его трудно понять. Мой же код пока простой и я не могу придумать что-то более сложное и крутое. Например для описания опкодов команд я сделал так.

#define BEGIN_STRUCT_OPCODE_DEFINE() \                                                              
  14 static struct asm_code asm_code[] = {                                                               
  15                                                                                                     
  16 #define END_STRUCT_OPCODE_DEFINE() \                                                                
  17 };                                                                                                  
  18                                                                                                     
  19 #define ADD_OPCODE(lbl, level, req) \                                                               
  20     {#lbl, level, lbl, req},                                                                        
  21                                                                                                     
  22 struct asm_code {                                                                                   
  23     char *label;                                                                                    
  24     uint8_t level_rm;                                                                               
  25     uint8_t opcode;                                                                                 
  26     uint8_t req_ops;                                                                                
  27 };                                                                                                  
  28                                                                                                     
  29 BEGIN_STRUCT_OPCODE_DEFINE ()                                                                       
  30     ADD_OPCODE (INT,    IMM8, 1)                                                                    
  31     ADD_OPCODE (ADD,    RM_IMM_2, 2)                                                                
  32     ADD_OPCODE (SUB,    RM_IMM_2, 2)                                                                
  33     ADD_OPCODE (XCHG,   RM_RM_2, 2)                                                                 
  34     ADD_OPCODE (MOV,    RM_IMM_2, 2)                                                                
  35     ADD_OPCODE (MUL,    RM_1, 1)                                                                    
  36     ADD_OPCODE (DIV,    RM_1, 1)                                                                    
  37     ADD_OPCODE (INC,    RM_1, 1)                                                                    
  38     ADD_OPCODE (DEC,    RM_1, 1)                                                                    
  39     ADD_OPCODE (AND,    RM_IMM_2, 2)                                                                
  40     ADD_OPCODE (OR,     RM_IMM_2, 2)                                                                
  41     ADD_OPCODE (CLI,    VOID, 0)                   
  42     ADD_OPCODE (STI,    VOID, 0)                                                                    
  43     ADD_OPCODE (CMP,    RM_IMM_2, 2)                                                                
  44     ADD_OPCODE (XOR,    RM_IMM_2, 2)                                                                
  45     ADD_OPCODE (CLC,    VOID, 0)                                                                    
  46     ADD_OPCODE (STC,    VOID, 0)                                                                    
  47     ADD_OPCODE (CLD,    VOID, 0)                                                                    
  48     ADD_OPCODE (STD,    VOID, 0)                                                                    
  49     ADD_OPCODE (SAL,    RM_R_IMM_2, 2)                                                              
  50     ADD_OPCODE (SAR,    RM_R_IMM_2, 2)                                                              
  51     ADD_OPCODE (SHL,    RM_R_IMM_2, 2)                                                              
  52     ADD_OPCODE (SHR,    RM_R_IMM_2, 2)                                                              
  53     ADD_OPCODE (IN,     AX_R_IMM_2, 2)                                                              
  54     ADD_OPCODE (OUT,    IMM_R_AX_2, 2)                                                              
  55     ADD_OPCODE (PUSHA,  VOID, 0)                                                                    
  56     ADD_OPCODE (PUSHF,  VOID, 0)                                                                    
  57     ADD_OPCODE (POPA,   VOID, 0)                                                                    
  58     ADD_OPCODE (POPF,   VOID, 0)                                                                    
  59     ADD_OPCODE (PUSH,   RM_R_IMM_1, 1)                                                              
  60     ADD_OPCODE (POP,    RM_1, 1)                                                                    
  61     ADD_OPCODE (NEG,    RM_1, 1)                     
  62 END_STRUCT_OPCODE_DEFINE ()                                                                         
  63                                                                                                     
  64 static uint32_t size_asm_code = sizeof (asm_code) / sizeof (asm_code[0]); 

Да, я пробовал читать чужой код компиляторов, но совсем чуть-чуть, просто я не понимал вообще ничего тогда, и решил, что буду развиваться самостоятельно.

Продумывая эту игру про космос я придумал мини игру по военной симуляции. Эта идея ошеломила меня. Я подумал, а неплохо бы её выделить в отдельную игру, как раз протестирую компилятор с эмулятором.

Идея игры заключается в том, что нам нужно разработать код прошивки для каждого юнита и здания. Писать нужно на ассемблере 16-битном. Я подготовил картинки как будут выглядеть юниты.

Коллектор:

Коллектор

Коллектор

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

Сканер:

Сканер

Сканер

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

Танк:

Танк

Танк

Боевая единица, пока сказать особо нечего.

Инжектор:

Инжектор

Инжектор

Может внедрять свой код врагам, дезинформация, внедрение своих прошивок, это всё его работа.

Дрон:

Дрон

Дрон

Дрон может обнаружить вражеские юниты, если они не замаскировались. Юнит может замаскироваться полностью, то-есть если на клетке 120 единиц, то маскируются все, но можно замаскировать например 100 единиц и оставить 20 на виду. Это я прочитал в книге «Искусство войны», когда ты специально делаешь вид, что отряд слабый и тем самым привлекаешь врага в ловушку.

Доставщик:

Доставщик

Доставщик

Доставщик доставляет боеприпасы, так как у киборгов и танков они кончаемы.

Киборг:

Киборг

Киборг

Боевая единица

Ещё я подумываю сделать флот, но пока это только в планах.

Сделан кстати командный центр:

Командный центр

Командный центр

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

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

Делаю игру на своём простеньком движке с opengl. У меня ещё такое желание есть. В windows при падении приложения можно получить coredump файл. Это настраивается через реестр. Думаю сделать возможность, чтобы игроки могли скинуть мне coredump по почте или в мессенджере, чтобы я мог изучить где ошибка. Очень бы этого хотелось, но специально баг не буду делать. :)

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

https://vkplay.ru/play/game/radio_attack/

© Habrahabr.ru