Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Wypadanie przedmiotów w grze
Forum PHP.pl > Forum > PHP
Diwi
Witam. Pisząc silnik gry napotkałem problem. Otóż zazwyczaj po zabiciu potwora wypadają z niego jakieś przedmioty, załóżmy że np. jest 1% szansy że wypadnie jakiś drogocenny kamień ale 20% że jakiś średni miecz. Czy istnieje jakiś algorytm który jest w stanie wybrać co wypadło wg procentu szansy ?

Pozdrawiam
Fipaj
Robisz tablicę, na sto elementów... (można to zrobić jakąś jedną funkcją, nie pamiętam jaką). Potem rand(), jeśli wypadło 1, dostaje kamień; else { robisz tablicę na pięć elementów, wybierasz 1, jeśli wypadło na ten jeden jedyny - dostajesz miec }

Proste, pomyśl trochę...
tiraeth
A ja to rozwiązałem tak:

  1. <?php
  2. $przedmioty[] = array(
  3. 'name' => 'Magiczny miecz wilka',
  4. 'p' => '20');
  5. $przedmioty[] = array(
  6. 'name' => 'Nadkruszony szafir',
  7. 'p' => '1');
  8.  
  9. /***
  10.  * Powiedzmy, że tablica $przedmioty to zwrócona przez MySQL tablica z przedmiot
    ami (posortowanymi wg. procentu malejąco):
  11.  * while($row = mysql_fetch_assoc($result))
  12.  * { $przedmioty[] = $row; }
  13.  */
  14.  
  15. $items = count($przedmioty); # Liczba przedmiotow
  16. $i=0;
  17. do
  18. {
  19.  $name = $przedmioty[$i]['name'];
  20.  $p = $przedmioty[$i]['p'];
  21.  $a = 100/$p;
  22.  $r = rand(1, $a);
  23.  if($r == 1)
  24.  {
  25. $item = true;
  26. $item_name = $name;
  27.  }
  28.  $i++;
  29. }
  30. while($item == false && $i < $items);
  31.  
  32. if($item == true)
  33. {
  34.  echo 'Z pola walki zabrano <b>'.$item_name.'</b>';
  35. }
  36. else
  37. {
  38.  echo 'Nie znaleziono żadnych przedmiotów';
  39. }
  40. ?>


W komentarzu napisałem, że pobierasz z bazy danych przedmioty sortując je wg. procentu malejąco smile.gif

I wcale nie jest tutaj potrzebna tablica 100-elementowa smile.gif
mike
IMO, przekombinowaliści.
  1. <?php
  2.  
  3. // tabela items to dane o przedmiocie i procent szans jak tzreb mieć żeby go zdoby
    ć
  4.  
  5. $objDB->query( 'SELECT * FROM items WHERE percentage >= ' . rand( 1, 100 ) . 'ORDER BY RAND() LIMIT 1' );
  6.  
  7. // i już mamy przedmiot tongue.gif
  8.  
  9. ?>


1. Losujemy procent szans, np.: 40%
a) Możemy dostać każdy przedmiot, który wymaga 40%
b ) ... ale i każdy, który wymaga więcj, np.: 60%, 70%, ...
c) ... no oczywiście nie możemy dostać tego, któremu trzeba 5%.

2. Resztę załatwia baza. Losuje ona jeden element, który wymaga szans większych, bądź równych tym które wylosowaliśmy. Czyli dostać możemy przedmiot, który wymaga przykładowych 40% ale i taki który wymaga 80%.

Ja bym to widział tak.
ebe
Cytat
Robisz tablicę, na sto elementów... (można to zrobić jakąś jedną funkcją, nie pamiętam jaką). Potem rand(), jeśli wypadło 1, dostaje kamień; else { robisz tablicę na pięć elementów, wybierasz 1, jeśli wypadło na ten jeden jedyny - dostajesz miec }

Proste, pomyśl trochę...


Jednocześnie dokupujesz kostki RAM do serwera tongue.gif
dr_bonzo
Cytat
załóżmy że np. jest 1% szansy że wypadnie jakiś drogocenny kamień ale 20% że jakiś średni miecz

I tak dalej? A procenty uzupelniaja sie do 100?
SongoQ
W programowaniu jak w zyciu, czym prostrzy algorytm tym efektowniejszy.
Diwi
Hmm.. Pomysł mike_mecha wydaje mi się najprostszy biggrin.gif. Będe musiał przetestować smile.gif.

Pozdrawiam
php programmer
// wersja z możliwośćią wielokrotnego wyboru

szansa['miecz'] = 20;
szansa['kamien'] = 1;
itd

foreach ($szansa as $nazwa => $wartosc)
if ( $wartosc >= rand(1,100) ) WyrzućPrzedmiot[$nazwa];
mike
Cytat(php programmer @ 2005-08-29 15:26:31)
// wersja z możliwośćią wielokrotnego wyboru

A po co zaraz puszczać pętlę questionmark.gif

U mnie taka możliwośc jest na końcu zapytania tongue.gif

  1. ... ORDER BY RAND() LIMIT 1


Zmieniasz wartość w LIMIT, lub go usuwasz i masz wielokrotny wybór.
splatch
Cytat(mike_mech)
W programowaniu jak w zyciu, czym prostrzy algorytm tym efektowniejszy.


Chyba miałeś na myśli - w programowaniu jak w życiu, im prostszy skrypt tym efektywniejszy...
"Efektowny" to chyba nie jest odpowiednie słowo w tym miejscu.
FiDO
Cytat
IMO, przekombinowaliści.

IMO niedoceniles problemu ;]


Cytat
$objDB->query( 'SELECT * FROM items WHERE percentage >= ' . rand( 1, 100 ) . 'ORDER BY RAND() LIMIT 1' );

