SVGAlib: Helft mir bei meinem Spiel

Hallo,
Ich bin gerade dabei ein "Spiel" zu coden. Der Spieler hat ein Raumschiff (als Rechteck dargestellt) und kann ballern (ein Punkt der von links nach rechts fährt). Jo. Das wars erstmal.

Erklärung zum Code: Das Raumschiff wird erstellt und befindet sich auf einem eigenen GraphicContext. Danach wird eine Schleife aufgerufen, die mit Escape beendet wird. Wenn man auf die Leertaste drückt, wird die Funktion Schuss() aufgerufen. (Die Funktion Schuss() läuft auf einer extra Ebene ab.)

Damit ergibt sich auch schon mein Problem. Das Programm kehrt erst wieder an den Anfang der Schleife zurück, wenn die Funktion Schuss() beendet wird. Ich will aber, mit der Leertaste sozusagen eine Instanz aufrufen, neben der parallel andere Instanzen laufen können, so dass der, der am schnellsten auf der Leertaste herumhackt, am meisten Schüsse abfeuern kann.

Wie realisiere ich das?

Code:
#include <stdio.h>
#include <vga.h>
#include <vgagl.h>
#include <unistd.h>
#include <vgakeyboard.h>

#define SCANCODE_ESCAPE 1 
#define SCANCODE_SPACE 57 

int x_box = 0;
int y_box = 90;
int box_breite = 20;

void schuss();


int main () {

vga_init(); 
vga_setmode(G320x200x256); 
keyboard_init();
gl_setcontextvga(G320x200x256);
GraphicsContext physicalscreen;
gl_getcontext(&physicalscreen);
gl_fillbox(x_box, y_box, box_breite, 20, 5);
gl_copyscreen(&physicalscreen);
while (keyboard_keypressed (SCANCODE_ESCAPE) == 0) {
keyboard_update();
if (keyboard_keypressed (SCANCODE_SPACE) == 1) {
schuss();}
};


vga_setmode(TEXT);

return 0;

}

void schuss() {

GraphicsContext shoot;
gl_getcontext(&shoot);
for (int i=box_breite+1; i< 320-box_breite; i++) 
{
gl_setpixel(i, 100, 4);
usleep(10000);
gl_setpixel(i-1, 100, 0);
}
vga_waitretrace();
gl_copyscreen(&shoot);

}

Weiterführend ergibt sich dann das Problem, dass wenn ich einen Gegner einführe, der sich immer hin und her bewegt, sich so nicht realisieren lässt, da ja die Funktion für den Gegner eine Endlosschleife darstellte, die nie verlassen wird und das Programm damit nichtmehr auf Interaktionen reagiert.
 
Solche Funktionen müssen als Thread bzw. Kindprozesse umgesetzt werden. 'fork()' dürfte da weiterhelfen.
 
super! Jetzt geht es :D

nur dass mein System abschmiert :/ Ich beende die Childprozesse meines Wissens mit exit(0). Leider klappt das auch nicht und so langsam nervt es den PC neuzustarten ;)

Hier mal der aktuelle Code (ich habe ihn etwas abgeändert. Der Schuss ist jetzt nicht mehr nur eine Funktion, sondern eine Klasse. Inwiefern das in diesem Fall Sinn macht sei dahingestellt. Aber wenn der Gegner mal zurückschießen soll, kann ich so das Programm leichter umbauen, imho.)

Der Code:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <vga.h>
#include <vgagl.h>
#include <unistd.h>
#include <vgakeyboard.h>
#include <sys/types.h>
#define SCANCODE_ESCAPE 1 
#define SCANCODE_SPACE 57 


int box_breite = 20;

//Klasse für Schuss
class cschuss {
public: void render();
        
GraphicsContext schuss;    
private: int i;

};

//Rendert den Schuss
void cschuss::render() {
gl_getcontext(&schuss);
for (i=box_breite+1; i<319; i++) {
gl_setpixel(i, 100, 4);
usleep(20000);
gl_setpixel(i-1, 100, 0); 
if (i==318) {usleep(20000); gl_setpixel(i, 100, 0);} }
vga_waitretrace();
gl_copyscreen(&schuss);
}


