[ reiser @ 28.08.2003. 12:31 ] @
Pisem Arkanoid u Delphiju 6. Dosao sam do kreiranja nivoa, i imam jedan problem. Kad se igrica startuje, treba da iscita .dat fajl u kome se nalaze podaci za odredjeni nivo. Prvo idu koordinate plocice (recimo 2 23), pa zatim ostali podaci za tu plocicu. E sad, kad program iscita koordinate, kako da on napravi TImage objekat sam od sebe, koji ce se nalaziti na koordinatama 2 23 ?
[ overflow @ 28.08.2003. 15:17 ] @
Code:

Var Img : TImage;
Begin
   Img := TImage.Create(Form1);  // owner je dakle Form1
   Img.Left := 2;
   Img.Top := 32;
   Img.Parent := Form1;    
   .
   .
   .
End;
[ reiser @ 28.08.2003. 15:28 ] @
Samo da probam pa cu da javim kako sam proso... :D
[ reiser @ 28.08.2003. 15:44 ] @
Bravo majstore, ajde sad mi kazi jos kako da ucitam odredjeni deo slike, a ne celu sliku i vise necu da gnjavim. Napravio sam jedan bmp, koji sadrzi sve vrste zidova. Kako da ucitam recimo zid u 3. koloni i 2. redu ?
[ overflow @ 28.08.2003. 19:46 ] @
Mislim da bi ti funkcija BitBlt bila od pomoci za tako nesto, mada nisam siguran da je to i najelegantnije resenje. Njome sa source handle kopiras sa odredjene XY koordinate odredjen width i height na destination handle. Pogledaj help za detalje oko koriscenja.
[ reiser @ 29.08.2003. 19:24 ] @
ufff..., ima li neki drugi nacin?
[ goblin @ 31.08.2003. 13:30 ] @
BitBlt je zaista sjajna API funkcija za kopiranje delova slika (i mnogih drugih stvari i to veoma brzo). Mada deluje kao izuzetno komplikovana, jedina stvar koja je kod nje zastrasujuca jeste sto ima vise parametara i sto ne radi sa nekim TCanvas objektom kao takvim, vec sa handlerom (hDC) nekog canvasa. Dakle, u parametrima ove funkcije ide Timage.Picture.Bitmap.Cavas.Handle (ako radis sa bitmapom u TImage, mada ne bi trebalo da bude problema ni sa Graphic umesto Bitmap, ako imas jpeg sliku... onda ti je ugnjezden objekat TJpeg, a ne TBitmap - mada ovo ruku na srce nisam probao).
Sve u svemu, evo ti aktivan primer iz jedne moje male desktop igre:

Code:

BitBlt(frmMAIN.Canvas.Handle, lastX, lastY, image1.Width, 
image1.Height,BackroundBuffer.Canvas.Handle, lastX, lastY, SRCCOPY);


frmMAIN je naziv forme na kojoj iscrtavam, mada to moze da bude bilo koja komponenta koja ima canvas sa mogucnoscu pisanja, cak i neka bitmapa
backgroundBuffer je TBitmap koji cuva sliku desktopa. lastX i lastY su koordinate gornjeg levog ugla pravougaonika, a image1.Width i image1.height su, nagadjas...

Medjutim, vaznija stvar ovde je malo nepraktican sistem rada... nikako ti ne preporucujem da pravis previse objekata TImage na formi... nikako. Mislim, ne znam kako ce uopste da izgleda igra, ali ako nameravas da kreiras 20x20 plocica to ti je 400 objekata... kako ces da drzis celu zver pod kontrolom? Prijateljski savet sa cuvanje zivaca: nabaci neki paintbox (unutar kojeg ces po mogucstvu da presretnes i ponistis poruku WM_ERASEBKGND da bi izbegao suvisan & ruzan refreshing, a pritom ti osnovno iscrtavanje ostaje netaknuto) i na njemu iscrtavaj celu stvar. Brze, efikasnije i lakse za odrzavanje. Believe me :)

