Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailemVyřešeno OOP - objekty zasahujúce mimo?

Mal by som praktickú otázku ohľadne OOP. Prerábam jednu hru, čo som kedysi napísal v Turbo Pascale do C#. Jedná sa o klasiku, húsenica, známa v zjednodušenej forme na starých Nokiách a v zložitejšej forme ako Wurmi. Samozrejme, moja prerábka bola najlepšia. ;-) Ale k veci:

Červík Wurmi by mal vystupovať ako samostatný objekt, čo sa implementácie pohybu týka. Obsahuje teda:
- informáciu o umiestnení tela pre každý článok
- začiatok a koniec tela
- smer

Do toho chcem implementovať metódy na posuv červíka. Lenže, ak má byť tento objekt samostatný, tak z neho nemôžem odkazovať na kreslenie hracej plochy. Musel by som teda v obsluhe červíka implementovať posuv interne až potom po použití v programe urobiť krok červíka a následne ručne volať metódu kreslenia. Nebolo by teda lepšie implementovať kreslenie červíka do jeho objektu priamo a na kresliace metódy vytvoriť delegátov, ktorí budú volaní v objekte červíka a bude v nich adresa rutín pre kreslenie požičaná z hlavnej obslužnej rutiny? Tým pádom bude objekt samostatný a prehľadný.

Chcem sa teda spýtať, aké riešenie sa v takýchto prípadoch používa najčastejšie? Je aj nejaká výhodnejšia tretia možnosť? (V zmysle, čo je najvhodnejšie urobiť.)

Ono je plno seriálov o OOP, len všade sa používajú jednoduché príklady, kde takéto veci nie je nutné riešiť.

