Показать сообщение отдельно
Старый 20.02.2011, 23:50   #1
YellowAfterlife
ПроЭктировщик
 
Аватар для YellowAfterlife
 
Регистрация: 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). Обычно это вторая строка программы. Если таковой нет, просто добавьте
uses keys; 
после строки '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, или же простой метод тыка, можно обнаружить, что скобки не влияют ни на что кроме внешнего вида кода. То есть последнюю строку можно сократить до:
b := i and key_down > 0; 
Если же нам для каких-то целей нужно состояние кнопки в виде 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 за это полезное сообщение:
LTS (23.02.2011), m.ksy (21.02.2011), odd (22.02.2011), RblSb (06.07.2014), ViNT (21.02.2011)