Proviamo un progetto per gestire un po' di JSL
Molto tempo fa ho suggerito di scrivere uno scroller laterale https://community.jmp.com/t5/Uncharted/Wild-Road-Map/bc-p/20996/highlight/true#M5 . Se non giocavi ai videogiochi negli anni '80, https://en.wikipedia.org/wiki/Parallax_scrolling ha alcuni esempi. Gli scroller laterali sono giochi 2D in cui un personaggio si muove da sinistra a destra e lo sfondo può avere più livelli che scorrono a velocità diverse per dare un senso di profondità 3D. Altre varianti potrebbero essere anche i ponticelli con piattaforma con una dimensione di scorrimento verticale.
Ci sono problemi da risolvere:
- sviluppo di giochi (JMP può semplificarne la scrittura?)
- grafica del gioco (che aspetto ha?)
- audio del gioco (hai sentito?)
- input di gioco (come mi muovo?)
- gioco (succede qualcosa?)
1. Sviluppo del gioco
Sto utilizzando un progetto JMP (e, proprio di recente, sto passando a un progetto autonomo JMP 16). Comincio a piacermi il progetto autonomo per un progetto che ha da cinque a dieci file indipendenti. Dispone di schede per i file aperti e punti di ancoraggio per la finestra di registro. Il progetto autonomo memorizza tutto in un unico file (zip, sotto le coperte) e lo decomprime e lo reimballa automaticamente non appena viene aperto e chiuso.
Far funzionare questo gioco è stato più semplice perché il file per la grafica, il file per l'audio e il file per il gioco sono file separati e relativamente piccoli. Ciò semplifica la ricerca di cose, come JSL che gestisce il gioco tra i personaggi del gioco. Il progetto mostra i file in schede, in questo modo:
A JMP project with several files.A JMP project with several files.A JMP project with several files.A JMP project with several files.A JMP project with several files.Un progetto JMP con diversi file.
Ci sono nove file aperti non appena si apre questo progetto; il file che contiene la definizione della classe per i vampiri nel gioco è attualmente visibile. Non sono completamente a mio agio con quando i file vengono salvati nuovamente nel progetto e quando il progetto è già stato salvato, quindi utilizzo le icone evidenziate in alto a sinistra prima di chiudere il progetto. Ho anche agganciato il registro in basso a sinistra. I progetti sembrano essere isolati dal resto di JMP e tra loro, quindi hanno il proprio registro.
Il file MakeAddin non fa parte del gioco, ma fa parte dello sviluppo del gioco. Se quella scheda è aperta e la ^R (eseguo), rigenererà il componente aggiuntivo. Cosa succede se eseguo un'altra scheda? Quel JSL viene eseguito, il che potrebbe non essere l'inizio della logica del gioco. Ma l'ho fatto sempre, per errore, quindi l'ho risolto in questo modo:
- Esiste un file principale, game.jsl, che include tutti gli altri file in un ordine ragionevole.
- La maggior parte dei file sono indipendenti e creano semplicemente una classe o uno spazio dei nomi.
- Il filesidedcroller.jsl necessita del caricamento di tutti gli altri file (è il ciclo principale del gioco).
Tutti i file indipendenti FINE con
try(include("game.jsl"),if(!contains(char(exception_msg),"includes itself through a closed path"),show(exception_msg)));che eseguirà il file game.jsl dopo il file corrente. Il file game.jsl tenterà di includere nuovamente il file corrente e genererà un errore di inclusione ricorsivo, che verrà ignorato, o qualche altro errore, che verrà segnalato. Il file a scorrimento laterale, che deve essere l'ultimo, ha l'istruzione try come file Primo linea. In questo modo il file game.jsl include tutto il resto prima che venga eseguito il resto del file a scorrimento laterale.
Il file game.jsl ha questo aspetto
files = {"AUDIO.jsl", "RGBA.jsl", "ASSETS.jsl", "LAYERS.jsl", "VAMPIRE.jsl", "BEAR.jsl",
// currently SIDESCROLLER contains the game logic. All of the files include this file,
// at the end, except for SIDESCROLLER which include it at the start. SIDESCROLLER is
// dependent on all of the other files being loaded. The other files are not order-dependent.
"SIDESCROLLER.jsl"};
For( iFile = 1, iFile <= N Items( files ), iFile += 1,
Try(
Include( files[iFile] ), // this exception is EXPECTED if you start one of the other files; it is OK!
If( !Contains( Char( exception_msg ), "includes itself through a closed path" ),
Show( files[iFile], exception_msg )
)
)
);Ora, qualunque file venga modificato può essere eseguito. Tranne...se viene modificato più di un file, assicurati di salvare quelli che non vengono eseguiti esplicitamente! L'inclusione ottiene la copia del disco, non la copia della scheda di modifica. Ma se modifichi solo un file, a causa del modo in cui sono impostate le inclusioni sopra, utilizzerà la copia corrente della scheda di modifica senza bisogno di salvare.
Lista dei desideri:
- salva tutto prima di eseguirlo (o includilo usa la copia della scheda di modifica)
- specificare un file di avvio durante l'esecuzione di un progetto (non il file di caricamento del progetto)
- documenta come il salvataggio di una scheda e il salvataggio del progetto sono uguali/diversi
- un modo per eseguire il comando salva tutto del progetto da JSL
2. Grafica del gioco
Questo progetto utilizza sia grafica generata da JSL che grafica bitmap scaricata. Sotto, il cielo azzurro, le montagne, gli alberi e il sentiero di ghiaia sono stati creati da JSL. La parete rocciosa è una bitmap piastrellata e i vampiri, i pipistrelli e l'orso sono sequenze bitmap animate. Crediti alla fine.
The little bear is idling; the vampires are releasing bats or disappearing.The little bear is idling; the vampires are releasing bats or disappearing.The little bear is idling; the vampires are releasing bats or disappearing.The little bear is idling; the vampires are releasing bats or disappearing.The little bear is idling; the vampires are releasing bats or disappearing.L'orsetto è inattivo; i vampiri liberano i pipistrelli o scompaiono.
Il file RGBA.jsl è una parte importante della grafica JSL. JMP può disegnare con trasparenza in un grafico e utilizzare bitmap con trasparenza in un grafico, ma non esiste un modo semplice, ad esempio, per creare un grafico a linee su uno sfondo trasparente e acquisire quella bitmap con lo sfondo trasparente. (Esiste un'opzione, Sfondo trasparente per le immagini PNG del report, che salva tutto tranne il grafico con trasparenza. Puoi modificare un SVG salvato per rimuovere lo sfondo, ma hai bisogno di un altro programma per trasformarlo nuovamente in un PNG su uno sfondo trasparente.)
Lista dei desideri
Il file RGBA crea una classe per creare bitmap con pixel trasparenti in cui non viene disegnato nulla. Potrebbe essere necessario estenderlo per le tue primitive preferite. Controlla gli alberi con foglie non del tutto opache e spazi vuoti tra le foglie. Albero di Bezier utilizzando Path() descrive il disegno degli alberi, ma non con il canale alfa. Le montagne sono diversi strati di un algoritmo di disegno di colline con parametri diversi e il cielo è un rettangolo ombreggiato dal blu al nero non trasparente. Il sentiero di ghiaia può essere piuttosto lento da generare, ma abbastanza veloce una volta percorso; ogni pezzo di ghiaia viene disegnato in una bitmap.
Il file ASSETS.jsl conosce le risorse bitmap utilizzate dal gioco, come aprirle, come normalizzarle e come nominarle. Poiché le animazioni sono disegnate da persone diverse, richiedono la normalizzazione per centrarle allo stesso modo. Tali informazioni sono conservate nella struttura in questo modo
Assets:vampire_images["hit"] = {{"attack/hit_1",.,.,0.80,0.5},che mostra il vampiro che libera i pipistrelli viene spostato (0,80 contro 0,5 negli altri) nella bitmap per gestire l'animazione extra ampia. I vampiri e l'orso hanno i propri strati nello scorrimento laterale e la loro trasparenza lascia trasparire strati più distanti.
Poiché il gioco è in realtà in un grafico, puoi sbirciarlo con lo strumento zoom per comprendere i livelli. Qui è ingrandito e puoi vedere che il cielo non è più grande, da sinistra a destra, della finestra. Non scorre. Ma gli strati sempre più vicini diventano sempre più ampi in modo da poter scorrere di più.
Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normalmente il cielo riempie il display, da sinistra a destra. Zoomando indietro, vedi il vampiro che sta per entrare sul palco.
Mentre l'orsetto cammina verso destra, le posizioni delle bitmap vengono regolate...
Not afraid.Not afraid.Not afraid.Not afraid.Not afraid.Non spaventato.
Appena passata la metà...
The NPCs animate even when off the display.The NPCs animate even when off the display.The NPCs animate even when off the display.The NPCs animate even when off the display.The NPCs animate even when off the display.Gli NPC si animano anche quando sono fuori dallo schermo.
E in fondo...
The little bear has reached the right-hand end of his world.The little bear has reached the right-hand end of his world.The little bear has reached the right-hand end of his world.The little bear has reached the right-hand end of his world.The little bear has reached the right-hand end of his world.L'orsetto ha raggiunto l'estremità destra del suo mondo.
I vampiri camminano più lentamente dell'orso. Si riprenderanno. Ed eccola qui con alcune immagini di sfondo e in primo piano cancellate...
Without all the layers, the characters seem to float.Without all the layers, the characters seem to float.Without all the layers, the characters seem to float.Without all the layers, the characters seem to float.Without all the layers, the characters seem to float.Senza tutti gli strati, i personaggi sembrano fluttuare.
3. Audio del gioco
Il suono è una parte importante di un’esperienza coinvolgente. Ho usato LMMS per creare i suoni di questo gioco e un vero sound designer potrebbe fare molto meglio. Ma è comunque abbastanza buono perché i suoni possono sovrapporsi senza interrompersi a vicenda. Su Windows. Probabilmente su Mac se qualcuno con un Mac trova un programma da riga di comando in grado di riprodurre un suono. Grazie @Jeff_Perkinson per avermi aiutato con il codice audio del Mac. Per Windows, il file AUDIO.jsl utilizza RunProgram per eseguire PowerShell che ha accesso al sistema audio di Windows. Su Mac utilizza un lettore audio da riga di comando, /usr/bin/afplay. Potresti causare l'arresto anomalo di JMP se provi a uscire da JMP prima che finisca la riproduzione dei suoni; lascia semplicemente che la barra di avanzamento finale finisca di riprodurre tutti i suoni iniziati.
4. Ingresso del gioco
Questo gioco utilizza la tastiera come dispositivo di input posizionando un MouseBox attorno alla casella del grafico che contiene il gioco.
New Window( "overlay",
mb = MouseBox(
V List Box(
hlistbox(
leftSpacer=spacerbox(size(5,windowy),color("black")),
gb = Graph Box(
suppressaxes,
framesize( windowx + 1, windowy + 1 ),
X Scale( -1, windowx ),
Y Scale( -1, windowy )
),Il MouseBox inoltra le sequenze di tasti a una piccola funzione che ricorda il tasto e l'ora
lastkey=empty();
lastkeyexpire=tickseconds();
spriteRunner = function({key},{},
lastkey=key;
lastkeyexpire=tickseconds()+1;
);Altrove l'azione del tasto viene ripetuta finché non diventa stantia un secondo dopo
While( go,
if( tickseconds() > lastkeyexpire,
lastkey="";
);
…Le chiavi guidano l'orsetto. Sono implementati nella macchina a stati finiti dell'orso (FSM). Un esempio che cambia l'orso da inattivo a camminante è nella funzione BEAR.jsl cycle():
If( begin,
laststate=m_state;
if( keystroke=="LEFT" & ( pFaceLeft=="faceright" | (pFaceLeft=="faceleft" & pName=="idle") ),
m_state = m_stateWalkLeft;Begin è vero se il ciclo di animazione corrente è all'inizio, il che costituisce un buon punto per cambiare stato. Sembra strano lasciare la parte centrale di un'animazione in salto a un'animazione inattiva. È passato un po' di tempo da quando ho scritto quella logica secondo cui l'orso dovrebbe iniziare a muoversi a sinistra solo se è rivolto a sinistra e inattivo, ma se è rivolto a destra... inizia ad andare a sinistra? Penso che ciò consenta un'inversione istantanea quando si cammina e forse impedisce un cambiamento nello stesso stato che potrebbe anche essere gestito in un altro modo.
5. Gioco
Realizzare un gioco avvincente è la parte difficile per me. Raccontare una storia, creare un obiettivo, aggiungere enigmi. Questo gioco è principalmente un ambiente, in attesa di un narratore. Ma ho aggiunto un po' di gioco.
,/*else if*/ keystroke=="DOWN" & m_NumRocks<6 & (m_state == m_stateWalkLeft | m_state==m_stateIdleLeft),
m_state = m_statePickLeft;
m_NumRocks = min(6,m_NumRocks+1);
// use SPACE to HIT
,/*else if*/ keystroke==" " & (m_state == m_stateWalkRight | m_state==m_stateIdleRight),
if(m_NumRocks,
m_NumRocks = max(0,m_NumRocks-1);
m_state = m_stateHitRight;
m_RockThrownRightFrom = m_x;
);Premendo la freccia giù si sollevano le rocce; l'orsetto ne può contenere fino a sei. Premendo la barra spaziatrice si lancia la roccia nella direzione opposta. L'orso prende nota del sasso lanciato dentro RockThrownRightFrom O RockThrown Sinistra Da che viene controllato dal codice nel ciclo principale che può vedere i vampiri e l'orso.
// check for interaction between bear and vampire
if(!ismissing(bearPlayer:m_RockThrownRightFrom),
if(bearPlayer:m_RockThrownRightFrom<GETPOS></GETPOS>
Colpire un vampiro con una roccia lo fa tornare indietro di 50 pixel. (In realtà, puoi prendere due vampiri con una fava nel modo in cui l'ho scritto.) I vampiri dovrebbero probabilmente essere in un elenco che potrebbe supportarne più di due. In realtà tutti gli NPC (personaggi non giocanti) dovrebbero essere in un elenco e dovrebbero essere sottoclassati da una classe base comune per effettuare le chiamate a cycle() in un ciclo invece di
vampire1:cycle(stagepos);
vampire2:cycle(stagepos);
bearPlayer:cycle(stagepos,lastkey);
ma ciò oscurerebbe semplicemente il funzionamento di questo semplice esempio.
Dovrebbero essere presenti due allegati: un file di progetto e un file del componente aggiuntivo. (Non posso allegare il progetto alla community in questo momento, ma se installi il componente aggiuntivo, c'è una copia del progetto nella directory del componente aggiuntivo.)
Crediti d'arte
Il sito di arte del gioco aperto ha molti più contenuti di varia qualità.