Salve gente oggi mi sto dedicando a capire bene il funzionamento dei template che ospitano i nostri personaggi.
Ovvero sto studiando lo schema e gli associamenti che avvengono fra le istruzioni della classe Sprite_Character
e i relativi template che abbiamo nella nostra cartella Graphics.
Premessa:
In sostanza voglio individuare le stringhe di codice che danno importanza a ciò che viene rappresentato nel template.
Riconoscerle e inseguito apportare delle modifiche al codice ruby per cambiarne le regole. Come ad esempio inserire
o sottrarre un numero di Pose; oppure aumentare o diminuire un numero di frames.
Ovviamente sono a conoscenza che esistono moltissimi scripts che trattano l'argomento e sono già belli pronti all'uso.
Però, lo scopo di questo piccolo tutorial è quello di saper apportare delle modifiche direttamente al codice che abbiamo
già a nostra disposizione nei nostri scripts di default.
Quindi fatti i relativi convenevoli Iniziamo ;)
Primo Punto:
Per prima cosa occorre studiare cosa ci viene dato a nostra disposizione:
E quindi possiamo notare che nella cartella " Graphics\Characters " sono depositati tutti i file.png che rappresenteranno i nostri personaggi (eroi o npg) che popoleranno il nostro gioco.
Scegliendo di aprire uno di questi file con un qualsiasi programma grafico (ad esempio Paint) possiamo determinare la grandezza dell'immagine, ad esempio:
Questa la si conosce già. E' il template di Charaset di default che ha dimensioni di 128x192.
Vi posso dire che le dimensioni non contano o comunque non assumono una particolare importanza, perché anche se
costruirete un template più grande ma mantenendo sempre l'ordine delle celle 4x4 , aldilà di quale sarà la dimensione
non importa il nostro chara avrà sempre (in questo caso) 4 frames per posa, per un totale di 4 pose.
Considerato quanto specificato nell'esempio, posso adesso chiarire da un punto di vista grafico cosa si intende per "Frames"
e cosa è una "Posa". Dunque..
Cosa sono i Frames?
Solitamente per definizione standard si intendono tutte quelle immagini che ritraggono un soggetto (o diversi) e ne catturano i movimenti. Per capire bene il concetto basta pensare subito ad un cartone animato, una Gif o un qualsiasi video.
Tutti questi esempi non sono altro che il prodotto scaturito da un accumulo di immagini messe in sequenza e fatte scorrere ad una determinata frazione di secondo. E quindi tutto ciò produce un'animazione. E qui volevo arrivare!
Per permettere ai nostri personaggi di gioco di muoversi all'interno delle nostre scene occorre Animarli.
Ciò che permette di realizzare un'Animazione adeguata e non "scattosa" quindi fluida, sono appunto i Frames.
Più ce n'è, Meglio è!
Questi Frames vengono rappresentati nel template orizzontalmente. Quindi prendendo come esempio visivo la tabella seguente, possiamo notare lo schema e l'ordine delle singole cellette. che in questo caso sono quattro per fila e le file sono anch'esse 4.
Dove F(1,2,3,4) sta ad indicare il numero di Frames, mentre P(1,2,3,4) sono le Pose.
Quindi adesso che abbiamo un'idea su ciò che significa Frames e come vengono rappresentati nel grafico del template,
possiamo vedere..
Cosa sono le Pose?
Le Pose in Rpg Maker (aldilà delle versioni del tool) sono le Tipologie di Movimento.
Ora rimanendo in RMXP nel caso del template posto in esame, quello schema lì convenzionalmente ospita le varie tipologie di Camminata: Posa Frontale, Laterale sinistra, Laterale destra e retro.
Quindi immaginiamocelo, da adesso in poi, in questo modo:
Riuscendo adesso ad interpretare lo schema grafico (ovvero il template), abbiamo già capito come dovrà essere impostata la nostra tabella concettuale. Quindi una volta che si hanno chiari il concetto di Pose; di Frames e la loro funzione e il come vengono rappresentati da un punto di vista tabellare. Adesso non ci resta che associare questi concetti alle istruzioni impartite dai nostri Sprite_Character, che abbiamo a disposizione all'interno del nostro script editor.
E quindi vi esorto a passare al nostro..
Secondo Punto:
Apriamo un progetto qualunque ( è preferibile uno nuovo dove appunto fare i nostri esperimenti in totale tranquillità).
Apriamo il nostro script editor e rechiamoci subito alle Classe..
Sprite_Character:
#------------------------------------------------------------------------------ # This sprite is used to display the character.It observes the Game_Character # class and automatically changes sprite conditions. #============================================================================== class Sprite_Character < RPG::Sprite #-------------------------------------------------------------------------- # * Public Instance Variables #-------------------------------------------------------------------------- attr_accessor :character # character #-------------------------------------------------------------------------- # * Object Initialization # viewport : viewport # character : character (Game_Character) #-------------------------------------------------------------------------- def initialize(viewport, character = nil) super(viewport) @character = character update end #-------------------------------------------------------------------------- # * Frame Update #-------------------------------------------------------------------------- def update super # If tile ID, file name, or hue are different from current ones if @tile_id != @character.tile_id or @character_name != @character.character_name or @character_hue != @character.character_hue # Remember tile ID, file name, and hue @tile_id = @character.tile_id @character_name = @character.character_name @character_hue = @character.character_hue # If tile ID value is valid if @tile_id >= 384 self.bitmap = RPG::Cache.tile($game_map.tileset_name, @tile_id, @character.character_hue) self.src_rect.set(0, 0, 32, 32) self.ox = 16 self.oy = 32 # If tile ID value is invalid else self.bitmap = RPG::Cache.character(@character.character_name, @character.character_hue) @cw = bitmap.width / 4 @ch = bitmap.height / 4 self.ox = @cw / 2 self.oy = @ch end end # Set visible situation self.visible = (not @character.transparent) # If graphic is character if @tile_id == 0 # Set rectangular transfer sx = @character.pattern * @cw sy = (@character.direction - 2) / 2 * @ch self.src_rect.set(sx, sy, @cw, @ch) end # Set sprite coordinates self.x = @character.screen_x self.y = @character.screen_y self.z = @character.screen_z(@ch) # Set opacity level, blend method, and bush depth self.opacity = @character.opacity self.blend_type = @character.blend_type self.bush_depth = @character.bush_depth # Animation if @character.animation_id != 0 animation = $data_animations[@character.animation_id] animation(animation, true) @character.animation_id = 0 end end end
Perfetto.
Ora, come è evidente, questa classe si occupa di identificare la variabile character appunto.
Quindi la idealizza tramite il metodo initialize; dopo di che con il relativo metodo update gli assegna le proprietà che dovrà avere. Ovvero le funzioni che sarà in grado di svolgere.
Tra le tante, possiamo notare apparire le due stringhe che controllano (o meglio assegnano) il numero di Frames e di Pose che dovrà avere il nostro template.
Per vederle occorre recarvi alla riga 47 e 48 dello Sprite_Character:
@cw = bitmap.width / 4 #numero di Frames @ch = bitmap.height / 4 #numero di Pose
Quando vedete queste due stringhe è comodo ricordarsi lo schema grafico precedente (ve lo ricordate?!)
In @cw = bitmap.width / verranno assegnati il numero di Frames.
In @ch = bitmap.height / verranno assegnate le Pose.
Quindi ricapitolando:
I Frames si visualizzano nel Template grafico orizzontalmente e sono il numero delle cellette che costituiscono la fila:
Quindi questa celletta:
è un Frame.
Più celle sviluppate in orizzontale costituiscono una fila che in gergo viene nominata..
Posa:
e loro si sviluppano verticalmente.
le stringhe di codice che permettono di riconosce e dare importanza al numero delle celle o delle file sono
le seguenti: @cw = bitmap.width / numero di frames
@ch = bitmap-height / numero di pose
Ma adesso vediamo di fare un esempio (Come giustamente suggerisce Guardian :) )
Allora, di default nella cartella Characters abbiamo all'incirca 199 file.png tutti quanti di proporzione 4x4.
(sappiamo già cosa significa)
Adesso facciamo invece che nel nostro gioco vengano accettati dei template che hanno come numero di Frames 6 ad esempio e un numero di Pose maggiore, tipo.. 8
(come nei comunissimi script che permettono una camminata in più direzioni).
Ora tempi fa realizzai io stesso un template di un chara a 8 direzioni e adesso vediamolo di riesumare:
Questo di qua ha una proporzione 4x8
Proviamo solo a scopo didattico ad aggiungere qualche frames in più.
Quindi prendete pure questa risorsa e modificatela orizzontalmente attraverso un qualsiasi vostro programma di grafica.
(Io userò il buon Paint)
Dunque fatte le relative modifiche il nostro nuovo template si presenterà in questo modo:
Per provarlo occorrerà modificare il codice seguente..
01: Rechiamoci in Sprite_Character (se non l'avete già fatto) modificate le due stringhe 47 e 48.
Scrivendo appunto:
@cw = bitmap.width / 6 @ch = bitmap.height / 8
Adesso solo con questa modifica, se non avete implementato le 8 direzioni, si eseguiranno solo i movimenti relativi alle 4 direzioni. Per testare quel template lì in maniera totale occorrerà modificare qualche stringa in più dei nostri script di default.
Perché in questo modo il Nuovo Template verrà accettato dal programma solo che l'unico inconveniente riguarderà
che le pose non corrispondono ai tasti direzionali. Per ovviare a questo problema occorrerà svolgere questi passaggi
(Andiamo un poco OT ma mi serve per dare un buon reso finale)
Camminata a 8 Direzioni modificando gli script di default:
Per Abilitarla, basta recarsi alla riga 214 di Game_Player:
case Input.dir4 when 2 move_down when 4 move_left when 6 move_right when 8 move_up end
e modificarla in questo modo:
case Input.dir8 when 2 move_down when 4 move_left when 6 move_right when 8 move_up when 1 move_lower_left when 7 move_upper_left when 3 move_lower_right when 9 move_upper_right end
Così facendo abbiamo abilitato la camminata a 8 direzioni però ancora le Pose non sono correlate correttamente alle direzioni. Quindi per permettere che lo siano, occorre Ritornare in Sprite_Characters:
Ovvero alla riga 58:
sx = @character.pattern * @cw sy = (@character.direction - 2) / 2 * @ch
Ricompaiono @cw e @ch (vi ricordate Frames e Pose) Non per nulla sx è rappresentato da @cw e sy da @ch.
(Tenete sempre a mente lo schema).
Comunque noi già sappiamo che RPG MAKER XP ha accettato benissimo i Charaset a più frame, quindi:
sx = @character.pattern * @cw
Possiamo anche lasciarlo così per com'è, non ci interessa. Vediamo invece di attuare delle modifiche in..
sy = (@character.direction - 2) / 2 * @ch
^^ lui si che necessita assolutamente delle modifiche. Anzi ne approfitto per ringraziare PROGM che nel lontano 2009
postò uno script in soccorso ad un utente della sezione Supporto Rgss, script che però andò perso poiché attualmente
è salvato su un'unica riga (maledetta a lei -.-) che io ho recuperato solo la parte che mi necessitava
(per fortuna che era all'inizio dello script) Comunque torniamo al discorso..
Dobbiamo modificare quella stringa lì e sostituiamola con questo:
if @character.is_a?(Game_Player) case @character.direction when 1 sy = 0 when 2 sy = @ch when 3 sy = 2 * @ch when 4 sy = 3 * @ch when 6 sy = 4 * @ch when 7 sy = 5 * @ch when 8 sy = 6 * @ch when 9 sy = 7 * @ch end else sy = (@character.direction - 2) / 2 * @ch end
Vediamo che la rincontriamo dopo per una cosa di default qualora non si dovessero realizzare dei parametri.
(Grazie ancora PRO)
Bene adesso siamo quasi giunti al termine della nostra spiegazione, dobbiamo recarci ora in..
Game_Character 3: ..........Daytan Daytan Daytan!
In questa classe si possono notare già dalle prime righe di codice i metodi che riguardano i movimenti e più sotto ci
sono pure le direzioni.
Ora analizzando questo script potete notare che i movimenti a 8 direzioni esistono di default. Però l'unica cosa che manca
sono le direzioni (o i sensi di marcia per intenderci) Quindi occorre crearli ! Ed è facile:
Recatevi alla riga 372 di Game_Character 3. Da lì fino alla riga 407 ci sono ospitate le quattro direzioni
Giù
Sinistra
Destra
Su
Appena sotto la riga 407 costruite le altre quatto direzioni in questo modo:
#-------------------------------------------------------------------------- # * Turn Lower_Left #-------------------------------------------------------------------------- def turn_lower_left unless @direction_fix @direction = 1 @stop_count = 0 end end #-------------------------------------------------------------------------- # * Turn Lower_Right #-------------------------------------------------------------------------- def turn_lower_right unless @direction_fix @direction = 3 @stop_count = 0 end end #-------------------------------------------------------------------------- # * Turn Upper_Left #-------------------------------------------------------------------------- def turn_upper_left unless @direction_fix @direction = 7 @stop_count = 0 end end #-------------------------------------------------------------------------- # * Turn Upper_Right #-------------------------------------------------------------------------- def turn_upper_right unless @direction_fix @direction = 9 @stop_count = 0 end end
Spiego un pochettino cosa ho fatto (nulla di eclatante, ho solo copia incollato ad esempio:
#-------------------------------------------------------------------------- # * Turn Up #-------------------------------------------------------------------------- def turn_up unless @direction_fix @direction = 8 @stop_count = 0 end end
Sostituendo i parametri, ad esempio ho visto che esiste già la dicitura:
lower_left ; lower_right ; upper_left ; upper_right
utilizzata all'interno dei metodi riguardanti il movimento a 8 direzioni
(ho soltanto riciclato questi termini e utilizzati dove mi necessitava)
poi cos'altro ho fatto.. nella variabile @diraction ho visto che quei numeri l' (2,4,6,8) corrispondono ai numeri del tastierino
numerico della tastiera, quelli che solitamente vengono associati ai tasti direzionali di alcuni giochi per pc.
Sempre per logica ho sperimentato se tale dicitura potesse comprendere anche i valori (1.3.7.9) che corrispondono alle
diagonali.
In sostanza quel turn uo lì, l'ho copiato 4 volte in più e le copie le ho fatte diventare le quattro direzioni diagonali.
Adesso siamo pronti,rimanendo sempre all'interno di Game_Character 3, nel dirigerci alla riga 101 poco più su.
Finalmente siamo al cospetto dei 4 metodi che si occupano di far muovere il chara diagonalmente:
#-------------------------------------------------------------------------- # * Move Lower Left #-------------------------------------------------------------------------- def move_lower_left # If no direction fix unless @direction_fix # Face down is facing right or up @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction) end # When a down to left or a left to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 2)) # Update coordinates @x -= 1 @y += 1 # Increase steps increase_steps end end #-------------------------------------------------------------------------- # * Move Lower Right #-------------------------------------------------------------------------- def move_lower_right # If no direction fix unless @direction_fix # Face right if facing left, and face down if facing up @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction) end # When a down to right or a right to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 6)) or (passable?(@x, @y, 6) and passable?(@x + 1, @y, 2)) # Update coordinates @x += 1 @y += 1 # Increase steps increase_steps end end #-------------------------------------------------------------------------- # * Move Upper Left #-------------------------------------------------------------------------- def move_upper_left # If no direction fix unless @direction_fix # Face left if facing right, and face up if facing down @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction) end # When an up to left or a left to up course is passable if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 8)) # Update coordinates @x -= 1 @y -= 1 # Increase steps increase_steps end end #-------------------------------------------------------------------------- # * Move Upper Right #-------------------------------------------------------------------------- def move_upper_right # If no direction fix unless @direction_fix # Face right if facing left, and face up if facing down @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction) end # When an up to right or a right to up course is passable if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 6)) or (passable?(@x, @y, 6) and passable?(@x + 1, @y, 8)) # Update coordinates @x += 1 @y -= 1 # Increase steps increase_steps end end
Bene. Adesso vi spiego cosa abbiamo ottenuto fino ad ora:
Allora, il programma riconosce i chara.png di proporzione 6x8 ; il chara cammina in tutte le 8 direzioni ..
Ma ancora le nostre otto pose non ne vogliono sapere di associarsi alle 8 direzioni di camminata.. Perché!!?
Ve lo spiego subito:
Adesso che abbiamo le conoscenze necessarie possiamo modificare quei quattro metodi in maniera corretta,
Procediamo:
Prendiamo in esempio il primo:
#-------------------------------------------------------------------------- # * Move Lower Left #-------------------------------------------------------------------------- def move_lower_left # If no direction fix unless @direction_fix # Face down is facing right or up @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction) end # When a down to left or a left to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 2)) # Update coordinates @x -= 1 @y += 1 # Increase steps increase_steps end end
Intanto mettiamolo a confronto con una normalissima camminata di default ad esempio Move_Down (così a caso):
#-------------------------------------------------------------------------- # * Move Down # turn_enabled : a flag permits direction change on that spot #-------------------------------------------------------------------------- def move_down(turn_enabled = true) # Turn down if turn_enabled turn_down end # If passable if passable?(@x, @y, 2) # Turn down turn_down # Update coordinates @y += 1 # Increase steps increase_steps # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x, @y+1) end end
Notiamo sin da subito che i due metodi si presentano in maniera diversa.
Move_Down ha la direzione cosa che Move_Lower_Left non ha.Perché di default prima non esisteva il metodo
Turn_Lower_Left. Ma adesso non è più così! ;)
Benissimo avendo capito questo passaggio, possiamo adesso implementare il metodo turn_lower_left all'interno
di move_lower_left. così:
#-------------------------------------------------------------------------- # * Move Lower Left #-------------------------------------------------------------------------- def move_lower_left(turn_enabled = true) # Turn Lower_Left if turn_enabled turn_lower_left end #....ecc non abbiamo ancora finito..
In questo modo abbiamo impostato il senso di marcia. Continuiamo..
Lasciamo ora tutto così per com'è e fra i due end finali (appunto) inseriamogli un return, in questo modo:
end return passable?(@x,@y,1) end
Adesso il nostro metodo Move_Lower_Left si presenterà in questo modo:
#-------------------------------------------------------------------------- # * Move Lower Left #-------------------------------------------------------------------------- def move_lower_left(turn_enabled = true) # Turn Lower_Left if turn_enabled turn_lower_left end # If no direction fix unless @direction_fix # Face down is facing right or up @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction) end # When a down to left or a left to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 2)) # Update coordinates @x -= 1 @y += 1 # Increase steps increase_steps end return passable?(@x, @y, 1) end
Applichiamo queste modifiche anche agli altri tre rimanenti e otterremo questo:
#-------------------------------------------------------------------------- # * Move Lower Left #-------------------------------------------------------------------------- def move_lower_left(turn_enabled = true) # Turn Lower Left if turn_enabled turn_lower_left end # If no direction fix unless @direction_fix # Face down is facing right or up @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction) end # When a down to left or a left to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 2)) # Update coordinates @x -= 1 @y += 1 # Increase steps increase_steps end return passable?(@x,@y,1) end #-------------------------------------------------------------------------- # * Move Lower Right #-------------------------------------------------------------------------- def move_lower_right(turn_enabled = true) # Turn Lower right if turn_enabled turn_lower_right end # If no direction fix unless @direction_fix # Face right if facing left, and face down if facing up @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction) end # When a down to right or a right to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 6)) or (passable?(@x, @y, 6) and passable?(@x + 1, @y, 2)) # Update coordinates @x += 1 @y += 1 # Increase steps increase_steps end return passable?(@x, @y, 3) end #-------------------------------------------------------------------------- # * Move Upper Left #-------------------------------------------------------------------------- def move_upper_left(turn_enabled = true) # Turn Upper Left if turn_enabled turn_upper_left end # If no direction fix unless @direction_fix # Face left if facing right, and face up if facing down @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction) end # When an up to left or a left to up course is passable if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 8)) # Update coordinates @x -= 1 @y -= 1 # Increase steps increase_steps end return passable?(@x, @y, 7) end #-------------------------------------------------------------------------- # * Move Upper Right #-------------------------------------------------------------------------- def move_upper_right(turn_enabled = true) # Turn Upper Right if turn_enabled turn_upper_right end # If no direction fix unless @direction_fix # Face right if facing left, and face up if facing down @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction) end # When an up to right or a right to up course is passable if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 6)) or (passable?(@x, @y, 6) and passable?(@x + 1, @y, 8)) # Update coordinates @x += 1 @y -= 1 # Increase steps increase_steps end return passable?(@x, @y, 9) endPerfetto Abbiamo Finito! :D
Spero che tutto sia stato di vostro gradimento. E' ovvio che un tutorial del genere non è destinato a dei programmatori esperti. Piuttosto mi rivolgo a coloro che vogliono imparare a fare le cose da se, capire meglio i processi logici del codice e
in un futuro prossimo sviluppare nuove idee e magari di migliorarne di già esistenti. Quindi è un tutorial per niubbi di livello medio come dire per coloro a cui piace far le cose da se :)
Comunque...
Ad ogni modo, una nozione del genere (credetemi) apre un mondo, soprattutto per chi è all'inizio.
Vi auguro una buona serata :)
Modificato da Lomax_Iced, 07 June 2016 - 23:56 PM.