Allegro - kłopot z poruszaniem obiektem.

0

Mam pewien problem z poruszaniem się we własnym programie. Problem wygląda następująco: sprawdzam al_keyread() jaki klawisz został wciśnięty jeżeli to strzała w gore, lub w dol to odpowiednio zmniejszam lub zwiększam x. Lecz kiedy zmieniam kierunek (nacisnę strzałkę w gore tuż po naciśnięciu strzałki w dół) to zamiast poruszać się od razu do góry, przeskoczę o 1 pole w dół i dopiero wtedy zacznę iść w górę. Problem jest tylko przy zmianie kierunków

program Statki;
uses allegro;

const
  ScreenWidth=1200;
  ScreenHeight=720;

var
  wymiary, i, j, f :integer;
  paleta:al_paletteptr;
  plansza:array [1..40,1..20] of integer;

procedure inicjalizacja;
begin
al_init;
al_install_keyboard;
al_install_timer;
al_set_color_depth(32);
al_set_gfx_mode(Al_GFX_AUTODETECT_WINDOWED,ScreenWidth,ScreenHeight,0,0);
al_clear_to_color(al_screen, al_makecol(128,128,128));
paleta:=@al_default_palette;
end;


procedure rysowaniepol (wymiary:integer);
var
  x1,x2,y:integer;

