pascal Управление "сценой": примеры кода и технических приёмов для простой анимации и "игр"

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

Почему эти детали не входят в программу - потому что научиться понимать структуру кода/основные идеи программирования можно и без них, но с ними программы будут куда более "реальными" и настоящими ;)

Прежде чем начать вникать в примеры ниже, посмотрите урок по простейшей анимации в консоли.

Пример №1 -- перемещение символа по экрану

Если использовать обычный способ ввода данных, который известен нам из курса, управлять позицией символа на виртуальной сцене мы можем как-то так:

uses Crt; //  импортираем модуль Crt

procedure drawFrame(skin: char; position: integer);
var i: integer;
begin
  for i:=1 to (position-1) do
    write(' ');
  writeln(skin);
end;

function getNewPosition(position: integer): integer;
var command: char;
begin
  readln(command);
  if (command = '2') then
    result := position + 1
  else
    if (position > 1) then
      result := position - 1;
end;

//  *
var position: integer;
  skin, command: char;
begin
  skin := '*'; // внешний вид
  command := '1'; // последняя введенная команда 
  position := 1; // текущая позиция
  while(command <> 'q') do
  begin
    ClrScr(); // обновляем "кадр"
    drawFrame(skin, position); // рисуем очередной кадр
    position := getNewPosition(position); // обрабатываем ввод
  end;

  writeln('Программа завершена!');

  readln();
end.

Пример №2 - ввод символа без нажатия Enter

Управление позицией символа можно сильно упростить, если не перейти от readln(), который требует нажатия Энтер для получения значения символьного типа к функции ReadKey() из модуля Crt:

uses Crt; //  импортираем модуль Crt

procedure drawFrame(skin: char; position: integer);
var i: integer;
begin
  for i:=1 to (position-1) do
    write(' ');
  writeln(skin);
end;

function getNewPosition(position: integer): integer;
var command: char;
begin
  command := ReadKey(); // вместо readln(command)
  if (command = '2') then
    result := position + 1
  else
    if (position > 1) then
      result := position - 1;
end;

//  *
var position: integer;
  skin, command: char;
begin
  skin := '*'; // внешний вид
  command := '1'; // последняя введенная команда
  position := 1; // текущая позиция
  while(command <> 'q') do
  begin
    ClrScr(); // обновляем "кадр"
    drawFrame(skin, position); // рисуем очередной кадр
    position := getNewPosition(position); // обрабатываем ввод
  end;

  writeln('Программа завершена!');

  readln();
end.

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

Пример №3 - Продолжаем работу программы/анимацию сцены, даже если пользователь бездействует, но при этом в готовности обработать команду

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

Перепишем предыдущий пример пример используя новую изученную возможность:

uses Crt; //  импортираем модуль Crt

procedure drawFrame(skin: char; position: integer);
var i: integer;
begin
  for i:=1 to (position-1) do
    write(' ');
  writeln(skin);
end;

procedure handleCommand(var position: integer; var command: char);
begin
  command := ReadKey(); // вместо readln(command)
  if (command = '2') then
    position += 1
  else
    if (position > 1) then
      position -= 1;
end;

//  *
var position: integer;
  skin, command: char;
begin
  skin := '*'; // внешний вид
  command := '1'; // последняя введенная команда
  position := 1; // текущая позиция
  while(command <> 'q') do
  begin
    ClrScr(); // обновляем "кадр"
    drawFrame(skin, position); // рисуем очередной кадр
    Delay(500);
    {далее высчитываем новую позицию только если клавиша нажата,
      иначе просто отрисовываем кадр заново без изменений
    }
    if (keypressed()) then
      handleCommand(position, command); // обрабатываем ввод
  end;

  writeln('Programma zavershena!');

  readln();
end.