#24.2 pascal Управление "сценой": примеры кода и технических приёмов для простой анимации и "игр"
Primary tabs
Задача этого урока - познакомить вас с техническими деталями, которые хотя и не входят в основную программу нашего курса базовой алгоритмической подготовки, тем не менее позволят проще управлять консольной программой, напр. не нажимая каждый раз 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;
procedure getNewPosition(var position: integer; var command: char);
begin
readln(command);
if (command = '2') then
position := position + 1
else
if (position > 1) then
position := position - 1;
end;
// *
var position: integer;
skin, command: char;
begin
skin := '*'; // внешний вид
command := '1'; // последняя введенная команда
position := 1; // текущая позиция
while(command <> 'q') do
begin
ClrScr(); // обновляем "кадр"
drawFrame(skin, position); // рисуем очередной кадр
getNewPosition(position, command); // обрабатываем ввод
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;
procedure getNewPosition(var position: integer; var command: char);
begin
command := ReadKey(); // вместо readln(command)
if (command = '2') then
position := position + 1
else
if (position > 1) then
position := position - 1;
end;
// *
var position: integer;
skin, command: char;
begin
skin := '*'; // внешний вид
command := '1'; // последняя введенная команда
position := 1; // текущая позиция
while(command <> 'q') do
begin
ClrScr(); // обновляем "кадр"
drawFrame(skin, position); // рисуем очередной кадр
getNewPosition(position, command); // обрабатываем ввод
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.
По этому коду:
- Видео разбор - обновляем сцену даже если пользователь ничего не делает
- если часто нажимать клавишу "2" (команда "вправо"), а потом перестать, то из-за задержки обработки ( в т.ч. из-за вызова Delay() в потоке ввода накопятся символы и даже после того как мы перестанем нажимать "2" (вправо) звездочка продолжить двигаться вправо, но потом стабилизируется.
Воспроизвести такое накопление символов в потоке ввода (а он условно "открыт" всегда, вне зависимости от того вызван ли его чтение в программе или нет), можно, например, с помощью кода:
uses Crt;
var a, i, j: integer;
c: char;
begin
a := 1;
// начни вводить символы с клавитуры
// используем цикл для того, чтобы успеть ввести много символов
for i:=1 to 2000 do
begin
for j:=1 to 1000000 do
a := a + 1;
a := 1;
end;
// начинаем читать поток ввода через ReadKey()
writeln('Start reading');
for i:=1 to 10 do
begin
c := ReadKey();
writeln();
writeln(c);
end;
writeln('Programma zavershena!');
readln();
end.
- Log in to post comments
- 1978 reads