Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: SDL: Kaksi pikku ongelmaa

Lahha [24.07.2006 02:05:41]

#

Teen tässä pientä harjottelu projektia, mut ny ois kaks pientä onglemaa.

Ongelmat:
1- Kun ampuu peli jää jökkiin. Tiedän miksi sillä aikaa kun ammus on näytöllä ei voi tehä mitään mutta se jää senki jälken jökkii.
2- Nyt kun lisäsin ääniä niin kun yrittää käynnistää pelin se valittaa :"Proseduurin aloitus kohtaa SDL_Error ei löydy dynaamisesti linkitettävästä kirjastosta SDL.dll"


Nappulat

Nuolista -Liikkuu
1,2 ja 3 -Vaihtaa alusta
Välilyönti -Ampuu
ESC -Lopettaa

Tolla ois viimesin toimiva versio.(Ei ääniä eikä ampumista)
http://www.freewebs.com/lahha/Peli.sfx.exe

#include <SDL/SDL.h>  // sisällytetään SDL:n otsikkotiedostot


#pragma comment(lib, "SDLmain.lib")  // otetaan SDL:n LIB-tiedostot mukaan. Kun nämä rivit ovat ohjelman alussa,
#pragma comment(lib, "SDL.lib")      // sinun ei tarvitse lisätä LIB-tiedostoja "käsin"
#pragma comment(lib, "SDL_mixer.lib")
// #pragma-rivit toimivat VAIN Visual c++:alla! gcc:llä parametri -lSDL ajaa saman asian



void PiirraKuva(SDL_Surface *kuva, SDL_Surface *naytto, int x, int y);	// aliohjelma, joka piirtää kuvan
void PiirraAmmus(SDL_Surface *tausta, SDL_Surface *kuva, SDL_Surface *ammus, SDL_Surface *naytto, int x, int y);  // Piirtää ammuksen

int main(int argc, char *argv[]) {
    /********************************************
    * alustetaan SDL:n video-ominaisuudet.
    ********************************************/
    if( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 )  // jos paluuarvo on pienempi kuin 0, tapahtui virhe
    {
        fprintf(stderr, "SDL:n alustus ei onnistunut: %s\n", SDL_GetError()); //virheestä tiedot tiedostoon
        SDL_Quit();
        return 0; // lopetetaan ohjelma
    }


	// open 44.1KHz, signed 16bit, system byte order,
	//      stereo audio, using 1024 byte chunks
	if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) < 0)
	{
		printf("Mix_OpenAudio: %s\n", Mix_GetError());
		return 0;
	}



    // vaihdetaan ikkunan nimi (näkyy tehtäväpalkissa)
    SDL_WM_SetCaption("KatiskaGame", NULL);


    // SDL on nyt alustettu virheettömästi.

    /*********************************************
    * muut valmistelut
    *********************************************/


	SDL_Surface * naytto = new SDL_Surface;               // näkyvä pinta
    SDL_Surface * kuva = new SDL_Surface;               	// pinta laatikolle
    SDL_Surface * tausta = new SDL_Surface;				// pinta taustalle
	SDL_Surface * ammus = new SDL_Surface;				// pinta ammukselle
	Mix_Chunk *aani;

    // vaihdetaan resoluutio
    naytto = SDL_SetVideoMode(1024, 768, 32, SDL_HWSURFACE|SDL_FULLSCREEN|SDL_DOUBLEBUF);

    // ladataan bittikartat
	kuva = SDL_LoadBMP("Art\\1.bmp");
    tausta = SDL_LoadBMP("Art\\tausta.bmp");
	ammus = SDL_LoadBMP("Art\\ammus.bmp");

    int lootax=400;
    int lootay=600;

	// laatikon koordinaatit

    Uint8* nappi;                    // näppäimet
    SDL_Event tapahtuma;                // tapahtumat
    int hiiri,x,y;                    // hiiren tila

    bool pois=false;


	aani=Mix_LoadWAV_RW(SDL_RWFromFile("Sound\\M1.ogg", "rb"), 0);

	// olemme jo ladanneet äänitiedoston
	if(Mix_PlayChannel(0, aani, -1)==-1)
		{fprintf(stderr, "Virhe : %s ", Mix_GetError());}   // virhe

    /*********************************************
    * pääsilmukka
    *********************************************/



    while(pois==false) {

        // poistutaanko
        SDL_PollEvent(&tapahtuma);
            if ( tapahtuma.type == SDL_QUIT )  {  pois = true;  }  //poistumistapahtuma
            if ( tapahtuma.type == SDL_KEYDOWN )  {
                    if ( tapahtuma.key.keysym.sym == SDLK_ESCAPE ) { pois = true; }   // näinkin voi lukea näppäimiä
            }

        // liikutetaan laatikkoa
        nappi = SDL_GetKeyState(NULL);
        if ( nappi[SDLK_UP] ) { lootay -= 1; }
        if ( nappi[SDLK_DOWN] ) { lootay += 1; }
        if ( nappi[SDLK_LEFT] ) { lootax -= 1; }
        if ( nappi[SDLK_RIGHT] ) { lootax += 1; }
		if ( nappi[SDLK_1] ) { kuva = SDL_LoadBMP("Art\\1.bmp"); }
		if ( nappi[SDLK_2] ) { kuva = SDL_LoadBMP("Art\\2.bmp"); }
		if ( nappi[SDLK_3] ) { kuva = SDL_LoadBMP("Art\\3.bmp"); }
		if ( nappi[SDLK_SPACE] ) { PiirraAmmus(tausta, kuva, ammus, naytto, lootax, lootay); }



        hiiri=SDL_GetMouseState(&x,&y);    // luetaan nappien tila

        if(hiiri & SDL_BUTTON(1))     // ykkösnappi pohjassa
            pois=true;


		SDL_SetColorKey(kuva, SDL_SRCCOLORKEY, SDL_MapRGB(kuva->format,0,0,0));//Läpinäkyvyys
        PiirraKuva(tausta, naytto, 0, 0);        // piirretään tausta
        PiirraKuva(kuva, naytto, lootax,lootay); // piirretään alus



        // nyt kuva on piirretty, mutta koska käytämme kaksoispuskurointia, kuva ei näy vielä
        // siksi tarvitsemme SDL_Flip()-funktiota
        SDL_Flip(naytto);
    }

	delete tausta;		// vapautetaan muisti
	tausta = 0;			// varmuuden vuoksi
	delete kuva;		// vapautetaan muisti
	kuva = 0;			// varmuuden vuoksi
	delete ammus;		// vapautetaan muisti
	ammus = 0;			// varmuuden vuoksi
	delete tausta;		// vapautetaan muisti
	naytto = 0;			// varmuuden vuoksi



	Mix_FreeChunk(aani);
	aani = NULL; //varmuuden vuoksi

    SDL_Quit(); // "suljetaan" SDL

    return 0;
}

