Spiel Programmieren mit BCB 6
-
Gib dir Recht Jansen,
@Clip du hast wahrscheinlich das Fenster vergrößert und gespeichert.MfG FB
-
Hallo,
es giebt noch ne andere Möglichkeit das Flackern zu
Verhindern, indem man vor dem Neuzeichnen wartet bis der
Elektronenstrahl unten ist, also im Blank bereich (Vsync).Das geht mit Inline Assembler sehr gut, zumindest bei den
meisten Grafikkarten.hier der Code:
//- z.B. ausgelöst durch Timer asm mov dx, 3dah loop1: asm in al, dx asm test al, 8 asm jz loop1 //- Bild neuzeichnen //- weiterer Code
Also mit dem BCB kann man so gut wie alles machen, und oft sehr
Einfach, wenn man die richtige Lösung hat.gruß Micha
-
achso!
-
@Windoof und junix: Mein Beitrag war weder auf DirectX- noch auf OpenGL-Programmierung bezogen. Davon hab ich nämlich absolut keine Ahnung. Ne, ich meinte das Verwenden der Windows GDI (oder eben auch GDI+). Wenn man schlau programmiert (Achtung: Schlüsselstelle ;)), dann merkt man sicher keinen Performance-Unterschied. Ein Mix aus VCL und WinAPI macht's halt. Beim Erstellen von DC's oder Bitmaps kann man die einfachen Methoden der VCL nutzen. Wenn's ums Zeichnen geht, ist WinAPI sicher angebrachter. Tja, und weil ich dann direkt auf die Handles zugreife, ist diese Methode u.U. sogar noch schneller als MFC.
-
Schau mal hier rein vielleicht interesiert es euch auch:
http://www.c-plusplus.net/forum/viewtopic.php?t=67214
-
kann man auch ohne API(DX, Open GL) ein kleines game machen?
z.B. eine Wiese(ScrollBild) über die man mit einer Figur (Bild) per Pfeiltasten läuft?
-
Don Karlo schrieb:
kann man auch ohne API(DX, Open GL) ein kleines game machen?
z.B. eine Wiese(ScrollBild) über die man mit einer Figur (Bild) per Pfeiltasten läuft?Ja kann man mit Bitmap und Canvas
gruß Micha
-
Don Karlo schrieb:
kann man auch ohne API(DX, Open GL) ein kleines game machen?
z.B. eine Wiese(ScrollBild) über die man mit einer Figur (Bild) per Pfeiltasten läuft?Schau mal diese Komponennte an
http://www.hellix.com/Products/TOpenGL.aspIch denke mal da brauchste keine komplizierten API Befehle
-
promicha schrieb:
Don Karlo schrieb:
kann man auch ohne API(DX, Open GL) ein kleines game machen?
z.B. eine Wiese(ScrollBild) über die man mit einer Figur (Bild) per Pfeiltasten läuft?Ja kann man mit Bitmap und Canvas
gruß Micha
Hmm hab mich mal nach Canvas umgesehn, aber nix gefunden, bzw kein Beispiel für dessen Funktion. Kannst du eventuel ein kleines Beispiel geben?(wäre Supi) einfach nur ein Images per PfeilTasten steuern. Für eine Animation von 3 Bildern ( linker Schritt, mitte, rechter schritt,mitte, linker schritt ....usw) brauch ich doch noch kein Open GL oder?
-
Nein das Stimmt dafür brauchste kein OpenGL!
Schau mal hier her:
http://www.c-plusplus.net/forum/viewtopic.php?t=67600promicha hat nen guten Code erstellt
-
Hmm den Thread kenn ich, da hat er nur geschrieben wie man mehrere Bilder animiert, aber net wie man sie gezielt mit den Pfeiltasten verschieben kann.
-
So, fertig.
@Don Karlo
@Ag3ntIch habe jetzt mal auf die ganz Schnelle ein kleines Spiel erstellt, nichts
Grossartiges, aber zum kennenlernen der Canvas Funktionen ausreichend.Hinweis
Vor weg sei gesagt, das ich das ebend zwischen Tür und Angel programmiert
habe, daher ist der Code auch dementsprechen, bitte gewöhnt euch nicht an
viele Globale Variablen zu setzten, benutzt Strukturen und so. Ich möchte
euch nicht zum schlechten Programmierstill führen, daher seht den Code
bitte als reines "Canvas-Beispiel" an.Das Raumschiff wird mit der Maus gesteuert und mit der linken Maustaste
wird gefeuert.
Durch druck auf "q" kann man das Spiel verlassen, und bei 640 Punkte endet
es von selbst.So, wenn ihr den Hinweis gelesen habt und auch Verstanden habt, so könnt ihr
das Projekt "BCBGame" hier runterladen@Don Karlo
Um die Pfeiltasten abzufragen, benutz man OnKeyDown und OnKeyUp.
Canvas sind in der Hilfe sehr gut beschrieben, schaue dir mal die Hilfe-FAQ
von Junix an: ??? Junix wo ist die URL ???
Ansonsten "C++Builder-Hilfe"->"VCL-Referenz"->"Alphabetische Liste der..."->"TC"->"TCanvas"
oberhalb sind die links zu Methoden und Eigenschaftengruß Micha
-
promicha: über der Threadübersicht z.B.
-junix
-
Ah jetzt ja,
war mir nicht gleich aufgefallen, du hattest es sonst in deiner Signatur.
also Don Karlo, lese dir das mal durch und du wirst sehen wie gut die Hilfe
ist.gruß Micha
-
Erst einmal Gratulation sieht super aus.
Kannst du den Code vielleicht bischen erklären ???
Im momment plan ich erlich gesagt fast nichts davon Nagut ein Teil schon aber die *Bitmap geschichte z.B. nicht
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "jpeg.hpp" #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; int backpos=0,shipX=320,shipY=400; bool gegnerda[15]; int gegnerbold = 0; bool GameOver = false; long Punkte = 0; bool fire = false; int firecount = 0; int energy = 100; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { Form1->Close(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { GameOver = false; //Buttons unsichtbar Button1->Visible = false; Button2->Visible = false; Form1->Cursor = crSizeAll; //Bitmaps erstellen Graphics::TBitmap *puffer = new Graphics::TBitmap(); Graphics::TBitmap *backpic = new Graphics::TBitmap(); Graphics::TBitmap *ship = new Graphics::TBitmap(); Graphics::TBitmap *gegnerA = new Graphics::TBitmap(); Graphics::TBitmap *gegnerB = new Graphics::TBitmap(); puffer->Width = 640; puffer->Height = 480; //Grafiken in die Bitmaps laden TJPEGImage *jtemp = new TJPEGImage(); jtemp->LoadFromFile(ExtractFilePath(ParamStr(0))+"back.jpg"); backpic->Assign(jtemp); delete jtemp; ship->LoadFromFile(ExtractFilePath(ParamStr(0))+"ship.bmp"); gegnerA->LoadFromFile(ExtractFilePath(ParamStr(0))+"gegnerA.bmp"); gegnerB->LoadFromFile(ExtractFilePath(ParamStr(0))+"gegnerB.bmp"); //Transparents Einstellung für Schiff und Gegner ship->TransparentColor = clBlack; ship->Transparent = true; gegnerA->TransparentColor = clBlack; gegnerA->Transparent = true; gegnerB->TransparentColor = clBlack; gegnerB->Transparent = true; //Alle Gegner aktivieren for (int w=0;w<16;w++) { gegnerda[w] = true; } DWORD idleTime; bool alleweg; bool treffer = false; int gpos; //Spiel Schleife while (!GameOver) { //Zeit setzten idleTime = GetTickCount() + 50; //Programm Messages abarbeiten Application->ProcessMessages(); //Hintergrund in Puffer zeichnen puffer->Canvas->CopyRect(Rect(0,0,640,480),backpic->Canvas,Rect(0,960-backpos,640,1440-backpos)); backpos++; if (backpos == 960) { backpos = 1; } // Shiff reinzeichnen puffer->Canvas->Draw(shipX,shipY,ship); //Laserstrahl wenn fire = true if (fire && firecount<4) { firecount++; puffer->Canvas->Pen->Color = clAqua; puffer->Canvas->PenPos = Point(shipX+39,shipY); puffer->Canvas->LineTo(shipX+39,0); energy = energy - 2; } else if (firecount >=4 && firecount < 20) { firecount++; } else { treffer = false; firecount = 0; } if (!fire) { firecount = 0; if (energy<100) energy++; } //Energie Balken zeichnen puffer->Canvas->Rectangle(20,460,122,470); puffer->Canvas->Brush->Color = clYellow; puffer->Canvas->FillRect(Rect(21,461,21+energy,469)); if (energy <= 0) GameOver = true; //nun kommen noch die Gegner alleweg = true; gpos = 20; gegnerbold++; if (gegnerbold >=30) gegnerbold = 0; for (int r=8;r<16;r++) { if (gegnerda[r]) { alleweg = false; if (firecount > 0 && firecount < 5) { if (shipX+39>=gpos && shipX+39<=gpos+60 && !treffer) { Punkte = Punkte + 10; gegnerda[r] = false; treffer = true; } else { if (gegnerbold<=15) { puffer->Canvas->Draw(gpos,80,gegnerA); } else { puffer->Canvas->Draw(gpos,80,gegnerB); } } } else { if (gegnerbold<=15) { puffer->Canvas->Draw(gpos,80,gegnerA); } else { puffer->Canvas->Draw(gpos,80,gegnerB); } } } gpos = gpos + 70; } gpos = 20; for (int i=0;i<8;i++) { if (gegnerda[i]) { alleweg = false; if (firecount > 0 && firecount < 5) { if (shipX+39>=gpos && shipX+39<=gpos+60 && !gegnerda[i+8] && !treffer) { Punkte = Punkte + 10; gegnerda[i] = false; treffer = true; } else { if (gegnerbold<=15) { puffer->Canvas->Draw(gpos,10,gegnerA); } else { puffer->Canvas->Draw(gpos,10,gegnerB); } } } else { if (gegnerbold<=15) { puffer->Canvas->Draw(gpos,10,gegnerA); } else { puffer->Canvas->Draw(gpos,10,gegnerB); } } } gpos = gpos + 70; } if (alleweg) { for (int i=0;i<16;i++) { gegnerda[i] = true; } } //Punkte Reinschreiben puffer->Canvas->Brush->Style = bsClear; puffer->Canvas->Font->Color = clYellow; puffer->Canvas->Font->Name = "Arial"; puffer->Canvas->Font->Size = 16; puffer->Canvas->Font->Style << fsBold; puffer->Canvas->TextOutA(20,10,"Score: "+IntToStr(Punkte)); //so Spielende bei 640 Punkte mal festlegen if (Punkte >= 640) { GameOver = true; } //Zeit abwarten while (GetTickCount() < idleTime) { Application->ProcessMessages(); } //Puffer auf Form kopieren Form1->Canvas->CopyRect(Rect(0,0,640,480),puffer->Canvas,Rect(0,0,640,480)); } //Speicher Aufräumen delete puffer; delete backpic; delete ship; delete gegnerA; delete gegnerB; //Form wieder ihr Standart Face geben Form1->Canvas->Brush->Color = clBtnFace; Form1->Canvas->FillRect(Rect(0,0,640,480)); //Buttons sichtbar Button1->Visible = true; Button2->Visible = true; Form1->Cursor = crDefault; Punkte = 0; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { //Wenn q Taste gedrückt, dann Spiel verlassen if (char(Key) == 'Q') GameOver = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { //Schiff position mit MausCursor koordinieren if (X<640 && X>0) shipX = X-39; if (Y>150 && Y<410) shipY = Y-30; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { //Laser an fire = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { //Laser aus fire = false; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { //Fenster-Buttons deaktivieren, da Exit per Button DeleteMenu(GetSystemMenu(Handle, false), SC_CLOSE, MF_BYCOMMAND); DeleteMenu(GetSystemMenu(Handle, false), SC_MINIMIZE, MF_BYCOMMAND); DeleteMenu(GetSystemMenu(Handle, false), SC_MAXIMIZE, MF_BYCOMMAND); } //---------------------------------------------------------------------------
-
Also nun hab ich den Code eigenlich so langsam verstanden
-
Ja?
Gut, dann erkennst du sicherlich das hier mit Millisekunden gemessen wird.
bei spielen ist das Timing immer wichtig, und es ist gut zu wissen wie
lange eine Bestimmte Funktion braucht bis sie Ausgefürt wurde.Da im Code ja schon die Entsprechenden Vorgaben sind um folgende Aufgabe
zu Lösen, dürfte es kein Problem sein.
Aufgabe:
Ändere den Code mal so ab das du messen kannst wie viel Millisekunden die
Funktion nach "//Hintergrund im Puffer zeichen" benötigt, also dieses
puffer->Canvas->CopyRect....
Um dir diesen Wert dann anzeigen zu lassen kannst du die Funktion missbrauchen,
welche die Punkte auf dem puffer schreibt, also statt Punkte deinen Wert.
Die Lösung zu dieser Aufgabe springt einem Förmlich ins Gesicht.Der Sinn ist, zu verstehen das bei sehr vielen zeichnenoperation das ganze
auch stark ausbremsen kann.gruß Micha
-
Trotzdem hab ich noch ein paar Fragen
Also was bewirkt folgende Anweisung:
Application->ProcessMessages();
Ich werde von den BCB Beispielen einfach nicht schlau
Ansonsten Super Code
Woher kann man solche Spiel Grafiken herbekommen ???
-
Micha ich versteh deine Aufgabe nicht ganz
So ???
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "jpeg.hpp" #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; int backpos=0,shipX=320,shipY=400; bool gegnerda[15]; int gegnerbold = 0; bool GameOver = false; long Punkte = 0; bool fire = false; int firecount = 0; int energy = 100; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { Form1->Close(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { GameOver = false; //Buttons unsichtbar Button1->Visible = false; Button2->Visible = false; Form1->Cursor = crSizeAll; //Bitmaps erstellen Graphics::TBitmap *puffer = new Graphics::TBitmap(); Graphics::TBitmap *backpic = new Graphics::TBitmap(); Graphics::TBitmap *ship = new Graphics::TBitmap(); Graphics::TBitmap *gegnerA = new Graphics::TBitmap(); Graphics::TBitmap *gegnerB = new Graphics::TBitmap(); puffer->Width = 640; puffer->Height = 480; //Grafiken in die Bitmaps laden TJPEGImage *jtemp = new TJPEGImage(); jtemp->LoadFromFile(ExtractFilePath(ParamStr(0))+"back.jpg"); backpic->Assign(jtemp); delete jtemp; ship->LoadFromFile(ExtractFilePath(ParamStr(0))+"ship.bmp"); gegnerA->LoadFromFile(ExtractFilePath(ParamStr(0))+"gegnerA.bmp"); gegnerB->LoadFromFile(ExtractFilePath(ParamStr(0))+"gegnerB.bmp"); //Transparents Einstellung für Schiff und Gegner ship->TransparentColor = clBlack; ship->Transparent = true; gegnerA->TransparentColor = clBlack; gegnerA->Transparent = true; gegnerB->TransparentColor = clBlack; gegnerB->Transparent = true; //Alle Gegner aktivieren for (int w=0;w<16;w++) { gegnerda[w] = true; } DWORD idleTime; bool alleweg; bool treffer = false; int gpos; //Spiel Schleife while (!GameOver) { //Zeit setzten idleTime = GetTickCount() + 50; //Programm Messages abarbeiten Application->ProcessMessages(); //Hintergrund in Puffer zeichnen puffer->Canvas->CopyRect(Rect(0,0,640,480),backpic->Canvas,Rect(0,960-backpos,640,1440-backpos)); backpos++; puffer->Canvas->Brush->Style = bsClear; puffer->Canvas->Font->Color = clYellow; puffer->Canvas->Font->Name = "Arial"; puffer->Canvas->Font->Size = 16; puffer->Canvas->Font->Style << fsBold; puffer->Canvas->TextOutA(20,420,"Idle Time: "+IntToStr(idleTime)); if (backpos == 960) { backpos = 1; } // Shiff reinzeichnen puffer->Canvas->Draw(shipX,shipY,ship); //Laserstrahl wenn fire = true if (fire && firecount<4) { firecount++; puffer->Canvas->Pen->Color = clAqua; puffer->Canvas->PenPos = Point(shipX+39,shipY); puffer->Canvas->LineTo(shipX+39,0); energy = energy - 2; } else if (firecount >=4 && firecount < 20) { firecount++; } else { treffer = false; firecount = 0; } if (!fire) { firecount = 0; if (energy<100) energy++; } //Energie Balken zeichnen puffer->Canvas->Rectangle(20,460,122,470); puffer->Canvas->Brush->Color = clYellow; puffer->Canvas->FillRect(Rect(21,461,21+energy,469)); if (energy <= 0) GameOver = true; //nun kommen noch die Gegner alleweg = true; gpos = 20; gegnerbold++; if (gegnerbold >=30) gegnerbold = 0; for (int r=8;r<16;r++) { if (gegnerda[r]) { alleweg = false; if (firecount > 0 && firecount < 5) { if (shipX+39>=gpos && shipX+39<=gpos+60 && !treffer) { Punkte = Punkte + 10; gegnerda[r] = false; treffer = true; } else { if (gegnerbold<=15) { puffer->Canvas->Draw(gpos,80,gegnerA); } else { puffer->Canvas->Draw(gpos,80,gegnerB); } } } else { if (gegnerbold<=15) { puffer->Canvas->Draw(gpos,80,gegnerA); } else { puffer->Canvas->Draw(gpos,80,gegnerB); } } } gpos = gpos + 70; } gpos = 20; for (int i=0;i<8;i++) { if (gegnerda[i]) { alleweg = false; if (firecount > 0 && firecount < 5) { if (shipX+39>=gpos && shipX+39<=gpos+60 && !gegnerda[i+8] && !treffer) { Punkte = Punkte + 10; gegnerda[i] = false; treffer = true; } else { if (gegnerbold<=15) { puffer->Canvas->Draw(gpos,10,gegnerA); } else { puffer->Canvas->Draw(gpos,10,gegnerB); } } } else { if (gegnerbold<=15) { puffer->Canvas->Draw(gpos,10,gegnerA); } else { puffer->Canvas->Draw(gpos,10,gegnerB); } } } gpos = gpos + 70; } if (alleweg) { for (int i=0;i<16;i++) { gegnerda[i] = true; } } //Punkte Reinschreiben puffer->Canvas->Brush->Style = bsClear; puffer->Canvas->Font->Color = clYellow; puffer->Canvas->Font->Name = "Arial"; puffer->Canvas->Font->Size = 16; puffer->Canvas->Font->Style << fsBold; puffer->Canvas->TextOutA(20,10,"Score: "+IntToStr(Punkte)); //so Spielende bei 640 Punkte mal festlegen if (Punkte >= 640) { GameOver = true; } //Zeit abwarten while (GetTickCount() < idleTime) { Application->ProcessMessages(); } //Puffer auf Form kopieren Form1->Canvas->CopyRect(Rect(0,0,640,480),puffer->Canvas,Rect(0,0,640,480)); } //Speicher Aufräumen delete puffer; delete backpic; delete ship; delete gegnerA; delete gegnerB; //Form wieder ihr Standart Face geben Form1->Canvas->Brush->Color = clBtnFace; Form1->Canvas->FillRect(Rect(0,0,640,480)); //Buttons sichtbar Button1->Visible = true; Button2->Visible = true; Form1->Cursor = crDefault; Punkte = 0; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { //Wenn q Taste gedrückt, dann Spiel verlassen if (char(Key) == 'Q') GameOver = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { //Schiff position mit MausCursor koordinieren if (X<640 && X>0) shipX = X-39; if (Y>150 && Y<410) shipY = Y-30; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { //Laser an fire = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { //Laser aus fire = false; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { //Fenster-Buttons deaktivieren, da Exit per Button DeleteMenu(GetSystemMenu(Handle, false), SC_CLOSE, MF_BYCOMMAND); DeleteMenu(GetSystemMenu(Handle, false), SC_MINIMIZE, MF_BYCOMMAND); DeleteMenu(GetSystemMenu(Handle, false), SC_MAXIMIZE, MF_BYCOMMAND); } //---------------------------------------------------------------------------
-
Ag3nt schrieb:
Also was bewirkt folgende Anweisung:
Application->ProcessMessages();
Das bewirkt, dass das Programm an dieser Zeile erstmal stehenbleibt und alle Messages, die für das Fenster (die Form) anstehen, abgearbeitet werden. Wenn das für dich wie chinesisch klingt, schau dir mal in den FAQs das Thema "Windows Messages" an.