Jump to content
Rpg²S Forum

Keroro

Utenti
  • Posts

    646
  • Joined

  • Last visited

Posts posted by Keroro

  1. Visto che Matty95 è latitante vedrò di scrivere qualcosa io.

     

    Short Lesson 1: Le stringhe

    Da quel che leggo gran parte di voi finora per memorizzare informazioni a carattere testuale ha utilizzato il tipo built-in char.

    Il tipo char è nato 40 anni fa e rappresenta una sequenza di 8 bit che codificati in ASCII ci danno un singolo carattere.

    Finora avete utilizzato array di char e questo presenta il problema che se volete memorizzare una parola di lunghezza superiore alla fissata il programma crasha per buffer overflow.

    Per evitare problemi di lunghezza dei caratteri e dover gestire dinamicamente la memoria in modo ottimale, utilizziamo il costrutto string della standard library.

    Vi mostro un esempio:

    #include <iostream>
    #include <string>
    
    using namespace std; //utile per imparare, dopo se ne farà a meno
    
    int main(){
    string temp;
    cout << "Inserisci il tuo nome avventuriero: ";
    cin >> temp;
    cout << "Bene, il tuo nome e' "<< temp<< "!\n";
    system("PAUSE");
    return 0;
    }

    La forza di string è che permette facilmente di copiare il contenuto di una stringa in un'altra o concatenare stringhe o fare altre operazioni sulle stringhe, spesso prone agli errori per via della memoria limitata.

     

    	string a, b;
    cout << "Inserisci il valore di a: ";
    cin << a;
    b = a;
    cout << "Il valore di b e' "<< b << endl;
    a = "ciao ";
    b = "mondo";
    c = a+b;
    cout << c;

     

    Tutto questo è possibile perché string è una classe. Le classi in c++ sono magiche ;O

     

    Compito per casa:

    Esaminare e testare 3 esempi dal sito
    escluso il primo.

     

    Short Lesson 2: Le classi

    Da quel che abbiamo visto finora una classe è un nuovo tipo di variabile che ha le sue operazioni, (se avete aperto il link, anche le sue funzioni).

    E' arrivato il momento di creare una nostra classe piuttosto che usarne una creata da altri come string. Da dove cominciamo?

    Una classe non è altro che un modello astratto che semplifica l'oggetto da rappresentare elencando solo le proprietà di interesse, anche perché se dovesse elencare ogni sfaccettatura un solo oggetto richiederebbe un'infinità di codice.

    Vogliamo creare un rpg in c++, prendiamo carta e penna ed immaginiamo come vogliamo realizzarlo.

    Solo dopo aver progettato tutto conviene mettersi di fronte al pc.

     

    Nel nostro rpg interpretiamo un personaggio e avremo a che fare con altri personaggi, amichevoli o meno :D.

    Nota

    Seguiranno una serie di spoiler che presentano il codice volta per volta, consiglio di leggere prima tutto il testo e poi aprire gli spoiler rileggendolo, a mio parere avere un'idea globale delle cose permette di scrivere codice migliore.

    Se poi siete smaliziati e sapete già programmare prendetelo come esercizio, dopo aver letto il testo una volta rileggetelo ed intanto programmate, quando avete finito di programmare e quello che avete fatto funziona (o se non funziona e vi arrendete) allora aprite gli spoiler e confrontate.

    L'importante è che produciate codice corretto ed in qualche modo equivalente per rimanere al passo con l'evoluzione della cosa :3

    Immaginiamo quindi di partire creando una classe Character che rappresenta lo scheletro di un qualsiasi personaggio del nostro rpg, noi inclusi.

     

    class Character {
    };

    E' importante il ; a fine dichiarazione, il compilatore vi romperà spesso le scatole quando ve ne scordate

     

    Vogliamo che il nostro personaggio abbia un nome

     

    #include <iostream>
    #include <string>
    
    using namespace std; //utile per imparare, dopo se ne farà a meno
    
    class Character {
    private:
    	string name;
    public:
    	string getName(){
    		return name;
    	}
    	/** Costruttore della classe
    	**/
    	Character(string name){
    		this->name = name;
    	}
    };
    
    int main(){
    string temp;
    cout << "Inserisci il tuo nome avventuriero: ";
    cin >> temp;
    Character eroe(temp); //creo un'istanza dell'oggetto Character e passo temp come nome
    cout << "Bene, il tuo nome e' "<< eroe.getName() << "!" <<endl;
    system("PAUSE");
    return 0;
    }

    La classe è suddivisa in due sezioni, private e public.

    In private va tutto quello accessibile solo dalle funzioni della classe.

    In public va tutto quello accessibile da chiunque.

    Una funzione dentro una classe viene in genere chiamata metodo.

    Character ha due metodi, getName e Character.

    Un metodo che ha lo stesso nome della classe è un costruttore e viene chiamato quando viene creata un'istanza della classe, per farla semplice quando creiamo una variabile del tipo classe E creiamo in memoria lo spazio corrispondente.

    Il main è identico a quello della lezione sulle stringhe con in più l'istanziamento di un oggetto eroe.

    e delle caratteristiche tipiche da rpg: Strenght, Agility, HP e TotalHP.

     

    class Character {
    private:
    	string name;
    	int strenght;
    	int agility;
    	int hp;
    	int totalHp;
    /*....*/
    };

     

    La forza può andare da 1 a 10, l'agilità da 1 a 10, gli hp da 0 (morto) a 10.

    Il nostro personaggio avrà 4 in forza, 7 in agilità e 3/3 hp.

     

    #include <iostream>
    #include <string>
    #include <sstream>
    
    using namespace std; //utile per imparare, dopo se ne farà a meno
    
    namespace Util {
    /** Converte un intero in una stringa **/
    string toString(int number){
    	stringstream ss;
    	ss << number;
    	return ss.str();
    }
    };
    
    
    class Character {
    private:
    	bool morto;
    	string name;
    	int strength;
    	int agility;
    	int hp;
    	int totalHp;
    public:
    	/** Il Costruttore della classe
    		Inizializzo le variabili
    	**/
    	Character(string name){
    		this->name = name;
    		strength = 1;
    		agility = 1;
    		hp = 1;
    		totalHp = 1;
    		morto = false;
    	}
    
    	bool isAlive(){
    		return !morto;
    	}
    
    	/** Get **/
    	string getName(){
    		return name;
    	}
    	int getStrength(){
    		return strength;
    	}
    	int getAgility(){
    		return agility;
    	}
    	int getHp(){
    		return hp;
    	}
    	int getTotalHp(){
    		return totalHp;
    	}
    
    	/** Set **/
    
    	void setStrength(int strength){
    		if (strength < 1 || strength > 10) return;
    		else this->strength = strength;
    	}
    	void setAgility(int agility){
    		if (agility < 1 || agility > 10) return;
    		else this->agility = agility;
    	}
    	void changeHp(int delta){
    		if (hp + delta < 1){
    			hp = 0;
    			morto = true;
    		} else if (hp+delta >totalHp){
    			hp = totalHp;
    		} else hp +=delta;
    	}
    	void setTotalHp(int totalHp){
    		if (totalHp<1 || totalHp > 10) return;
    		else this->totalHp = totalHp;
    	}
    	/** toString(), restituisce le informazioni come un'unica stringa**/
    
    	string toString(){
    		stringstream ss; //l'uso di uno string stream è analogo ad un output stream (cout)
    		ss << "Nome : "<<name<<" STR: "<< Util::toString(strength) <<" AGI: "<<Util::toString(agility)<<" HP: "<<Util::toString(hp)<<"/"<<Util::toString(totalHp);
    		return ss.str(); //restituisce una stringa
    	}
    };
    
    int main(){
    string temp;
    cout << "Inserisci il tuo nome avventuriero: ";
    cin >> temp;
    //creo l'istanza
    Character eroe(temp);
    //cambio le statistiche
    eroe.setAgility(7);
    eroe.setStrength(4);
    eroe.setTotalHp(3);
    eroe.changeHp(10);
    //stampo il risultato
    cout << eroe.toString() << endl;
    system("PAUSE");
    return 0;
    }

    Uso un namespace per raggruppare funzioni utili, per accedere al namespace basta usare due due punti, uso stringstream per avere uno stream che convertirò in stringa, sono "cose avanzate" ma non è necessario che capiate queste, piuttosto soffermatevi sulle funzioni get e set delle statistiche del personaggio e su come nel main chiamo i metodi per modificare il personaggio

     

     

    Sono molto celere nei commenti, se avete dubbi per qualsiasi cosa chiedete ;O

    Vi lascio due compitini per casa:

    • Aggiungere alla classe personaggio una variabile gold che tiene traccia delle finanze sempre positiva, tuttalpiù nulla, naturalmente si parte senza soldi, bisogna creare un metodo per restituire il valore ed uno per cambiarlo.

    • Creare un nemico di nome Wolfgang, con strength a 10, agility a 5 e 4 su 4 hp e stamparlo a video.

    Le soluzioni dei compitini dovranno pervenire in spoiler, pena l'azzeramento dei voti dal mio registro
    :biggrin:

    Nella prossima lezione implementeremo il combattimento, speriamo che il nostro eroe rimarrà vivo o.o
  2. Un'altra soluzione:

     

    #include <iostream>
    using namespace std;
    
    int main() {
    int mese = 9;
    char * mesi[12] = {"Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"};
    if (mese < 13 && mese >0) cout << "Siamo in " << mesi[mese-1] << endl;
    else cout << "Mese non corretto!"<<endl;
    return 0;
    }

     

     

    Per il c++ consiglio l'ide Code::Blocks

  3. Ecco cos'era allora :O

    Aggiungo codice che non c'entra un cazzo e quello che funzionava smette di funzionare, toglievo il codice neoaggiunto e si comportava in un altro modo ancora XD.

    La mia avventura con il game boy classic finisce qui, non ho intenzione di adeguarmi a programmare con mille mila array, passo al game boy advance u_u (o ricomincio sul pc, ho trovato del codice che avevo scritto 3 anni fa :o)

  4. Per ora ho lasciato stare, penso che quando mi servirà stampare un'immagine a tutto schermo barerò usando i banchi di memoria del gbc :rovatfl:

    Condivido codice e idee, così incentivo altri a farlo http://www.rpg2s.net/forum/public/style_emoticons/default/sisi.gif (soprattutto ProGM a continuare con i tutorial XD)

    Sto studiando un modo per gestire fluidamente animazioni e implementare timer, il delay(x) nel while(1) non mi convince, pensavo di basarmi sulla funzione clock e sincronizzarmi con il vbl

    #include <time.h>
    //
    int main(){
    clock_t old_time, now, delta;
    //...
    old_time = clock();
    while (1){
    now = clock();
    delta = now - old_time;
    old_time = now;
    update_world(delta);
    wait_vbl_done();
    }
    return 0;
    }
    
    La variabile delta indica i cicli di clock trascorsi, dovrebbe essere piccola come un UINT8, ma è un UINT16 ed il fatto che sia unsigned mi rompe le scatole per creare i timer, anche se fortunatamente ho cassato l'idea dei puntatori a funzione, rimpiango le funzioni implicite di linguaggi come javascript...
    Pensavo di fare la delta globale, in modo che evito di passarla a cascata ad ogni sottofunzione che ha bisogno di animarsi :D

    Ho provato a usare anche gli sprite, li ho istanziati con lo schermo off con move_sprite(n,0,0), fuori schermo, poi li warpo tranquillamente a schermo on con move_sprite e li aggiorno con scroll_sprite. (giusto?)
    Il personaggio spara 6 colpi, quindi ho pensato 2 sprite di personaggio + 6, uno per proiettile
    Ogni colpo è uno sprite.
    #define MAX_PROIETTILI 6
    struct proiettile {
    UINT x;
    UINT y;
    };
    struct eroe {
    UINT x;
    UINT y;
    UINT velx;
    UINT vely;
    struct proiettile pistola[MAX_PROIETTILI];
    }
     
    struct eroe Hero; //var globale eroe
     
    /* Da chiamare con lo schermo off */
    void init_eroe(UINT8 x, UINT8 y){
    UINT8 i;
    struct proiettile * p = Hero.pistola;
    Hero.x = x;
    Hero.y = y;
    Hero.velx = 0U;
    Hero.vely = 0U;
    set_sprite_data(0U,3U,sprite_eroe); //lo sprite ha 3 tile
    //lo sprite 0 e lo sprite 1 sono il chara
    set_sprite_tile(0U,0U); //allo sprite 0 assegna il tile 0
    set_sprite_tile(1U,1U); //allo sprite 1 assegna il tile 1
    move_sprite(0U,Hero.x,Hero.y);
    move_sprite(1U,Hero.x,Hero.y+8U);
    for (i=0U;i<MAX_PROIETTILI;i++){
    //i proiettili vanno dallo sprite 2 a 7. il tile 2 è la grafica del proiettile
    set_sprite_tile(2U+i, 2U);
    move_sprite(2U+i,0U,0U); //sposto il proiettile iesimo in (0,0)
    p[i].x = 0U; //aggiorno le coordinate del singolo proiettile
    p[i].y = 0U;
    }
    }
    
    PS: Il fatto che ad ogni costante numerica unsigned vada aggiunta una U finale è una rottura di palle U_U
  5. Ciao, ho letto i tutorial della prima pagina e ho iniziato a fare delle prove
    Non mi funziona il passaggio da APA a sprite mode o almeno, la prima volta funziona (seppur con qualche glitch grafico) mentre dopo la grafica va a donnine allegre.

    Questo è il codice, include il title.h dell'esempio dell'APA

    #include <gb/gb.h>
    #include <gb/drawing.h>
    #include <stdio.h>
    #include "title.h"
     
     
    /* Chiamami prima di disegnare qualcosa*/
    void draw_start(){
    DISPLAY_OFF;
    HIDE_SPRITES;
    HIDE_WIN;
    HIDE_BKG;
    disable_interrupts();
    }
     
    /* Chiamami dopo aver disegnato qualcosa in sprite mode (non in APA!) */
    void draw_end(){
    SHOW_BKG;
    SHOW_WIN;
    SHOW_SPRITES;
    DISPLAY_ON;
    enable_interrupts();
    }
     
    void disable_APA(){
    UINT8 i;
    for (i=0;i<255;i++){
    remove_VBL(i);
    remove_LCD(i);
    }
    LCDC_REG = 0x07;
    mode(0xE2);
    }
     
     
    int main(){
    UINT8 su,giu,dx,sx;
    su = 0x01; //su
    giu = 0x02; //giu
    dx = 0x03; //destra
    sx = 0x04; //sinistra
    do {
    //Title Screen
    draw_start();
    draw_image(title_tiledata);
    gotogxy(2,15);
    gprintf("Press %c to Start", dx);
    DISPLAY_ON;
    enable_interrupts();
    //Aspetto che disegni tutto
    wait_vbl_done();
    //Pressione tasto DX
    waitpad(J_RIGHT);
    waitpadup(); //aspetta il rilascio dei tasti
    //Non voglio piu' usare APA
    disable_APA();
    draw_start();
    [url="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"]printf[/url]("nSchermo PulitonPress Start");
    draw_end();
    //Pressione tasto START
    waitpad(J_START);
    waitpadup();
    //Aspetto che disegni tutto
    wait_vbl_done();
    } while (1);
    return 0;
    }
    
    Come si risolve :?
  6. Una cosa è parlare di usare l'etere o altre sostanze come mezzo di trasporto di informazioni un'altra è quella di un apparecchio succhia anima: scientificamente è assurdo in quanto l'anima non ha estensione fisica e le teorie che sostengono il contrario, come quella dei 21 grammi su cui hanno fatto il film, sono state confutate da decenni.
  7. Malanga non ha fatto altro che divulgare il "cosa" hanno raccontato i suoi esaminati.

    Quello che credo è che però, assunti i racconti per veri, sia ancora lontano dall'individuare il "perché": perché gli alieni rapiscono ed inseriscono chip.

    Secondo me l'aspirazione dell'anima (o animosità) tramite chip è una teoria campata per aria e sono in disaccordo con questa visione mistica in cui con tutte le creature terrestri ed extraterrestri che esistono è stato individuato l'uomo come serbatoio di anima.

    Se aspirata da qualche parte l'anima deve finire, si immagazzina nel chip in modo che è necessario un secondo intervento per rimuoverlo?

    E come fa un chip di un isotopo di silicio non presente sulla terra ad avere la capacità di assorbire ma anche solo di rilevare l'anima?

    Oppure questa viene trasmessa come un'onda elettromagnetica?

    Si aggiungo tante domande fantatecnologiche tanto di natura fisica che metafisica.

     

    Io penso che se i chip sottopelle esistano essi siano o un sistema di monitoramento, come quello che piantiamo nel collo degli uccelli prima della migrazione o negli animali della savana, o un sistema di rilascio di sostanze (esempio banale: rilascio di isotopi radiattivi per tenere sotto controllo determinati tipi di cancro)

    Il motivo? Ognuno di noi può essere stato soggetto ad un esperimento e diventare il progetto di una di queste entità, che siano alieni e non, governi o scienziati pazzi.

     

    Il problema è: dove sono questi chip?

    Il tuo amico dice di avercelo nella mano, apriamolo e vendiamo il chip su ebay, esistono miglioni di fanatici disposti a spendere qualunque cifra per queste cose, diventiamo ricchi :O

     

    Apo: Il video della fisica quantistica che hai postato è fatto da un ragazzo che ha una conoscenza di fisica che si ferma a wikipedia, il principio di Heisenberg nel campo in cui lavora Malanga viene usato anche per energia e tempo. Nel finale inoltre vuol fare intendere che la coscienza umana è superiore ad ogni macchina. Che poi l'autore sia tutt'altro che un affidabile e rigoroso uomo di scienza è un altro discorso.

  8. mi sono accorto che Graphic.frame_count viene caricato da Scene_file quindi non è necessaria alcuna compensazione :D

     

    #se sono passate almeno 7 oreif (Graphics.frame_count / Graphics.frame_rate)> 25200  var = 2#altrimenti se sono passate almeno 5 oreelsif (Graphics.frame_count / Graphics.frame_rate)> 18000  var = 1end

  9. La funzione version restituisce una stringa fissata da me e serve solo a distinguere una dll da una più aggiornata, perché prevedo di aggiungere nuove funzioni e potrà essere utile controllare di avere la dll "compatibile".

    Ho aggiornato la dll, mi ero scordato di togliere la creazione del file debug.txt, e ho aggiunto una classe che la gestisce =)

     

    Download aggiornato

     

    #==============================================================================# ** Kerolib Class#------------------------------------------------------------------------------#  This class handles the libKeroro.dll. Its functions include the md5#  hash of a file. Add this class before Game_Temp.#  Version 01#============================================================================== class Kerolib  #--------------------------------------------------------------------------  # * Object Initialization  #--------------------------------------------------------------------------  def initialize	@kero_md5 = Win32API.new('libKeroro.dll','file_md5',['P','P'],'V')	@kero_ver = Win32API.new('libKeroro.dll','version',['P'],'V')	@md5 = ' '*32 #buffer di 32 byte	@buffer = ' '*8 #buffer di 8 byte  end  #--------------------------------------------------------------------------  # * Get the md5 hash of the file given by filename  #--------------------------------------------------------------------------  def hash(filename)	@md5 = ' '*32  #crea un nuovo buffer	@kero_md5.call(filename,@md5)	return @md5  end  #--------------------------------------------------------------------------  # * Get the Version of the DLL  #--------------------------------------------------------------------------  def version	@buffer = ' '*8 #crea un nuovo buffer	@kero_ver.call(@buffer)	return @buffer  endend

     

    test code:

      kerolib = Kerolib.new  a = kerolib.hash('Game.exe')  b = kerolib.hash('Game.ini')  c = kerolib.version()  p a  p b  p c

  10. Risultato: Hai una buona memoria. Sei molto socievole. Preferisci pianificare il da farsi anche per le piccole cose. Sembra inoltre che sei un tipo curioso, vero? E magari ora vuoi sapere come lo so.

     

    Unica imprecisione: non voglio sapere come lo sai, riesco ad intuirlo con buona approssimazione :)

     

    L'idea dell'analisi dell'input nel contesto rpgmaker è molto interessante, attendo ulteriori sviluppi.

  11. Non sapevo che criptassi le risorse all'interno di un unico file, per questo ho proposto quella versione :)

    Visto che ne avevate bisogno ho creato una dll che calcola l'hash md5 di un file e può essere usata sia da rpg maker xp che da rpg maker vx.

    Potete scaricarla da http://www.gamemaker.it/ruby/download_lib.php

     

    Script di esempio:

      kero_ver = Win32API.new('libKeroro.dll','version',['P'],'V')  kero_md5 = Win32API.new('libKeroro.dll','file_md5',['P','P'],'V')  version = ' '*8  md5 = ' '*32  kero_ver.call(version)  p version  kero_md5.call('Game.exe', md5)  p md5

     

    Sono funzioni abbastanza semplici, non ho voluto definire classi o roba pesante, gestitela come volete!

    Se vi garba fatemelo sapere :D

  12. Aaaah quindi non c'è alcun tipo di confronto tra la nuova e vecchia versione!

    Ma a questo punto si potrebbe anche ottimizzare la banda, se 5 update sovrascrivono Scripts.rxdata quello che conta è solo l'ultimo :3

    Io farei così:

    I file rxdata che pesano di più sono 3: Animations, Scripts e Tilesets, gli altri non pesano molto e possono essere aggiornati sempre e accomunati nella categoria Other

    Ogni patch quindi è formata da massimo 4 file, una per categoria, Patch1_1 Patch1_2 Patch1_3 Patch1_4 corrispondono rispettivamente alle patch per Animations,Scripts,Tilesets, Other

     

    Esempio file di log.txt online, la presenza di 1 dopo il nome della patch indica la presenza di _1 (Animation), quella dopo di _2 (Scripts) e così via..

    Update1,1,1,0,1Update2,1,0,0,0Update3,0,1,0,1

     

    Struttura richiesta

    #Init@ani = nil@scr = nil@til = nil@other = Array.new

    Parsing del log.txt

    begin  file = File.new('log.txt','r')  while (temp = file.gets)	#Separo ogni valore e lo metto nell'array arr	arr = temp.split(/,/)	if arr[1] == 1	  @ani = arr[0]	end	if arr[2] == 1	  @scr = arr[0]	end	if arr[3] == 1	  @til = arr[0]	end	if arr[4] == 1	  @other.push arr[0]	end  end  file.closerescue => err  p errend

    Scaricamento

    if @ani != nil  download($host + '/patch/'+@ani + '_1.zip')endif @scr != nil  download($host + '/patch/'+@scr + '_2.zip')endif @til != nil  download($host + '/patch/'+@til + '_3.zip')end@other.each { |file| download($host + '/patch/'+file + '_4.zip') }

    Se hai N patch, con questo sistema scarichi al massimo N+3 patch ma puoi anche scaricarne solo 1 se tutte modificano lo stesso file critico, es tutte modificano solo Scripts verrà scaricata solo l'ultimo Update.

    In questo esempio verranno scaricati:

    Update2_1.zipUpdate3_2.zipUpdate1_3.zipUpdate1_4.zipUpdate3_4.zip

    Sono più file ma si risparmiano almeno 200 kb

     

    (in questo esempio trascuro il versioning, il controllo se abbiamo bisogno di tutte le patch, può essere fatto in modo semplice o tramite un array di stringhe in cui controlliamo se l'update è stato già fatto oppure salvandosi solo la stringa dell'ultimo update eseguito e processare da lì in poi)

  13. Risposta banale

    #Immaginando di aver assegnato alla switch 555 l'abilitazione dello shopif !$game_switches[555] && ((Graphics.frame_count / Graphics.frame_rate)> 18000)  $game_switches[555] = trueend

     

    Perché questa soluzione non mi piace?

    Innanzitutto affinché la switch si accenda le ore di gioco devono essere strettamente continue, se salvo, chiudo, riapro e ricarico il timer è resettato (perché frame_count riparte da 0 sempre).

    Quindi bisogna trovare una soluzione più elaborata, ad esempio sommare i secondi ottenuti dall'ultimo salvataggio.

    Inoltre trovo frame_count su frame_rate un metodo poco affidabile di calcolare il tempo trascorso in quanto non ne conosco l'implementazione ed i frame tendono a fluttuare un casino per loro natura.

     

    Trovare però una soluzione più complessa mi ha spinto a creare qualcosa di carino che appena rifinito pubblico :)

×
×
  • Create New...