Jsou zobrazeny jen nové odpovědi. Zobrazit všechny
Předmět Autor Datum
Prekresluje objekt HRACIEPOLE a nie objekt cervik. Objekt cervik ma len metody na zmenu jeho stavu (…
MM.. 25.06.2009 00:57
MM..
Veď práve aj preto sa pýtam, aby som to urobil čo najrozumnejšie, nechcem to robiť hŕ.
msx. 25.06.2009 21:11
msx.
Ked nechces mat kreslenie v cervikovi, tak ako uz pisal JaFi - mozes mat napr. base-class s metodami…
MM.. 25.06.2009 21:21
MM..
Tak už viem. Vhodnejším riešením by bolo toto: Vytvoriť triedu, ktorá bude zobrazovať na obrazovke…
msx. 25.06.2009 21:43
msx.
To doplnene nerob. Mal by si rozmyslaj aj nad tym ze v buducnosti budes napr. chciet vytvorit 10 obj…
MM.. 25.06.2009 21:58
MM..
Nižšie som napísal, ako by to bolo lepšie spraviť. Dať červíkovi objekt hracia plocha. Pri pridávaní… nový
msx. 25.06.2009 22:50
msx.
Ano to je trochu problem, ale tie kroky musis podla mna takto: najprv odstranit koniec (ak sa ma ods… nový
MM.. 25.06.2009 22:55
MM..
V tom problém nevidím, skôr je problém v tom, že keby som dal dvoch červíkov, bol by problém s kkolí… nový
msx. 25.06.2009 23:34
msx.
Proč vše vymýšlíš naopak? Proč prostě červovi plátno nepředáš? Ať už jako property nebo v konstrukto… nový
Jan Fiala 25.06.2009 22:18
Jan Fiala
Aby mohlo byť v budúcnosti viac červíkov, nemôžem v konštruktore odovzdať plátno, ale objekt hracia… nový
msx. 25.06.2009 22:42
msx.
No, to sa sice da (dat objektu aj objekt ktory ho vytvoril), ale narazis na "slucku" pri definovani… nový
MM.. 25.06.2009 22:53
MM..
Tak, objekt hracia plocha bude fukcionalita kreslenia, červík si cez tento objekt bude kresliť čo tr… nový
msx. 25.06.2009 23:44
msx.
Hlavně necpi to vykreslování do červíka, ten by vůbec o nějakém vykreslovaní neměl nic vědět... Čím… nový
MaSo 25.06.2009 22:13
MaSo
Zrovna pro tento typ aplikace bych MVC nepoužil. Když chceš zatlouct hřebík, vezmeš kladivo. Můžeš t… nový
Jan Fiala 25.06.2009 23:20
Jan Fiala
Kľudne môže byť vykresľovanie aj v červíkovi. Koľko pohľadov na červíka potrebuješ? Mne by stačil je… nový
los 25.06.2009 23:21
los
Vykresľovanie bude v objekte, ktorý sa predá červíkovi v konštruktorovi, čiže, ak bude plátno väčšie… nový
msx. 25.06.2009 23:39
msx.
Předáš mu objekt, který umožňuje vykreslení. Ale ten objekt zase nic neví o červovi. Takže ten objek… nový
Jan Fiala 26.06.2009 00:18
Jan Fiala
Áno, všetko súhlasím. Ale ide o to, že s plátnom bude previazané pole, kde budú uložené hodnoty, čo… nový
msx. 26.06.2009 08:09
msx.
Tiez suhlasim s tym, ze cervik nema nic spolocne s vykreslovanim... ten sa ma starat sam o seba... m… nový
Intex 26.06.2009 08:01
Intex
Neviem, nakoľko máš naštudované OOP, ale mám pocit, že si úplne preskočil analýzu a návrh a ideš imp… nový
los 25.06.2009 23:47
los
Kreslenie bude v v objekte hracia plocha. Ak budem chcieť zmeniť kreslenie na iné, tak zmením tento… nový
msx. 26.06.2009 08:15
msx.
Takže mám to takto: Objektu záhrada odovzdám objekt PictureBox, kam má kresliť. V tomto objekte sú… poslední
msx. 27.06.2009 23:44
msx.

Prekresluje objekt HRACIEPOLE a nie objekt cervik. Objekt cervik ma len metody na zmenu jeho stavu (pohyb apod). (ked chces mat ten objekt cervik striktne univerzalny).
Alebo mozes urobit metodu cervika ktora dostane ako parameter hracie pole a urobi si s nim co chce (otestuje dalsi krok, zmeni stav policok hracieho pola, resp. "umiestni sa" do hracieho pola apod). Fyzicky vykresluje aj tak WM_PAINT v aplikacii CELE POLE NARAZ na zaklade nejakeho pola cisel, a nie nejaky objekt cervik.
Snaz sa aby to bolo co najprehladnejsie a najlogickejsie, co je casto vtedy ked objekty popisuju akokeby realne objekty, v realite ziaden cervik nic nekresli (nechceli mu predat farbicky v drogerii :)
P.S> premyslenie/vymyslenie co najlepsieho objektoveho modelu je pri vyvoji asi to nahlavnejsie a kludne moze zabrat aj nejaky cas straveny premyslanim a vymyslanim roznych moznosti ake objekty a metody zadefinovat (co prave asi aj robis co je dobre) este predtym ako sa vobec zacne nieco programovat. Nechaj si dostatok casu a skus rozmyslat nad viacerymi moznostami objektov a ich metod. Na to co si pisal v otazke zabudni. Objektov/tried budes mat viac, nielen cervika.

Ked nechces mat kreslenie v cervikovi, tak ako uz pisal JaFi - mozes mat napr. base-class s metodami na kreslenie a od neho odvodit cervika. Potom ked bude niekto chciet pouzit toho isteho cervika s inymi metodami na kreslenie tak ho odvodi od ineho base-classu. Napriklad. Moznych slusnych rieseni je mnoho, zavisi od toho jak to chce mat clovek zapuzdrene, jak sa da dany problem rozdelit na mensie ciastkove problemy, jaky sa predpoklada vyvoj/modifikacie do buducna apod. Nejake smerniky na metodu ale medzi tymi slusnymi rieseniani nie su.

Tak už viem. Vhodnejším riešením by bolo toto:

Vytvoriť triedu, ktorá bude zobrazovať na obrazovke to čo treba, tam kde treba. Bude sa jej musieť dať jedine objekt plátna, na ktorý bude vykresľovať. Červík bude potomkom a teda vo vlastnej triede bude môcť kresliť ako chce, pretože zvonka dostane plátno. Ak budem potrebovať z programu niečo vykresliť, napríklad zablikanie červíka na konci hry a podobne, tak dám na to červíkovi len príkaz a aplikácia nijako do plátna nebude zasahovať. Takto bude červík samostatný, plátno bude mať vlastné, akurát, že odkaz na plátno dostane z aplikácie. Aplikácia bude mať na starosť len test, či hra beží alebo skončila a teda bude vyriešené aj prípadne zväčšenie plochy v novej verzii (v konštruktore bude ako parameter aj plocha, akú si má červík vytvoriť.

Doplnené:
Ešte lepšie bude, ak červík plátno vytvorí a odovzdá ho v nejakom verejnom člene aplikácii. Aplikácia ho už len správne dosadí do obrázku.

To doplnene nerob. Mal by si rozmyslaj aj nad tym ze v buducnosti budes napr. chciet vytvorit 10 objektov cervik a tak rozsirit hru na multiplayer apod, takze cervik by nemal vytvarat platno. Objekty sa snazit robit co najstriktnejsie oddelene zmyslom a funkcionalitou. Tym zvysis sancu ze vyuzijes vyhod OOP (menej chaosu a jednoduchsie rozsirenie do buducnosti).
P.S. preto som aj v uplne prvom navrhu vcera oddelil hraciu plochu a cervika, tak je jednoduchsie zabezpecit aby cerviky vedeli zistovat aj kolizie medzi sebou keby ich tam bolo viac apod - dostanu plochu ako pole a mozu si testovat co chcu). Ale je to na tebe jak si to vymyslis, moznosti je dost.

Mudrujem a sam robim vacsinou ne-OOP v asm :-) Ale to je ina vec, obcas pouzijem OOP ked sa to hodi a viem ze tym vyuzijem vyhod OOP.

P.S. a dufam ze je jasne ze moze existovat napr. objekt triedy hra (v nej by malo byt platno), ktory napr. v konstruktore alebo v metode OdstartujHru(kolkohracov) vytvori objekt(y) triedy cervik a ulozi ich ako napr. private data v triede hra. Tym su cerviky v hre a hra moze volat metody svojich cervikov a predavat im platno. Paralelne moze bezat ina hra (iny objekt hra), ktora ma ine platno, vytvori inych (svojich) cervikov a bude im predavat ako parameter ine platno. Apod. Ked das platno do cervika tak sa toto logicke usporiadanie meni na chaos a pridanie multiplayera alebo multihry sa z jednoducheho new hra zmeni na nocnu moru.

Nižšie som napísal, ako by to bolo lepšie spraviť. Dať červíkovi objekt hracia plocha. Pri pridávaní prípadného multiplayera by sa ale pohyb musel vyhodnotiť v dvoch krokoch:
1. otestovať prekážky
2. pohnúť všetkých červov

Pretože, ak by sa testovalo a hneď na to pohol červík, potom ďalší testoval, pohol a tak ďalej, mohol by nastať dve situácie, ktoré by sa riešili odlišne:
1. červík 1 by vrazil do konca červíka 2, program by to vyhodnotil ako náraz, lebo červík 1 by sa pohol skôr.
1. červík 2 by vrazil do konca červíka 1, program by to vyhodnotil ako posun, lebo červík 1 by sa pohol skôr a uvoľnil by mu miesto.

V tom problém nevidím, skôr je problém v tom, že keby som dal dvoch červíkov, bol by problém s kkolíziami medzi červíkmi. Ale podľa toho, čo som napísal, že najprv testy, potom kroky, ktreba ošetriť aj prípad, že dvaja červíci by sa hlavami hrnuli v rovnaký čas na rovnaké miesto. Pre vyhodnocovanie kolízií by v jednom prípade (test 1. červíka, krok 1. červíka, test 2. červíka, krok 2. červíka) znamenalo, že nabúral 2. červík a v druhom prípade (test 1. červíka, test 2. červíka, krok 1. červíka, krok 2. červíka), že nenarazí ani jeden. Takže najlepšie bude vyhodnotiť čo je pred každým červíkom podľa toho sa zariadiť, urobiť kroky všetkých červíkov a nakoniec skontrolovať vzájomné kolízie. Aby to takto mohlo fungovať, červík musí mať verejné metódy:
- testuj čo je pred tebou
- urob krok
- testuj kolíziu s iným červíkom
V prípade monoplayera sa posledná nevyužije, ale pre prípad budúceho doplnenia do hry je vhodné ju implementovať. V pôvodnej verzii pre DOS by bolo pridanie druhého červíka bez kompletného prepísania kódu nemožné. Vďaka OOP to tu bude potom hračka. Vďaka za nápad s viacerými červíkmi ani som o tom neuvažoval. Keď to bude hra hotová, dám vedieť.

No dúfam, že takto to už bude vyzerať dobre.

Proč vše vymýšlíš naopak?
Proč prostě červovi plátno nepředáš? Ať už jako property nebo v konstruktoru nebo jako parametr metody na vykreslení...

V té první části jsi se v podstatě dobral k tomu, co jsem psal na začátku.
a pokud to chceš mít opravdu jako OOP, měl bys začít vytvořením základního objektu (jedno pole), které bude mít všechny společné metody.
Od něj odvodíš vykreslení zdí, překážek, červa(ů), laskomin pro červy...

Aby mohlo byť v budúcnosti viac červíkov, nemôžem v konštruktore odovzdať plátno, ale objekt hracia plocha, ktorý bude obsahovať plátno a pole, kde bude uložené, čo sa na plátne nachádza. Ide o to, že ak urobím jednu zmenu v plátne, aby o tom vedeli aj prípadní ďalší červíci. Ak odovzdám len plátno, tak to bude len nakreslené a z nakresleného nezistím čo tam je, len pomocou "GetPixel".

Doplnené: Potom bude červík úplne samostatný objekt, pretože na kreslenie bude volať metódy objektu hracia plocha, ktorý dostane v konštruktore.

No, to sa sice da (dat objektu aj objekt ktory ho vytvoril), ale narazis na "slucku" pri definovani tried: trieda A obsahuje objekt triedy B, a trieda B obsahuje objekt triedy A, ktoru triedu zadefinujes ako prvu? ;-)
P.S: tusim ze na to je nieco specialne v OOP ale zhlavy neviem, az taky majster v OOP niesom. Je lepsie asi davat im z plochy len platno a pole ako parametre apod, nie cely objekt.

