|
20.02.2011, 23:50
|
#1
|
ПроЭктировщик
Регистрация: 19.02.2011
Сообщений: 134
Написано 81 полезных сообщений (для 219 пользователей)
|
Пример использования lib_keys (отслеживание одновременного нажатия кнопок)
Как вам, возможно, известно, MidletPascal не поддерживает одновременного определения нескольких нажатий кнопок. То есть, вы не можете поймать одновременно нажатые кнопки Вверх + Вправо, или Выбор + Вниз (к примеру). Это явно сужает диапазон игр, которые можно реализовать на MP (как факт, сразу выпадают платформеры и практически все динамические игры). Но есть очень милая библиотека Lib_keys, позволяющая получить целочисленную (точнее сказать, набор битов), определяющую текущее состояние кнопок. Эта тема посвящена работе с данной библиотекой.
Установка Для того чтобы использовать Lib_keys, нужно проделать несколько простых шагов:
1. Скачать Lib_keys (ссылка в предыдущем параграфе), и скопировать содержимое zip-папки в под-папку Libs в основной папке MidletPascal.
2. Для проэкта, которому предстоит использовать данную библиотеку, выставить тип MIDlet'а на MIDP2.0 Fullscreen. Это делается следующим образом: Для MP 2.*, в Properties\Build configurations изменить MIDlet type для всех активных конфигураций.
Для MP 3.3, в панели Project Manager поочередно для всех элементов в папке Configurations изменить MIDlet type 3. Добавить "keys" в список используемых библиотек (uses). Обычно это вторая строка программы. Если таковой нет, просто добавьте после строки 'program *;' .
Константы Основная тема библиотеки предлагает нам использовать набор констант из Lib_game, то есть:
const UP_PRESSED = 2; DOWN_PRESSED = 64; LEFT_PRESSED = 4; RIGHT_PRESSED = 32; FIRE_PRESSED = 256; GAME_A_PRESSED = 512; GAME_B_PRESSED = 1024; GAME_C_PRESSED = 2048; GAME_D_PRESSED = 4096;
Как вариант, можно использовать и свой набор констант, до тех пор пока вы понимаете что они значат, и у них правильное значение. К примеру, я использовал более короткие имена констант с одинаковым префиксом:
const key_up = 2; key_down = 64; key_left = 4; key_right = 32; key_fire = 256; key_game_a = 512; key_game_b = 1024; key_game_c = 2048; key_game_d = 4096;
Переменная » Кнопки В данном случае, лучшим вариантом будет использовать AND (И) для битового сравнения переменных. Работает это следующим образом:
5 and 4 = 1, поскольку 5 = 4 + 1, 4 есть в обоих числах, 1 есть лишь в одном числе.
6 and 9 = 0, поскольку 6 = 4 + 2, 9 = 8 + 1, совпадений нет.
То есть, чтобы проверить, есть ли константа кнопки в полученной переменной состояний, нам нужно проделать следующее:
var i, j: integer; // ... i := get_key_states; j := i and key_down; // если зажата кнопка "вниз", j = 64
Но это не очень близко к тому что (скорее всего) нам нужно, поскольку переменная не логическая, и к тому же разная по велечине для всех кнопок. Поэтому нужно, как минимум, преобразовать ее в логическую. Сделать это можно с помощью обыкновенного оператора > (больше):
var i: integer; b: boolean; // ... i := get_key_states; b := ((i and key_down) > 0); // b = true, если кнопка нажата
Используя немного знаний о приоритетах операторов в MP, или же простой метод тыка, можно обнаружить, что скобки не влияют ни на что кроме внешнего вида кода. То есть последнюю строку можно сократить до: Если же нам для каких-то целей нужно состояние кнопки в виде 0\1, то можно добавить следующую функцию:
function iand(a, b: integer): integer; begin if a and b > 0 then iand := 1 else iand := 0; end;
Теперь мы можем, к примеру, сформировать вектор "направления" кнопок-стрелок, используя следующий код:
var i, x, y: integer; // ... i := get_key_states; x := iand(i, key_right) - iand(i, key_left); y := iand(i, key_down) - iand(i, key_up);
После его выполнения, x будет указывать на смещение по горизонтали (-1..1), а y - на смещение по вертикали. То есть после этого мы можем просто домножить x и y на скорость передвижения, и прибавить их к координатам контроллируемого обьекта. Итого, для создания типичной игры, где стрелочки служат исключительно для перемещения игрока, поможет следующий код (с примером):
program keys1; // Код системы: uses keys; // используется lib_keys const // константы кнопок: key_up = 2; key_down = 64; key_left = 4; key_right = 32; key_fire = 256; key_game_a = 512; key_game_b = 1024; key_game_c = 2048; key_game_d = 4096; var key_x, key_y, key_v: integer; key_a, key_b, key_c, key_d, key_f: boolean; // iand - битовое И (возращает 1 или 0): function iand(a, b: integer): integer; begin if a and b > 0 then iand := 1 else iand := 0; end; // getkeys - процедура обновления переменных состояний кнопок. procedure getkeys; begin key_v := get_key_states; key_x := iand(key_v, key_right) - iand(key_v, key_left); key_y := iand(key_v, key_down) - iand(key_v, key_up); key_a := key_v and key_game_a > 0; key_b := key_v and key_game_b > 0; key_c := key_v and key_game_c > 0; key_d := key_v and key_game_d > 0; key_f := key_v and key_fire > 0; end; // -- Ниже идет код примера -- var x, y, s: integer; procedure mainDraw; begin setColor(239, 235, 231); fillRect(0, 0, getWidth, getHeight); setColor(0, 0, 0); fillEllipse(x - 8, y - 8, 16, 16); drawText(integerToString(key_v), 2, 2); rePaint; end; begin x := getwidth div 2; // X круга y := getheight div 2; // Y круга s := 4; // скорость передвижения mainDraw; repeat getkeys; if true then begin x := x + key_x * s; y := y + key_y * s; if key_f then begin x := random(getwidth); y := random(getheight); end; while x < 8 do x := x + getwidth + 16; while x >= getwidth + 8 do x := x - getwidth - 16; while y < 8 do y := y + getheight + 16; while y >= getheight + 8 do y := y - getheight - 16; mainDraw; end; delay(32); until false; end.
Итого...
У нас теперь есть игра с мячиком, который можно передвигать по экрану, оборачивать вокруг краев экрана и даже телепортировать!
Невиданный список возможных взаимодействий с игроком, не так ли?
Нажата, зажата, отпущена - определение состояний кнопок по одной переменной Казалось бы, как можно отловить событие нажатия или отпускания кнопки, если мы знаем лишь то, нажата ли она на данный момент? Но это можно, и более того, несложно сделать. Логика для данного алгоритма выглядит следующим образом:
Если кнопка нажата: Если ранее кнопка не была нажата: Кнопку нажали только что. Теперь кнопка нажата. Иначе(если кнопка не нажата): Если ранее кнопка была нажата: Кнопку только что отпустили. Теперь кнопка не нажата.
А код, соответсвенно:
k := get_key_states; if k and key_code > 0 then begin if not b then begin // только что была нажата кнопка end; b := true; // сейчас кнопка нажата end else begin if b then begin // только что была отпущена кнопка end; b := false; // сейчас кнопка отпущена end;
Ну и программа-пример, куда ведь без нее:
program keys2; uses keys; const key_up = 2; key_down = 64; key_left = 4; key_right = 32; key_fire = 256; key_game_a = 512; key_game_b = 1024; key_game_c = 2048; key_game_d = 4096; var k: integer; key_f, key_fp, key_fr: boolean; begin key_f := false; repeat k := get_key_states; key_fp := false; key_fr := false; if k and key_fire > 0 then begin if not key_f then begin key_fp := true; end; key_f := true; end else begin if key_f then begin key_fr := true; end; key_f := false; end; if key_fp then i := i + 2; if key_fr then i := i - 1; setColor(239, 235, 231); fillRect(0, 0, getWidth, getHeight); setColor(0, 0, 0); if key_f then setColor(255, 0, 0); drawText(integerToString(i), 2, 2); rePaint; delay(32); until false; end.
Ну, в общем-то это и все по этому поводу.
Если есть вопросы, задавайте.
Удачного создания игр
|
(Offline)
|
|
Эти 5 пользователя(ей) сказали Спасибо YellowAfterlife за это полезное сообщение:
|
|
21.02.2011, 01:14
|
#2
|
Модератор
Регистрация: 03.04.2007
Сообщений: 2,252
Написано 597 полезных сообщений (для 817 пользователей)
|
Ответ: Пример использования lib_keys (отслеживание одновременного нажатия кнопок)
Хорошие примеры, полезные, так держать!
Подобные статьи рекомендую размещать в разделе Наше Open Source Software, предназначенном специально для подобных статей.
Завтра эту тему и тему про ввод тоже туда перенесу.
|
(Offline)
|
|
25.03.2011, 20:51
|
#3
|
Оператор ЭВМ
Регистрация: 05.09.2010
Сообщений: 26
Написано 5 полезных сообщений (для 16 пользователей)
|
Ответ: Пример использования lib_keys (отслеживание одновременного нажатия кнопок)
Спасибо за пример!
Вопрос: Можно ли сделать либу, которая возврвщает событие KeyUP в виде кода кнопки (мне кажется так проще проверять одновременное нажатие кнопок)
и сделать проверку кнопок примерно так
uses (к примеру)keyup;
var up,down,left,right:boolean;
pressed:integer;
begin
pressed:=keytoaction(Getkeypressed);
if pressed=ga_UP then up:=true;
if pressed=ga_DOWN then down:=true;
if pressed=ga_LEFT then left:=true;
if pressed=ga_RIGHT then right:=true;
pressed:=keyup.keyup;
if pressed=ga_UP then up:=false;
if pressed=ga_DOWN then down:=false;
if pressed=ga_LEFT then left:=false;
if pressed=ga_RIGHT then right:=false;
if up then begin
y:=y-1;
...
end;
if down then begin
y:=y+1;
...
end;
..
..
..
И.Т.Д
end;
|
(Offline)
|
|
26.03.2011, 00:12
|
#4
|
ПроЭктировщик
Регистрация: 19.02.2011
Сообщений: 134
Написано 81 полезных сообщений (для 219 пользователей)
|
Ответ: Пример использования lib_keys (отслеживание одновременного нажатия кнопок)
Сообщение от LTS
Спасибо за пример!
Вопрос: Можно ли сделать либу, которая возврвщает событие KeyUP в виде кода кнопки (мне кажется так проще проверять одновременное нажатие кнопок)
|
Можно. Вложение.
На самом деле это вызывает одну проблему - если пользователь нажимает или отпускает две кнопки за раз, то ловится одна.
Поэтому кроме этого я добавил простую систему - GetKeyNum возращает количество нажатых в этот момент кнопок, GetKey(index) возращает индекс нажатой кнопки (index в диапазоне 1..GetKeyNum).
Библиотека не совместима с аналогичными ей (насколько я знаю, из таковых только Lib_sensor, и одна моего авторства... но я ее еще не выложил), поскольку перезаписываются события основного модуля.
Все функции:
KeyStart - инициализирует библиотеку. Желательно вставить в самое начало программы.
GetKeyLen:integer - возращает максимальное замеченное количество нажатых за раз кнопок. Оставлена в ознакомительных целях.
GetKeyNum:integer - возращает количество нажатых в данный момент кнопок.
GetKey(n:integer):integer - возращает n-ую нажатую кнопку. Если n < 1, возращается первая кнопка. Если n > GetKeyNum, возращается 0.
GetKeyPressed:integer - возращает последнюю нажатую кнопку, аналогично GetKeyClicked.
GetKeyReleased:integer - возращает последнюю отпущенную кнопку.
Пример кода:
program SampleProject; uses ukey; var t, i: integer; s: string; function DrawTextBy(s: string; x, y: integer): integer; begin DrawText(s, x, y); DrawTextBy := y + GetStringHeight(s); end; begin KeyStart; Debug('Start.'); repeat SetColor(240, 240, 240); FillRect(0, 0, GetWidth, GetHeight); SetColor(80, 80, 80); t := GetStringHeight('World.'); DrawText('Max keys: ' + GetKeyLen, 0, 0); s := ''; for i := 1 to GetKeyNum do s := s + GetKey(i) + ';'; DrawText('Now keys: ' + GetKeyNum, 0, t); DrawText('Key indexes: ' + s, 0, t * 2); s := ''; for i := 1 to GetKeyNum do s := s + KeyToAction(GetKey(i)) + ';'; DrawText('Game indexes: ' + s, 0, t * 3); RePaint; forever; end.
__________________
Мой сайт-блог. Игры, обновления, примеры для Haxe, JavaScript(+HTML5), GameMaker, Love2d...
|
(Offline)
|
|
Эти 3 пользователя(ей) сказали Спасибо YellowAfterlife за это полезное сообщение:
|
|
26.03.2011, 14:48
|
#5
|
Оператор ЭВМ
Регистрация: 05.09.2010
Сообщений: 26
Написано 5 полезных сообщений (для 16 пользователей)
|
Ответ: Пример использования lib_keys (отслеживание одновременного нажатия кнопок)
Спасибо!!
Отличная либа, как раз то что было нужно!!
|
(Offline)
|
|
14.09.2013, 23:04
|
#6
|
Оператор ЭВМ
Регистрация: 25.08.2013
Адрес: Москва
Сообщений: 45
Написано 13 полезных сообщений (для 28 пользователей)
|
Ответ: Пример использования lib_keys (отслеживание одновременного нажатия кнопок)
а как же getkeyclicked в ukey?
|
(Offline)
|
|
20.09.2013, 02:07
|
#7
|
ПроЭктировщик
Регистрация: 19.02.2011
Сообщений: 134
Написано 81 полезных сообщений (для 219 пользователей)
|
Ответ: Пример использования lib_keys (отслеживание одновременного нажатия кнопок)
Сообщение от RblSb
а как же getkeyclicked в ukey?
|
Можно, но зачем?
Если нужен эффект "пока не нажмут любую клавишу", это достигается условием рода
if (get_key_states <> 0) then
// было что-либо нажато
end;
Как обстоят дела в Некропостии, кстати?
__________________
Мой сайт-блог. Игры, обновления, примеры для Haxe, JavaScript(+HTML5), GameMaker, Love2d...
|
(Offline)
|
|
22.09.2013, 20:12
|
#8
|
Оператор ЭВМ
Регистрация: 25.08.2013
Адрес: Москва
Сообщений: 45
Написано 13 полезных сообщений (для 28 пользователей)
|
Ответ: Пример использования lib_keys (отслеживание одновременного нажатия кнопок)
Сообщение от YellowAfterlife
Можно, но зачем?
|
Ну, отпускание клавиш использовать не очень-то удобно, например в играх на реакцию, да и в общем оно бесполезно, а писать и использовать алгоритм на основе getkeypressed нет особого желания... Не могли бы вы добавить getkeyclicked? Был бы благодарен
Сообщение от YellowAfterlife
Как обстоят дела в Некропостии, кстати?
|
Ну, если автор темы еще жив, почему бы не написать? МП тоже еще не умер.
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 18:21.
|