Randomowy czas timera.

0

Witam. Chciałbym by moj timer nie powtarzał się dokładnie wtedy kiedy chcę, a by działo się to randomowo.
Bardziej chodzi mi o określony czas a + random liczba z czasu b.
W kodzie wygląda to tak:

procedure TForm1.CheckBox5Click(Sender: TObject);
var
i:integer;

begin;
for i := 0 to SpinEdit6.Value do
if Checkbox5.Checked then
begin
Timer7.Interval := (Spinedit5.Value *1000 + (random(i)*1000));
Timer7.Enabled := True;
end
Else
begin
Timer7.Enabled := False;
end;
end; 

W timerze jest dajmy na to

memo1.lines.add('Czas: ' + (TimeToStr(Time)));

W pewnym stopniu jest spoko, gdyż gdy np. Spinedit5.Value := 1, a Spinedit6.value := 5 to funkcja się z timera powtarza się co randomowy czas pomiędzy 1, a 6 sekund, z tym że na każde kliknięcie checkboxa jest generowany nowy czas (nowy interval timera). Bardziej mi zależy by czas timera zmieniał się sam.
Teraz wygląda to np. tak:

Czas: 2304
Czas: 2308
Czas: 2312
Czas: 2316
Czas: 2320

Bardziej mi zależy na czymś takim:

Czas: 2304
Czas: 2305
Czas: 2308
Czas: 2312
Czas: 2314
Czas: 2309

Mam nadzieję że połapiecie się w tym co tu napisałem i dacie rade mi pomóc.
Dzięki :D

1

A wywołałeś gdzieś na początku Randomize? :]

Aby timer czekał na wykonanie akcji za każdym razem dłuższą lub krótszą chwilę od poprzedniej, zmieniaj Interval w zdarzeniu OnTimer, a nie po kliknięciu na checkbox; Zobacz na poniższy przykład:

procedure TForm1.CTimerTimer(Sender: TObject);
begin
  CTimesList.Items.Insert(0, TimeToStr(Now()));
  CTimer.Interval := (Random(CDelayTime.Value) + 1) * 1000;
end;

To jest zdarzenie OnTimer komponentu o nazwie CTimer; Do ListBoxa o nazwie CTimesList w każdym wywołaniu zdarzenia zostaje dodana nowa pozycja (na górę listy) z bieżącym czasem; Następnie losowany jest nowy interwał, na podstawie wartości z komponentu CDelayTime (to SpinEdit), określającego maksymalną liczbę sekund oczekiwania; Powyższy kod daje poniższe wyniki:

timer.png

Jak widać różnice czasów wywołań są różne, od jednej sekundy do pięciu; Jeżeli chcesz uniknąć powtórek i w każdym wywołaniu zdarzenia nadawać inny interwał niż poprzednio to musisz zapamiętywać go w dodatkowej zmiennej czy polu klasy (albo skorzystać z właściwości Timer.Tag);

Wartość w komponencie CDelayTime (czyli w SpinEdit) można zmieniać w dowolnym momencie, bez konieczności zatrzymywania i wznawiania pracy timera; Kod timera i tak wykonywany jest w ramach głównego wątku, więc tego nie trzeba synchronizować.

0

Jak najbardziej mi pomogło.
Dziękuję :)

Mógłbyś mi jeszcze pomóc z tym? Bo mi się coś zepsuło xD

var
HP1:integer;
HP2:integer;
HPd:double;
i:integer;
begin
HP1:=memreadinteger(Player_MaxHP);
HP2:=memreadinteger(Player_HP);
Hpd:= HP2/HP1*100;
for i := -SpinEdit2.Value to SpinEdit2.Value do
begin

if (HP2/HP1 *100)  < HPs.value + random(i) then

  begin
  Say(Spell.Text);
  Listbox3.Items.Add('Healed with : ' + (inttostr(HP2) + ' ' + 'HP' + ' '+ '(' + (FloatToStr(round(HPd))) + '%' + ')') + '.');
  end;

end;
end; 

Ja to rozumiem tak, że np:
HP2 := 2000 (current);
HP1 := 3000;
Jeżeli 2000/3000*100 (w zaokrągleniu 67%... po prostu obliczanie %, gdyż hp2 to zmienna. HP się ciągle zmienia) <= Hps.Value (dajmy na to 70) + Random z liczby 20 (pomiędzy -20, a 20) to wtedy ma się postać uleczyć za pomocą czaru.

Jeżeli 67% <= 70 +(dajmy na to wylosowało -20, co daje 50 w takim razie)
to heal... powinno być spoko, bo hp mam więcej.

Jeżeli 67 <= 70 + wylosowane 10 (80)
to wtedy heal.

Jednak mi ciągle spamuje funkcja z procedury say.
Co jest nie tak?

0

Zmieniłem na coś takiego:

procedure TForm1.Timer1Timer(Sender: TObject);
var
HP1:integer;
HP2:integer;
HPd:double;
i:integer;
begin
for i := (-SpinEdit2.Value) to (SpinEdit2.Value) do
HP1:=memreadinteger(Player_MaxHP);
HP2:=memreadinteger(Player_HP);
Hpd:= HP2/HP1*100;
if ((HP2/HP1*100) + (random(i)))  < HPs.value then