// i już mamy przedmiot tongue.gif

Tylko, ze losowany niezgodnie z zasadami podanymi na poczatku.
Po wylosowaniu jakiegos progu procentowego zostaja nam tylko rekordy z wiekszym prawdopodobienstwem wystapienia niz wylosowane.. i do tego momentu jest dobrze (no prawie..), bo sposrod tych elementow losujesz kolejny niestety juz na rownych prawach, czyli jesli wylosuje sie prog dajmy na to 30% to zarownio element majacy 31% jak i element majacy prawdopodobienstwo wystapienia rowne 50% beda mialy rowne szanse przy losowaniu a tak nie mialo byc.

Robilem cos podobnego niedawno w pracy (losowanie wazone), zrobilem do tego procedure, ale mysql takich mozliwosci jeszcze w wersji produkcyjnej nie daje, wiec trzeba sobie radzic inaczej smile.gif. Algorytm polega na tym, ze do jakiejs tymczasowej tablicy (czy to w bazie czy php) wpisujemy kazdy element tyle razy ile wynosi jego waga, czyli np. dla wartosci 20%, 25% i 50% wpisujemy kolejne elementy w ilosciach 20, 25 i 50 (w tym przypadku akurat mozna te wagi skrocic, bo maja NWD > 1), a nastepnie losujemy z tej tablicy/tabeli w sposob tradycyjny. Teraz elementy maja takie szanse jak miec powinny smile.gif
mike
Cytat(FiDO @ 2005-08-30 09:55:30)
IMO niedoceniles problemu ;]

Masz racje. Po tym jak wypowiedziałem się tutaj zaczął mnie ten problem nurtować. I doszedłem do takich samych wniosków co Ty.

Gdyby nie to drugie losowanie ( już na takich samych prawach ) nie byłó by tak źle. Ale wprowadzenie losowania ważonego wydaje się koniecznością.
ActivePlayer
a co jeśli przedmiotów jest hm.... 10 000... dajmy na to 100 rodzajów chełmów, 1000 rodzajów mieczy, itp itd... (tak duzo po powiedzmy generuje dynamicznie)... procent tez jest skladany dynamicznie... zakladając ze srednie prawdopodobienstwo wynosci 50%... mamy 10 000 * 50 = 500 000.
Tworzymy taka tablice po to zeby wylosowac z niej 1 element ?hm... any other ideas?
FiDO
Wtedy gorzej.. znalazlem takie cos: http://forums.devarticles.com/t8783/s.html
Niezbyt rozumiem na pierwszy rzut oka dlaczego to dziala, ale dziala.. i jest zdecydowanie bardziej wydajne i mniej pamieciozerne.
ActivePlayer
z linka:
  1. SELECT [FieldsList]
  2. FROM [TableName] WHERE [WhereStatements]
  3. ORDER BY Rand()*(1/Weight) LIMIT 1;


1/waga * losowy float ... <hmmm> moze to i dziala...
Diwi
Dobrze. To teraz następny problem który pojawił się podczas pisania skryptu który walczy z czymś biggrin.gif. Mamy sobie algorytm który oblicza szanse wygrania z przeciwnikiem. No i załóżmy że wyjdzie 70% szans na wybranie. Jak wg tych szans zdobyć informacje czy ktoś wygrał ?

Pozdrawiam
dr_bonzo
Rzuc K100 i jesli wynik bedzie mniejszy niz 70 to wygra walke. No chyba ze walka wyglada: cios za cios.
FiDO
Wylosowac liczbe z przedzialu 1-100, szanse na wylosowanie liczby mniejszej lub rownej 70 sa rowne mniej wiecej wlasnie 70%, dalej powalcz sam smile.gif

edit: ech.. nie zdazylem ;p
L_Devil
Gdy przeczytałem problem zaczął mnie nurtować i wpadłem na takie rozwiązanie... nie jest najlepsze, gdyż dwukrotnie musimy wykonać pętle for, ale mam nadzieję że ci się do czegoś przda smile.gif

  1. <?php
  2. /* Definiujemy tablice naszego ekwipunku */
  3. $arrItemChance = array();
  4. $arrItemName = array();
  5.  
  6. /* wpiszmy coś do tych tablic */
  7. $arrItemChance[] = 1;
  8. $arrItemName[] = "Szlachetny kamień";
  9. $arrItemChance[] = 10;
  10. $arrItemName[] = "Cenny miecz";
  11. $arrItemChance[] = 45;
  12. $arrItemName[] = "Normalny miecz";
  13. $arrItemChance[] = 80;
  14. $arrItemName[] = "Zardzewiały miecz";
  15.  
  16. /* Do obliczeń */
  17. $intMaxChance = 0;
  18.  
  19. /* Pierwsza pętla, obliczająca maskymalną szansę */
  20. $l = count($arrItemChance);
  21. for($i=0; $i < $l; $i++)
  22. {
  23. $intMaxChance += $arrItemChance[$i];
  24. }
  25.  
  26. /* Bierzemy się za losowanie :) */
  27. $intChance = rand(0, $intMaxChance);
  28.  
  29. /* No i ostatnia pętla, pobierająca dany przedmiot;-) */
  30. $l = count($arrItemChance);
  31. for($i=0; $i < $l; $i++)
  32. {
  33. if($intChance > $arrItemChance[$i])
  34. {
  35. $intChance -= $arrItemChance[$i];
  36. }
  37. else
  38. {
  39. echo "Na placu broni znalazłeś " . $arrItemName[$i];
  40. break;
  41. }
  42. }
  43. ?>
Forgoot
Kiedy będzie można zagrać w tą grę??

Na przyszlość:
Tego typu pytania proszę kierować na PW
---
nospor
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.