|
[ Dark Icarus @ 03.03.2005. 22:33 ] @
| Ovo je thread u kome ćemo pokušati da zajedničkim snagama napravimo igru u VBu. Smatrajte ovo tutorialom, poligonom za vežbanje, i besplatnim kursom - sve u jednom.
Ko god hoće da učestvuje, može da "upadne" kad god hoće u projekat, samo neka se u prvom javljanju predstavi i da kaže kako stoji sa programiranjem i šta misli da mu najbolje ide. Neko predznanje rada u VBu je dobro došlo, ali potrudićemo se da čak i totalnim VB početnicima obezbedimo dovoljno informacija da mogu odmah da počnu.
Inače, ja već 5 godina iz hobija pravim sitnije igre, koje uglavnom napustim na pola projekta, ali sam usput pokupio gomilu korisnog znanja. Trenutno pravim pravu pravcatu komercijalnu igru u VBu. Cilj ovog tutorijala mi je da na jednom mestu obezbedim VB početnicima dobru količinu onih trikova koje sam ja morao da učim postepeno i sa svih strana. Ne pretendujem da budem neki autoritet ovde, ako se nađe neko iskusniji od mene mogao bi sigurno i mene nešto da nauči.
Tutorial će biti koncipiran na sledeći način: Na početku svakog koraka, objasniću ključne stvari vezane za "lekciju" koju obrađujemo. Onda ću postaviti problem i vaš će posao biti da rešite taj problem, tako što ćete poslati svoju verziju koda. Kasnije kada se uhodamo verovatno ćemo raspoređivati zaduženja. Svačije rešenje će biti proanalizirano, ukazaćemo na potencijalne greške, biraćemo optimalno rešenje i ići dalje kroz proces pravljenja igre.
Cilj je da na kraju svi koji učestvuju u ovoj temi iz nje izađu sa malo boljim razumevanjem pravljenja igara. A možda budemo imali i "diplomski projekat". :)
Imajte na umu da ovde radimo zajedno, a ne takmičimo se jedni protiv drugih, što znači da nema kečeva i petica. Nema ni domaćih zadataka; radite onaj deo koda koji hoćete, kada hoćete. Idealno bi bilo da ovo preraste u temu u kojoj će malo iskusniji podučavati one malo manje iskusne.
|
[ Dark Icarus @ 03.03.2005. 23:06 ] @
Korak minus 2: PRE POČETKA PROČITATI OVO
Pa, nema razloga da ne počnemo odmah.
Pretpostaviću da se svi koji su ovde ušli razumeju u programiranje u VBu barem na elementarnom nivou. Pretpostaviću da ste upoznati sa nekim osnovnim konceptima.
Neophodno znanje koje morate da imate jeste:
- šta je varijabla, a šta je konstanta
- tipove varijabli (npr. ako znate razliku između Integer i String tipa to je sasvim dovoljno, ostalo ćemo da učimo usput)
- šta su procedure
- ključne reči: Dim, Sub
- operacije nad varijablama: +, -, =, /, *
Ako neko ima problema sa ovim pojmovima, možemo da uvedemo korak -3 gde ću pokušati da objasnim.
Za početak, da se dogovorimo oko sledećih stvari.
- Koristićemo Visual Basic 6.0. (Verujem da će kod koji pravimo biti kompatibilan i sa VB 5.0)
- Koristićemo neka osnovna pravila kodiranja (koja ćemo da definišemo kada za to dođe vreme, dogovorno, ali moraćemo da ih se svi pridržavamo)
- Pravimo jedan jedini glavni projekat. To će biti igra koju za sada zovemo Vectorball. Neki primeri u tutorialu ne moraju biti deo igre, ali trudićemo se da se ne udaljavamo od teme.
- Pre prelaska na svaki sledeći korak, dogovorićemo se oko toga šta je "zvanična" verzija igre i postovaćemo njen kod.
- kod će biti komentarisan gde god je to moguće
Dalje, nekoliko osnovnih smernica za one koji imaju nekog iskustva: (ako ne razumete šta neke od ovih stvari znače, nije problem, pojasnićemo posle)
- nećemo koristiti Variant tip podataka.
- uvek ćemo koristiti Option Explicit.
- imaćemo jednu jedinu formu u igri.
- počećemo da pišemo kod u prostoru forme, ali ćemo brzo preći na module
- počećemo da radimo sa VB kontrolama (Timer, Shape, Line), ali ćemo ih se otarasiti već u nižim koracima
Opis igre:
Za početak, dovoljno je znati da pokušavamo da napravimo klon Ponga: igru za dva igrača u kojoj svaki kontroliše po jedan "reket" (reket prvog igrača je na levoj strani ekrana, drugog na desnoj). Loptica vrluda po ekranu i odbija se od gornji i donji zid, kao i od rekete. Igrač postiže poen ako loptica prođe iza protivničkog igrača.
(Kasnije možemo da dodajemo na milione originalnih stvari koje će igru učiniti svojstvenom.)
Za sada toliko, naredni korak (minus 1) govori o tome kako pripremiti VB za pravljenje novog projekta.
[ Dark Icarus @ 04.03.2005. 20:35 ] @
Korak minus 1: PRIPREMA VBa ZA PRAVLJENJE NAŠE IGRE
Pre nego što krenemo sa stvarnim programiranjem, moramo da pripremimo VB i da podesimo naš projekat. Ovaj korak je prilagođen početnicima u VBu. Stvari upućene početnicima će biti ubačene u okvire (poput citata) sa plavim naslovom. Iskusniji korisnici će verovatno hteti da preskoče sve ove okvire, jer su tu pokrivene samo osnovne stvari.
U svakom slučaju objašnjenje šta smo sve odradili je dato na kraju poglavlja.
Kreiranje projekta
Za iskusnije:
Startujte VB6 i kreirajte novi projekat Standard Exe.
Citat: ZA POČETNIKE:
Kao prvo, trebalo bi da startujete VB6 i da dobijete početni prompt. Izaberite New Project -> Standard Exe. Ako vam se prompt ne pojavi izaberite opciju (u glavnom meniju) File->New Project-> Standard Exe.
Kreira se projekat koji se zove Project1, sa jednim obrascem (formom) koji se zove Form1. Pošto je ovo prva stvar sa kojom se VB programeri suočavaju, verujem da vam je barem poznato kako izgleda. Sve što ćete videti na ekranu je naš obrazac, koji izgleda kao normalan prozor, (kojem u title-baru piše Form1) bez ičega na sebi osim čudne mreže tačaka.
Od sada, sve što budemo radili, radićemo u ovom projektu.
Podešavanje projekta
Odmah ćemo podesiti neke osnovne osobine našeg projekta da bismo mogli da ga raspoznajemo u moru drugih projekata na kojima možda radimo.
Za iskusne korisnike: Promenite ime projekta u VectorBall a Version Number projekta u 0.0.1.
Citat: ZA POČETNIKE:
U glavnom meniju idite na Project->Project 1 Properties...
Kao i uvek, dobićete prozor sa gomilom tabova i svakojakih polja - mnoga od njih nikada nećete koristiti. Za sada, ignorišite sve osim sledećih:
U General tabu: u polju Project Name, gde trenutno piše "Project1", promenite ime projekta u VectorBall. Ovo je interno ime i ne sme da ima razmake.
U Make tabu:
-promenite verziju vaše aplikacije (boks Version Number) u 0, 0, 1 . Isključite opciju Auto Increment jer nam neće trebati.
-promenite naslov vaše aplikacije (boks Application, polje Title:) u Vector Ball.
U ovom tabu se inače nalaze polja koja ćemo popunjavati pred kraj projekta a koja će pružati neke informacije krajnjem korisniku fajla, što nam za sada stvarno nije prioritet. Posle ćete ovde moći da menjate ikonicu za .exe fajl našeg projekta itd.
I to je to. Kliknite OK da prihvatite sve promene.
Podešavanje obrasca - Properties Window
E, gospodo, stvari se sada već malo zahuktavaju. Moramo da podesimo naš obrazac i da ga pripremimo za igru koju ćemo da pravimo.
Za malo iskusnije:
u našem obrascu postarajte se da sledeći propertyji budu promenjeni:
(Name): fMain
AutoRedraw: False
BackColor: &H0& (kada pravite igre, UVEK koristite Palette colors, NIKAKO System Colors)
BorderStyle: 1 - Fixed Single
Caption: VectorBall Main Window
Enabled: True
ForeColor: &HFFFFFF& (opet Pallette color, i to bela)
KeyPreview: True
ScaleMode: 3-Pixel
Na kraju, ručno mišem resize-ujte fMain da mu visina bude oko 400 a širina oko 600 (gledajte ScaleHeight i ScaleWidth dok menjate veličinu prozora)
Primetićete da sam obrazac nazvao fMain. U mojoj nomenklaturi, stavljam prefiks "f" ispred obrazaca, "m" ispred modula, i "c" ispred klasa.
Citat: ZA POČETNIKE:
Properties Window se dobija pritiskom na F4 ili preko glavnog menija: View->Properties Window.
Videćete prozor sa dve kolone, u levoj se nalaze imena properties-a a u desnoj njihove vrednosti. Properties posmatrajte kao varijable obrasca, od kojih se većini može menjati vrednost (neke su read-only doduše, ali to za sada nije bitno). Mogu biti različitih tipova - uglavnom su to Long i String tipovi. Za sada ćemo se pozabaviti samo onim svojstvima koja su nama trenutno bitna.
(Name) : ovo svojstvo određuje kako ćemo mi u programu da zovemo naš obrazac. Korisnik nikada ne mora da zna ime obrasca. (Name) mora biti jedna reč, bez ikakvih spejsova ili specijalnih karaktera. Ako baš morate da nazovete obrazac sa dve reči, koristite podvlaku ili pišite reč jednu za drugom. - npr. MojObrazac ili Matematicke_Funkcije
U polju desno od (Name) ukucajte "fMain" (bez navodnika). Ovo će biti ime našeg obrasca.
AutoRedraw: nije ključno za početak, ne morate da znate šta radi, ali svejedno ga podesite na False (kliknite na malo sivo dugme sa strelicom na desnoj strani polja da dobijete opcije True i False i onda kliknite na False). Ovo će ubrzati crtanje grafike.
BackColor: određuje boju prozora. Ovo je prvo svojstvo koje će proizvesti vidljivu promenu na našem prozoru. Probajte da podesite boju prozora. Boja je predstavljena brojevima (RGB brojevima, o kojima za sada ne morate ništa da znate, ali sigurno ste se susretali sa njima). Umesto da ukucavate brojeve, koristite strelicu sa desne strane polja i dobićete niz kvadratića sa raznim bojama. Klikom na kvadratić ćete dodeliti tu boju našem prozoru. Eksperimentišite malo.
Ono što je bitno to je da primetite dve različite grupe boja - Palette i System. Da ne tupim mnogo o tome, za sada je dovoljno da znate da nama treba Palette skupina boja. Kada birate boju kliknite na Palette i dodelite prozoru neku življu boju, npr. crvenu ili žutu. Primetite kako se boja našeg prozora menja.
Posle malo eksperimentisanja, podesite boju na CRNU.
BorderStyle: određuje, između ostalog, da li korisnik može da menja veličinu prozora mišem. Mi ne želimo da on to može u našoj igri tako da ćemo ovo podesiti na 1-Fixed Single (opet, klikom na strelicu i odabirom ove opcije).
Možda ćete primetiti kako se okvir našeg obrasca malo smanjio. Pazite, vi i dalje možete da menjate veličinu našeg obrasca (resize pomoću miša), ali to je zato što ste vi programer. Kada korisnik bude startovao igru, prozor će biti strogo fiksne veličine.
Caption:Ovo svojstvo daje vidljive promene na obrascu. Umesto Form1 u polje desno od polja Caption unesite neku - bilo koju - reč. A sada pogledajte šta piše u vrhu našeg obrasca. Upravo ste saznali koje svojstvo je zaduženo za ispisivanje naslova u vrhu prozora. Caption se koristi u velikom broju kontrola (npr. Screen Button) kao svojstvo koje određuje šta će biti ispisano.
Par puta sam naišao na početnike koji su imali problema sa razumevanjem razlike između imena obrasca i Caption-a obrasca. Pa da rešimo to jednom za svagda: (Name) je INTERNO svojstvo, koje će SAMO PROGRAMER znati i koje će samo njemu koristiti kada on bude programirao aplikaciju. Caption je sa druge strane svojstvo koje sadrži tekst koji će pisati u NASLOVU obrasca. Caption može da sadrži razne specijalne znakove poput razmaknice, dvotačke itd. dok se (Name) svojstvo mora imenovati u skladu sa strogim pravilima - samo slova i brojevi, bez razmaknice.
Enabled:ovo bi trebalo da već bude True, ali svejedno proverite. Slično važi i za Visible svojstvo.
Nikako nemojte postavljati ova dva svojstva na False (Enabled=false znači da je prozor vidljiv ali da neće reagovati na komande korisnika, dok Visible=false znači da ste potpuno sakrili prozor od korisnika)
ForeColor: Slično kao BackColor, izaberite neku boju iz palete. Ovo će biti boja kojom ćemo crtati razne linije na ekranu. Promenom ove opcije nećete videti nikakvu promenu na ekranu. Kada počnemo da crtamo linije biće vam jasno čemu ovo služi.
ScaleMode:Ovo podesite na 3-Pixel. Ovo svojstvo određuje merne jedinice kojima ćemo izražavati koordinate elemenata na prozoru. Kao programerima igara, mnogo nam je lakše da radimo u pikselima.
KeyPreview:: Podesite na True. Ovo će naterati Windows da sve tastere koje pritisnemo prvo prosledi našem prozoru (u izvesne procedure koje ćemo kasnije da odradimo).
Podešavanje preferenci
Za iskusnije: Podesite "Require Variable Declaration" ili ručno kucajte Option Explicit u svim modulima i formama koje budemo pravili. Preporučujem da iskoriste "Editor Format" tab i da prilagode izgled editora svojim potrebama. Posebno preporučujem da ručno podesite Foreground boju za Identifier Text na nešto što je bar malo različito od crne - najverovatnije će vam odgovarati tamnosiva - kako bi se razlikovalo "Identifier Text" od "Normal Text"-a. Ovako će se zagrade, separatori argumenata i sl. onda videti malo jače u odnosu na nazive varijabli, što po mom ličnom mišljenju ume da bude veoma korisno za preglednost pojedinih dužih formula, poziva procedura sa više argumenata itd.
Citat: ZA POČETNIKE:Bilo bi uputno odmah na početku podesite opcije koje će naš rad učiniti lakšim. u glavnom meniju birajte Tools->Options... i naći ćete se na ekranu za opcije. Početnicima preporučujem da ne eksperimentišu mnogo sa ovim opcijama, ali sledeće stvari morate da podesite:
- u Editor tabu: opcija "Require Variable Declaration" mora biti uključena. Ova opcija je vrlo bitna.
- u Advanced tabu: opcija "SDI Development Environment" bi trebalo da bude isključena, kako vas ne bi zbunjivala; uz ogradu da će možda korisnicima Delphija ovakav izgled biti poznatiji.
- u General tabu: selektujte opciju "Break On All Errors"
Ostale opcije možete da menjate po želji. Npr. ako vas tačke na obrascima nerviraju slobodno ih isključite tako što ćete odčekirati "Show Grid".
Project Explorer: vaš najbolji prijatelj
Uključite Project Explorer pritiskom na Ctrl-R i proverite da se projekat zove VectorBall, i da ima jedan obrazac koji se zove fMain.
Citat: ZA POČETNIKE:Na kraju bih vam obratio pažnju da koristite Project Explorer. Dobija se preko glavnog menija (Viev-> Project Explorer) ili preko tastature na Ctrl-R . Za sada nam ovaj alat ne može mnogo pomoći, ali u slučajevima da projekat ima veliki broj modula i obrazaca ovaj mali prozorčić može da ih sortira i da učini život mnogo lakšim.
Toplo preporučujem da se upoznate detaljno sa Project Explorerom.
ZAKLJUČAK
Da sumiramo šta smo uradili. Stvorili smo projekat, nazvali ga VectorBall, promenili neka svojstva glavnog obrasca (properties) da bismo ga spremili za našu igru.
[ fLuXx @ 01.04.2005. 16:19 ] @
Super ideja! Evo, ja hocu da se prikljucim. Znam VB podosta, koristim uglavnom API, ActiveX izbegavam iz sve snage. Znam i matematiku (onoliko koliko treba za ovako nesto). Nemam pojma o DirectX-u, ali hocu da naucim (ako ce igra uopste biti pravljena uz pomoc DX-a). Podrzavam ovaj poduhvat i pozivam i ostale da se prikljuce.
P.S.
Da li ce se lopta odbijati uvek pod istim uglom od reketa ili ce se ugao menjati u zavisnosti od toga gde loptica udari? Ako je prvi slucaj, onda je to mnogo lako, cak i za pocetnike. A i ne uvodi nivo slucajnosti u igru. Ovaj drugi nacin je bolji.
[ Dark Icarus @ 05.04.2005. 22:23 ] @
Naravno, svaka pomoć je dobrodošla.
Loptica će se u početku odbijati samo po fiksnim obrascima (da bi ljudi ukapirali kako to radi), pa ćemo posle preći na randomizaciju delta koordinata lopte (i na kraju na sinuse i kosinuse i računanje delte lopte svakog ciklusa).
Poenta je da projekat počne od ogoljene verzije ponga urađenog sa shape-ovima, tajmerima i keydown/keyup-om, a dogura do prave pravcate igre sa APIjem i, možda (zavisi da li će ljudi hteti da slušaju dalje) i do DirectXa.
[ Aleksandar Ružičić @ 05.04.2005. 23:03 ] @
da li cemo hteti da slushamo???? :D NARAVNO!!!!!
[ fLuXx @ 08.04.2005. 17:24 ] @
Ej, pa zar niko vise nije zainteresovan za ovaj program? E, pa koga nema bez njega se moze! Ja mislim da sa projektom treba krenuti, a drugi ce se (nadajmo se) prikljuciti kasnije. Bilo je jos pokusaja da se program pravi u grupi (i ja sam dao predlog), ali svi su pali u vodu. Ne zelim da se to desi i ovom projektu. Ja mislim da sa radom treba da se pocne pod hitno inace ce propasti kao i ostali.
Doduse, mozda su ostali projekti propali, jer nisu bili u TOP temi, pa nisu bili ni uoceni. Trebalo bi ovu temu postaviti kao TOP, stvarno, jako malo tema je TOP u VB forumu: svega dve. Neka ovo razmotri mod ako procita.
@Dark Icarus
Pravis komercijalnu igru u VB-u? Neznam zasto, ali mislim da su me svuda ubedjivali da VB nikako nije pogodan za pravljenje igrica, posebno ne komercijalnih, jer je spor ili tako nesto. Kako ti ide taj posao?
[ Aleksandar Ružičić @ 08.04.2005. 20:36 ] @
nije da nas nema zainteresovanih samo jos nije pravo vreme da se ukljucimo, milism na mene :D, ja planiram da se prikljucim negde kad budemo poceli sa API-jem, jer sve do toga mi vise nije zanimljivo...
A svi projekti (pa i Slagalica koja je u TOP-u!) koji su radjeni grupno su propali jer nije bilo pravog vodje, tj. organizatora svega. Mada cini mi se da ce ovaj projekat zaziveti jer imamo iskusnog organizatora koji se MNOGO razume u pravljenje igara :D Samo kad bi on nasao vremena da posveti nama koji zelimo nesto da naucimo :P (sala naravno) I naravno kad bi se prikljucili (kasnije, kad/ako stignemo do directx-a) i ostali koji se razumeju u game developing (mislim na TheAlas-a :p)...
brb, krcko
[ Marko_L @ 08.04.2005. 20:54 ] @
Citat: Doduse, mozda su ostali projekti propali, jer nisu bili u TOP temi, pa nisu bili ni uoceni. Trebalo bi ovu temu postaviti kao TOP, stvarno, jako malo tema je TOP u VB forumu: svega dve. Neka ovo razmotri mod ako procita.
Imate i jedan projekat u TOP temi (mislim na TV Slagalicu), pa je opet propao.Jedno vreme se "zahuktalo", a onda samo jednostavno stalo.Dakle, nije problem u tome da li je neka tema TOP ili nije, već u (ne)ozbiljnosti učesnika u istim, kao i u lošoj organizaciji.Koliko sam video samo Shadowed i Krcko su ozbiljno radili na tome, a ostali (čak i pokretač teme) su više gledali iz prikrajka, nego što su se priključivali projektu.
Što se tiče ove teme, ukoliko Dark Icarus prihvati da nastavi rad na ovom projektu i tema postane svojevrsni tutorijal za izradu igre, nije problem da se u dogovoru sa ostalim moderatorima TOP-uje, ali za sada ne vidim razloga za to.
[ Shadowed @ 09.04.2005. 00:27 ] @
Slagalica je propala zato sto je mene mrzelo da sam uradim ceo program (konkretno asocijacije). Krcko je isprobavao svoju verziju koliko se secam sto je bilo OK, ali ostali su samo posmatrali a cela stvar je bila zamisljena kao zajednicki rad. Da je radjeno kao tutorijal bilo bi drugacije organizovano od pocetka i imalo bi smisla da jedan ili dvoje urade uz objasnjenja. Ali, nije bio tutorijal i tako...
Mislim da bi moglo da se topuje al' da se okanemo slagalice onda na ovoj temi ;).
[ Dark Icarus @ 09.04.2005. 14:58 ] @
Ma evo i ja sam postao zabušant, nisam bio na netu 2-3 nedelje... odavno pišem neke korake tutorijala ali treba to upakovati... često postajem preopširan (kao što svi na forumu već znaju), ne mogu da se odlučim za koji nivo programera pišem... (npr. da li da objašnjavam event-driven arhitekturu windowsa, da li da objašnjavam UDTe...) i tako dalje. Da i ne pominjemo da imam a) ispite i b) svoju igru. Ali, ne bojte se, radi se!
A što se tiče topovanja teme to neće biti potrebno, jer dok malo krenemo tema će se zahuktati toliko da će večito biti na prvoj strani :) Ne bih ga stavljao na TOP da ga ne izbaksuziramo :) A i realno, projekat još nije ni zaslužio topovanje. Kada tutorial bude završen, možda ga i prebacim u HTML i okačim negde na net, pa ako zaslužuje da bude stavljen u "korisne resurse" u prvoj top temi, i time ću biti više nego zadovoljan.
Bar neće pasti u zapećak dok god sam ja živ da ubacujem novi post bar jednom na nedelju dana.
A sada dajte da malo poradimo na tome da ovaj tutorijal bude vredan toga. Evo prvo ja: očekujte korake 0 i 1 vrlo uskoro.
@fLuXx
Lele, nemoj da počinjemo sa temom "komercijalne igre u VBu". Recimo samo da "komercijalna igra" nije samo FPS: www.gametunnel.com
[ Dark Icarus @ 09.04.2005. 17:18 ] @
Korak 0: JOŠ MALO SUVOPARNOG FILOZOFIRANJA
Evo nas na pragu da počnemo i sa samim kodom. Ali ne lezi vraže, nismo mi te sreće: prethodno moramo da odradimo još malo opšte teorije. Trudiću se da svedem bullshit na minimum... gest unapred osuđen na propast :)
Sve igre na svetu funkcionišu na nekoliko zajedničkih principa. U ovom koraku ću objasniti te principe, na kojima će se zasnivati i naš VectorBall. A vi ćete mi oprostiti ako ovde kažem nešto što već odavno znate.
Sveta trijada programiranja: input, process, output.
Igra je, u suštini, aplikacija kao i svaka druga, u tom smislu da mora da ispuni sledeće: a) uzima podatke od igrača, b) procesuje te podatke i c) izbacuje rezultate na ekran. Ovaj isti princip pokreće i Excel, i Pong, i FarCry. Za sada ćemo se držati Ponga kao dobre polazne tačke za opisivanje. Igra Pong sadrži dva reketa, jednu lopticu, i pokazivač rezultata, i to je sve što je potrebno da savršeno ilustruje način na koji funkcionišu igre.
Početnici će verovatno pitati: Kako to igra uspeva da radi? Kako pomera rekete? Kako odbija lopticu?
Jedna reč: varijable. Mnogo varijabli.
Njeno veličanstvo varijabla
Sve što postoji u game-worldu mora biti uskladišteno u memoriji u vidu varijabli. Svaki reket, svaka loptica, svaki tenk, vojnik i konjanik, svaki space invader. Mi, programeri, pomoću varijabli kompjuteru opisujemo poziciju, ponašanje i stanje svega što u našoj igri postoji. Za procesor je to samo gomila brojeva u RAM memoriji. Ali takva gomila brojeva koje će on iskoristiti da na pravi način nacrta loptu, rekete, rezultat, tenkove - tako da to ima smisla igraču.
Uzmimo lopticu u Pongu i pretpostavimo da stoji u mestu. Šta nam je neophodno da bismo opisali kompjuteru našu lopticu? Da bi igrač postao svestan loptice, kompjuter je mora nacrtati na ekranu, a da bi je kompjuter nacrtao na ekranu, on mora znati njenu poziciju. A pozicija se može iskazati brojevima. I eto naših prvih varijabli. :)
Bez preteranog ulaska u Dekartove koordinatne sisteme (koji nas čekaju za nekoliko koraka), za sada ćemo se zadovoljiti time da poziciju loptice opišemo njenim rastojanjem od gornje i leve ivice ekrana. Našu lopticu možemo da opišemo tako što ćemo reći kompjuteru da se nalazi 60 piksela od leve ivice (ovo se zove X koordinata) i 100 piksela od gornje ivice ekrana (Y koordinata). Ili, skraćeno, koordinate loptice su: X = 60 i Y = 100. Sve što nam sada treba jeste da kompjuteru kažemo da nacrta sličicu loptice na ovim koordinatama (kasnije ćemo detaljno obrađivati crtanje na ekranu).
Znači, u našem programu se već nalaze dve varijable: X koordinata lopte i Y koordinata lopte. Nazovimo ove dve varijable LoptaX i LoptaY (u ovom koraku još se ne bavimo kodiranjem, već samo principima programiranja, pa nećemo ovde deklarisati varijable).
Da bismo crtali rekete takođe nam treba njihova pozicija na ekranu, pa ćemo imati i varijable koje će opisivati njihovu poziciju. Takođe ćemo imati varijable koje će čuvati rezultat. I na kraju ćemo imati varijable koje će opisivati kretanje loptice i reketa.
I eto, samo desetak-dvadesetak varijabli nam je dovoljno da napravimo jedan Pong. Ali te varijable nam ne vrede ništa ako tek tako stoje i kuliraju. Pong u kojem loptica i reketi stoje u jednom mestu ne bi bio preterano uspešna igra, zar ne? Naravno da ne. Treba nam način da pokrećemo lopticu, da pomeramo rekete, da odbijamo lopticu od njih. Kako se to postiže? Prosto - menjamo vrednost varijabli. Razmislite. Ako hoćemo da pomerimo lopticu 10 piksela udesno, samo treba da promenimo vrednost varijable LoptaX (LoptaX = LoptaX + 10). Međutim, kako menjamo te vrednosti? Koliko često? Kojom prilikom? Kojim zakonitostima?
E, to nas dovodi do drugog glavnog principa kako funkcionišu igre: petlja.
Naša igra je jedna velika petlja
Petlje i multitasking: Nekada davno, u vreme Komodora 64, programiranje je bilo relativno jednostavno. Izvršavao se jedan program u jednom trenutku. Nije bilo multitaskinga, paralelnih procesa, multithreadinga i ostalih bakrača. A onda su došle platforme poput PCja i Macintosha, čiji su operativni sistemi polako ali sigurno počeli da se snalaze u multitasking sredini.
I tako su počeli problemi za programere igara.
Igra nije namenjena za multitasking. Kada pravimo igru, mi hoćemo da ona besramno uzurpira kompletan procesor, celu radnu memoriju, i polovinu hard diska. Ne želimo da nam neki tamo Windows traći dve trećine radne memorije. Šta će nam multitasking? Ko još igra Quake 3 i onako usput paralelno sa tim kucka dokument u Wordu?
Ono što je problematično je to što je i dragi nam Visual Basic praktično dizajniran za programiranje multitasking projekata. Pravljen je tako da program koji napišemo reaguje na određene događaje - pritisak dugmeta na formi, pritisak na enter, prelazak strelicom preko nekog polja - itd. Ostatak vremena, program stoji i ništa ne radi. Ovo se zove event-driven programiranje ("programiranje pokretano događajima"). Što je sjajno, ako pravite bazu podataka.
Ali mi smo programeri igara. Mi ne pravimo baze podataka. Mi preziremo baze podataka. Mi se gnušamo baza podataka. Mi mrzimo programere baza podataka, i tučemo se sa njima do smrti kada ih sretnemo na ulici.
Minesweeper i šah i sl. su jedine igre koje mogu bez blama da koriste event-driven programiranje. Za te igre to može da posluži. Ali mi, gospodo, pravimo arkadnu igru. Nama event-driven programiranje ne odgovara. Zato, mi odbacujemo ovaj tip programiranja. I zato ćemo mi sada da malo pričamo o petljama.
Kao što sam već rekao, varijable ne vrede ništa ako samo stoje i ne menjaju se. Ali kada ih menjamo? Koliko često apdejtujemo njihove vrednosti?
Zavisi. Ako igrate RTS, Pong, ili neku pucačinu, ne želimo novi frejm svake dve sekunde, zar ne? Ne, mi želimo onoliko frejmova koliko naša jadna napaćena konfiguracija može sebi da priušti. Dakle, mi već pomenutu svetu trijadu programiranja ponavljamo nebrojenih XY puta svake bogovetne sekunde (uzimamo input; apdejtujemo vrednosti varijabli; crtamo elemente na ekranu).
Recimo da je prihvatljivo da apdejtujemo varijable 25 puta u sekundi. (kasnije ćemo naučiti da tempiramo procesor da ovo radi). Ovo nećemo postići ako čekamo neki event, čak i ako je to Timer event. I zato moramo da se okrenemo petlji.
Do...Loop petlja je sasvim prihvatljiva. Da ne bismo potpuno uzurpirali resurse windowsa, moramo da obezbedimo i drugim procesima šansu da "dišu" (inače će se kompjuter zaglaviti). Za ovo nam služi komanda DoEvents, koja otprilike kaže windowsu "odradi šta treba, a onda se pod hitno vrati na izvršavanje ovoga koda".
Da li vam je sada jasno kako igra radi?
Code: Public Sub MainProcess
Dim Igrac_Signalizirao_Izlaz As Boolean
Do
DoEvents
Uzmi_Input ' miš, tastatura, štagod
Procesuj_Input ' npr. ako je igrač pritisnuo Escape, onda Igrac_Signalizirao_Izlaz = True
Procesuj_Gameworld ' obradi svaku jedinicu, metak, loptu, kap kiše i cvetić na ekranu
Procesuj_Output ' izbriši ekran, nacrtaj sve što treba, započni/prekini zvukove itd.
Loop Until Igrac_Signalizirao_Izlaz
Naravno, ovo je VRLO pojednostavljen prikaz celog procesa. Pre ove procedure treba odraditi inicijalizaciju varijabli; treba pripremiti prozor; treba obraditi error handling; itd, itd. Ali ovo ionako nije zvaničan kod naše igre. Ovo je samo ilustracija.
Praktična primena
Šta sve ovo znači primenjeno na Pong ili naš VectorBall? (i dalje smo samo u teoretisanju; u slučaju da se zbunite ili zagubite čitajući sledeće redove, to nije problem, oni su tu da bi vam pokazali kako jedna prosta ideja evoluira; objašnjenje korak po korak će sigurno biti dato kada krenemo sa samom igrom).
Sećate se varijabli LoptaX i LoptaY? Pretpostavimo da se loptica kreće udesno po ekranu (povećava joj se X koordinata) brzinom od 50 piksela u sekundi. Ako se petlja izvršava 25 puta u sekundi, to znači da svaki prolaz kroz petlju (koji ću od sada, pa za vjeki vjekova, ja zvati tick ili ciklus) treba da pomeri lopticu za 2 piksela udesno.
Što će reći da je cela mudrost pokretanja loptice udesno u našoj igri sledeća: da u našu petlju (tačnije, proceduru Procesuj_Gameworld) stavimo LoptaX = LoptaX + 2. Naravno, mi ne želimo da loptica ide samo udesno (otišla bi sa ekrana pre nego što biste stigli da kažete "hej, pa ova loptica će otići sa ekrana"), pa na primer možemo da uradimo sledeće korake :
- umesto "LoptaX = LoptaX + 2" stavićemo "LoptaX = LoptaX + DeltaLoptaX",
gde će DeltaLoptaX će biti varijabla, koja će imati neku početnu vrednost (npr. 3).
- u svakom ciklusu ćemo proveravati da li se loptica sudarila sa reketom broj 1, i ako jeste, onda ćemo joj promeniti DeltaLoptaX:
If LopticaSeSudarilaSaReketom Then DeltaLoptaX = - DeltaLoptaX
što će efektivno promeniti smer njenog kretanja po horizontali.
Slično tome, možemo da ubacimo: promenu DeltaLoptaY; uslove za odbijanje od vrha i dna ekrana; uslove da ako loptica izađe kroz levu i desnu stranu ekrana (igrač postigao pogodak) da se poveća rezultat za 1 u korist jednog igrača; i tako dalje, i tako dalje.
E sad, šta je sve ovo trebalo da znači?
Manipulišući vrednostima LoptaX i LoptaY na različite načine, ubacujući provere, uslove i grananja, mi možemo da od vrlo jednostavne premise, i manipulišući sa 10ak varijabli, napravimo vrlo lep Pong.
Metodologija rada
Tokom prethodne briljantne demonstracije, trebalo je da primetite kako radi mozak programera: postavi premisu, vidi problem, smisli rešenje. Svi programi su puni bagova i problema. To je normalno. Umesto da odmah krenete da pišete kod celog Ponga, naravno da ćete prvo napisati npr. kod za pozicioniranje lopte. Onda ćete ustanoviti da vam se loptica ne pomera. To posmatrate kao problem koji treba rešiti. Onda smišljate privremeno rešenje, da vam se loptica kreće udesno 2 piksela u svakom ciklusu. Dalje bi tok misli verovatno išao ovako:
Problem : loptica se kreće samo u desnom smeru
Rešenje : kretanje loptice levo-desno staviti u varijablu DeltaLoptaX i svakog ciklusa LoptaX = LoptaX + DeltaLoptaX
Problem : loptica opet samo stoji u mestu
Rešenje : inicijalizovati DeltaLoptaX pri startu programa na 2
Problem : loptica se i dalje kreće samo desno
Rešenje : ubaciti proveru za sudar sa reketima; ako dođe do sudara, loptica će se odbiti. Odbijanje uzrokuje da DeltaLoptaX pomnožimo sa -1
Problem : loptica ide samo levo-desno
Rešenje : ubacićemo DeltaLoptaY
Problem : loptica se ne odbija od gornje i donje ivice ekrana:
Rešenje : ubaciti proveru da li je loptica izašla iz ekrana i ako jeste vratiti je malo prema ekranu i pomnožiti DeltaLoptaY sa -1
I tako dalje, i tako dalje... shvatili ste poentu.
ZAKLJUČAK
Ukratko, ova lekcija (ciljana prvenstveno na početnike) nam je objasnila kako srž naše igre čini petlja koja mnogo puta u sekundi (npr. 25 puta) menja gameworld, tako što menja varijable igre po pravilima koje mi (programeri) postavljamo, a zatim koristi te iste varijable kako bi nacrtala elemente na ekranu... i taj proces se ponavlja... i ponavlja... i ponavlja...
[ pimpBOY @ 01.05.2005. 18:19 ] @
profo 'ocemo nastavak!!!
[ Dark Icarus @ 02.05.2005. 15:25 ] @
E pa izvin'te, ali i meni je raspust!
:) Šalim se, odavno radim na prvim koracima, ali imam jedno pitanje pre nego što odemo predaleko sa kodom: da li hoćete da pišem imena procedura i varijabli na srpskom ili engleskom? Ja imam običaj da pišem imena na engleskom, iz dva razloga:
- manje para oči kada vidite "If BallCollided Then CalcBallCoordinates" nego "If LoptaSudarila Then IzracunajKoordinateLopte"
- kod može da bude internacionalan
Komentare, naravno, obavezno pišem na srpskom (ako baš hoćemo da internacionalizujemo kod bar je lako prevesti sve komentare).
[ Aleksandar Ružičić @ 02.05.2005. 18:20 ] @
ja mislim da je vecina nas navikla na englesku nomenklaturu, bar ja se ne secam da li sam ikad jednoj promenjivoj dao ime na srpskom :)
[ Dark Icarus @ 03.05.2005. 00:26 ] @
Korak 1: ZDRAVO, SVETE
Konačno je došlo vreme za malo pravog posla. Zato, bez uvoda, bez ikakvih diverzija, bacićemo se na kodiranje.
Danas nećemo praviti preterane egzibicije u kodu. Počećemo sa definisanjem toka aplikacije, a u sledećoj lekciji ćemo napraviti lopticu i teren.
Sa programerske strane... danas ćemo naučiti da koristimo evente i kreirati jednu kontrolu - Timer. Ceo kod će nam za sada biti u jednoj formi. Za one koji misle da je ovo neefikasno, molim vas primetite da smo tek na prvom koraku.
Ako već niste, kreirajte i podesite projekat kao što piše u koraku -1. Sada bi trebalo da imate formu koja se zove fMain.
Kako početi
Tok naše aplikacija ima tri bitne tačke: inicijalizaciju, glavnu petlju, terminaciju.
Inicijalizacija je ulazna tačka u našu aplikaciju. Ovo je kod koji će se izvršiti samo jednom, i to kada igra počne. Ovde ubacujemo bitne stvari koje određuju tok naše aplikacije. Uglavnom, ovde se izvršava inicijalizacija varijabli (postavljanje početnih vrednosti).
Glavna Petlja - objašnjena u koraku 0. Ponavljaće se dvadesetak puta u sekundi i zadužena je za obradu svega - inputa, gameworlda i outputa.
Terminacija - takođe bitan deo svake aplikacije, koji se izvršava na kraju, kada igrač hoće da izađe iz naše aplikacije. Ovde oslobađamo sve resurse sistema koje smo zauzeli tokom izvršavanja igre, "penzionišemo" prozor aplikacije itd.
Za ove svrhe ćemo napraviti tri vrlo, vrlo bitne procedure.
InitializeApplication
MainLoop
TerminateApplication
Ove procedure će biti definisane u prostoru forme fMain, za sada; A pošto već sve radimo u jednoj formi, neka sve tri procedure budu privatne (private).
Citat: ZA POČETNIKE:Da bismo pisali kod za naš prozor, sve što treba da uradimo jeste da kliknemo desnim dugmetom na naš prozor fMain i kliknemo na opciju "Show Code...". Ili, u Project Exploreru (Ctrl+R) "označimo" (highlightujemo) fMain i kliknemo na dugme "Show Code" u vrhu Project Explorera.
Nadam se da svi znaju šta je procedura, a šta funkcija, šta je njen domen (scope), kako se iste definišu, kako im se prosleđuju argumenti, itd. Ako ima neko ko prati tutorijal a ne zna šta je procedura, onda nažalost ne poseduje osnovna znanja da mu pristupi. Ne gubite nadu! Samo nađite neku dobru knjigu, naučite osnovne stvari o procedurama i vratite se ovde.
Za one koji znaju šta je procedura ali ne stoje dobro sa vizuelnim jezicima ili sintaksom VBa:
Ako hoćemo da napravimo proceduru, koristimo ključnu reč Sub, praćenu imenom procedure. Pre ključne reči "Sub", moramo da odredimo opseg ("Scope") procedure, tj. da ukucamo reč koja određuje na kojem nivou definišemo proceduru. Procedura može da bude vidljiva samo u onom modulu/prozoru u kojem se nalazi, u kojem se slučaju zove privatna procedura (ključna reč "Private"). Međutim, ako hoćemo da procedura bude vidljiva svim prozorima u projektu, takva procedura je javna (ključna reč "Public").
Generalno, ako procedura ne mora da komunicira sa drugim prozorima, ništa nas ne sprečava da je proglasimo za javnu, ali zašto bismo to radili? To je kao da kupujete markicu za saobraćajnu zonu koju nikada nećete koristiti: komplikovano, nepotrebno, i skupo.
Za definisanje privatne procedure pišemo: Private Sub ImeProcedure()
A za javnu pišemo: Public Sub ImeProcedure()
Primetite da ako ukucate ovu komandu (zagrade na kraju ne morate da kucate, dodaće ih sam program) i pritisnete "enter", VB automatski generiše "Exit Sub" dva reda ispod nje. Sve što se nalazi između reči "sub" i "end sub" je deo naše procedure.
Takođe primetite da VB ima opciju da sam kreira proceduru za vas (Tools>Add Procedure...), ali ja je nisam nikada koristio; bolje je da vežbate da kreirate procedure tako što ćete ih ukucavati u direktno u Code Window.
Kod našeg prozora bi sada trebalo da izgleda otprilike ovako: Code: Option Explicit
_______________________________________
Private Sub InitializeApplication
End Sub
_______________________________________
Private Sub MainLoop
EndSub
_______________________________________
Private Sub TerminateApplication
EndSub
(horizontalne linije automatski generiše VB između procedura)
E sada, moramo da uredimo da naš program učita InitializeApplication kad se aplikacija pokrene. Sada ćemo da naučimo da koristimo Evente. Svaki prozor "okida" evente kada se nešto desi. Postoje eventi za sve i svašta - kada se pritisne dirka, pomeri miš, učita prozor... E, nas interesuje ono za učitavanje prozora.
Kreirajte proceduru Form_Load.
Citat: ZA POČETNIKE:Da bismo pristupili Eventima prozora fMain, moramo da budemo u Code Window-u fMain-a.
Odmah iznad koda, trebalo bi da vidite dva textbara, jedan pored drugog. Na levom bi trebalo da piše (General). Kliknite na njega i dobićete dve opcije - (General) i Form. Kliknite na Form. VB će vam sam generisati proceduru Form_Load u kodu, što je upravo ono što nama treba. (Desni textbar sadrži sve moguće evente koje vaš prozor može da pozove; ako kliknete na taj textbar, videćete da postoji još mnogo, mnogo eventa; ako kliknete na bilo koji od njih VB će vam automatski generisati proceduru za taj događaj. Nama treba upravo Form_Load event.
U proceduri Form_Load ukucajte jednu jedinu instrukciju - Call InitializeApplication
Ako se pitate zašto sam komplikovao stvari i pravio proceduru InitializeApplication, ako sam već mogao sve instrukcije za inicijalizaciju da ubacim u proceduru Form_Load, nemojte više da se pitate. Razlog je sledeći: sada mogu da pomerim proceduru InitializeAplication u koji god modul hoću, mogu u njoj da kucam šta god hoću, to je moja procedura. Sa druge strane, procedura Form_Load je interna procedura u fMain i neće se nikada pomeriti odatle. Hoću da učinim proceduru InitializeApplication što je moguće više nezavisnom - jer možda sutradan odlučim da je pomerim u modul mInits, ili da inicijalizujem igru iz potpuno drugog prozora.
Slično, kreirajte proceduru Form_Terminate. Event Terminate će se izvršiti kada naša forma bude uništena, bilo da je korisnik isključi na Alt-F4, bilo klikom na close dugme. U proceduri Form_Terminate ukucajte Call TerminateApplication.
Kao što verovatno znate, ključna reč Call nije obavezna za upotrebiti. Ako ne stavimo Call pri pozivu procedure, možemo da iza imena procedure navedemo argumente bez da ih stavimo u zagradu. Po meni, ovo je varvarski i ekstremno nečitko - ja UVEK stavljam argumente u zagradu, i UVEK koristim komandu Call pri pozivu procedure. Ako procedura ima samo jedan argument, možete da izostavite Call i da opet strpate argument u zagradu - ali zbog doslednosti i čitljivosti koda uvek je dobra ideja da se ispraksate da nikada ne izostavljate Call.
Naravno, sve ovo se ne primenjuje na funkcije. Ako ćete da koristite funkciju sa Call (što je moguće), onda vam ne treba njena povratna vrednost - pa zašto biste je onda uopšte deklarisali kao funkciju a ne kao proceduru?
Sada, treba nam MainLoop procedura. Odlučio sam da u prvih par koraka ne koristimo pravu petlju, već kontrolu tajmer, zato što je većina početnika upoznata sa datom kontrolom. (Kod koji stavimo u neki tajmer će se izvršavati svakih XX milisekundi, gde je XX vrednost tajmerovog svojstva Interval)
Na prozoru fMain kreirajte kontrolu tajmer. U Object Properties (F4) postavite interval na bilo koju vrednost a kao (Name) ukucajte GameClock. Kliknite dva puta na tajmer. Vratićete se u Code Window a VB će vam generisati proceduru GameClock_Timer. Ono što bude u ovoj proceduri će se izvršavati svakih XX milisekundi. Mi hoćemo da se svaki put kada tajmer okine događaj izvrši neki kod. Slično kao sa Form_Load i Form_Terminate, nećemo ove komande pisati u GameClock_Timer već ćemo ih staviti u nezavisnu proceduru.
Kreirajte privatnu proceduru ExecuteGameTick. Ova procedura će biti sa nama do kraja tutorijala. Kasnije ćemo je pozivati iz beskonačne petlje (tome služi MainLoop), a za sada, izvršavaćemo je kad god se tajmer GameClock okine.
U GameClock_Timer proceduru ukucajte komandu Call ExecuteGameTick.
A sada, čisto radi vežbe, stavite Enabled svojsvo tajmera na False. Ovo će sprečiti tajmer da radi odmah na početku igre.
Red je da poradimo malo na inicijalizaciji tajmera. U proceduri InitializeApplication stavite red Code: GameClock.Enabled = True ' uključujemo Tajmer
GameClock.Interval = 50 ' podešavamo interval na 50 milisekundi .
Ovo sam uradio da bih demonstrirao da se svojstva kontrola mogu menjati i tokom samog koda.
Pošto pomoću komentara malo sredimo kod, dobijamo otprilike sledeće:
Code: Option Explicit
'===========================================
'INICIJALIZACIJA
Private Sub InitializeApplication()
GameClock.Enabled = True
End Sub
'===========================================
'PROCESS
Private Sub MainLoop()
'ova procedura sluzi da poziva ExecuteGameTick u beskonacnoj petlji.
'za sada je prazna jer ExecuteGameTick
'To bi trebalo da izgleda ovako:
'Do
' DoEvents
' Call ExecuteGameTick
'Loop
End Sub
Private Sub ExecuteGameTick()
'kljucna procedura za igru.
'instrukcije ove procedure se odigravaju pri svakom ciklusu, znaci mnogo puta u sekundi.
'zato, ova procedura ce pozivati dogadjaje za:
' - unos podataka
' - obradu podataka
' - output (npr. crtanje na ekran)
End Sub
'===========================================
'TERMINACIJA
Private Sub TerminateApplication()
End Sub
'===========================================
'===========================================
'PROCEDURE FORME I NJENIH KONTROLA
Private Sub Form_Load()
Call InitializeApplication
End Sub
Private Sub Form_Terminate()
Call TerminateApplication
End Sub
Private Sub GameClock_Timer()
Call ExecuteGameTick
End Sub
Sada imamo početak, kraj i proces aplikacije. Iako je većina procedura (InitializeApplication, TerminateApplication) prazno, neka ih tu, 'leba ne jedu.
ZAKLJUČAK
Danas smo kreirali procedure za inicijalizaciju, terminaciju i obradu procesa aplikacije. Zatim smo kreirali "događaje" (evente) Form_Load, Form_Terminate i (pošto smo kreirali tajmer po imenu GameClock) GameClock_Timer; ovi eventi služe da pozivaju naše procedure onda kada je to potrebno.
Sada naša aplikacija počinje procedurom InitializeApplication, završava se procedurom TerminateApplication, a u međuvremenu se izvrši mnoštvo ExecuteGameTick događaja.
Znam da nije mnogo, ali mislim da bolje da sada prekinemo nego da se zagušimo u prvom koraku. A u koraku 2 se konačno bacamo na lopticu i rekete.
[ sergio_mrav @ 04.05.2005. 15:49 ] @
Pamtimo, upijamo.....
[ pimpBOY @ 05.05.2005. 23:37 ] @
i ocemo jos...
[ negyxo @ 06.05.2005. 20:14 ] @
Evo tek sad sam malo procitao i reko da dam neki komentar kad ono...
Citat:
Ali mi smo programeri igara. Mi ne pravimo baze podataka. Mi preziremo baze podataka. Mi se gnušamo baza podataka. Mi mrzimo programere baza podataka, i tučemo se sa njima do smrti kada ih sretnemo na ulici.
...jel ti to ozbiljno? Ajd onda da te vidim sutra u 3 ispred ulice pa da se potucemo :)
[ GMC @ 11.05.2005. 12:48 ] @
Evo samo da svojim postom vratim temu na vrh stranice, a vrlo rado cu se prikljuciti cim uspijem instalirati VB :)
(ocu da pravim igricu a ne znam ni instalirati program heheh)
[ Dark Icarus @ 24.05.2005. 12:06 ] @
Citat: negyxo: ...jel ti to ozbiljno? Ajd onda da te vidim sutra u 3 ispred ulice pa da se potucemo  Hehe.... šala mala, of course  . U stvari poenta je bila da programeri igara predstavljaju vrlo usko specijalizovanu populaciju i da ih ostali programeri zato gledaju iskosa.
Inače, žao mi je što moram da vas obavestim da se selim pa ćete se još načekati do narednih koraka.  Trudiću se da budem brz.
[ Mare_Sk8er @ 24.05.2005. 14:48 ] @
Kada ce biti nastavka?!!
[ steewsc @ 20.06.2005. 18:59 ] @
Hi!
Nisam se bavio Game Developing, ali nakon sto sam dobio prvi komp i igrao prvu igricu (bese to 1989.) hteo sam da i ja napravim neku igricu.
Ali otisao sam na drugu stranu i sada sam DB tip programera.
Procito sam temu i hocu da ucestvujem.
Radio sam neke stvari oko reketa.
Planiram da post-ujem nakon sto |Dark Icarus| post-uje svoj
nastavak, da ne bih narusio strukturu tutorijala (Treba da ide sve po redu).
P.S.
D.I. pozuri
[ Dark Icarus @ 23.06.2005. 21:11 ] @
Rado bih požurio, ali nemam pristup internetu na svojoj novoj lokaciji (ni kablovski, ni telefon). Ovo kuckam sa drugog kompa. Sorry. Možda stignem sa fakulteta da uploadujem još pokoji korak.
Svim novim "članovima" pozdrav i obećanje da ću se potruditi u najskorijem roku...
@steewsc
Nije problem da postuješ o reketima, ako je neko "lako štivo" za početnike, mehanika igre je ionako bila u planu za sledeći korak. Znači, ništa o grafičkim procedurama, ali sve što je vezano za varijable reketa i njihovo ponašanje na ekranu može da prođe.
Čak i ohrabrujem ljude koji su već programirali Pong da i oni postuju ovde, nisam ja jedini koji ovde ima da se trudi (pogled ispod oka ka krckoorascicu)
[ Aleksandar Ružičić @ 23.06.2005. 23:34 ] @
Citat: Dark Icarus: ... (pogled ispod oka ka krckoorascicu)
lol :D
pokusacu da napisem nesto mada ja bas i nisam neko ko ume dobro da objasnjava (mozda nece biti bas jasno pocetnicima) :p
[ steewsc @ 25.06.2005. 11:39 ] @
API funkcija za primer koji sledi je GetAsyncKeyState
Public Declare Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer
---------------------------------------------------
Funkcija u primenjenom obliku izgleda ovako:
If GetAsyncKeyState(vbKeyW) And &H8000 Then
r_reket.Top = r_reket.Top - 10
End If
U opstem obliku bi ovo izgledalo ovako:
If GetAsyncKeyState(KOD_ZA_NEKI_TASTER) And &H8000 Then
'Neka komanda
End If
Svaki taster na tastaturi ima svoj ASYNC kod.
Na primer 119 je kod za [w].
(Ovo mozete isprobati kada u nekom text-ualnom polju
drzite ALT i pritisnete na NUM delu tastature 119)
Dakle ako je taster [w] pritisnut funkcija ce vratiti vrednost
TRUE i izvrsice se "Neka komanda".
[ steewsc @ 25.06.2005. 12:26 ] @
Rekete sam obelezio na sledeci nacin:
l_racquet '- Left Racquet
r_racquet '- Right Racquet.
Trenutno bih da na njih gledamo kao na dva objekta,
koji imaju samo jednu jedninu osobinu (.Top)
ciju vrednost menjamo (povecavamo ili smanjujemo).
Vrednost menjamo pritiskom tastera na tastauri,
pa je potrebno pratiti dogadjaje na istoj.
Za to bih iskoristio Timer kontrolu, koju smo inace ubacili u formu
pod imenom GameClock, Proceduru ExecuteGameTick i modul (npr. mAPIFunc).
Da je u pitanju jedan objekat (Kao u DXBall-u) moglo bi drugacije,
ali za ovaj slucaj moramo da iskoristimo API funkciju za pracenje dogadjaja
na tastaturi.
===================Function======================
Code:
Public Declare Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer
===================Function======================
(Ovaj kod se inace kopira u modul mAPIFunc)
(Modul se u projekat ubacuje tako sto kliknete desnim klikom
negde unutar prozora Project Explorer (CTRL+R) zatim Add->Module i kliknete na Module.
Nakon toga u Project Exploreru dobijete Module1 i onda mu promenite Name u mAPIFunc)
Funkcija je krajnje prosta!|
__________________________/
Definisana je kao Public iz tog razloga sto se nalazi
u mAPIFunc, a mi je koristimo u fMain.
Funkcija se zove GetAsyncKeyState i samo ime govori sta funkcija radi.
Svaki taster na tastaturi ima svoj Async CODE i kada ga pritisnemo
iz tastature se taj kod salje (kodiran/dekodiran) komp-u na dalju obradu,
a tom tasteru STATE dobija vrednost TRUE.
Kada mi podignemo prst sa njega njegovo STATE(eng.:State = Stanje)
dobija vrednost FALSE.
Posto svaka igra ima svoje upravljacke kontrole tako sam i
ja za ovaj primer postavio sledece:
=============Kontrole za pomeranje racqueta=================
1. Player: W (UP) ; S (DOWN)
2. Player: UpArrow (UP) ; DownArrow (DOWN)
=============Kontrole za pomeranje racqueta=================
E, GetAsyncKeyState API funkcija sluzi da ispita da li je stanje nasih tastera
TRUE ili FALSE (Da li su pritisnuti ili ne).
Pa sledi kod za Proceduru ExecuteGameTick (koja se izvrsava svakih 50 miliseconds)
'======================1. Deo koda=======================
Code:
'\/-Oba reketa idu gore
If GetAsyncKeyState(vbKeyW) And &H8000 Then
If GetAsyncKeyState(vbKeyUp) And &H8000 Then
l_racquet.Top = l_racquet.Top - 5 'levi reket ide gore
r_racquet.Top = r_racquet.Top - 5 'desni reket ide gore
End If
End If
'\/-Oba reketa idu dole
If GetAsyncKeyState(vbKeyS) And &H8000 Then
If GetAsyncKeyState(vbKeyDown) And &H8000 Then
l_racquet.Top = l_racquet.Top + 5 'levi reket ide dole
r_racquet.Top = r_racquet.Top + 5 'desni reket ide dole
End If
End If
'========================2. Deo koda====================
'======================== (PLayer 1) =====================
'\/-Levi reket ide gore
If GetAsyncKeyState(vbKeyW) And &H8000 Then
l_racquet.Top = l_racquet.Top - 10
End If
'\/-Levi reket ide dole
If GetAsyncKeyState(vbKeyS) And &H8000 Then
l_racquet.Top = l_racquet.Top + 10
End If
'======================== (PLayer 2) =====================
'\/-Desni reket ide gore
If GetAsyncKeyState(vbKeyUp) And &H8000 Then
r_racquet.Top = r_racquet.Top - 10
End If
'\/-Desni reket ide dole
If GetAsyncKeyState(vbKeyDown) And &H8000 Then
r_racquet.Top = r_racquet.Top + 10
End If
'======================== End =====================
-U 1. delu koda imamo slucaj kada se istovremeno pritisnu
2 tastera i to:
W (Up za Player 1) i UpArrow (Up za Player 2)-Oba R idu GORE
&
S (Down za Player 1) i Down Arrow (Down za PLayer 2)-Oba R idu DOLE
-U 2. delu koda se nalaze naredbe za slucaj kada se pritisne
samo jedan taster.
Kao sto se da primetiti iz gornjeg koda reket ide:
GORE kada se njegovo svojsvto TOP smanjuje,
a DOLE kada se TOP povecava !!!
To je to !!!
[ Aleksandar Ružičić @ 26.06.2005. 01:17 ] @
heh, bas sam ja sad hteo da okacim kod za pomeranje reketa :D (ali bez api-ja, necemo odmah advanced :p) ali mislim da je steewsc sve veoma dobro objasnio tako da nema potreba da jos i ja pisem :D
[ Dark Icarus @ 27.06.2005. 13:49 ] @
Odlično, odlično, krenulo je, samo bih imao par smernica koje će kod učiniti čitljivijim.
a) Umesto da stalno pišete Code: If GetAsyncKeyState(vbKeyW) And &H8000 Then ... , bolje je da napravite funkciju:
Code: Public Function KeyPressed(iKey As Long) As Boolean
KeyPressed = ((GetAsyncKeyState(iKey) And &H8000) = &H8000)
End Function i onda samo pišete Code: If KeyPressed(vbKeyW)...
Naravno, preterano stekovanje procedura nije baš najpoželjnija stvar, ali na ovom nivou nam je cilj da pišemo čitljiv kod, a ne da ga optimizujemo do daske.
b) steewsc, nije mi jasno šta će ti ono što si obeležio kao "prvi deo koda" kada se proverava da li su obe dirke pritisnute. I ako se istovremeno pritisnu oba tastera, biće obrađeni jedan po jedan u "drugom delu koda". Predlažem da prvi deo izbrišete. Osim ako nemaš neki razlog zašto se reketi pomeraju za 50% brže kada se oba pomeraju u istom smeru (jer će ti se u tom slučaju izvršiti i prvi i drugi deo koda i svaki reket će ukupno preći 5 piksela u prvom delu koda i još 10 u drugom redu).
c) mislim da je krajnje vreme da naučimo ponešto novo i o konstantama. Umesto da pomerate Top za 5 ili 10 ili koju god vrednost, bolje je da u kod stavite:
Code: Private Const C_RacquetSpeed As Single = 10
' ovo treba ukucati odmah ispod Option Explicit naredbe
Sada u celom kodu gde god imamo npr.
Code: l_racquet.Top = l_racquet.Top + 10
menjamo u
Code: l_racquet.Top = l_racquet.Top + C_RacquetSpeed
'Ajde da vidimo ko ima ideju zašto je to dobro.
VRLO BITNO!!! Primetite da sam konstantu imenovao sa C_ i onda ime konstante. Ovo je neki moj interni način imenovanja konstanti. Inače programeri konstante imenuju VELIKIM_SLOVIMA, ali meni je to uvek bilo nekako glupavo (čini mi se kao da se konstante deru na mene sa monitora). Uvek je neophodno imati NEKI način da se konstante razlikuju od varijabli, tako da ja koristim C_ImeKonstante.
(Ako neko ne zna teoriju iza konstanti... hm... haj'mo ovako, na brzinu: Konstanta je kao varijabla, samo što kada joj jednom zadaš vrednost, ona ne može da se promeni tokom programa.)
d) kad smo već kod imenovanja, preporučujem da rekete ne zovete prefiksima l_ i r_ jer se prefiks odvojen podvlakom pre imena varijable u programiranju koristi za oznaku tipa varijable ili nivoa na kojem je deklarisan. Npr g_Objekat je globalni objekat, m_Device je device definisan na nivou modula, b_Destroyed bi mogla biti boolean varijabla... Na ovu nomenklaturu ćete vrlo često nailaziti tako da je bolje da rekete nazovete drugačije.
Predlažem da ih preimenujete u RacquetLeft i RacquetRight.
To je to, sada moram da idem, a kad ću opet doći do civilizacije i izlaza na internet, ne zna se... u međuvremenu, srećno!
I pozdrav!
[ steewsc @ 30.06.2005. 11:12 ] @
Evo me ponovo!!!
Sto se tice onog 1. dela koda potpuno si u pravu. Ispravio sam to
(Potpuno beskorisno i ometa rad)
E sad, u vezi konstante C_RacquetSpeed:
To je OK, ali sam ja mislio da umesto da se reketi krecu const brzinom postavimo
neko blago ubrzanje.
Potrebno je da definisemo varijabilu (Promenljivu) V_RacquetStep
Code:
Private V_RacquetStep As Long
Naravno ispod Option Explicit-a !!!
Zatim u kod za InitializeApplication() ubaciti:
Code:
V_RacquetStep = 1
U kod za ExecuteGameTick()
Code:
If KeyPressed(vbKeyW) Then
If RacquetLeft.Top > 20 Then
V_RacquetStep = V_RacquetStep + 0.6
RacquetLeft.Top = RacquetLeft.Top - Round(V_RacquetStep, 0)
Else
V_RacquetStep = 0
End If
End If
If KeyPressed(vbKeyS) Then
If RacquetLeft.Top < 300 Then
V_RacquetStep = V_RacquetStep + 0.6
RacquetLeft.Top = RacquetLeft.Top + Round(V_RacquetStep, 0)
Else
V_RacquetStep = 0
End If
End If
'=================================================
If KeyPressed(vbKeyUp) Then
If RacquetRight.Top > 20 Then
V_RacquetStep = V_RacquetStep + 0.6
RacquetRight.Top = RacquetRight.Top - Round(V_RacquetStep, 0)
Else
V_RacquetStep = 0
End If
End If
If KeyPressed(vbKeyDown) Then
If RacquetRight.Top < 300 Then
V_RacquetStep = V_RacquetStep + 0.6
RacquetRight.Top = RacquetRight.Top + Round(V_RacquetStep, 0)
Else
V_RacquetStep = 0
End If
End If
A zatim dodamo jos tri reda na kraju naseg koda:
Code:
Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
V_RacquetStep = 0.1
End Sub
[Ovu poruku je menjao steewsc dana 30.06.2005. u 12:14 GMT+1]
[ steewsc @ 30.06.2005. 11:15 ] @
Objasnjenje Koda:
Varijabila za razliku od konstante moze da menja svoju vrednost;
Pri samom startu igre V_RacquetStep dobija vrednost 1.
(Ovo se izvrsava unutar InitializeApplication())
Kada pritisnemo neki od kontrolnih tastera V_RacquetStep se poveca
za 0.6 :
Code:
'....
V_RacquetStep = V_RacquetStep + 0.6
RacquetLeft.Top = RacquetLeft.Top - Round(V_RacquetStep, 0)
'....
(Neznam zasto, ali kad stavim 0.5 reketi se ne pomeraju)
U sledecem redu se vidi da se vrsi zaokruzivanje na celebrojnu vrednost.
Tako da se postepeno reketi ubrzavaju.
A nakon toga sto pustimo neki kotrolni taster, V_RacquetStep
dobija vrednost 0.1 (A za to je zasluzan kod u dogadjaju KeyUp)
Code:
Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
V_RacquetStep = 0.1
End Sub
Ovo sa ubrzanjem moze da se izbaci ako je nepotrebno.
===========================================================
-To je to sto se tice reketa i mislim da je za sada dovoljno.
©i@
[Ovu poruku je menjao steewsc dana 30.06.2005. u 12:18 GMT+1]
[Ovu poruku je menjao steewsc dana 30.06.2005. u 12:24 GMT+1]
[ mladenovicz @ 30.06.2005. 11:24 ] @
Citat: steewsc:
(Neznam zasto, ali kad stavim 0.5 reketi se ne pomeraju)
Pogledaj kako radi Round funkcija
[ steewsc @ 30.06.2005. 11:30 ] @
Ma OK,
ali V_RacquetStep se povecava svaki put za 0.5.
Tako da kada ima vrednost X.5 zaokruzio bi na X.
U prvom slucaju bi bilo 0, ali u sledecem bi vec bilo 1,
pa zatim 2 itd. Ali nece, evo bas sad probam.
[ mladenovicz @ 30.06.2005. 12:01 ] @
Obavezno stivo na temu zaokruzivanja
How To Implement Custom Rounding Procedures
[Ovu poruku je menjao mladenovicz dana 30.06.2005. u 13:04 GMT+1]
[ Aleksandar Ružičić @ 30.06.2005. 12:22 ] @
problem ti je ovde:
Code:
Private V_RacquetStep As Long
Long tip moze da drzi veoma velike brojeve ali NE i float-point (aka decimalne) brojeve a 0.5 je decimalni broj ;)
umesto Long koristi Single ili Double (oba tipa su za decimalne brojeve samo sto Double ima veci "kapacitet", za ovu nasu igru ja bih koristio Single)
dakle:
Code:
Private V_RacquetStep As Single
ce resiti problem :D
/edit
tek sad procitah ceo kod (izvini, procitao sam samo Zeljkov quote) ne znam samo iz kog razloga koristis Round? Top property je Single tipa i ako deklarises V_RecquetStep kao Single zasto bi zaoukruzivao?
[Ovu poruku je menjao krckoorascic dana 30.06.2005. u 13:32 GMT+1]
[ Dark Icarus @ 04.07.2005. 08:43 ] @
Pozdravljam eksperimentisanje sa varijablama, i rad sa floating point-om. Ali, koliko vidim ovaj postojeći kod je previše komplikovan. Jednostavnost, ljudi, jednostavnost! Plus, kada se desi KeyUp event BILO KOJE dirke to će uzrokovati da svi reketi momentalno uspore na nulu. Ne vidim zašto koristiš KeyUp kada imamo KeyPressed proceduru. Ovo je sve, složićete se, neprihvatljivo za jedan Pong. Ako hoćete da imate ubrzanje reketa, to se radi na sledeći način:
Umesto konstante za brzinu reketa uvedite konstantu za maksimalnu brzinu i još jednu za ubrzanje reketa. Zatim brzinu reketa odvojte u jednu varijablu za svaki reket.
Zatim radite sledeće u svakom ciklusu:
AKO je pritisnuta dirka da reket ide naviše, brzina reketa = brzina reketa- ubrzanje
AKO je pritisnuta dirka da reket ide naniže, brzina = brzina + ubrzanje.
AKO nije pritisnute ni jedna dirka za dati reket, brzina = brzina - ubrzanje * Sgn(brzina) ' ako ne razumete, samo pogledajte help za Sgn funkciju
AKO je brzina veća od max brzine, brzina = max. brzina
AKO je brzina manja od -max brzine, brzina = -max. brzina
AKO je reket udario u gornji ili donji zid, brzina = 0 (hint: prostim manevrom u ovoj liniji možete da uradite algoritam za odbijanje reketa od zidova ako ide velikom brzinom!)
Dodao bih tu kasnije još par korekcija da nam reket ne bi podrhtavao u mestu usled trećeg AKO, ali o tom potom. Mogao sam lakše ovo da vam iskucam kao kod, ali namerno nisam - ovo nije tutorijal "kako koristiti Ctrl-C i Ctrl-V".
Ovako se postižu sve kalkulacije ubrzanja u jednostavnom "min speed-max speed-accelleration" modelu. Postoje i napredniji modeli (frikcioni model, Runge-Kutta integracija itd.) ali oni se koriste za simulaciju realistične fizike koja za naš Pong nije primenjiva (bar ne dok je običan Pong ) tako da o tome nećemo sada. 
[ Mydoom.f @ 10.07.2005. 20:35 ] @
Ljudi, jel ce biti nastavka???!!!
[ steewsc @ 18.07.2005. 19:59 ] @
Ja se izvinjavam sto kasnim!!!
(Procitao sam round tut. od MS-a, bio na nekom kampovanju balblablabl NIJE BITNO)
Nakon sto sam procitao sta je D.I. napisao, primenio i ispravio sam svoj kod tako da sada stvari stoje ovako:
Svaki reket ima svoju brzinu.
Maximalna brzina i ubrzanje je KONSTANTNO i isto za oba reketa.
Brzine: V_lRacquetSpeed, V_rRacquetSpeed as Single
Ubrzanje: Const V_RacquetAcc As Single = 0.5
Max. Brzina: Const V_RacquetMaxSpeed As Single = 5
(Sve ovo definisemo u Option Explicit kao Private)
Ako postavimo u INICIJALIZACIJI sledece:
Code:
V_lRacquetSpeed=0
V_rRacquetSpeed=0
I sada kada pritisnemo neki od kontrolnih tastera (npr. vbKeyW) desava se sledece:
Proveri se da li je V_lRacquetSpeed >= V_RacquetMaxSpeed, sto nije tacno u
prvom slucaju
i onda se V_lRacquetSpeed poveca za V_RacquetAcc (odnosno za 0.5).
Nakon toga se promeni vrednost:
RacquetLeft.Top-a
u
RacquetLeft.Top - V_lRacquetSpeed.
U sledecem ciklusu V_lRacquetSpeed ima vrednost 0.5, ali i dalje je manja od V_RacquetMaxSpeed.
I tako prodju 10 ciklusa i V_lRacquetSpeed bude jednako sa V_RacquetMaxSpeed, a onda, da se dalje
ne bi povecavala, V_lRacquetSpeed dobija vrednost od V_RacquetMaxSpeed i tako sve dok se ne pusti vbKeyW.
Kada se pusti vbKeyW V_lRacquetSpeed ponovo dobija vrednost 0.
--------------------------------------------------------------------------------
Ovo isto se primeni i za slucaj kada se pritisne vbKeyS, ali uz promenu reda:
RacquetLeft.Top - V_lRacquetSpeed
u
RacquetLeft.Top + V_lRacquetSpeed (Da bi isao na dole!!!)
I isto tako isto i za drugi (desni) reket, ali uz koriscenje:
V_rRacquetSpeed (umesto V_lRacquetSpeed).
--------------------------------------------------------------------------------
I to bi bilo to sto se tice reketa od mene. Sledeca stvar bi po meni bila loptica.
[ steewsc @ 18.07.2005. 20:00 ] @
Za lopticu sam iskoristio jos jedan shape sa imenom OBall.
OBall.Height=17
i
OBall.Width=17
---------------------------------------------------------
Loptica je objekat koji mora NON-STOP da se krece.
Za sada cemo se zadovoljiti sa CIK-CAK kretanjem loptice.
Ponovo koristimo GameClock, a ovaj put za kretanje OBall-a.
(Molio bih D.I.-a ili Krcka da me isprave, jer ce ako ovako nastavim
procedura MainLoop ostati prazna  !!!)
Ali dok ne dodje do ispravke †RADICEMO KAKO JA KAZEM, ILI VAS NECE BITI!!!†