int main () {

vga_init(); 
vga_setmode(G320x200x256); 
keyboard_init();
gl_setcontextvga(G320x200x256);
GraphicsContext physicalscreen;
gl_getcontext(&physicalscreen);
gl_fillbox(0, 90, box_breite, 20, 5);
gl_copyscreen(&physicalscreen);

while (keyboard_keypressed (SCANCODE_ESCAPE) == 0) { //Solange Escape nicht gedrückt wird
keyboard_update();                                   //Keyboardeingabe abfragen 
if (keyboard_keypressed (SCANCODE_SPACE) == 1) {     //Wird Space gedrückt...
pid_t pSCHUSS = fork();                                
if(pSCHUSS == 0) {cschuss pSCHUSS; pSCHUSS.render(); exit(0);}  //...wird ein Schuss erstellt und am Ende gelöscht
sleep(1); //Verzögerung bis zum nächsten Schuss: 1 sek.                  
}};


vga_setmode(TEXT);

return 0;
}

Edit: Wenn man während der sleep-Zeit zu oft die Leertaste drückt, stürzt der Rechner ab. Ich habe gelesen, dass das daran liegen kann, dass mehrere Childprozesse die selbe Speicheradresse zugewiesen bekommen, deswegen soll man die Funktion wait() verwenden. Wenn ich wait(); vor sleep(1); bringt das allerdings nichts.
 
Jep, hast Recht.

Aber um wieder zum Beenden des Kindprozesses zurückzukommen:
Code:
while (keyboard_keypressed (SCANCODE_ESCAPE) == 0) { //Solange Escape nicht gedrückt wird
keyboard_update();                                   //Keyboardeingabe abfragen     
   if (keyboard_keypressed (SCANCODE_SPACE) == 1) {     //Wird Space gedrückt...
    pid_t pSCHUSS=fork();                                                        //...Kindprozess starten
                              
      if(pSCHUSS == 0) {cschuss pSCHUSS; pSCHUSS.render(); exit(1);}  //Überweisen der Klasse cschuss an den Kindprozess pSCHUSS, Aufrufen der Animation, Beenden des Kindprozesses
    sleep(1);              
}};

Das Problem hier ist, dass sich mit exit(1) oder return(1), etc. nicht der Kindprozess beendet, sondern das ganze Programm und dazu dann auch noch ohne in den Textmodus umzuschalten. Was bedeutet, dass ich neustarten darf um weiter zu experimentieren. Wieso wird in diesem Fall nicht nur der Kindprozess beendet?
 
Ich konnte den Code jetzt nur überfliegen... Aber versuch mal anstatt exit(0) bzw. exit(1) ein einfaches break zu benutzen... damit müsstest du dann die kopfgesteuerte schleife beenden und danach beendet sich der prozess selbst.
 
break; beendet das Programm leider auch.

Meinst du mit "kopfgesteuerte Schleife" die while-Schleife? Die darf nämlich nicht beendet werden.
 
ach, die darf nicht beendet werden? dann lass doch einfach das exit bzw break weg. wozu willst du das dann sonst benutzen? also was soll das genau machen? sorry ich hab leider keine zeit mir den code genau anzusehen...

edit: also wenn du mit dem exit(0) den childprozess beenden willst, dann musst du eine message an die prozess-id schicken, dass er beendet wird. musst du mal googlen oder in die msdn schauen. "prozesse beenden" oder ähnlich...

achso, nochwas: sleep(1) wartet nicht eine sekunde, sondern sleep(1000) wartet eine sekunde ;) man muss das in millisekunden angeben...
 
Original von M4CH!N3
achso, nochwas: sleep(1) wartet nicht eine sekunde, sondern sleep(1000) wartet eine sekunde ;) man muss das in millisekunden angeben...

Code:
SLEEP(3)                                        Linux Programmerâs Manual                                       SLEEP(3)

NAME
       sleep - Sleep for the specified number of seconds

SYNOPSIS
       #include <unistd.h>

       unsigned int sleep(unsigned int seconds);
 
