Pomoc w zrobieniu minigry

0

Witam!
Ostatnio chciałem zrobić małą grę, ale mam z nią kłopot i chciałbym prosić o pomoc.

Od początku: Gra ma polegać na jeżdżeniu samochodzikiem i zbieraniu gwiazdek. Samochodzik jest przedstawiany za pomocą komponentu Image (wartość AutoSize ustawiona na true) i poruszany za pomocą Timer'ów (na przykład dla jeżdżenia w lewo:

procedure Tsam.tlewoTimer(Sender: TObject);
begin
paliwo(Sender);         // procedura odejmująca lub dodająca paliwo
gwiazdka(Sender);       // procedura sprawdzająca pozycję samochodziku i gwiazdki (o tym niżej)

// isam to nazwa Image'a z obrazkiem samochodziku
if isam.Left > 5 then
  isam.Left := isam.Left - 1;

// poniższy zapis umożliwia "rozbicie" samochodu
if isam.Left <= 5 then begin
  isam.Picture.LoadFromFile('kraksalewo.bmp');
  przegrana(Sender);  //procedura przerywająca grę
end;
end;

Dla pozostałych kierunków użyłem analogicznej jak wyżej procedury.)

Timer'y są uruchamiane za pomocą procedury OnKeyDown (ich nazwy to tdol, tgora, tlewo, tprawo):

procedure Tsam.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
{ k to zmienna globalna określające kierunek jazdy
  Wprowadziłem zabezpieczenie polegające na tym, że
  gdy zmienna k jest równa np. lewo, to nie można pojechać
  od razu w prawo (byłoby to nienaturalne) }

if Key = vk_Left then begin
  if k <> 'prawo' then begin
    isam.Picture.LoadFromFile('samlewo.bmp');
    tlewo.Enabled := true;
    k := 'lewo'
  end;
end;
if Key = vk_Right then begin
  if k <> 'lewo' then begin
    isam.Picture.LoadFromFile('samprawo.bmp');
    tprawo.Enabled := true;
    k := 'prawo';
  end;
end;
if Key = vk_Up then begin
  if k <> 'dol' then begin
    isam.Picture.LoadFromFile('samgora.bmp');
    tgora.Enabled := true;
    k := 'gora';
  end;
end;
if Key = vk_Down then begin
  if k <> 'gora' then begin
    isam.Picture.LoadFromFile('samdol.bmp');
    tdol.Enabled := true;
    k := 'dol';
  end;
end;
end;

Ich wyłączenie umożliwia procedura OnKeyUp formatki:

procedure Tsam.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
case Key of
vk_Left : begin
            tlewo.Enabled := false;
            tpaliwominus.Enabled := false;  // Timer powodujący utratę paliwa
          end;
vk_Right : begin
            tprawo.Enabled := false;
            tpaliwominus.Enabled := false;
          end;
vk_Up : begin
            tgora.Enabled := false;
            tpaliwominus.Enabled := false;
          end;
vk_Down : begin
            tdol.Enabled := false;
            tpaliwominus.Enabled := false;
          end;
end;
end;

Pozycję gwiazdki ustala procedura:

procedure Tsam.losujgwiazdke(Sender: TObject);
begin
Randomize;
// istar to nazwa Image'a z rysunkiem gwiazdki
istar.Left := Random(265) + 8;
istar.Top := Random(165) + 8;
istar.SendToBack;
isam.BringToFront;

{ poniższe zmienne określają punkty, według których
  będzie sprawdzana pozycja samochodziku i gwiazdki
  (ale o tym w innej procedurze). Zmienne te obowiązują
  dla całego programu }

gl := istar.Left - 10;
gp := istar.Left + istar.Width + 10;
bg := istar.Top - 10;
bd := istar.Top + istar.Height + 10;
end;

Jest ona wywoływana na początku programu i po każdym "zdobyciu" gwiazdki.

Mój problem polega na procedurze sprawdzającej pozycję samochodu i gwiazdki, oraz jej "zdobycie".
Procedura wygląda tak:

procedure Tsam.gwiazdka(Sender: TObject);
var
x, iw, ih : Integer;
begin
x := StrToInt(lgwiazdki.Caption);  //pobiera liczbę z Label'a (liczba zdobytych gwiazdek)
iw := isam.Width;   // zmienna określająca szerokość Image'a z samochodzikiem
ih := isam.Height;  // zmienna określająca wysokość Image'a z samochodzikiem

if x >= 10 then begin  // po zdobyciu 10 gwiazdek
  wygrana(Sender);     // następuje wygrana
  Exit;                // i koniec procedury