Pozdrav, Milan

P.S. Ako zaista zelis da radis na neki laksi nacin (?) probaj da radis sa Pixels metodom nekog TCanvas-a kojom pristupas individalnim pikselima, tj. njegovoj boji... ali u stvari dobijes komplikovaniji kod... izbor je tvoj.
[ reiser @ 31.08.2003. 16:00 ] @
@goblin:
Hvala na iscrpnom odgovoru, pokusacu da radim sa tom naredbom (pocetnik sam). Zanima me da li to moze da se uradi sa ScanLine precedurom?
[ goblin @ 31.08.2003. 20:28 ] @
Ma, može i tako, ali onda moraš da znaš programiranje dinamičkih promenljivih... Tu imaš nesto što se zove pokazivač na niz bajtova - bez uvrede, ali mislim da na tvom uzrastu ovo može da bude samo noćna mora, bez ikakve potrebe. Nauči prvo rad na jednostavnijim pokazivačkim strukturama pre nego sto uplivaš u ovakve tipove podataka (PByteArray). Moraš da paziš na dužinu niza, kako pristupaš podacima na koje pokazuje pointer, posle memorijski bafer da oslobadjaš... pošto kažeš da si početnik mislim da sve ovo može samo da ti napravi još veću glavobolju od one koje leči.

Sve u svemu, ScanLine bi ti bilo još veće komplikovanje. Pojam "komplikovanje" shvati uslovno... uvek komplikovanost nekog pristupa u programiranju zavisi od uvežbanosti u toj oblasti... posle par programa sa thread-ovima ili dll-ovima pitaćeš se zašto ti nije ranije palo na pamet da kreneš da radiš sa njima pa će kasnije upotreba istih da bude samo stvar potrebe a ne neophodnosti - ScanLine je još jedan sjajan metod ali... da li se isplati cimanje?

Odgovor na tvoje pitanje - možeš da uradiš sa ScanLine, ovaj metod je bolji i brži od Pixels property-ja, ali je BitBlt najbolji. Ne zaboravi da ti je BitBlt WinAPI funkcija... nema gomilanja VCL koda oko tvoje komande... BitBlt radi direktno na handler-u tvojeg platna... tj. najveća brzina! Opet, za BitBlt ti treba najmanje filozofije i rada.
Trust me.
Srećno zaranjanje u Delphi :)
[ reiser @ 01.09.2003. 11:40 ] @
Hvala, napravio sam sa BitBln, ali ide mnooooogo sporo. Kako da uradim to sa PaintBox, celo vece se mucim i ne mogu nikako...
[ Rapaic Rajko @ 01.09.2003. 15:41 ] @
Pogledaj primere za TCanvas.CopyRect(). To ti je 'zapakovano' koriscenje BitBlt funkcije, ali tebi kao pocetniku ce biti lakse za koriscenje.
Batali ScanLine, jer rad sa pixelima u for (ili bilo kojoj drugoj) petlji je spor.

Rajko
[ goblin @ 01.09.2003. 17:01 ] @
Sporo sa BitBlt? Čekaj, pa kako vršiš iscrtavanja? Tj. ako koristiš tajmer koliki ti je interval-nije valjda ispod 100ms? nije valjda da iscrtavaš SVE tj celu formu (treba da iscrtavaš samo deo platna koji se menja)... optimizuj kod, nije stvar u BitBlt-u! Ako bi dao neku skicu kako ti otprilike radi program možda bi neko mogao da ti pomogne...

P.S. Nije bitno na čemu iscrtavaš (da li je to forma ili paintbox) sve dok imaš OnPaint događaj ili dok možeš da utičeš na iscrtavanje te komponente...
[ reiser @ 01.09.2003. 20:07 ] @
Nisi me razumeo. BitBln radi perfektno, ali imam mnogo TImage objekata na ekranu, pa je racunar preopterecen, i loptica ide mnogo sporo. Evo procedure koja iscrtava nivo :
Code:

// Crta plocice (!Brick)
procedure TMainWindow.LevelDraw;
var
 C1  : Integer;
 C2  : Integer;
 Bmp : TBitmap;
begin
 Bmp := TBitmap.Create;
 Bmp.LoadFromFile('bricks.bmp');
 For C1 := 1 to 18 Do
  For C2 := 1 to 31 Do
   If Brick[C1, C2, 1] <> '' Then Begin
    Img[C1, C2] := TImage.Create(MainWindow);
    With Img[C1, C2] Do Begin
     Parent := MainWindow;
     Left := (C1 - 1) * 49 + 1;
     Top := (C2 - 1) * 25 + 1;
     Width := 49;
     Height := 25;
     BitBlt(Canvas.Handle, 0, 0, 49, 25, Bmp.Canvas.Handle,
            (StrToInt(Brick[C1, C2, 2]) - 1) * 49, (StrToInt(Brick[C1, C2, 3]) - 1) * 25, SRCCOPY);
     OnMouseMove := FormMouseMove;
     OnClick := FormClick;
    End;
   End;
 Bmp.Free;
end;

Ajde sad kazi mi kako ovo da uradim sa PaintBox ?
[ goblin @ 01.09.2003. 21:47 ] @
Nisam iskompajlirao, ali teorijski bi trebalo da radi:
Code:

procedure TMainWindow.LevelDraw;
var
 C1  : Integer;
 C2  : Integer;
 Bmp : TBitmap;
 Left, Top : Integer;
begin
 // neka ti se PaintBox zove ClientPaintBox
 Bmp := TBitmap.Create;
 try
  Bmp.LoadFromFile('bricks.bmp');  
  For C1 := 1 to 18 Do
   For C2 := 1 to 31 Do
    If Brick[C1, C2, 1] <> '' Then Begin
      Left := (C1 - 1) * 49 + 1;
      Top := (C2 - 1) * 25 + 1;
      BitBlt(ClientPaintBox.Canvas.Handle, Left, Top, 49, 25, Bmp.Canvas.Handle, (StrToInt(Brick[C1, C2, 2]) - 1) * 49, (StrToInt(Brick[C1, C2, 3]) - 1) * 25, SRCCOPY); 
{
ovo postavis u object inspektoru za paintbox koji dovoljno prosiris da bi se sve videlo
      OnMouseMove := FormMouseMove;
      OnClick := FormClick;
}
    End;
  finally
   Bmp.Free;
  end;
end;



E, sad, ne mogu da ti garantujem da ce ovo da radi (posto ne znam uopste sta ce ti trodimenzionalni niz kad sam ja uvek koristio dvodimenzionalni niz zapisa) ali mislim da ces dobiti ideju sta se uopste radi gore. Posto mi je za nedelju dana jedan ispit ne mogu da ti garantujem ni to da cu se uopste pojvaljivati na forumu narednih desetak dana (dvodelni ispit), ali ako i dalje imas problema prijavi, mozda se ponudi i neko drugi da ti pomogne...

P.S. uvek kad dinamicki kreiras objekte (kao sto si ti kreirao TBitmap) radi sa njima u nekom try bloku da bi ti sto pre postala navika
[ reiser @ 02.09.2003. 10:21 ] @
Sve bi lepo bilo kad bi ovo radilo. Isto ovo sam i ja probao, ali uopste nece da iscrta slicicu na PaintBox - na njemu nema nista. Ako kreiram TImage objekat nalik PaintBox-u, onda radi dobro, ali je pozadina bela, a kad stavim na Transparent := TRUE, ide sporo.
3D nizove koristim zato sto postoji mogucnost da jedna plocica treba, recimo tri puta da se udari lopticom da bi ona nestala, itd itd...
Evo podatka za jednu plocicu :

