Page 3 of 3

Re: C++ Projektit / Esimerkki koodit

Posted: Wed Jul 06, 2011 12:00 pm
by MaGetzUb
Kiitos avusta. :) Muuten pitääkö olla linkattuna jotain toisia linkkejä linkittää projektiin kuin(mingw32, SDLmain, SDL), jotta saisin joko cout:la tai printf:ä edes jotain infoa ulos mitä tapahtuu pelin muuttujapuolella. Nimittäin tällä hetkellä ne eivät kirjoita mitään. Vaikka on iostream includettu.. (Sitä tuskin vissiin edes tarvii..?)

Re: C++ Projektit / Esimerkki koodit

Posted: Wed Jul 06, 2011 3:37 pm
by JATothrim
MaGetzUb wrote:Kiitos avusta. :) Muuten pitääkö olla linkattuna jotain toisia linkkejä linkittää projektiin kuin(mingw32, SDLmain, SDL), jotta saisin joko cout:la tai printf:ä edes jotain infoa ulos mitä tapahtuu pelin muuttujapuolella. Nimittäin tällä hetkellä ne eivät kirjoita mitään. Vaikka on iostream includettu.. (Sitä tuskin vissiin edes tarvii..?)
SDL tekee standardivirtojen kanssa kepposet: se ohjaa virrat tiedostoihin. Ts. int main(int argc, char ** argv); ei ole ohjelman oikea main() funktio koska 'main' on määriteltu esikääntäjän makroksi SDL.h:ssa, joka taas tekee omia säätöjään ennenkuin antaa kontrollin tälle vale-main()ille. (mm. debuggaus ei onnistu ellei SDL_init():lle anna "paracute" flagia)

Ongelma ratkeaa joko ohjaamalla toisen kerran virrat takaisin konsoliin, tai kiertämällä SDL:n entrypoint härpäkkeet:
#include <SDL/SDL.h> // SDL:n headerin includetus.
#undef main // poista SDL:n headerin makro pasta, joka uudelleen määrittelee 'main' nimen. (Eli main():isi ei ollutkan 'main', vaan jokin muu makron määräämä nimi, jota oikea main() kutsui jostain SDL:n syövereistä.)

#include <iostream>:n tarvii aina jos käytät tiedostossa cout:ia tai cin:iä, koska eihän muuten kääntäjä tiedä mitä cout ja cin meinaavat. Note: C++:ssa C-kielen headerit sisällytetään muodossa #include <c[C-standardikirjason_header_nimi_ilman .h päätettä]> Esim. "#include <cstdio>" printf():ää varten.

Re: C++ Projektit / Esimerkki koodit

Posted: Wed Jul 06, 2011 6:50 pm
by MaGetzUb
Eli siis mitä ymmärsin tuosta viestistäsi, minun pitää siis kutsua #include <SDL.h>:n jälkeen undef main? :) Ja Enköhän ole oikein nuo kirjastot hoitanut:

Code: Select all

#include <iostream>
#include <cmath>
#include <string>
#include <cstdlib>
#include <sstream>

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_rotozoom.h>

//Ja tähän kohtaan: undef?
#undef main
//^ noin? :P
#define PI 3.141592653589793
Sisälsikös cstdlib Rand() -funktion?
JAtothrim wrote: mm. debuggaus ei onnistu ellei SDL_init():lle anna "paracute" flagia)
Eli siis SDL_Init(SDL_INIT_EVERYTHING|PARAC[H]UTE?);

Re: C++ Projektit / Esimerkki koodit

Posted: Wed Jul 06, 2011 10:33 pm
by temu92
SFML on kyllä SDL:n verrattuna paljon parempi eikä siinä muistaakseni ollut tuommoisia tyhmä turhia lisäkikkailuita vaadittuna, että jotain näkyy konsoli-ikkunassakin. Se on lisäksi helppokäyttöisempi joten suosittelen siihen tutustumista jos vaan mahdollista (eli siis et ole tekemässä jotain valtavaa projektia jo SDL:llä ja SFML:ään vaihto olis vaan tyhmää kesken kaiken).

Re: C++ Projektit / Esimerkki koodit

Posted: Thu Jul 07, 2011 3:43 am
by MaGetzUb
temu92 wrote:SFML on kyllä SDL:n verrattuna paljon parempi eikä siinä muistaakseni ollut tuommoisia tyhmä turhia lisäkikkailuita vaadittuna, että jotain näkyy konsoli-ikkunassakin. Se on lisäksi helppokäyttöisempi joten suosittelen siihen tutustumista jos vaan mahdollista (eli siis et ole tekemässä jotain valtavaa projektia jo SDL:llä ja SFML:ään vaihto olis vaan tyhmää kesken kaiken).
Joo ei mulla ollu tarkoitus muutaku tehä luokat kuville ja äänille. SDL:ä, et niitä voi sitten käyttää myöhemmissä projekteissa. :P Pitääpä tutustua tuohon SFML:n.. Näytti aika mielenkiintoiselta.. :)

Re: C++ Projektit / Esimerkki koodit

Posted: Thu Jul 07, 2011 7:54 am
by JATothrim
Yksi viimeisimpiä asitoita jonka opettelin C++:sta oli pointer-to-member-function konsepti. Menetelmällä käytännössä voidaan poistaa tietystä paikkaa koodista helposti if- ja switch-rakenteita, tai ajaa samaa jäsen funktiota usealle eri oliolle.

Code: Select all

class DoStuff
{
public:
    void stuff1();
    void stuff2();
    void strufN();

    //typedeffi on kätevä:
    typedef void (DoStuff::*ptrtomemberfn)();
    ptrtomemberfn selectedfunc;
};

DoStuff doit1, doit2;
doit1.selectedfunc = &DoStuff::stuff1; // asetetaan "pointteri" jäsen funktioon.
(doit2 .* doit1.selectedfunc)(); //kutsuu DoStuff::stuff1 jäsen funktiota [i]doit2 oliolla[/i].
Lisää (ja parempaa) tietoa http://www.parashift.com/c++-faq-lite/p ... mbers.html sivuilta.

Re: C++ Projektit / Esimerkki koodit

Posted: Fri Jul 08, 2011 11:53 pm
by MaGetzUb
Muutamia funktioita geometriaan:
(vaatii cmath kirjaston sisällytettynä ja PI määrityksen)

Code: Select all

#include <cmath>
#define PI 3.141592653589793
Funktiot:

Code: Select all

double cos2(double deg){return cos(wrapangle(deg)*PI/180);}
double sin2(double deg){return sin(wrapangle(deg)*PI/180);}

double getangle(double  x,double  y, double  x2, double  y2){
    double vecunX = x-x2;
    double vecunY = y-y2;
    double atn = atan2(vecunY, vecunX);

    if (x2>=x && y2 < y) {
        return 90-(abs(atn)*180/PI-90);
    }else if(x2 < x && y2<=y){
        return 180.0-(atn)*180/PI;
    }else if(x2<x && y2>=y){
        return 180.0+abs(atn)*180/PI;
    }else if(x2>=x && y2>y){
        return wrapangle(270-(90-abs(atn)*180/PI));
    }
    return 0;
}

double distance(double  x,double  y, double  x2, double  y2){
    return pow((x2-x)*(x2-x)+(y2-y)*(y2-y), 0.5);
}

double wrapangle(double angle){
    if(angle<0){
        return 360-(fmod(abs(angle), 360.0));
    }
    return fmod(angle, 360.0);
}

Re: C++ Projektit / Esimerkki koodit

Posted: Sun Jul 10, 2011 12:45 am
by esa94
MaGetzUb wrote:Muutamia funktioita geometriaan:
(vaatii cmath kirjaston sisällytettynä ja PI määrityksen)

Code: Select all

#include <cmath>
#define PI 3.141592653589793
Funktiot:

Code: Select all

double cos2(double deg){return cos(wrapangle(deg)*PI/180);}
double sin2(double deg){return sin(wrapangle(deg)*PI/180);}

double getangle(double  x,double  y, double  x2, double  y2){
    double vecunX = x-x2;
    double vecunY = y-y2;
    double atn = atan2(vecunY, vecunX);

    if (x2>=x && y2 < y) {
        return 90-(abs(atn)*180/PI-90);
    }else if(x2 < x && y2<=y){
        return 180.0-(atn)*180/PI;
    }else if(x2<x && y2>=y){
        return 180.0+abs(atn)*180/PI;
    }else if(x2>=x && y2>y){
        return wrapangle(270-(90-abs(atn)*180/PI));
    }
    return 0;
}

double distance(double  x,double  y, double  x2, double  y2){
    return pow((x2-x)*(x2-x)+(y2-y)*(y2-y), 0.5);
}

double wrapangle(double angle){
    if(angle<0){
        return 360-(fmod(abs(angle), 360.0));
    }
    return fmod(angle, 360.0);
}
Why would you even do that, son?

Tuon pitäisi olla korkeintaan makro :<
EDIT:

miksei ole omassa nimiavaruudessa?


Re: C++ Projektit / Esimerkki koodit

Posted: Sun Jul 10, 2011 8:25 am
by MaGetzUb
esa94 wrote:
MaGetzUb wrote:Muutamia funktioita geometriaan:
(vaatii cmath kirjaston sisällytettynä ja PI määrityksen)

Code: Select all

#include <cmath>
#define PI 3.141592653589793
Funktiot:

Code: Select all

double cos2(double deg){return cos(wrapangle(deg)*PI/180);}
double sin2(double deg){return sin(wrapangle(deg)*PI/180);}

double getangle(double  x,double  y, double  x2, double  y2){
    double vecunX = x-x2;
    double vecunY = y-y2;
    double atn = atan2(vecunY, vecunX);

    if (x2>=x && y2 < y) {
        return 90-(abs(atn)*180/PI-90);
    }else if(x2 < x && y2<=y){
        return 180.0-(atn)*180/PI;
    }else if(x2<x && y2>=y){
        return 180.0+abs(atn)*180/PI;
    }else if(x2>=x && y2>y){
        return wrapangle(270-(90-abs(atn)*180/PI));
    }
    return 0;
}

double distance(double  x,double  y, double  x2, double  y2){
    return pow((x2-x)*(x2-x)+(y2-y)*(y2-y), 0.5);
}

double wrapangle(double angle){
    if(angle<0){
        return 360-(fmod(abs(angle), 360.0));
    }
    return fmod(angle, 360.0);
}
Why would you even do that, son?

Tuon pitäisi olla korkeintaan makro :<
EDIT:

miksei ole omassa nimiavaruudessa?

Miksi pitäisi olla omassa nimiavaruudessa? Ja makroihin en ole tutustunut, niin näin oletin nuo funktiot olevan tarpeeksi käteviä.

Re: C++ Projektit / Esimerkki koodit

Posted: Sun Jul 10, 2011 10:17 am
by JATothrim
MaGetzUb wrote:
esa94 wrote:
MaGetzUb wrote:Muutamia funktioita geometriaan:
(vaatii cmath kirjaston sisällytettynä ja PI määrityksen)

Code: Select all

#include <cmath>
#define PI 3.141592653589793
Funktiot:

Code: Select all

double cos2(double deg){return cos(wrapangle(deg)*PI/180);}
double sin2(double deg){return sin(wrapangle(deg)*PI/180);}

double getangle(double  x,double  y, double  x2, double  y2){
    double vecunX = x-x2;
    double vecunY = y-y2;
    double atn = atan2(vecunY, vecunX);

    if (x2>=x && y2 < y) {
        return 90-(abs(atn)*180/PI-90);
    }else if(x2 < x && y2<=y){
        return 180.0-(atn)*180/PI;
    }else if(x2<x && y2>=y){
        return 180.0+abs(atn)*180/PI;
    }else if(x2>=x && y2>y){
        return wrapangle(270-(90-abs(atn)*180/PI));
    }
    return 0;
}

double distance(double  x,double  y, double  x2, double  y2){
    return pow((x2-x)*(x2-x)+(y2-y)*(y2-y), 0.5);
}

double wrapangle(double angle){
    if(angle<0){
        return 360-(fmod(abs(angle), 360.0));
    }
    return fmod(angle, 360.0);
}
Why would you even do that, son?

Tuon pitäisi olla korkeintaan makro :<
EDIT:

miksei ole omassa nimiavaruudessa?

Miksi pitäisi olla omassa nimiavaruudessa? Ja makroihin en ole tutustunut, niin näin oletin nuo funktiot olevan tarpeeksi käteviä.
Kaikki C++ oppaat: Macros are evil. Oikeasti, makrot on saatu C++:aan perintönä C-kielestä, jossa niiden käyttö oli vaivatonta ja ellei jopa suositeltavaa. Jos meinaat C++:aa kirjoittaessa tehdä makron, ollaan jo hakoteillä, koska C++:n inline funktio ajaa asian monta kertaa paremmin. Funkkarista voidaan tehdä vieläpä suoraan template versio, jolloin ei tarvita naputellla erikseen double ja float versioita. :>
Vinkki vinkki note note: cmath:ssa on PI vakio valmiina: M_PI, ja tästä puolikas M_PI_2, etc. ;)
EDIT: niin tänks wrapanglesta. :]

Re: C++ Projektit / Esimerkki koodit

Posted: Sun Jul 10, 2011 2:47 pm
by Dimple
JATothrim wrote: Kaikki C++ oppaat: Macros are evil. Oikeasti, makrot on saatu C++:aan perintönä C-kielestä, jossa niiden käyttö oli vaivatonta ja ellei jopa suositeltavaa. Jos meinaat C++:aa kirjoittaessa tehdä makron, ollaan jo hakoteillä, koska C++:n inline funktio ajaa asian monta kertaa paremmin. Funkkarista voidaan tehdä vieläpä suoraan template versio, jolloin ei tarvita naputellla erikseen double ja float versioita. :>
Vinkki vinkki note note: cmath:ssa on PI vakio valmiina: M_PI, ja tästä puolikas M_PI_2, etc. ;)
EDIT: niin tänks wrapanglesta. :]
Riippuu kääntäjästä löytyykö M_PI vai ei. Ainakaan Visual C++ 2010 ei tunnista sitä. Aika ihmeellistä kyllä, ettei se kuulu standardiin. :( http://cboard.cprogramming.com/cplusplu ... -m_pi.html. Koodi toimii siis useammissa kääntäjissä, jos sen vakion määrittelee itse.

Eikös inline ole muuten vain vihje kääntäjälle? Kääntäjän ei siis ole pakko optimoida sitä funktio kutsua pois vaikka funktio olisi inline.

@Esa94:
Ei paria tuollaista funktiota tarvitse välttämättä omaan nimiavaruuteensa laittaa. Hankaloittaa vain käyttämistä.

@MaGetzUb:
Mitä sen getangle-funktion on tarkoitus tehdä? Palauttaa minkä kahden välinen kulma?

Re: C++ Projektit / Esimerkki koodit

Posted: Sun Jul 10, 2011 5:12 pm
by esa94
Kaikkien funktioiden kuuluisi olla omissa käyttötarkoituksen tai kirjaston mukaisissa nimiavaruuksissaan. Se ei myöskään vaikeuta käyttämistä lainkaan. Miksi luulit että using-lause on ylipäätään olemassa? Onko standardikirjaston funktioita, olioita ja luokkia mielestäsi jotenkin hankala käyttää kun ne ovat omassa nimiavaruudessaan?

JATothrim: Perehdy C1X:n geneerisiin makroihin. Ajavat saman asian kuin ylikuormittaminen.
Joissain tapauksissa makrojen käyttöä ei voi välttää, sillä malleja ei vain voi aina raiskata miten haluaa. Arvojen antaminen niille on kuitenkin ihan kätevä tapa luoda asioita (Esimerkiksi jos luokan jäsenen koko riippuu malliparametrista, voidaan sille antaa jokin numero kätevästi käännöksen yhteydessä)
Implisiittisen tyyppimuunnoksen takia float-versioita funktioista jotka vain muuntavat arvoja cmathin funktioille ei kannata tehdä. Tyyppi joudutaan kuitenkin yhä muuntamaan takaisin doubleksi.

math.h:n vakiot eivät ole standardissa mutta _GNU_SOURCE tai _USE_MATH_DEFINES (riippuen kääntäjästä) korjaa sen asian. En muista tukeeko clang niitä lainkaan, mutta todennäköisesti se hyväksyy GNU:n vivun.

C++–opas ei ole absoluuttinen auktoriteetti. Ei gotoonkaan kuole.

Re: C++ Projektit / Esimerkki koodit

Posted: Sun Jul 10, 2011 7:36 pm
by MaGetzUb
JATothrim wrote: EDIT: niin tänks wrapanglesta. :]
Juu, eipä mitään. :P Tuon wrapanglen kanssa sai oikeasi pähkäilläkkin hetkenaikaa, et miten sen kannattaisi toteuttaa, loppujenlopuksi se se olikin aika yksinkertaista. :D
Dimple wrote:@MaGetzUb:
Mitä sen getangle-funktion on tarkoitus tehdä? Palauttaa minkä kahden välinen kulma?
Siis se toimii samalla lailla, kuin CoolBasic:n Getangle. Eli se palauttaa kahden koordinaatin välisen kulman.

Re: C++ Projektit / Esimerkki koodit

Posted: Sun Jul 10, 2011 8:23 pm
by Dimple
Mikä idea on laittaa kaikki funktiot nimiavaruuteen vain "koska niin kuuluu tehdä"? Kyllä mielestäni pitää jokin syy olla siihen, että jotain ominaisuutta käytetään. Jokin muu syy kuin se, että jollain foorumille kirjoittelevalla on jumaluuskompleksi.

Nimiavaruudet keksittiin siksi, että eri kirjastoissa voisi olla saman nimisiä funktioita ilman, että se aiheuttaisi ongelmia, kun molempia kirjastoja halutaan käyttää samassa ohjelmassa. Ratkaisu on toimiva, ja kirjastoissa on hyvä tapa käyttää nimiavaruuksia, vaikka on ilman niitäkin pärjätty (esim. C:n kirjastot).

Mutta mitä hyötyä on tehdä näin?

Code: Select all

namespace NameSpace {

    void func() {}

}

using namespace NameSpace;

int main() {
    
    func();
    return 0;
}
Tuossahan menetetään kaikki nimiavaruudesta saatava hyöty. Hieman parempi olisi tehdä näin:

Code: Select all

namespace NameSpace {

    void func() {}

}

using NameSpace::func;

int main() {
    
    func();
    return 0;
}
Mutta edelleen, jos joku toinenkin kirjasto käyttää "func"-nimistä funktiota, ollaan ongelmissa. Paras tapa olisi tehdä näin:

Code: Select all

namespace NameSpace {

    void func() {}

}

int main() {
    
    NameSpace::func();
    return 0;
}
Tämä on myös se tapa, mitä itse käytän, mutta se hankaloittaa funktioiden käyttämistä, kun jokaisen kutsun eteen pitää kirjoittaa se nimiavaruus. Vaikka käyttäisi using-sanaa, täytyy se kuitenkin aina muistaa laittaa sinne. Jos käyttää sitä jokaiselle funktiolle erikseen, täytyy se myös muistaa laittaa jokaiselle erikseen. Vähänkään isommissa kirjastoissa nimiavaruutta kannattaa ehdottomasti käyttää, mutta mielestäni muutaman funktion kanssa se vain hankaloittaa asioita. Lisäksi nimiavaruuden käyttäminen sitoo kirjaston C++:an vaikka muu koodi olisikin C yhteensopivaa.
esa94 wrote: Kaikkien funktioiden kuuluisi olla omissa käyttötarkoituksen tai kirjaston mukaisissa nimiavaruuksissaan. Se ei myöskään vaikeuta käyttämistä lainkaan.
Tuo on kyllä puhdasta potaskaa. Jos pitää muistaa enemmän asioita kun käyttää niitä funktioita, silloin niitä on hankalampi käyttää.

@MaGetzUb:
Eli tekeekö tämä saman asian? Onko sinun koodissasi positiivinen kulma toiseen suuntaan?

Code: Select all

#include <cmath>
#include <cstdio>

#define PI 3.14159

// Strukti, joka tallentaa vektorin
struct Vect2D {

	Vect2D(double newX, double newY) { x = newX; y = newY; }

	double x;
	double y;
};

// Laskee kahden vektorin välisen pistetulon
double dot(Vect2D vect1, Vect2D vect2) {
	return vect1.x*vect2.x + vect1.y*vect2.y;
}

// Laskee vektorin suuruuden (tai pituuden, miten tykkää)
double magnitude(Vect2D vect) {
	return sqrt(pow(vect.x, 2) + pow(vect.y, 2));
}

// Laskee kahden pisteen välisen kulman käyttäen pistetulon määritelmää ( dot(a,b) = |a||b| * cos phi <=> phi = acos(dot(a,b) / (|a||b|)) )
double getAngle(double x, double y, double x2, double y2) {

	// Tämä tarkistus estää sen, että jaettaisiin nollalla.
	// Käytännössä virheentarkistus kannattaisi toteuttaa paremmin, mutta funktion pysäyttäminen
	// saa nyt luvan riittää. :)
	if(x2-x == 0 && y2-y == 0)
		return 0;

	// Muodostetaan vektorit.
	Vect2D vect(x2-x, y2-y);
	Vect2D vect2(1, 0);

	// Lasketaan vektoreiden välinen kulma.
	double angle = acos(dot(vect, vect2) / (magnitude(vect)*1) );

	// Palautetaan joko kulma tai sen käänteisluku. Ilman tätä funktio palauttaisi saman kulman
	// pisteille (0,0)->(1,1) ja (0,0)->(1,-1).
	if(vect.y >= 0)
		return angle;
	else
		return -angle;
}

// Oma toteutukseni WrapAnglelle, joka on helppo muistaa ja toteuttaa lennossa.
double wrapAngle(double angle) {
	while(angle > 360)
		angle -= 360;
	while(angle < 0)
		angle += 360;

	return angle;
}

int main() {

	printf("getAngle-testi: %f", wrapAngle(getAngle(0, 0, 1, -1) / PI * 180)); // Pitäisi palauttaa 315 (eli getAngle palauttaa -45 astetta)
	printf("\nwrapAngle-testi: %f", wrapAngle(1445)); // Pitäisi palauttaa 5
	printf("\nwrapAngle-testi: %f", wrapAngle(-1445)); // Pitäisi palauttaa 355

	getchar();
	return 0;
}

Re: C++ Projektit / Esimerkki koodit

Posted: Sun Jul 10, 2011 9:36 pm
by koodaaja
using on siitä näppärä avainsana, että saa itse määrätä mitä nimiavaruuksia käytetään - eli jos kutsutaan kirjasto::funktio -nimistä funktiota hyvin usein, nimeä voi lyhentää. Toisaalta, jos myös nimiavaruus kirjasto2 sisältää funktion nimeltä funktio, jota ei kutsuta laajan ohjelman aikana kuin kerran, ei tarvitse alkaa kikkailla uudelleennimeämisten kanssa vaan voi kutsua yksinkertaisesti kirjasto2::funktio().

Itse en ylipäänsäkään juuri nimiavaruuksia käyttele. Kun pitää luokkiensa nimet ristiriidattomina niin niissä voi vaikka jokaisessa olla metodi luokka::metodi :)

Re: C++ Projektit / Esimerkki koodit

Posted: Mon Jul 11, 2011 3:37 pm
by esa94
Dimple wrote:Mutta mitä hyötyä on tehdä näin?

Code: Select all

namespace NameSpace {

    void func() {}

}

using namespace NameSpace;

int main() {
    
    func();
    return 0;
}
Tuossahan menetetään kaikki nimiavaruudesta saatava hyöty.
Ei tokikaan, sillä käytössäsi on todennäköisesti ainakin muutama kirjasto jotka määrittelevät omat funktionsa ja mahdollisesti cmath, jonka lisäksi NameSpace on vähintäänkin omassa otsaketiedostossaan.

Code: Select all

namespace NameSpace = ns
ns::func()

Re: C++ Projektit / Esimerkki koodit

Posted: Mon Jul 11, 2011 5:18 pm
by Dibalo
Dimple wrote:Mikä idea on laittaa kaikki funktiot nimiavaruuteen...
Jos foorumisoftassa olisi tykkää-painike, niin käyttäisin. :mrgreen:

Re: C++ Projektit / Esimerkki koodit

Posted: Mon Jul 11, 2011 6:09 pm
by esa94
ratingit toimivat paremmin

viimeksi kun näin plus-arvostelua kokeiltavan ei siitä tullut mitään

Re: C++ Projektit / Esimerkki koodit

Posted: Wed Jul 11, 2012 2:51 pm
by Sami The Great
Palasin itse takaisin C++:n maailmaan ja totesin, että foorumilla on ollut aika hiljaista sen suhteen viime aikoina, jos vertaa esim vuosia taaksepäin. Joten päätimpä nostaa tämän aiheen taas esille, jos joku innostuisi taas koodailemaan jotakin :D

Aloitin Cocos2D-x:lla uutta projektia, ja kirjastoa tarkemmin tutkaillessani huomasin, että se ei sisällä omaa resurssi manageria, joten päätin tehdä sellaisen itse. Jos joku joskus kyseisellä kirjastolla koodailee peliään ja kiroaa miksi kuvien lataaminen etukäteen on niin vaikeaa / ei halua käyttää aikaa ja päästä helpommalla, niin voit tulla tänne ja kopioida ehkei nopeimman, mutta toimivan resurssi managerin. Manageri pystyy lataamaan tekstuureita PNG-kuvista, musiikkia sekä ääniä. Halutessaan tietenkin tämä on helppo muokata vastaamaan myös jonkin toisen kirjaston tarkoituksia. Muuttaa vain AssetResource structista tekstuurin tyyppiä halutun kirjaston vastaavaksi ja korvaa loadCocos2D-funktion omalla, joka lataa vaikka SDL-surfacen.

Käyttö:
Manageri toimii singletonina ja näin ollen sitä voidaan käyttää missä tahansa kohtaa koodia.

Code: Select all

minioid::ResourceManager::getSingletonPtr()->"TÄHÄN KUTSUTTAVA METODI"
Ennen käyttöä manageri pitää alustaa init()-funktiolla.
Manageri toimii niin, että se lataa resursseja taustalla yhden per frame, joten muista kutsua update()-funktiota aina joka framella. Latauksen päättymisen tiedät, kun isLoading() palauttaa false.
Resursseja lisätään latausjonoon load-funktiolla. HUOM! resurssi EI OLE käytössä heti tämän komennon jälkeen, vaan se lisätään ladattavien resurssien listalle. Voit tarkistaa onko resurssi ladattu isLoaded-funktiolla.
load-funktio tarvitsee myös parametriksi ladattavan resurssin tyypin. (RES_TYPE_TEXTURE, RES_TYPE_SOUND tai RES_TYPE_MUSIC) Kun olet kerran määritellyt resurssin tyypin, niin manageri hoitaa loput itsestään.
Muista vapauttaa ladatut tiedostot remove-komennolla tai vastaavasti voit tyhjentää koko managerin clear-komennolla.

Tässä vielä pieni esimerkki käytöstä:

Code: Select all

minioid::ResourceManager* myResMgr = minioid::ResourceManager::getSingletonPtr();
myResMgr->init();

myResMgr->load("ukkeli.png", minioid::RES_TYPE_TEXTURE);
myResMgr->load("rajahdys.wav", minioid::RES_TYPE_SOUND);
myResMgr->load("musiikki.mp3", minioid::RES_TYPE_MUSIC);

while(1) //MAINLOOP
{
    myResMgr.update();
    if(myResMgr.isLoading())
    {
       //Näytetään latausikkuna ja päivitetään vaikka latauspalkkia
    }
    else
    {
       //Kaikki on ladattu ja pyöritetään peliä
    }
}
EDIT: Parantelin vielä vähän koodia. Lisäsin setResourceFolder nimisen funktion helpottamaan, ettei tarvitse aina kirjoittaa root-kansion nimeä jokaisen resurssin lataukseen. Lisäksi justFinished funktiolla saa tiedon, että kaikki on ladattu valmiiksi kyseisen framen aikana. Tätä voi käyttää, jos tarvitsee vielä alustaa joitakin muuttujia ennen pelin aloittamista.

Sitten vielä itse koodi:

standards.h

Code: Select all

#ifndef CHA_STANDARDS_H
#define CHA_STANDARDS_H

#include <vector>
#include <string>
#include <algorithm>

#endif
ResourceManager.h

Code: Select all

#ifndef CAM_ASS_MGR_H
#define CAM_ASS_MGR_H

#include "standards.h"
#include "cocos2d.h"
#include "SimpleAudioEngine.h"

namespace minioid
{

enum
{
	RES_TYPE_TEXTURE = 1,
	RES_TYPE_SOUND,
	RES_TYPE_MUSIC,
};

struct AssetResource
{
	std::string path;
	int type;
	cocos2d::CCTexture2D* texture;
};

class ResourceManager
{
public:

	ResourceManager();
	~ResourceManager();

	//Use singleton pointer to control the manager. ResourceManager::getSingletonPtr->...
	static ResourceManager* getSingletonPtr();

	//Init the manager.
	void init();

	//Updates loading queue. Call this once per frame!
	void update();

	//Add load request to queue.
	//path - relative file path
	//resourceType - resource type. (RES_TYPE_TEXTURE) see enum.
	void load(std::string path, int resourceType);

	//Returns true if file has been already loaded.
	//path - relative file path
	bool isLoaded(std::string path);

	//Removes and unload resource.
	void remove(std::string path);

	//Clears and unload whole manager.
	void clear();

	//Returns true if loading isn't completed yet. When false, you know loading is finished.
	bool isLoading();

	//Returns loading progress as float between 0 and 1. Use this for your progress bar etc.
	float getProgressPercent();

	//Get loaded texture
	//filename - filename of loaded texture
	//Warning! Use this method only after current resource is loaded! (you can check isLoaded())
	cocos2d::CCTexture2D* getTexture(std::string filename);

	//Return true if loading has JUST finished
	bool justFinished();

	//Set root folder for resources
	//Default is "data"
	void setResourceFolder(std::string path);

private:
	std::string resFolder;
	bool justFin;
	int totalAssets;
	int loadedAssets;
	bool isLoadingAssets;
	static ResourceManager* singleton_assetMgr;
	std::vector<AssetResource> loadingQueue;
	std::vector<AssetResource> loadedFiles;

	void cocos2DLoad(AssetResource res);
	void cocos2DUnload(AssetResource res);
};

}
#endif
ResourceManager.cpp

Code: Select all

#include "ResourceManager.h"

namespace minioid
{

ResourceManager::ResourceManager()
{
}

ResourceManager::~ResourceManager()
{
}

ResourceManager* ResourceManager::singleton_assetMgr;

ResourceManager* ResourceManager::getSingletonPtr()
{
	if(!singleton_assetMgr)
	{
		singleton_assetMgr = new ResourceManager();
	}
	return singleton_assetMgr;
}

void ResourceManager::init()
{
	clear();
	loadingQueue.clear();
	loadedFiles.clear();
	isLoadingAssets = false;
	loadedAssets = 0;
	totalAssets = 0;
	justFin = false;
	resFolder = "data";
}

void ResourceManager::update()
{
	justFin = false;
	if(!loadingQueue.empty())
	{
		AssetResource pathToLoad = loadingQueue.back();

		cocos2DLoad(pathToLoad);
		loadingQueue.pop_back();
		if(loadingQueue.empty()) justFin = true;
	}

	loadedAssets = (int)loadedFiles.size();
	totalAssets = ((int)loadingQueue.size())+loadedAssets;
	if(loadingQueue.empty()) isLoadingAssets = false;
	if(!loadingQueue.empty()) isLoadingAssets = true;
}

void ResourceManager::load(std::string path, int resourceType)
{
	isLoadingAssets = true;
	AssetResource fileToLoad;
	fileToLoad.path = path;
	fileToLoad.type = resourceType;
	loadingQueue.push_back(fileToLoad);
}

bool ResourceManager::isLoaded(std::string path)
{
	std::vector<AssetResource>::iterator it;
	for(it=loadedFiles.begin(); it < loadedFiles.end(); it++)
	{
		AssetResource tempRes = *it;
		if(path == tempRes.path) return true;
	}
	return false;
}

void ResourceManager::remove(std::string path)
{
	std::vector<AssetResource>::iterator it;
	for(it=loadedFiles.begin(); it < loadedFiles.end(); it++)
	{
		AssetResource tempRes = *it;
		if(path == tempRes.path)
		{
			cocos2DUnload(tempRes);
			loadedFiles.erase(it);
		}
	}
}

void ResourceManager::clear()
{
	std::vector<AssetResource>::iterator it;
	for(it=loadedFiles.begin(); it < loadedFiles.end(); it++)
	{
		AssetResource tempRes = *it;
		remove(tempRes.path);
	}
	loadingQueue.clear();
	loadedFiles.clear();
}

bool ResourceManager::isLoading()
{
	return isLoadingAssets;
}

float ResourceManager::getProgressPercent()
{
	if(totalAssets == 0) return 0;
	return ((float)loadedAssets)/((float)totalAssets);
}

void ResourceManager::cocos2DLoad(AssetResource res)
{
	std::vector<AssetResource>::iterator it;
	for(it=loadingQueue.begin(); it<loadingQueue.end(); it++)
	{
		AssetResource tempRes = *it;
		if(tempRes.path == res.path)
		{
			std::string loadPath = ""+resFolder+"/"+tempRes.path;
			if(res.type == RES_TYPE_TEXTURE)
			{
				cocos2d::CCTexture2D* tex = cocos2d::CCTextureCache::sharedTextureCache()->addImage(loadPath.c_str());
				tempRes.texture = tex;
				loadedFiles.push_back(tempRes);
				break;
			}
			if(res.type == RES_TYPE_SOUND)
			{
				CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect(loadPath.c_str());
			}
			if(res.type == RES_TYPE_MUSIC)
			{
				CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic(loadPath.c_str());
			}
		}
	}
}

void ResourceManager::cocos2DUnload(AssetResource res)
{
	if(res.type == RES_TYPE_TEXTURE)
	{
		cocos2d::CCTextureCache::sharedTextureCache()->removeTexture(res.texture);
	}
	if(res.type == RES_TYPE_SOUND)
	{
		CocosDenshion::SimpleAudioEngine::sharedEngine()->unloadEffect(res.path.c_str());
	}
}

cocos2d::CCTexture2D* ResourceManager::getTexture(std::string filename)
{
	std::vector<AssetResource>::iterator it;
	for(it=loadedFiles.begin(); it<loadedFiles.end(); it++)
	{
		AssetResource tempRes = *it;
		if(tempRes.path == filename) return tempRes.texture;
	}
	return 0;
}

bool ResourceManager::justFinished()
{
	return justFin;
}

void ResourceManager::setResourceFolder(std::string path)
{
	resFolder = path;
}

}