P.S.2. aha ty chces odovzdat len objekt hracia plocha ale nie objekt hra, to je samozrejme OK. Uz blbnem :)

Hlavně necpi to vykreslování do červíka, ten by vůbec o nějakém vykreslovaní neměl nic vědět... Čím obecněji napíšeš třídu/y červíka, tím více reusenutelná ta třída bude, pohledů pak na ni může být třeba milion různých.

Viz návrhový vzor MVC.

Zrovna pro tento typ aplikace bych MVC nepoužil. Když chceš zatlouct hřebík, vezmeš kladivo. Můžeš to také udělat tak, že si najmeš 3 lidi - jeden bude držet hřebík, druhý do něho tlouct kladivem a třetí kontrolovat správnou hloubku. Výsledkem bude také zatlučený hřebík...

Vykresľovanie bude v objekte, ktorý sa predá červíkovi v konštruktorovi, čiže, ak bude plátno väčšie alebo objekty iné, tak červíka to vôbec nemusí zaujímať, lebo bude volať metódy kreslenia v predanom objekte. V objekte bude plátno a pole, v ktorom bude uložené, čo sa na plátne nachádza. Červík bude úplne samostatný objekt, ktorý bude len využívať iné objekty. Tak ako napríklad formulár vo Windows Forms aplikáciách obsahuje iné objekty, tak aj červík bude obsahovať objekt na kreslenie. Prípadné kreslenie v aplikácii nebude nutné, lebo červík si nakreslí všetko potrebné. Ak náhodou bude treba niečo predsa len kresliť (skôr už nejaké efekty a tak, tak si ich cez ten objekt, ktorý sa odovzdal červíkovi vykreslí aplikácia sama, pretože odkaz na objekt bude vlastniť aj ona.

Doplnené: V skratke teda: Miesto plátna sa dá červíkovi objekt, ktorý obsahuje aj plátno, ale okrem neho ďalšie pre červíka podstatné informácie.

Předáš mu objekt, který umožňuje vykreslení. Ale ten objekt zase nic neví o červovi. Takže ten objekt na kreslení sám o sobě nic nevykreslí, pouze obsahuje nějaké obecné metody, které červ na kreslení použije a bude vlastně červ vykreslovat.
Aby mohla aplikace vykreslit červa, musela by o něm něco vědět a v tomto případě by se ti to hodně komplikovalo...

Plátno jako takové je objekt, který už potřebné metody obsahuje. Takže předáním plátna červovi mu současně předávám i systémové nastroje na vykreslení. Červ nebude sám o sobě nic kreslit (nebudeš programovat kreslení úseček), ale použije pro kreslení metody plátna.
Možná v tomto bodě jsme si nerozuměli.

Áno, všetko súhlasím. Ale ide o to, že s plátnom bude previazané pole, kde budú uložené hodnoty, čo sa na plátne nachádza. Toto bude v tom objekte a preto sa červovi neodovzdá plátno, ale celý objekt. V tom objekte budú rovno aj metódy na prepočet. V prípade druhé červa v hre sa druhému odovzdá ten istý objekt a keďže bude objekt v pamäti ten istý, tak druhému červovi sa na objekte všetko bude meniť tak ako bude treba. Ide o to, že ak to bude len plátno, tak červík nebude vedieť čo je na ňom. Ja totiž chcem, aby si hodnoty na plátne pamätal kresliaci objekt. Odovzdaním objektu inému červovi sa takto poskytnú informácie o obsahu plátna aj inému červovi. Ak si bude obsah plátna pamätať červ, tak druhý červ nebude mať ako zistiť čo je na plátne. Preto chcem obsah plátna prenechať objektu kresliaca plocha. Proste zapuzdriť čisto kresliacu plochu.

Tiez suhlasim s tym, ze cervik nema nic spolocne s vykreslovanim... ten sa ma starat sam o seba... ma sa prepocitat, mal by vediet, ktorym smerom ide, ale aby sa mal aj vykreslit mi nepride ako rozumne riesenie... Cervik ako taky by nemusel nic vediet o svojom okoli, aj napriek tomu, ze bude stale iba jeden pohlad...

Neviem, nakoľko máš naštudované OOP, ale mám pocit, že si úplne preskočil analýzu a návrh a ideš implementovať metódy, ktoré ani nevieš umiestniť. Stále sa sústredíš len na červíka a nad ostatnými objektami sa príliš nezamýšľaš.

Najprv by si si mal identifikovať všetky objekty, ktoré v tvojej hre vystupujú, t.j. hracia plocha, červík, prekážka, kapusta a čo ja viem čo ešte. Pre každý tento objekt by si mal potom identifikovať jeho vlastnosti, ako napr. pozícia, a aj metódy, ktoré sa s jednotlivými objektami budú vykonávať.

Čo ti z toho vyjde závisí od toho, čo chceš dosiahnuť. Ak chceš mať napríklad možnosť "jednoducho" vymeniť hraciu plochu, napr. namiesto 2D plochy v okne formulára za nejakú, ktorá sa bude zobrazovať 3D, tak vykresľovanie bude zrejme zabezpečovať hracia plocha. Ak takéto ambície nemáš, tak si vykresľovanie môže robiť každý predmet hracej plochy vo vlastnej réžii.

Tiež si premysli, ako bude vyzerať tvoja herná slučka (game loop) - kedy budeš posúvať červíkov, kedy budeš zisťovať kolízie, kedy budeš získavať vstup z klávesnice, kedy budeš vykresľovať...

K analýze a návrhu tiež patrí aj voľba technológie, ktorú chceš použiť. Bude to GDI, Direct3D, OpenGL, použiješ XNA, alebo niečo iné?

Kreslenie bude v v objekte hracia plocha. Ak budem chcieť zmeniť kreslenie na iné, tak zmením tento objekt a červovi odovzdám iný. Podstatné je, aby vykresľovacia metóda mala rovnaké parametre. Môžem to urobiť dokonca tak, že urobím abstraktnú triedu kresliacej plochy a z nej urobím rôznych potomkov. Podľa toho, akého potomka priradím h hlavnej triede, tak sa bude vykresľovať. A bude to úplne obyčajná grafika cez DrawImage a niekoľkých BMP súborov, ktoré chcem neskôr vložiť do resource, aby neboli mimo EXE súboru.

Takže mám to takto:

Objektu záhrada odovzdám objekt PictureBox, kam má kresliť. V tomto objekte sú implementované všetky metódy na kreslenie a tiež na vytváranie objektov v záhrade. Čiže v programe nepotrebujem vygenerovať súradnice kapusty pri vytváraní záhrady, ale záhrada vygeneruje sama a odovzdá súradnice.

Objektu Wurmi odovzdám objekt záhrada. Kompletný pohyb červíka je implementovaný v ňom. Ak zje kapustu, tam objekt záhrada vygeneruje novú. Ak chce nakresliť články tela, objekt záhrada ich vie vykresliť, keďže kreslenie je v nej. Vytváranie a zanikanie článkov tela je ale implementované v tomto objekte.

Aplikácia vytvorí plátno na PictureBox. Vytvorí objekt záhrada a odovzdá mu už pripravený PictureBox. Aplikácia naaranžuje záhradu, ale príkazy na kreslenie odovzdáva objektu záhrada. Potom vytvorí objekt Wurmi a odovzdá mu objekt záhrada, aby Wurmi vedel, kam patrí. Cez Timer je riadený pohyb červa. Podľa stlačenej klávesy aplikácia odovzdáva objektu Wurmi informáciu o pokuse zmeniť smer. Ak je to možné, objekt Wurmi si ho zmení. Aplikácia si následne od objektu Wurmi vypýta, aký objekt je pred hlavou červa a prikáže mu urobiť krok. Zobrazia sa informácie o dĺžke a času do konca hry. Potom sa otestuje, či pred hlavou červa nebola otrava alebo či neskončil čas. Ak áno, hra končí, inak sa to celé opakuje dokola.

Ak budem chcieť v budúcnosti pridať červa, nebude nič jednoduchšie. Vytvorím len ďalší objekt Wurmi a odovzdám mu rovnaký objekt záhrada a dvaja červi budú v jednej záhrade.

Ďakujem zúčastneným za pomoc.

Zpět do poradny Odpovědět na původní otázku Nahoru