Brick[x, y, 1] := 3; // Koliko puta loptica treba da udari plocicu da bi ona nestala
Brick[x, y, 2] := 1; // X koordinata 1. plocice u bmp slici
Brick[x, y, 3] := 3; // Y koordinata 1. plocice u bmp slici
Brick[x, y, 4] := 2; // X koordinata 2. plocice u bmp slici
Brick[x, y, 5] := 3; // Y koordinata 2. plocice u bmp slici
Brick[x, y, 6] := 3; // X koordinata 3. plocice u bmp slici
Brick[x, y, 7] := 3; // Y koordinata 3. plocice u bmp slici
Brick[x, y, 8] := U; // Da li je plocica unistiva ili ne (U - unistiva, N - neunistiva)
Brick[x, y, 8] := 150; // Koliko poena vredi plocica

Nadam se da si razumeo ovo sto sam napisao, posto nisam bas dobar u objasnjavanju. :)

Pozdrav, Marko.

P.S. Zelim ti srecu na ispitu !
[ goblin @ 02.09.2003. 10:44 ] @
Kad radis sa TPaintBox onda ti nije fora da naredis iscrtavanje - kao kod TImage. Kad nesto nacrtas na platnu TImage komponente to i ostaje (jer ti zapravo kreiras bitmapu!).
Kad radis sa TPaintBox moras da razmisljas na drugaciji nacin - moras da koristis OnPaint event (kada sistem posalje poruku da je potrebno iscrtavanje) i da iscrtavas kad ti se on pojavi. Ako hoces da ti bas iscrtas, onda fizicki pozoves paintbox.Repaint metod (ja sam pretpostavljao da si ovo vec znao).
Ako ti je pozadina bela znaci da treba da odradis jedan FillRect sa bojom koju hoces. Batali Transparent za ovakve stvari...
Batali trodimenzionaln niz, napravi nesto ovako:
Code:

type

TBrick = record
 NumOfHits, X1, Y1, X2, Y2, X3, Y3 : Integer;
 Destructible : Boolean;
 Value : Integer;
end;

TBricks = array[1..50] of TBrick;
...
var 
 Bricks : TBiricks;

Lakse ces da skapiras sta radis (jer ces imati imena promenljivih umesto brojeva) a i nece ti trebati typecast iz stringa u sve i svasta (komplikujes kod bezveze).

Evo kako je sve ispalo sa paintbox-om (moj Snake):
http://www.geocities.com/lordgoblin83/prgsnake.htm

Pozdrav (e sad i definitivno :)
[ reiser @ 02.09.2003. 11:11 ] @
Ma ja sam vec probao i sa PaintBox.Refresh i PaintBox.Repaint i sa PaintBox.Update, nije telo. Sigurno nesto ne radim dobro. Pozabavicu se time malo duze..
[ reiser @ 02.09.2003. 18:25 ] @
Hvala puno na pomoci, napravio sam. Kad igricu privedem kraju postovacu je ovde pa da vidite sta sam napravio. :)
[ reiser @ 06.09.2003. 20:16 ] @
Ajde sad jos jedno pitanje.... Kada napravim Timer i stavim mu da na 1 ms poziva formu BallMove, loptica ide previse sporo. Ovaj problem sam resio sa Application.OnIdle, ali kada sam odneo do komsije program, loptica je isla mnooogo sporo. Kako ovo da resim, da uvek brzina loptice bude ista, bez obzira na brzinu compa ?
[ morlic @ 06.09.2003. 20:49 ] @
Koristi multimedia timers. Vec sam ovih dana postovao slican odgovor:

timeKillEvent
TimeProc
timeSetEvent

Rade na svim windows platformama i imas u MSDN-u objasnjenja kako se koriste.
[ -zombie- @ 06.09.2003. 21:43 ] @
ali u svakom slučaju nemoj da stavljaš tajmer na 1ms. (usput, na win95/98/me ni ne radi na manje od 10ms valjda).

ljudsko oko registruje nekih 20-25 frejma u sekundi. znači, u najgorem slučaju ti treba tajmer na 40ms.