/**********************************
* Aliohjelma bittikartan piirtämiseen
* Parametreina osoitin kuvan pintaan (lähteeseen), osoitin näyttöpintaan (kohteeseen) sekä koordinaatit, mihin
* kohtaan kohdepintaa kuva piirretään
**********************************/
void PiirraKuva(SDL_Surface *kuva, SDL_Surface *naytto, int x, int y)
	{

    if ( kuva == NULL ) {
        fprintf(stderr, "Kuvannäyttö ei onnistunu: %s\n", SDL_GetError());
        return;
    }

    // mihin näytöllä
    SDL_Rect alue;
    alue.x = x;
    alue.y = y;


    // näytölle
    SDL_BlitSurface(kuva, NULL, naytto, &alue); // koska toinen parametri on NULL, piirretään koko kuva
	}

void PiirraAmmus(SDL_Surface *tausta, SDL_Surface *kuva, SDL_Surface *ammus, SDL_Surface *naytto, int x, int y)
{

	SDL_Rect alue;

	int yy=y;

    if ( ammus == NULL )
	{
        fprintf(stderr, "Kuvannäyttö ei onnistunu: %s\n", SDL_GetError());
        return;
    }

	y -=20;


	while(y != 0)
		{
		y -= 4;

		alue.x = x;
		alue.y = y;

		// näytölle
		PiirraKuva(tausta, naytto, 0, 0);        // piirretään tausta
        PiirraKuva(kuva, naytto, x,yy); // piirretään alus
		SDL_BlitSurface(ammus, NULL, naytto, &alue);

		SDL_Flip(naytto);

		SDL_Delay(5);
		}

}

Heikki [24.07.2006 07:01:12]

#

1. Ongelmasi on tuo PiirraAmmus, se nimittäin pyörii tietyn ajan ja blokkii muun pelin siksi aikaa.

