Оберон-клуб «ВЄДАsoft»

Твердыня модульных языков
Текущее время: 23 фев 2019, 19:19

Часовой пояс: UTC + 2 часа




Начать новую тему Ответить на тему  [ 1 сообщение ] 
Автор Сообщение
 Заголовок сообщения: Часть пятая. Что то с памятью...
СообщениеДобавлено: 24 апр 2012, 23:40 
Не в сети
Администратор
Аватара пользователя

Сообщения: 187
Часть пятая. Что то с памятью...
Оглавление

Что то с памятью моей стало...


В прошлой части мы научились выводить в консоли различные сообщения. Теперь настало время не только читать с консольного окна но и принимать различные сообщения от внешних устройств (пока что научимся принимать сообщения от устройств ввода/вывода).

Итак давайте зададимся целью создать игру. Простенькую консольную игрушку вроде арканоида или сокобана.

ИзображениеИзображение

Для некоторых эти игры вызывают ностальгическое чувство утери прекрасного времени нашей молодости.
Ээээххх не будем о грустном, приступим к теоретическим вопросам.
Во первых графику в консоли мы можем реализовать только текстовыми символами(нет, возможна и GDI графика, но это уже будет не чистая консоль) Вот коды символов консоли для наших целей

Код: "CODE"
 
0 1 2 3 4 5 6 7 8 9 A B C D E F
B ░ ▒ ▓ │ ┤ ╡ ╢ ╖ ╕ ╣ ║ ╗ ╝ ╜ ╛ ┐
C └ ┴ ┬ ├ ─ ┼ ╞ ╟ ╚ ╔ ╩ ╦ ╠ ═ ╬ ╧
D ╨ ╤ ╥ ╙ ╘ ╒ ╓ ╫ ╪ ┘ ┌ █ ▄ ▌ ▐ ▀
 


Из этого ясно, что символу ▓ будет соответствовать код 0B2X, а символу ╟ соответственно 0С7X

В консольных приложениях есть два пути взаимодействия с пользователем. Высокоуровневый ввод/вывод и низкоуровневый.
С высокоуровневыми конструкциями WriteStr() и ReadString() мы уже знакомы по предыдущим статьям,
так что давайте рассмотрим низкоуровневые конструкции и особенности Оберон компиляторов обрабатывать данные.

Как положено в таких разработки, для приёма сообщений от операционной системы нам понадобится две вещи.
Первая - это цикл (не вечный) и вторая - это сам приёмник информации (чаще всего это функция).

Выглядеть всё наше хозяйство будет вот так

Код: "OBERON"
  1. REPEAT
  2.  
  3. W.GetNumberOfConsoleInputEvents(C.hIn,r);
  4. C.ReadConsoleData(CD);
  5.  
  6. UNTIL (CD.KeyCode=W.VK_ESCAPE) OR Exit;


Цикл мы предусмотрительно сделали с выходом по условию (забегая вперёд - или по клавише Esc или по внутреннему какому то условию)
Я не привожу здесь описаний и код всего взаимодействия, моя цель объяснить особенности наших внутренних обёрток для API операционной системы.

Отвлекусь от темы и объясню, что такое так называемая обёртка в программировании.

Посмотрим на следующую функцию

Код: "OBERON"
  1. PROCEDURE WriteStr* (str: String);
  2. VAR
  3. n,i,c:Integer;
  4. BEGIN
  5. n:=Length(str);
  6. W.WriteFile(hOut, str, n, NIL, NIL);
  7. END WriteStr;


В нутри её мы замечаем WinApi функцию WriteFile.
Так вот - обёртка это удобное представление некоих действий.
В данном случае, что бы постоянно не вычислять длину строки и не вызывать WinApi функцию вывода в консоль
мы просто написали свою и используем для вывода строк функцию WriteStr с единственным параметром - строка

Так же и библиотеки в языках высокого уровня - это всего лишь обёртки для API функций ОС.

Ну суд да дело, а кашу надо есть.
Функция WinApi - GetNumberOfConsoleInputEvents всего лишь ожидает от операционной системы сообщения (ну зачем нам гонять цикл не по делу) и затем передаёт управление далее программе.
Второй функцией мы видим C.ReadConsoleData(CD);.
Так как в секции импорта модуль консоли у нас определена как C
Код: "OBERON"
  1. IMPORT
  2. SYSTEM, C:=Console, W:=Windows;