Original von M4CH!N3
edit: also wenn du mit dem exit(0) den childprozess beenden willst, dann musst du eine message an die prozess-id schicken, dass er beendet wird. musst du mal googlen oder in die msdn schauen. "prozesse beenden" oder ähnlich...
Ok, danke. Das ist schonmal ein nützlicher Tip. Werde mich mal erkundigen.

Das exit(0) soll nur den Childprozess kicken, da er sonst den Speicher vollrammelt.


Gut, ich habe das Programm mal ein bischen umgebaut, so dass der Spieler mit dem Rechteck am unteren Bild hin und her wandern kann und dabei schießen. Das Problem ist nur, dass das Programm nach ein paar Schüssen das Kommando übernimmt, sich nicht mehr beenden lässt, mehrere Spieler Raumschiffe erstellt, die durch die Gegend saußen, wild in der Gegend rumballern und meinen Rechner abschießen.

Ich habe die 2 Klassen mittlerweile in eine Headerdatei ausgelagert, die dummerweise globale Voriablen enthält, da ich nicht genau weiß, wie ich auf eine Variable einer Klasse zurückgreife, um diese in einer anderen Klasse zu verwenden. Mit Vererbung würde das ja gehen, aber macht das wirklich Sinn? Bzw. gibt es einen Weg, die Variablen "private" zu lassen und trotzdem auf diese zurückzugreifen? Soll ja nichts verändert, sondern nur ein Wert überwiesen werden. Ich schätze da lande ich bei Pointern, ne?

raumschiff.hpp
Code:
#include "header.hpp"
	 int mBreite;
         int mHoehe;
         int mxpos;
         int mypos;
         int mFarbe;
//Klasse Raumschiff
class craumschiff {
public: craumschiff(int xpos, int ypos, int Breite, int Hoehe, int Farbe); 
	void init();        
	void links();
        void rechts();
GraphicsContext Raumschiff;

}; ////////////////

//Konstruktor Raumschiff
craumschiff::craumschiff(int xpos, int ypos, int Breite, int Hoehe, int Farbe) {  //Variablen werden beim Erstellen der Klasse übergeben
mBreite = Breite;
mHoehe = Hoehe;
mxpos = xpos;
mypos = ypos;
mFarbe = Farbe; 
}///////////////

//Funktion init(): Spieler auf Startposition
void craumschiff::init() {
gl_getcontext(&Raumschiff);
gl_fillbox(mxpos, mypos, mBreite, mHoehe, mFarbe); 
gl_copyscreen(&Raumschiff); 
}//////////////
 
//Funktion links(): Spieler nach links bewegen 
void craumschiff::links() {
gl_getcontext(&Raumschiff);
mxpos -= GESCHWINDIGKEIT;  
gl_fillbox(mxpos, mypos, mBreite, mHoehe, mFarbe); //Raumschiff wird um den Wert GESCHWINDIGKEIT nach links gesetzt 
gl_fillbox(mxpos+mBreite, mypos, mBreite, mHoehe, HINTERGRUNDFARBE); //Vorheriges wird gelöscht
gl_copyscreen(&Raumschiff); 
}/////////////

//Funktion rechts(): Spieler nach rechts bewegen 
void craumschiff::rechts() {
gl_getcontext(&Raumschiff);
mxpos += GESCHWINDIGKEIT;
gl_fillbox(mxpos, mypos, mBreite, mHoehe, mFarbe); //Raumschiff wird um den Wert GESCHWINDIGKEIT nach rechts gesetzt
gl_fillbox(mxpos-mBreite, mypos, mBreite, mHoehe, HINTERGRUNDFARBE); //Vorheriges wird gelöscht
gl_copyscreen(&Raumschiff); 
}/////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Klasse für Schuss
class cschuss {
public: cschuss(); 
	void render();
        
GraphicsContext schuss;    
private: 
         int msxposabs;
         int msxpos;

};////////////

cschuss::cschuss() {
msxpos = mxpos;
msxposabs = msxpos+0.5*mBreite; }