begin
  Say(Spell.Text);
  Listbox3.Items.Add('Healed with : ' + (inttostr(HP2) + ' ' + 'HP' + ' '+ '(' + (FloatToStr(round(HPd))) + '%' + ')') + '.');
  end;
end; 

user image
I nie wiem czemu, ale wgl. to nie jest randomowa liczba :< Zamiast to być np 50 + załóżmy 25 (75), a czasem 50-15 (35) to zawsze jest to poniżej 50 xd

1

Rzadko teraz zaglądam na forum. Ale spojrzałem obecnie i czytam ten wątek. No i się pogubilem. Kod Twój jest niesformatowany i dzianie opisujesz z jakimś debilnym skrotowcem "wgl. Także idzie się według mnie w tym wszystkim pogubić.

Ale jeżeli chodzi o ostatniego posta to nie wiem czy masz świadomość że w pętli wykonuje się jedynie ta linijka HP1:=memreadinteger(Player_MaxHP);. Może stąd wynikają różnice w wynikach od tego, czego się spodziewasz otrzymać.

0

@Maciek Maly - funkcja Random losuje liczbę naturalną, a Twoje i jako iterator pętli najpierw przyjmuje wartości ujemne, potem 0, a dopiero na końcu dodatnie; Ten kod działa nieprawidłowo, dlatego że jest nieprawidłowo napisany; Jeżeli chcesz losować liczby z danego zakresu to skorzystaj z funkcji RandomRange:

LNumber := RandomRange(-SpinEdit.Value, SpinEdit.Value);

Edit: Poza tym, tak jak napisał @olesio, pętla wykonuje tylko pierwszą linijkę pod nią, a reszty nie, dlatego że pozostałe instrukcje nie są zgrupowane np. blokiem Begin End; Lepiej by było gdybyś napisał co chcesz osiągnąć - łatwiej będzie odpowiedzieć, niż poprawiać Twój nieprawidłowo działający kod, nie wiedząc tego co on w ogóle ma robić.

0

Chcę osiągnąć to, by postać nie leczyła się dokładnie gdy HP% (HP2/HP1*100) spadnie poniżej HPs.Value.
Lepiej by to była liczba nieco bardziej randomowa.
Np. Gdy HPs Value wynosi 50, to chcę by postać się leczyła gdy ta liczba będzie mniejsza, lub większa o randomową liczbę ze SpinEdit2.value.
Jezeli HPs.Value wynosi 50, a SpinEdit2.Value wynosi 20 to żeby postać się leczyła od 30-70 %. Leczenie się to procedura Say(Spell.Text);
Jeżeli Hps.Value wynosi 80, a SpinEdit2.Value wynosi 5 to żeby procedura była wywoływana od 75-85.

0

W większości tych przypadków wystarczy użyć funkcji RandomRange - ona uprości obliczenia i zwiększy czytelność kodu.

0

W ten sposób?

 procedure TForm1.Timer1Timer(Sender: TObject);
var
HP1:integer;
HP2:integer;
HPd:double;
i:integer;
begin
Randomize;
i := RandomRange(-SpinEdit2.Value, SpinEdit2.Value);
HP1:=memreadinteger(Player_MaxHP);
HP2:=memreadinteger(Player_HP);
Hpd:= HP2/HP1*100;
if ((HP2/HP1*100) + (i))  < HPs.value then

begin
  Say(Spell.Text);
  Listbox3.Items.Add('Healed with : ' + (inttostr(HP2) + ' ' + 'HP' + ' '+ '(' + (FloatToStr(round(HPd))) + '%' + ')') + '.');
  end;
end;
0

furious programming
Tak. Uważam że tak napisany kod nie tylko działa ale i pomaga zrozumieć amatorom wiele niuansów (choć sterta innych wciąż czeka na zrozumienie... :=)
Jakoś nie widzę w Tobie człowieka pokroju tych, których pytałem o poradę. Najczęściej tamże spotykałem się z odpowiedziami, które cytować nie chcę.
Przecież nie muszę być natychmiast orłem. I skowronek uczy się latania nie mniej jak orzeł - prawda? Pozdrawiam i życzę wszystkiego najlepszego!
Ps:
Czy masz może jakieś sugestie choćby odnośnie Implode string'a według separatora? Explode ściągnąłem z SwissDelphiCenter jest tam także kod
odnośnie Implode ale nie ma example jak się odwołać do tego fragmentu kodu... Dla mnie wciąż za trudne ... Pomożesz? - Dzięki!

0

Rozumiem że chcesz wzorem języka PHP zrobić operacje łączenia stringów z elementów tablicy? Bo tak rozumiem Implode, które jest odwrotnością Explode. To najprościej pętlą lub tutaj funkcją Format mając na uwadze że nie jest to identyczny sprintf z PHP czy języków typu C++ także jako wartość drugiego parametru to ma być stworzona w taki sposób jak opisano na http://www.delphibasics.co.uk/RTL.asp?Name=format i mnóstwie innych stron będących do wygooglowania.

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