ako staviš timer na mnogo malu vrednost, windows (nt/2k/xp) će ti u svakom slučaju slati WM_TIMER (ili kako već) poruku na svaku milisekundu, ali ako ti je procedura koja se izvršava na tajmer malo komplexnija (ima petlje, radi neko iscrtavanje...), ona neće stići da se izvrši za tu jednu milisekundu, (nego će recimo izvršavanje svakog ciklusa na tvom (recimo sporijem) računaru trajati 3-4ms, a na drugom 2-3ms), nego će odgovarati na ove WM poruke samo onoliko puta u sekundi koliko stigne.

drugim rečima, u takvom slučaju, brzina tvoje aplikacije će zavisiti od brzine mašine, a to nisi hteo..

znači, stavi tajmer na između 10 i 50ms, (experimentiši) pa ostale parametre podešavaj u odnosu na to...
[ reiser @ 10.09.2003. 16:27 ] @
morlicu, moze li neki example ?
[ morlic @ 12.09.2003. 01:30 ] @
Evo malog primera koji sam ti napravio (trebalo mi je oko sat vremena).
Radio sam ga u D7 ali bi trebao da radi i pod starijim verzijama. Na formi
se nalazi i Image1 u koji treba ucitati surfer.bmp sliku ukoliko je delphi
izgubi. Kasno je pa cu komentarisati stvar drugi put. Eksperimentisi sa
vrednostima...

Primer je zakacen uz poruku...
[ reiser @ 12.09.2003. 15:33 ] @
Hvala na programu, ali ovo je sa TTimer, i ide sporo (necu da je pomeranje loptice po X osi, odnosno Y vece od 1 !). Ima li neki drugi nacin ? (TimeKillEvent, TimeProc, TimeSetEvent)

Pozdrav, Marko.
[ Zekica @ 12.09.2003. 20:47 ] @
Neznam da li je ovo što tebi treba, ali ja sam eksperimentisao.

Naime, timer u WIN98 ne može da se izvršava na intervalu manjem od ne znam tačno 10-40ms. (valjda nešto još iz vremena win 3.11)

Ja sam napravio TTimer komponentu, koja ne poziva sistemske funckije SetTimer, KillTimer... , već kreira poseban thread, koji poziva određenu funkciju svakih nnn ms.

Evo je komponenta u attachmentu, valjda znaš da instaliraš komponente....
[ reiser @ 14.09.2003. 10:27 ] @
Citat:

Ja sam napravio TTimer komponentu, koja ne poziva sistemske funckije SetTimer, KillTimer... , već kreira poseban thread, koji poziva određenu funkciju svakih nnn ms.


ovaj fajl sam otvorio sa delphiem, zatim sam isao na component -> install. Posle toga ubacim u Arkanoid kod 'Uses ....., ThreadTimer'. ThreadTimer komponentu postavim na formu. Sve namestim, stavim timer na enabled, interval na 40 ms, i na dogadjaj pod OnEvent, ne znam kako se zvase, podesim da poziva proceduru. (na svakih 40ms). Zatim u toj proceduri stavim, recimo naredbu ShowMessage('aaa');. Kada startujem program, procedura se uopste ne izvrsava, nema uopste ni ShowMessage poruke. :(
[ morlic @ 14.09.2003. 16:18 ] @
Ne mozes da pozivas iz niti ShowMessage vec samo iz glavne VCL niti.

U svakom slucaju mislim da bi ti najbolje bilo da koristis DirectX za to sto radis. Prvo imao bi resen problem treperenja, frejm rejta (brzine) pa cak i ocitavanja tastature. Sve ovo preko VCL-a je ocajno resenje. Neko je skoro postovao linkove za DelphiX i jos neke stvarcice. Plus MSDN u kome ima dosta primera.

Poenta onog sto sam predlozio u ranijem postu je da razdvojis brzinu racunara i onoga sto se desava u igrici. Od brzine racunara samo treba da zavisi frame rate (bar kada je prostija igrica u pitanju). Dakle probaj DirectX