//Rendert den Schuss
void cschuss::render() {
gl_getcontext(&schuss);
for (int i=200-mHoehe; i>0+mHoehe; i--) {
gl_setpixel(msxposabs, i, 4);            //Pixel wird, von der vom Zeitpunkt des Abschusses abhängigen XPos des Raumschiffes, erzeugt    
usleep(20000);                           //wandert nach oben. Pixel drunter wird gelöscht 
gl_setpixel(msxposabs, i+1, HINTERGRUNDFARBE); 
 }
vga_waitretrace();
gl_copyscreen(&schuss);
}//////////////

spaceinv.cpp
Code:
#include "header.hpp"
#include "raumschiff.hpp"

int main () {

vga_init(); 
vga_setmode(G320x200x256); 
keyboard_init();
gl_setcontextvga(G320x200x256);
GraphicsContext physicalscreen;
gl_getcontext(&physicalscreen);
gl_clearscreen(HINTERGRUNDFARBE);
gl_copyscreen(&physicalscreen);

//Spieler Raumschiff erstellen
craumschiff Spieler(150, 180, 20, 20, 4);
Spieler.init();


while (keyboard_keypressed (SCANCODE_ESCAPE) == 0) { //Solange Escape nicht gedrückt wird
keyboard_update();                                   //Keyboardeingabe abfragen     
   if(keyboard_keypressed(SCANCODE_CURSORLEFT) == 1) {Spieler.links(); usleep(20000);} //Pfeiltaste links: Funktion links() wird aufgerufen
   if(keyboard_keypressed(SCANCODE_CURSORRIGHT) == 1) {Spieler.rechts(); usleep(20000);} //Pfeiltaste links: Funktion links() wird aufgerufen
   if (keyboard_keypressed (SCANCODE_SPACE) == 1) {     //Wird Space gedrückt...
      pid_t pSCHUSS=fork();    
                              
      if(pSCHUSS == 0) {cschuss pSCHUSS; pSCHUSS.render();}  //...wird ein Schuss erstellt/gelöscht (Verzögerung bis zum nächsten Schuss: 1 sek.)
      if(pSCHUSS == -1) {vga_setmode(TEXT); return 1; }    
sleep(1);              
}
  
};


vga_setmode(TEXT);

return EXIT_SUCCESS;
}

header.hpp
Code:
#include <stdio.h>
#include <stdlib.h>
#include <vga.h>
#include <vgagl.h>
#include <unistd.h>
#include <vgakeyboard.h>
#include <sys/types.h>
#include <time.h>
#define SCANCODE_ESCAPE 1 
#define SCANCODE_SPACE 57 
#define SCANCODE_CURSORLEFT 75 
#define SCANCODE_CURSORRIGHT 77 
#define HINTERGRUNDFARBE 1
#define GESCHWINDIGKEIT 10

Der Fehler müsste irgendwo in der spaceinv.cpp liegen, imho. Allerdings finde ich ihn nicht :(
 
ich schau am wochenende mal drüber, wenn ich zeit finde... hab diese jetzt leider nicht. wenn du so lange warten kannst ;)
achso: klassennamen werden in c++ generell groß geschrieben... also CRaumschiff ;) nur so als kleiner tip...
 
du könntest z.b. funktionen einbauen, die dann die Membervariablen zurückgeben, z.B.:

Code:
int getWidth()
{
        return mBreite;
}
...
private:
        int mBreite;
...
 
Ok. Das sollte mir jetzt erstmal sehr viel weiter helfen. Je nachdem wie schnell der Optiker ist werde ich mich wieder an den Code setzen. Aber ohne scharf zu sehen, macht das alles keinen Spaß ;) Spätestens morgen wirds ein update geben.

@MACH!NE: Bis WE habe ich Zeit bzw. das Projekt wird bis dahin Zeit haben müssen auf Grund meiner Sehschwäche und der damit verbundenen Unlust ;)

Edit: Wegen dem Kindprozess schließen, hatte ich mir auch überlegt einfach einen Destruktor für die Klasse CSchuss einzubauen und den dann nach der pSCHUSS.render() Funktion aufzurufen. Würde das ausreichen?
 
Zurück
Oben