То и функция будет в этом модуле.
Открываем наш файл Console.Mod и... ничего вменяемого кроме копирайта не находим.
Однако после многочасовых поисков в любом текстовом редакторе натыкаемся на уже известную по имени функцию
ReadConsoleData которая как мы понимаем является обёрткой для какой то функции ReadConsoleInputX, таким же макаром исследуем модуль Windows.Mod исходя из W:=Windows в секции импорта и находим её описание а так же описание похожей функции
Код: "OBERON"
  1.  
  2. ReadConsoleInput- : PROCEDURE [WINAPI] (hConsoleInput: HANDLE; VAR lpBuffer: INPUT_RECORD;
  3. nLength: LONGINT; VAR lpNumberOfEventsRead: LONGINT): BOOL;
  4. ReadConsoleInputX- : PROCEDURE [WINAPI] (hConsoleInput: HANDLE; VAR lpBuffer: INPUT_RECORD_X;
  5. nLength: LONGINT; VAR lpNumberOfEventsRead: LONGINT): BOOL;


Что за дела? Спросите вы. Почему функция ReadConsoleInput это WinApi функция которая есть в описании а ReadConsoleInputХ это какая то новая функция с изменнённым типом lpBuffer: INPUT_RECORD_X.

Сейчас я вам всё объясню.

Посмотрим на апишную структуру INPUT_RECORD

Код: "OBERON"
  1. INPUT_RECORD* = RECORD [NOTAG]
  2. EventType*: INTEGER;
  3. Event*: RECORD [union]
  4. KeyEvent* : KEY_EVENT_RECORD;
  5. MouseEvent* : MOUSE_EVENT_RECORD;
  6. WindowBufferSizeEvent* : WINDOW_BUFFER_SIZE_RECORD;
  7. MenuEvent* : MENU_EVENT_RECORD;
  8. FocusEvent* : FOCUS_EVENT_RECORD;
  9. END;
  10. END;


Поле Event определено как UNION а значит это изменяемое поле и значение его будет зависить от EventType

То есть если EventType равен нулю то запонится поле KeyEvent, если двум то заполнится поле WindowBufferSizeEvent одно но!!!

ПОЛЯ UNION НЕ ПОДДЕРЖИВАЮТСЯ В ETH Oberon КОМПИЛЯТОРЕ!!!

И что же делать? Придётся создать структуру похожую, но с массивом данных, в которые и придут данные из Api функции, а потом уже по этим данным заполнить свою структуру для удобства.

Код: "OBERON"
  1. INPUT_RECORD_X* = RECORD [NOTAG]
  2. EventType*: INTEGER;
  3. Event*: RECORD [NOTAG]
  4. Data*: ARRAY 32 OF CHAR;
  5. END;
  6. END;


Data*: ARRAY 32 OF CHAR;
Вот в этот массив имеющий длинну самой большой структуры INPUT_RECORD мы и записываем наши данные.

После этого обрабатываем их обёрткой ReadConsoleData и заполняем уже нашу структуру CONSOLE_DATA

Код: "OBERON"
  1. CONSOLE_DATA* = RECORD
  2. EventType* : LONGINT;
  3. KeyDown* : LONGINT;
  4. KeyChar* : CHAR;
  5. KeyCode* : INTEGER;
  6. MouseX* : INTEGER;
  7. MouseY* : INTEGER;
  8. MouseBState* : SET;
  9. MouseCState* : SET;
  10. MouseEState* : SET;
  11. END;


Она включает в себя коды нажатых клавиш, координаты мышки а так же статусы сообщений (нажата/отжата кнопка, нажата правая/средняя/левая кнопка мыши)

Ну вот пожалуй и всё. Основные моменты я описал в данной статье, а частные вы можете посмотреть во вложении.
Посмотреть скриншоты игры и саму игру можно скачать тут - Скриншоты и описание.

Засим консольный цикл считаю законченым, далее мы перейдем уже к проработке GUI приложений, OpenGL библиотеке и так далее.


Вложения:
Комментарий к файлу: Исходные тексты и исполняемый файл
Game.zip [43.95 КБ]
Скачиваний: 386
Вернуться к началу
 Профиль  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ 1 сообщение ] 

Часовой пояс: UTC + 2 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group
Тех.поддержка phpBB