Направление движения — Abzac


PeriodicalsAbzac2004 No. 20 → Направление движения

Направление движения

В данный момент я занимаюсь созданием игры, и в один прекрасный момент передо мной возникла задачка: по направлению движения героя необходимо найти нужный спрайт (или группу спрайтов).

Для начала введу в курс дела. Итак, сначала у меня производится поиск кратчайшего пути (за что отдельное спасибо одному человеку) некоего персонажа, следствием которого является линейная запись (таблица) из координат героя по которым тот должен достигнуть указанной точки. Затем происходит преобразование этих координат в направление героя, которое получается путем вычитания последующих координат из предыдущих. Таким образом, получается одно из восьми чисел:  #FFFF, #0101, #00FF, #0001, #0100, #FF00, #01FF, #FF01. Это при условии, что герой может перемещаться по карте в восьми направлениях.

Так же нетрудно заметить, что в списке направлений отсутствует комбинация #0000. Почему? А все потому, что если бы она получилась в результате вычитания, это означало бы, что герой просто стоит на месте, т.е. никуда не двигается, следовательно учитывать эту комбинацию не нужно.

Например, в регистре BC, есть одно из восьми указанных выше чисел. Необходимо сделать процедуру, которая преобразует эти числа в число от 0 до 7, которое в свою очередь будет означать то или иное направление героя. Порядок чисел (что естественно) может быть любым.

Например, BC=#FFFF. Делаем CALL Calc. На выходе из этой процедуры в регистре A пусть будет число 0. И так для каждого из этих восьми чисел.

Сначала я сделал процедурку, которая просто (и тупо) перебирает все варианты. Но что-то мне подсказывало, что эту задачку можно решить более красиво и аккуратно. К сожалению, сам я так ничего и не придумал, поэтому обратился к друзьям по переписке и вот что из этого вышло.


Станислав Юдин

Вот такая мысль посетила. Набираю сразу в письме... Преобразуем двухбайтное число в четырехбитное.



CALC1    LD A,B
    AND %00000011
    LD B,A
    LD A,C
    AND %00000011
    SLA  B
    SLA  B
    OR B

;находим по таблице нужное значение
    LD C,A
    LD B,0
    LD HL,TABLE-1
    ADD HL,BC
    LD A,(HL)
    RET

TABLE    DB 3 ;1
    DB 0 ;2
    DB 2 ;3
    DB 4 ;4
    DB 1 ;5
    DB 0 ;6
    DB 6 ;7
    DB 0 ;8
    DB 0 ;9
    DB 0 ;10
    DB 0 ;11
    DB 5 ;12
    DB 7 ;13
    DB 0 ;14 ;ОБРЕЗАТЬ НЕЛЬЗЯ!
    DB 0 ;15 ;ОБРЕЗАТЬ НЕЛЬЗЯ!

Может быть где-то и есть ошибки, но суть надеюсь ясна. Что скажешь? Или плохое решение?


Влад Сотников

Поскольку в последовательности чисел я не заметил четкой закономерности, то иначе, как перебором, не сделать. Но перебор можно постараться сделать красивым и компактным. В предлагаемом варианте искомое число должно быть в data, иначе из цикла мы не выйдем. В противном случае вариант можно модифицировать.



CALC2
;IN: [BC] - NUMBER
    XOR A
    LD HL,DATA
LOOP    LD E,(HL)
    INC HL
    LD D,(HL)
    INC HL
    EX DE,HL
    AND A
    SBC HL,BC
    RET Z
    EX DE,HL
    INC A
    JR LOOP

DATA    DW #FFFF
    DW #00FF
    DW #01FF
    DW #FF00
    DW #0100
     DW #0101
    DW #FF01
    DW #0001

Еще вариант...

Я, как всегда, экономлю на памяти, а не на тактах.



CALC3
;IN: [BC]
;OUT: [D]
    XOR A
    LD D,A
    LD HL,DATA
LOOP2    LD A,C
    CP (HL)
    INC HL
    JR NZ,LOOP_12
    LD A,B
    CP (HL)
    LD A,D
    RET Z
LOOP_12    INC HL
    INC D
    JR LOOP2

Павел Стахов

Мой вариант считает свои числа в следующей последовательности:


;#ffff=0 (#0000)
;#ff00=1 (#0001)
;#ff01=2 (#0002)
;#00ff=3 (#0100)
;#0000=4 (#0101) - Нужна ли эта комбинация?
;#0001=5 (#0102)
;#01ff=6 (#0200)
;#0100=7 (#0201)
;#0101=8 (#0202)

CALC4    INC C
    INC B
    LD A,B
    ADD A,A
    ADD A,B
    ADD A,C

;Все, в A номер. Если тебе не нужна комбинация 4, то еще:
    CP 5    ;5,6,7,8 NC
    CCF     ;C
    SBC A,00        ;A=A-1
    RET

Дмитрий Быстров
Ты точно не забыл вариант #0000? Если нет, то:

CALC5    LD A,C
    ADD A,A
    ADD A,C ;-3..3
    ADD A,B ;-4..4, 0 НЕЛЬЗЯ
    ADD A,4 ;0..8, 4 НЕЛЬЗЯ
    CP 4
    ADC A,-1 ;0..7
    RET

Иван Рощин

Можно использовать такое преобразование:



;     BC     B+1,C     (B+1)*3+C
;     #FFFF     #00FF    #FF
;     #0101     #0201     7
;     #00FF     #01FF     2
;     #0001     #0101     4
;     #0100     #0200     6
;     #FF00     #0000     0
;     #01FF     #02FF     5
;     #FF01     #0001     1
;Соответствующий фрагмент программы:

CALC6    INC B
    LD A,B
    ADD A,A
    ADD A,B
    ADD A,C
;После чего заменяем #FF на 3:
    CP #FF
    JR NZ,$+4
    LD A,3
    RET

Если изменять B нельзя, добавляем команду DEC B.


* * *

Далее с регистром A можно делать все что угодно. Я, например, его использовал следующим образом:


    ADD A,A  ;A=A*8
    ADD A,A
    ADD A,A         
    LD HL,TABL
    LD E,A
    LD D,0
    ADD HL,DE ;Теперь HL указывает на табличку адресов спрайтов нужного направления.

; Далее ваши действия...

TABL
UP    DW SPRu1  ;Шаг левой ногой
    DW SPRu2  ;Промежуточный шаг 
    DW SPRu3  ;Шаг правой ногой
    DW SPRu2  ;Промежуточный шаг

DOWN    DW SPRd1  ;Шаг левой ногой
    DW SPRd2  ;Промежуточный шаг 
    DW SPRd3  ;Шаг правой ногой
    DW SPRd2  ;Промежуточный шаг

Благодарю всех откликнувшихся, я рад, что у меня есть такие друзья! Если у кого-то возникнут какие-либо вопросы или предложения, я с удовольствием их выслушаю.