end else begin         // jeżeli zdobyłeś mniej niż 10 gwiazdek:

  { k to zmienna globalna (typu String) określająca kierunek jazdy,
    zmienne gl, gp, bg i bd były opisane w procedurze losującej
    pozycję gwiazdki }

  if k = 'prawo' then begin
    if ((isam.Left + isam.Width) in [gl..gp]) and (isam.Top in [(bg-ih)..bd]) then begin
      x := x + 1;
      lgwiazdki.Caption := IntToStr(x);
      losujgwiazdke(Sender);  //procedura losująca pozycję gwiazdki
      Exit;                   // koniec tej procedury
    end;
  end;
  if k = 'lewo' then begin
    if (isam.Left in [gl..gp]) and (isam.Top in [(bg-ih)..bd]) then begin
      x := x + 1;
      lgwiazdki.Caption := IntToStr(x);
      losujgwiazdke(Sender);
      Exit;
    end;
  end;
  if k = 'gora' then begin
    if (isam.Left in [(gl-iw)..gp]) and (isam.Top in [bg..bd]) then begin
      x := x + 1;
      lgwiazdki.Caption := IntToStr(x);
      losujgwiazdke(Sender);
      Exit;
    end;
  end;
  if k = 'dol' then begin
    if (isam.Left in [(gl-iw)..gp]) and ((isam.Top + isam.Height) in [bg..bd]) then begin
      x := x + 1;
      lgwiazdki.Caption := IntToStr(x);
      losujgwiazdke(Sender);
      Exit;
    end;
  end;
end;
end;

Powyższa procedura raz sprawia, że gwiazdka znika i pojawia się w innym miejscu, a innym razem nie działa. Tak jakby w pewnych miejscach nie mogła zadziałać.
Czy da się to jakoś poprawić, tak, aby zawsze "zebrać" gwiazdkę?
Z góry dziękuję.

0
  1. Zamień K na zmienną dla której działa case ( i go użyj ), będzie ładniej, dodatkowo możesz używ else w case i obsługę błędu ( nieznany kierunek ). Przy takiej konstrukcji jaką masz losowanie może się po prostu nie odbyć.
  2. Zajrzyj do artykułu "Jak Zrobić Grę". Może się przyda. Jest tam poruszanie w danym kierunku i sprawdzanie kolizji.
  3. LoadFromFile w takiej ilości jest straszne:
    a) ImageList i rysuj odpowiedni obrazek na Canvasie
    b) kopiuj obrazek z ImageList do Image
    ( zamiast ImageList możesz dać choćby i tablicę TBitmap )
0

Poprawione, bo niezła sieczka

procedure Tsam.gwiazdka(Sender: TObject);
var
 x, iw, ih: Integer;
 Losuj: Boolean;
begin
 x := StrToInt(lgwiazdki.Caption);  //pobiera liczbę z Label'a (liczba zdobytych gwiazdek)
 iw := isam.Width;   // zmienna określająca szerokość Image'a z samochodzikiem
 ih := isam.Height;  // zmienna określająca wysokość Image'a z samochodzikiem

 if x > 9 then 
   begin  // po zdobyciu 10 gwiazdek
    wygrana(Sender);     // następuje wygrana
    Exit;                // i koniec procedury
   end;

  // jeżeli zdobyłeś mniej niż 10 gwiazdek:

  { k to zmienna globalna (typu String) określająca kierunek jazdy,
    zmienne gl, gp, bg i bd były opisane w procedurze losującej
    pozycję gwiazdki }


  if k = 'prawo' then Losuj := ((isam.Left + isam.Width) in [gl..gp]) and (isam.Top in [(bg-ih)..bd])
  else
  if k = 'lewo' then Losuj := (isam.Left in [gl..gp]) and (isam.Top in [(bg-ih)..bd])
  else
  if k = 'gora' then Losuj := (isam.Left in [(gl-iw)..gp]) and (isam.Top in [bg..bd])
  else
  if k = 'dol' then Losuj := (isam.Left in [(gl-iw)..gp]) and ((isam.Top + isam.Height) in [bg..bd])
  else Losuj := False;

  {LUB TAK:

  Losuj := False;
  if k = 'prawo' then 
    if ((isam.Left + isam.Width) in [gl..gp]) and (isam.Top in [(bg-ih)..bd]) then Losuj := True
	else
  else
  if k = 'lewo' then 
    if (isam.Left in [gl..gp]) and (isam.Top in [(bg-ih)..bd]) then Losuj := True
	else
  else
  if k = 'gora' then
    if (isam.Left in [(gl-iw)..gp]) and (isam.Top in [bg..bd]) then Losuj := True
    else
  else
  
  // ostatni warunek "dol" można usunąć, w końcu masz tylko 4 kierunki a ten jest tym ostatnim do sprawdzenia
  if k = 'dol' then 
    // pozostaje więc tylko to do sprawdzenia...
    if (isam.Left in [(gl-iw)..gp]) and ((isam.Top + isam.Height) in [bg..bd]) then Losuj := True;
 }	

 if Losuj then
   begin
    Inc(x);
    lgwiazdki.Caption := IntToStr(x);
    losujgwiazdke(Sender);  //procedura losująca pozycję gwiazdki
   end;
end;

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