Begin
  for x1:=1 to wymiary*2 do
    for y:=1 to wymiary do
      Begin
        case plansza[x1,y] of
        1 : al_rectfill(al_screen,(al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*(x1-1)+1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+1 , (al_SCREEN_w div 9) +(al_SCREEN_w div (wymiary*3))*(x1)-1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-1 , al_makecol(64,64,64));
        2 : al_rectfill(al_screen,(al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*(x1-1)+1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+1 , (al_SCREEN_w div 9) +(al_SCREEN_w div (wymiary*3))*(x1)-1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-1 , al_makecol(255,0,0));
        3 : al_rectfill(al_screen,(al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*(x1-1)+2 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+2 , (al_SCREEN_w div 9) +(al_SCREEN_w div (wymiary*3))*(x1)-2 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-2 , al_makecol(255,255,255));
        end;
      end;
 { for x2:=1 to wymiary do
    for y:=1 to wymiary do
      Begin
        case plansza[x2+20,y] of
        1 : al_rectfill(al_screen,(al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*(x2-1)+1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+1 , (al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*(x2)-1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-1 , al_makecol(64,64,64));
        2 : al_rectfill(al_screen,(al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*(x2-1)+1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+1 , (al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*(x2)-1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-1 , al_makecol(255,0,0));
        3 : al_rectfill(al_screen,(al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*(x2-1)+2 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+2 , (al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*(x2)-2 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-2 , al_makecol(255,255,255));
        end;
      end;    }
end;


procedure pola(wymiary : integer);
type
    osierecord = record
    u1,u2,u3,u4, d1,d2, su2, su4, sd2 : integer;
end;
var
  i : integer;
  osie : osierecord;
Begin
  i:=wymiary;
  osie.u1 := (al_SCREEN_w div 9);                                                 //pionowe osie (górne)
  osie.u2 := (al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*i;               //     |
  osie.u3 := ((al_SCREEN_w div 9)*5);                                             //     |
  osie.u4 := (al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*i;             //     |

  osie.d1 := (al_SCREEN_h div 5);                                                 // poziome osie (dolne)
  osie.d2 := (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*i);           //     ------------

  osie.su2 :=  (al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*wymiary;       //steady upper 2    |
  osie.su4 :=  (al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*wymiary;     //                  |
  osie.sd2 :=  (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*wymiary);   //                  -

  al_rectfill(al_screen, osie.u1, osie.d1 , osie.u2 , osie.d2 , al_makecol(64,64,128));
  al_rectfill(al_screen, osie.u3 , osie.d1 , osie.u4 , osie.d2 , al_makecol(64,64,128));
  for i:=0 to wymiary do
    Begin
    osie.u2 := (al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*i;
    osie.u4 := (al_SCREEN_w div 9)*5 + (al_SCREEN_w div (wymiary*3))*i;
    osie.d2 := (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*i);
    al_hline(al_screen , osie.u1 , osie.d2 , osie.su2 , al_makecol(0,0,0));
    al_hline(al_screen , osie.u3 , osie.d2 , osie.su4 , al_makecol(0,0,0));
    al_vline(al_screen , osie.u2 , osie.d1 , osie.sd2 , al_makecol(0,0,0));
    al_vline(al_screen , osie.u4 , osie.d1 , osie.sd2 , al_makecol(0,0,0));
    end;

  rysowaniepol(wymiary);
End;

procedure ustawianie_reczne(wymiary:integer);
var
  x,y, klawisz:integer;
Begin
  x:=1;
  y:=1;
  //repeat
    klawisz := al_readkey();
    plansza[x,y]:=3;
    if( (y-1<wymiary) and (plansza[x,y-1]=0) and (klawisz=21760) )then
      Begin

      y:=y+1;
      plansza[x,y-1]:=0;
      End;
    al_clear_keybuf();
    if( (y+1>1) and (plansza[x,y-1]=0) and (klawisz=21504) )then
      Begin
      y:=y-1;
      klawisz:=0;
      plansza[x,y+1]:=0;
      End;
    pola(wymiary);
  //until (al_key[al_Key_ENTER]);
  al_readkey();

end;

BEGIN
  for i:=1 to 40 do
    for j:=1 to 20 do
      plansza[i,j]:=0;

  wymiary:=6 ;
  inicjalizacja;
  pola(wymiary);
  ustawianie_reczne(6);
END.
2

jeżeli to strzała w gore, lub w dol to odpowiednio zmniejszam lub zwiększam x
Jeśli to strzałka sterowania wertykalnego, to zmieniasz pozycję horyzontalną? What?

1 : al_rectfill(al_screen,(al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*(x1-1)+1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+1 , (al_SCREEN_w div 9) +(al_SCREEN_w div (wymiary*3))*(x1)-1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-1 , al_makecol(64,64,64));
        2 : al_rectfill(al_screen,(al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*(x1-1)+1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+1 , (al_SCREEN_w div 9) +(al_SCREEN_w div (wymiary*3))*(x1)-1 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-1 , al_makecol(255,0,0));
        3 : al_rectfill(al_screen,(al_SCREEN_w div 9) + (al_SCREEN_w div (wymiary*3))*(x1-1)+2 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y-1))+2 , (al_SCREEN_w div 9) +(al_SCREEN_w div (wymiary*3))*(x1)-2 , (al_SCREEN_h div 5) + (al_SCREEN_h div (5*wymiary))*(3*(y))-2 , al_makecol(255,255,255));

Podczas programowania zapomnij o tym, że istnieje Ctrl-C Ctrl+V oraz kopiuj -> wklej.

type
    osierecord = record

Nazewnictwo typów w Pascalu nakazuje rozpoczynać nazwę od T i nie wykorzystywać sufiksu record, np. osierecord źle, ale TOsie - dobrze.


Odnośnie samego problemu:

Lecz kiedy zmieniam kierunek (nacisnę strzałkę w gore tuż po naciśnięciu strzałki w dół) to zamiast poruszać się od razu do góry, przeskoczę o 1 pole w dół i dopiero wtedy zacznę iść w górę
No tak, na logikę - najpierw przecież przeczytasz naciśnięcie strzałki w dół, a dopiero w następnym odświeżeniu dojdzie sygnał o strzałce w górę. Musiałbyś czytać bufor danych dopóki coś w nim jest, to pozwoliłoby w miarę zredukować występowanie tego "problemu".
inb4 nie, nie pytaj jak sprawdzić czy coś jest w buforze - jest to wyraźnie uwzględnione w dokumentacji Allegro.

PS wszystkie procedury oprócz inicjalizacja mają złe nazwy. Powinieneś móc powiedzieć, co robi dana funkcja, bez konieczności zaglądania do jej kodu (mniej lub więcej).
Czyli nie żadne pola, a raczej rysujOsie. Nazwa parametru tej procedury (wymiary) także pozostawia wiele do życzenia. Wymiar to tak samo promień, jak i szerokość, wysokość, długość, objętość, pole powierzchni... które z tych przyjmuje ta procedura powinno być oczywiste.

2

Problemy w ustawianie_reczne()
Wywal: al_clear_keybuf();
Wywal: klawisz:=0; i gdziekolwiek ten klawisz
Wywal: al_readkey(); na początku i na końcu
Korzystaj z al_key[] razem z AL_KEY_LEFT AL_KEY_RIGHT zamiast al_readkey()
Sprawdź dokładnie warunki: and (plansza[x,y-1]=0) and bo nie może być y-1 w obu przypadkach.

0

Dziękuje, za pomoc. Zastosowałem rady Patryka27 i _13th_Dragon. Ale złe działanie polegało na czymś innym

    if( (y-1<wymiary-1) and (plansza[x,y+1]=0) and (al_key[al_key_Down]) ) then
      Begin
        y:=y+1;
        plansza[x,y]:=3;
        plansza[x,y-1]:=0;
        RysujOsie(IloscPolPlanszy);
        al_rest(100);
      End;    

Zamiast zmieniać wartość planszy tylko na początku pętli, zmieniam w każdym ifie.

0

No to uprość to do czegoś takiego:

procedure ustawianie_reczne(wymiary:integer);
var x,y,d:integer;
begin
  x:=1;
  y:=1;
  while not al_key[al_Key_ENTER] do
  begin
    d:=0;
    if (al_key[al_key_Down])and(y-1<wymiary-1)and(plansza[x,y+1]=0) then d:=1
    else if (al_key[al_key_Up])and(y+1>1)and(plansza[x,y-1]=0) then d:=-1
    else continue;
    plansza[x,y]:=0;
    y+=d;
    plansza[x,y]:=3;
    RysujOsie(IloscPolPlanszy);
    al_rest(100);
  end; 
end;

1 użytkowników online, w tym zalogowanych: 0, gości: 1