Ammuksen piirtämistä ei kannatat ehdä tuolla tavalla. Parempi tapa on pitää jossain muistissa näytöllä olevat ammukset, ja sitten joka kerta kun pääsilmukka suoritetaan niin ammuksia liikutetaan ja ne piirretään uudestaan (ja samalla voidaan tarkistaa törmääkö ammus seinään/toiseen pelaajaan jne).

2. Ääniä varten sinun tulee ainakin sisällyttää SDL_Mixerin otsikkotiedostot: #include <SDL/SDL_mixer.h>. Ilman sitä koodi ei varmaankaan käänny?


Lopuksi vielä eräs juttu koodistasi:

SDL_Surface * naytto = new SDL_Surface;               // näkyvä pinta
    SDL_Surface * kuva = new SDL_Surface;                   // pinta laatikolle
    SDL_Surface * tausta = new SDL_Surface;                // pinta taustalle
    SDL_Surface * ammus = new SDL_Surface;                // pinta ammukselle

    // vaihdetaan resoluutio
    naytto = SDL_SetVideoMode(1024, 768, 32, SDL_HWSURFACE|SDL_FULLSCREEN|SDL_DOUBLEBUF);

    // ladataan bittikartat
    kuva = SDL_LoadBMP("Art\\1.bmp");
    tausta = SDL_LoadBMP("Art\\tausta.bmp");
    ammus = SDL_LoadBMP("Art\\ammus.bmp");

Vaikka kuinka hienosti muistat vapauttaa new:llä varaamaasi muistia lopussa, niin tuossa kohtaa ohjelma vuotaa muistia. Aluksi varaat SDL_Surfacelle muistia new:llä, mutta SDL_SetVideoMode ja SDL_LoadBMP hoitavat itse muistin varaamisen ja palauttavat osoittimen jo varattuun muistiin. Niinpä aluksi new:llä varaamasi muisti jää varatuksi, mutta mikään osoitin ei osoita siihen.

Metabolix [24.07.2006 13:33:12]

#

Ongelmasi varmaankin on se, että PiirraAmmus-funktion y ei ikinä päädy nollaksi, jos se ei aluksi satu olemaan jaollinen neljällä. Laitapa siis silmukka pyörimään niin kauan, kuin y on suurempi kuin nolla.

Toiseen kysymykseen suosittelisin uudemman SDL.DLL:n hankkimista.

Heikin sanoihin muistinkäsittelystä lisäisin, että SDL:n funktioiden palauttamat pinnat pitää vapauttaa SDL_FreeSurface-funktiolla. Ainoa poikkeus on näyttöpinta, jonka SDL vapauttaa itse.

SDL_Surface *ruutu;
SDL_Surface *kuva;

ruutu = SDL_SetVideoMode(640, 480, 32, 0);
kuva = SDL_LoadBMP("kuva.bmp");

SDL_FreeSurface(kuva); // Kuvat pitää aina vapauttaa.

Lahha [24.07.2006 15:16:59]

#

Kiitti nyt toimii muuten paitsi että ääniä ei kuulu ja tulee tää "Virhe : Tried to play a NULL chunk"

Metabolix [24.07.2006 16:33:03]

#

Eli toisin sanoen äänen lataaminen ei ole onnistunut. Uskaltaisin väittää, että Mix_LoadWav_RW-funktio ei osaa ladata kuin WAV-formaattia, kuten nimestäkin voi päätellä. Sitä paitsi tuossakin on taas muistivuodon paikka. Avaa ensin tiedosto, sitten käytä sitä ja lopuksi sulje se!

SDL_RWops * tiedosto = SDL_RWFromFile("joku.wav", "rb");
if (!tiedosto) {perror("Tiedosto ei auennut!\n"); exit(1);}
Mix_Chunk * aani = Mix_LoadWav_RW(tiedosto, 0);
if (!aani) {perror("Lataus ei onnistunut!\n"); exit(1);}
SDL_RWClose(tiedosto);

Mix_FreeChunk(aani);

Lahha [26.07.2006 21:36:33]

#

En saanu noita toimii. En edes .wav tiedostolla. Jos joku viittis nii vois laittaa sen tohon mun ohjelmaan ja sit jos joku vois tehä ees esimerkin miten toi ammuksen piirtäminen kannattais tehä.

Ohjelma voi laata tolta. Tän hetkisessä koodis ei oo mitää merkintöjä äänestä, mut sisältää ääni tiedostot. paketti sisältää koodin.

http://www.freewebs.com/lahha/Asenna peli.exe (n. 4.3Mb)

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta