Fire-Dragon-DoL Posted April 10, 2009 Share Posted April 10, 2009 (edited) Threading basilare, o anche Processi Paralleli in RGSS (applicati a rpgmaker)1.0 1. IntroduzionePer: RPG Maker XP/VXAutore: Fire-Dragon-DoLDescrizione: Questo tutorial tratta della progettazione di "processi paralleli" (pezzi di programma eseguiti in "contemporanea" ad altri) che consentono ad esempio aggiornamento di barre degli hp e atb in tempo reale, mentre potete continuare a muovere il vostro personaggio ed eseguire altre azioni (come gli eventi settati come "processi paralleli").Ultima modifica: 10/04/2009 21:38. 2. TutorialAvete presente quando mettete un processo parallelo per far ripetere un'azione all'infinito (per esempio l'aggiornamento della grafica di una barretta degli hp su mappa)?Vi è mai passato per la testa di voler fare la stessa cosa ma con l'RGSS? (in realtà i thread sono incorporati nel ruby...per comodità nel tutorial dirò RGSS)Questo è possibile... e offre tantissime possibilità, poichè differentemente dai processi paralleli sono molto leggeri (fin quando non li riempite voi di cose pesantissime)e soprattutto vi offrono la possibilità di non mettere quel maledetto eventino su ogni mappa per far comparire quella maledetta barra degli hp in alto a sinistra...Insomma hanno molteplici utilità...i thread servono quindi a far si che possiate fare delle azioni in parallelo. Come ho già detto, i thread sono una specifica del ruby e non dell'RGSS, quindi li trovate documentati qui:http://www.ruby-doc.org/core/classes/Thread.htmlIn questo link troverete anche cose che esulano da questo tutorial (almeno per il momento) poichè non ritenute necessarie (le ritengo basilari)Oltre a ciò, vi servirà una funzione (metodo) che ho creato io (ieri notte) per creare dei tempi di attesa all'interno dei thread (vi torneranno comodi per scriptare un ATB...) senzache il vostro gioco si "fermi tutto" (se usate sleep, non potrete muovere il personaggio...ma allora è come se non poteste creare operazioni parallele "temporizzate").In aggiunta a questo il vantaggio della mia funzione è che è in decimi di secondo (lo sleep è in secondi), quindi potete far aspettare un decimo di secondo (decisamente più utile che tempidi attesa in secondi!). Materiale:1) Funzione "wait"module Utils #potete metterla dove volete...io la preferisco qui, in questo modulo personalizzato module_function def wait(decseconds) #I tempi di attesa sono in decimi di secondo, quindi 10=1 secondo #Ottengo il numero di frame correnti trascorsi dall'avvio del gioco #questo valore lo calcolo qui per essere piu preciso possibile nell'attesa framescurrent=Graphics.frame_count #Ottengo i frame al secondo (FPS) e li gestisco come float per maggior precisione framepersec=Graphics.frame_rate.to_f #Calcolo quanti frame devo aspettare per arrivare a un tempo di attesa pari a decseconds #Come potete notare, framepersec/10.0 corrisponde ai Frame Per Decimi di secondo (FPDS? xD) framestowait=decseconds.to_f*(framepersec/10.0) #A questo punto, parto dal frame a cui siamo e cerco di ottenere quanti frame vanno aspettati #Faccio arrotondare i float a interi (perchè non esistono "mezzi frame" in rpg maker... #in altri giochi come WoW li ho visti ma non vorrei dir cavolate frametoreach=framescurrent+framestowait.round #Dopodichè aspetto fino a che il frame_count non equivale il frametoreach (visto che il frame_count) si autoincrementa con l'attesa #Ovviamente l'unico modo è creare un mini ciclo infinito all'interno della funzione while (Graphics.frame_count<frametoreach) #Aspetta e spera... xD end #Ricordo a tutti che un codice "attende" la fine di una chiamata di funzione per continuare... è su questo che si basa #questa funzione endend(per utilizzarla è sufficiente scrivere Utils::wait(numero_intero)) Note:1) Piccola legenda sui livelli per i tutorialParto dal presupposto che l'utente sappia programmare in qualche linguaggio (anche per gli eventi perchè è meglio per tutti)* = Conoscenza basilare degli eventi** = Conoscenza avanzata degli eventi*** = Conoscenza del Ruby**** = Conoscenza basilare dell'RGSS (fondamentalmente della documentazione)***** = Conoscenza avanzata dell'RGSS (praticamente conoscere perfettamente gli script di RPGMaker e come smucinarci al meglio) Livello tutorial: **** Partiamo dalla base...come ho detto il Thread è un vero e proprio processo, un pò come far partire un altro programma a fianco del vostro (a livello pratico non è così, ma rende l'idea) che possausare tutte le variabili/funzioni/classi/etc del vostro programma principale, modificandole a suo piacimento. Dunque, la sintassi per creare un Thread è veramente semplice, la cosa fondamentale però è memorizzare un riferimento a tale Thread in una variabile (in questo script useremo le globali)perchè se create un Thread infinito (per esempio per caricare l'ATB) vorrete poterlo mettere in pausa e soprattutto spegnerlo (eliminarlo) del tutto quando finisce (altrimenti il vostro ATBcontinuerà anche dopo la battaglia... portando a non voglio sapere quali errori). Sintassivariabile=Thread.new { }Tra le parentesi graffe metteteci il codice che volete...per creare un ciclo infinito (quindi un thread che viene eseguito all'infinito, ricordo che tutti i programmi sono cicli "infiniti" o quasi infinit (terminano quando li chiudete)variabile=Thread.new { while (true) end}Tutto quello che sta nel while viene ripetuto in eterno, ammenochè non "killate" (spegnete definitivamente) il thread (o processo), come riuscirci verrà spiegato a breveSe vi sta scomodo spegnere il thread esternamente, potete sempre mettere uno switch e usare quello nella condizione del while... quando il thread arriva alla fine, si spegne da solo(e forse questo è un approccio molto piu corretto di "killare" il vostro processo...anche più pulito, anche perchè sto leggendo in giro che Thread.kill potrebbe essere buggata...ma le vocisono di un anno fa...non so come si è evoluta la cosa nel frattempo). Un'alternativa per creare un Thread è la seguente:variabile=Thread.new([args]*) { |args|....}In questa situazione tutto ciò che è passato attraverso new (un array) sarà accessibile nel blocco del Thread come (in questo caso) args (la variabile tra | e |)... può farvi comodo per "parametrizzare"i thread (come sfruttare ciò è a vostra discrezione) A questo punto, come vi ho detto vogliamo poter "uccidere" (spegnere definitivamente e farlo crepare!) il nostro thread...la cosa è molto semplice ed eseguibile in due modi differenti:1)Thread.kill(variabile)2)variabile.killSemplice, sensato, immediato, logico! (mi sento sadico quando uso questo metodo...) Può essere comodo comunque per spegnere il vostro ATB all'istante, se la battaglia finisce...ovviamente se state facendo scritture di file e roba simile in un thread e lo spegnete, non voglio sapere quello che succede...quindi assicuratevi di spegnere thread "sicuri", oppure usate uno switch peruscire dal while...che era un metodo più certo e tranquillo Esistono altre piccole cose interessanti riguardo i thread... ad esempio, supponendo che variabile=Thread.new.... potete settare dei valori che potrete usare all'esterno nel seguente modovariabile["nome"]=qualcosaSe volete settare questi valori dall'interno del thread è semplice:variabile=Thread.new { #Questa riga Thread.current, è come se scrivessimo "variabile"... in poche parole si riferisce al nostro thread Thread.current["nome"]=qualcosa} Come sfruttarlo sta sempre a voi deciderlo... un semplice esempio potrebbe essere dare un nome univoco a ogni thread ["nome"] per l'appunto, poi usando questa comodissima funzione Thread.list otteniamoun array contenente tutti i thread in esecuzione... che potrete riconoscere tramite il vostro valore impostato "nome" Abbiamo infine gli ultimi due metodi utilissimi (ne esistono molti altri ma questa è una introduzione e soprattutto ritengo di aver spiegato le cose basilari e utili per i thread... esistono molte funzionipiuttosto avanzate)Il primo è Thread.stop, va usato all'interno del blocco del thread e lo mette in attesa, facendo eseguire altri threads.variabile=Thread.new { print "ciao" Thread.stop}e l'altro è variabile.wakeup... l'opposto di stop, ovvero riattiva il thread facendolo partire dal punto in cui si era fermato Questa era un'introduzione basilare ai thread... spero possiate sfruttarla in qualche modo, si accettano suggerimenti su come migliorare il tutorial (è il primo che scrivo, quindi criticate anche pesantemente :P )... grazie a tutti Edited April 10, 2009 by Fire-Dragon-DoL If you think C++ is not overly complicated, just what is a protected abstract virtual base pure virtual private destructor and when was the last time you needed one? (Tom Cargill) Se dovete fare una cosa semplice, tipo if (a==b) c='pippo';else c='pluto';Usate le funzionalita' del linguaggio piu' complicato che esiste: c=select decode(sign(a-b),0,"pippo","pluto"); Link to comment Share on other sites More sharing options...
Darklink92 Posted April 10, 2009 Share Posted April 10, 2009 Ottimo!Ma la funzione .update, non fà più o meno la stessa cosa? Partecipante al Rpg2s.net Game Contest 2008/2009http://www.rpg2s.net/contest/GameContest0809/gc0809-bannerino.jpgGioco in Sviluppo: Fantasy Chronicle Disponibile Versione demo!(capitolo 1)Sarica e commenta anche tu! http://img120.imageshack.us/img120/3914/adlucariodd0.pnghttp://img74.imageshack.us/img74/8841/admariomc6.pnghttp://img177.imageshack.us/img177/8113/adzsamuszd3.pnghttp://img359.imageshack.us/img359/9097/adfalcoqq6.pnghttp://img382.imageshack.us/img382/3572/adlucasom6.pnghttp://img501.imageshack.us/img501/5646/adsnakepp3.png http://team.ffonline.it/imgpersonaggio/cloud_it.jpghttp://team.ffonline.it/imgpersonaggio/cyan_it.jpghttp://team.ffonline.it/imgpersonaggio/steiner_it.jpg Un tizio riguardo Mario Galaxy io l'ho provato, molto divertente e colorato, ma nn c'entra nulla il termine "cpaolavoro" o "miglior gioco" x un gioco del genere, e ha se, nn puo essere paragonato a "veri" giochi del calibro di resident evil,tekken,gran turismo,rachet e clank,assassin's creed ecc..... Link to comment Share on other sites More sharing options...
Fire-Dragon-DoL Posted April 10, 2009 Author Share Posted April 10, 2009 Ottimo!Ma la funzione .update, non fà più o meno la stessa cosa? Devi perdonarmi ma temo di non capire la tua domanda... la funzione .update aggiorna i frame... il thread lancia una parte di codice come "a se stante" e viene eseguita in parallelo ad un'altra (magari quella principale) se intendi mettere qualcosa dentro .update, allora non è lo stesso... se metti il "wait" dentro l'update logicamente "metti in pausa" l'intero processo principale... di conseguenza non vedrai (graficamente) muoversi qualcosa o roba del genere... ma i thread possono essere usati anche a altri scopi:immagina di avere tre thread... con uno aumenti ogni 10 secondi una variabile, con un altro sposti avanti un evento ogni 3 secondi, con un altro ancora carichi una barretta tipo quella dell'atb che però può riguardare qualcos'altro... (oppure puoi mettere tutto in un unico thread che si stacchi dal principale...queste son scelte) è molto ampia l'utilità dei thread...devo dire che è anche difficile spiegarla, fondamentalmente gia due thread (ribadisco il processo principale è gia considerato un thread) e uno secondario dovrebbero bastare (effettivamente esegui il programma su due piani paralleli...dovresti riuscire a fare gia tutto) ovviamente come ho detto i thread sono molto piu veloci dei processi paralleli e pesano molto meno all'rpg maker If you think C++ is not overly complicated, just what is a protected abstract virtual base pure virtual private destructor and when was the last time you needed one? (Tom Cargill) Se dovete fare una cosa semplice, tipo if (a==b) c='pippo';else c='pluto';Usate le funzionalita' del linguaggio piu' complicato che esiste: c=select decode(sign(a-b),0,"pippo","pluto"); Link to comment Share on other sites More sharing options...
Keroro Posted April 28, 2009 Share Posted April 28, 2009 Non hai accennato al fatto che i Thread comportano degli enormi casini e nel momento che hai variabili condivise sono necessari metodi synchronized. I Miei Script:Salva Schermata (3 Aprile 2012)Attacco Personalizzabile (2 Aprile 2012)Keyboard Input (Porting) (17 Marzo 2012)Continua... Link to comment Share on other sites More sharing options...
Fire-Dragon-DoL Posted April 28, 2009 Author Share Posted April 28, 2009 Non hai accennato al fatto che i Thread comportano degli enormi casini e nel momento che hai variabili condivise sono necessari metodi synchronized. Non l'ho accennato perchè la libreria di gestione di variabili condivise (o comunque metodi di essa) non funzionano su rpg maker (testato) (forse perchè li gestisce da se in qualche modo) comunque finchè li si usa per animazioni dovrebbe andare ok... non ho testato su stesse variabili, ma in ruby se fai leggere/scrivere una globale da due thread in contemporanea non succede niente, che abbia una gestione interna? If you think C++ is not overly complicated, just what is a protected abstract virtual base pure virtual private destructor and when was the last time you needed one? (Tom Cargill) Se dovete fare una cosa semplice, tipo if (a==b) c='pippo';else c='pluto';Usate le funzionalita' del linguaggio piu' complicato che esiste: c=select decode(sign(a-b),0,"pippo","pluto"); Link to comment Share on other sites More sharing options...
Keroro Posted April 28, 2009 Share Posted April 28, 2009 RGSS non ha una gestione interna e neanche ruby altrimenti non avrebbe senso introdurre i Monitor e le Mutex.Se non vedi l'errore non significa che non ci sia, è semplicemente più sottile: se un thread modifica le variabili mentre stai facendo delle manipolazioni sulle stesse il risultato può discostarsi da quello previsto (ci sono un miliardo di esempi sul web).I thread sono più veloci ma aggiungono una notevole complessità logica che qualsiasi programmatore tende ad evitare senza benefici consistenti I Miei Script:Salva Schermata (3 Aprile 2012)Attacco Personalizzabile (2 Aprile 2012)Keyboard Input (Porting) (17 Marzo 2012)Continua... Link to comment Share on other sites More sharing options...
Fire-Dragon-DoL Posted April 28, 2009 Author Share Posted April 28, 2009 RGSS non ha una gestione interna e neanche ruby altrimenti non avrebbe senso introdurre i Monitor e le Mutex.Se non vedi l'errore non significa che non ci sia, è semplicemente più sottile: se un thread modifica le variabili mentre stai facendo delle manipolazioni sulle stesse il risultato può discostarsi da quello previsto (ci sono un miliardo di esempi sul web).I thread sono più veloci ma aggiungono una notevole complessità logica che qualsiasi programmatore tende ad evitare senza benefici consistenti So bene cosa sono i thread eh! Applicazione tipica di un thread: animazione ...è risaputo e quando usi un processo parallelo non fai nient altro di diverso in rpg maker... comunque in rpg maker non sono proprio implementate le librerie per gestire una cosa di questo tipo, però E' LOGICO e SENSATO che se tu modifichi una cosa in un thread e subito dopo la stessa in un altro ottieni risultati particolari e spesso non voluti sta al programmatore rifletterci su, io ho solo detto che esiste If you think C++ is not overly complicated, just what is a protected abstract virtual base pure virtual private destructor and when was the last time you needed one? (Tom Cargill) Se dovete fare una cosa semplice, tipo if (a==b) c='pippo';else c='pluto';Usate le funzionalita' del linguaggio piu' complicato che esiste: c=select decode(sign(a-b),0,"pippo","pluto"); Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now