Svejedno, jos jednom GameClock:
Da bi se loptica kretala u CIK-CAK putanji potrebno je NON-STOP smanjivati
(do gornje granice) .Top ili povecavati (do donje granice) .Top, povecavati .Left (do desne granice) ili smanjivati .Left (do leve granice).
Pocnimo od toga da se npr. OBall nalazi negde na sredini forme.
Moje koordinate za OBall su (174,293).
Prvo je npr. pokrecemo na dole-desno.
Potrebno je istovremeno povecavati .Top i .Left OBall-a i on ce se kretati
DOLE-DESNO. Povecavacemo ih za konstantnu vrednost(za sada).
Definisemo PROMENLjIVE u Option Explicit-u
Code:
Private BallXMove,BallYMove As Single
Private Racquet_Height As Integer
Private Score1 As Boolean
U inicijalizaciji:
Code:
BallYMove = 2
BallXMove = 2
Score = False
Znaci pomeranje na DOLE-DESNO:
Code:
OBall.Left = OBall.Left + BallXMove
OBall.Top = OBall.Top + BallYMove
Da se ne bi OBall kretao u nedogled, DOLE-DESNO, potrebno je postaviti prvo DONjU,a zatim i DESNU granicu kretanja. Svaka granica je jedan broj i potrebno je nakon povecanja(smanjenja) vrednosti .Left i .Top proveriti da li OBall nije presao preko granice.
Kada OBall.Top bude vece (ili jednako) od DONjE granice menjamo BallYMove:
Code:
BallYMove=-BallYMove
Slicnu proveru vrsimo za slucaj kada OBall.Top bude manje ili jednako od GORNjE
granice i tada takodje koristimo BallYMove=-BallYMove.
A dalje sledi provera da li je OBall presao desnu granicu i ako nije opet nastavljamo sa:
Code:
OBall.Left = OBall.Left + BallXMove
OBall.Top = OBall.Top + BallYMove
Ako jeste presao desnu granicu vrsimo proveru da li se u blizini nasao desni reket.
Code:
For Racquet_Height = 0 To 41
If OBall.Top = Round(RacquetRight.Top, 0) + Racquet_Height Then
GoTo Nastavi_Dalje
End If
Next Racquet_Height
Score1 = True
GoTo Restartuj
Zasto je bas zadnja vrednost koju promenljiva Racquet_Height uzima 41.
Pa ako spojite u jedno, onda se dobije:
Racquet_Height = 41, odnosno RacquetRight.Height je 41.
Pa da vidimo sta se ovde desava:
(Valjda zate kako radi For Next petlja?!)
OBall je presao desnu granicu i ako se njegov .Top nasao negde od
RacquetRight.Top do RacquetRight.Top + Racquet_Height onda se igra NASTAVLjA DALjE,ali uz promenu:
Code:
BallXMove = -BallXMove
sada se OBall krece "gore"- LEVO (Drugi smer!!!)
U slucaju da se nije nasao negde od RacquetRight.Top do
RacquetRight.Top + Racquet_Height 1. igrac je dobio poen, odnosno
po izlasku iz For...Next petlje Score1 postaje TRUE, sto se kasnije koristi
radi povecanja broja poen 1. igraca. Nakon ovoga izvrsava se deo koda koji
sve vraca na pocetak (SEM BROJA POENA  ).
!!! NE ZELIM DA PISEM KOD ZA DRUGI SLUCAJ (ZA LEVI REKET), ALI GA ZATO VI NAPISITE
ANALOGNO OVOME !!!
={©IÂ}=
[Ovu poruku je menjao steewsc dana 18.07.2005. u 22:57 GMT+1]
[ steewsc @ 14.08.2005. 20:11 ] @
Ej ljudi trenutno sam na moru u CG i lepo mi je  . Dok sam bio kuci elitesecurity.org mi nije radio i zato cim dodjem kuci ide se dalje. Ajd ©i@
[ Aleksandar Ružičić @ 16.08.2005. 03:56 ] @
Citat: steewsc: Ej ljudi trenutno sam na moru u CG i lepo mi je :). Dok sam bio kuci elitesecurity.org mi nije radio i zato cim dodjem kuci ide se dalje. Ajd ©i@
haha, posalji nam koju razglednicu :)
[ steewsc @ 17.10.2005. 11:18 ] @
Sada bih da se odradi odbijanje oBall-a (loptice) o reket u zavisnosti od ugla pod kojim udari u reket.
Da bi se to postiglo ja sam reket podelio na 4 oblasti (Height=40),
__ _ 0
| A|
|__| _ 10
| B|
|__| _ 20
| C|
|__| _ 30
| D|
|__| _ 40
a odijanje zavisi (pored toga u koju obalast reketa udari Oball) i od toga da li je BallY vece ili manje od nule.
Odnosno da li se krece na gore/na dole.
Pa da predjem na stvar:
Uzmimo slucaj kada se oBall krece na gore (BallY<0):
Imamo 5 moguca slucaja:
I)
Udarice u oblast A(>=0 i <=10)
II)
udarice u oblast B(>10 i <=20)
III)
udarice na granici izmedju B i C (20)
IV)
udarice u oblast C(>20 i <=30)
V)
udarice u oblast D(>30 i <=40).
B i C je sredina reketa i ako oBall udari u nju trebalo bi da se odbije kao od zida.
U ostala 4 slucaja loptica se odbija i dolazi do promene vrednosti BallY i to na sledeci nacic:
Oblast A => BallY=BallY + 1.5
Oblast B => BallY=BallY + 1
Oblast B & C => BallY=BallY (Ne menja se!!!)
Oblast C => BallY=BallY - 1
Oblast D => BallY=BallY - 1.5
Kod za Oblast A bi izgledao:
Code:
If Racquet_Height >= 0 Then
If Racquet_Height <= 10 Then
BallYMove = BallYMove - 1.5
End If
End If
Ostali su isti uz promenu brojeva (-1.5 -> -1 | -1 ->1 | 1 -> 1.5).
------------------------------
Za kretanje loptice na dole je obrnuto.
(<- ZA slucaj da neki neznaju ->)
Ispitivanje da li je BallY negativno ili pozitivno vrsi se na sledeci nacin:
Code:
If Ball<0 Then
'Slucaj kada se loptica krece na gore
Else
'Slucaj kada se loptica krece na dole
End if
END.
[ steewsc @ 17.10.2005. 11:20 ] @
Molio bih iskusnije da me isprave, ako znaju neki drugi nacin da se ovo izvede!
[ steewsc @ 30.11.2005. 12:19 ] @
Nemam drivere za graficku i zbog toga nemogu da nastavim.
Kad kupim novu graficku izbunaricu negde ovu temu.
Verovatno ce biti negde duboko, posto niko nece da radi.
Ajd.
[ Dark Icarus @ 21.12.2005. 09:10 ] @
Ne budi tako siguran... sto b' reko Švarci : I'll be baak.
Vraćam se na Net do nove godine i imam svaku nameru da nastavim sa našim zajedničkim radom na Vectorball-u. Pregledaću sve što je rađeno od jula, pa ću napisati najbolji i najjednostavniji mogući kod, debelo ga komentarisati i uploadovati projekat na net. A onda cu da podelim domaće zadatke. Ima li vas još ili ću da predajem praznoj učionici?
[ Aleksandar Ružičić @ 21.12.2005. 18:43 ] @
Citat: Dark Icarus:...Ima li vas još ili ću da predajem praznoj učionici?
ima nas ucho al smo mirni pa se necujemo :D
navalite ljudi, ja se ukljucujem cim se stigne kod api-ja... (koliko u sledecem koraku :D)
poz
[ steewsc @ 22.12.2005. 14:44 ] @
i ja sam tu.
Copyright (C) 2001-2025 by www.elitesecurity.org. All rights reserved.
|