jumpjack / Space1999Adventure

Apache License 2.0
1 stars 0 forks source link

[Not a bug] Wright e i giochi isometrici #1

Closed kesiev closed 1 year ago

kesiev commented 1 year ago

_(Scusami se ti rispondo tramite issue al tuo tweet https://twitter.com/_jumpjack_/status/1597868924347224065 ma non ho trovato contatti che mi permettessero di scrivere più di qualche riga)_

Hey ciao!

Vedo che hai dissezionato Isocat (https://www.kesiev.com/wright/issue/isocat) e abbia pensato di usare Wright.

Wright è un engine pensato principalmente per i giochi 2D più classici (sidescroller, SHMUP, puzzle, etc.) ma ogni tanto ho "sperimentato" quanto si possa tirare un engine semplice per fare qualcosa che non dovrebbe con i giusti hack, come per i giochi isometrici, FPS, giochi VR etc. e Isocat è uno di quegli esperimenti. Ma è un modo davvero "arcaico" di fare giochi di questo tipo per cui, se hai intenzione di provare Wright per un gioco isometrico complesso, preparati ad hack terribili e sinceramente ti consiglio di usare engine un pò più moderni o di fare qualcosa da te.

Provo comunque a risponderti: Isocat usa sprite 32x32 ma poi crea una piccola hitbox a croce per "fingere" che l'oggetto sia tridimensionale. C'é poi un sistema di collisioni "customizzato" sulle dimensioni di questa hitbox che verifica se il personaggio collide con le cose https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L388. Tutto il sistema è "tunato" su questa dimensione di tile, per cui cambiandone la grandezza e la relativa hitbox probabilmente dovrai anche cambiare diversi parametri per il sistema di collisioni.

Ad ogni modo il progetto che stai portando avanti mi sembra molto figo. Tieni duro!

jumpjack commented 1 year ago

Ciao, anche il gioco che sto cercando di portare a JS è "arcaico", quindi non è questo il problema: c'è semplicemente un omino che si sposta da una stanza all'altra, ogni stanza compare di volta in volta a seconda di quale porta l'omino prende; ogni tanto l'omino raccoglie un oggetto, e questo è tutto. Però non ho capito dove devo andare a smanettare per modificare queste dimensioni 32x32! Ho provato a cambiare dei 32 a caso qua e là ma senza successo... Sennò, hai altri engine da suggerire? Ho provato con MelonJS, ma non riesco a capire come funzionano le occlusions, quindi il mio omino passa sopra qualunque tile! Ho visto che c'è Phaser3, ma non riesco a trovare documentazione su come usare la nuova feature delle mappe isometriche, invece di un vecchio plugin isometrico per versioni precedenti. Ho trovato anche il tuo Akihabara, che però è ancora più vecchio di Wright; in teoria, a giudicare dalla homepage, direi che supporta l'isometrico:

image

Ma non riesco a trovare un esempio o un tutorial, hai qualche link da darmi?

Di engine isometrici ne ho trovati diversi, ma non riesco a trovarne uno utilizzabile:

https://github.com/jumpjack/isometric-game-js-test/blob/master/README.md

kesiev commented 1 year ago

Wright usa un sistema di stencil, che sono dei modelli che possono essere composti insieme tra di loro. Prendiamo il simbolo della mappa "#":

https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L510

"#":{ "set":{ "_":[ "stencil", "modelTile" ] }, "objectType":"obstacle" },

Questo setta lo stencil chiamato modelTile:

https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L108

"modelTile":{
      "image":"tiles", "width":32, "height":32,
      "hitbox":[ { "width":8, "height":12, "x":12, "y":2 }, { "width":18, "height":8, "x":7, "y":4 } ],
      "zSubindex":0
 },

Che suggerisce di prendere dall'immagine tiles (https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L20) un'area 32x32 con 2 hitbox e l'attributo zSubindex valorizzato a 0. L'attributo frame non è definito, quindi usa il valore di default 0 ma, volendo, puoi definire il frame per prendere un'altra immagine, come accade per gli altri elementi della mappa.

https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L511

"%":{ "set":{ "_":[ "stencil", "modelTile" ] }, "frame":8, "objectType":"obstacle" },

Il sito di Akihabara è piuttosto vecchio e non l'ho gestito io. Ai tempi un collaboratore voleva dargli un aspetto meno spartano di quello che gli diedi io in origine ;) Probabilmente ha trovato figo metterci un artwork isometrico. Ad ogni modo sarebbe possibile, considerando che è una libreria a più basso livello... ma servirebbe comunque scriversi da se le routine per gestire la profondità.

Su altri engine per fare giochi isometrici non ti sono molto d'aiuto e ti direi i soliti engine commerciali, molti dei quali li hai già elencato tu. Ad ogni modo, se ho qualche idea, non mancherò di farti sapere!

jumpjack commented 1 year ago

Sì, questo è quello che sono riuscito a capire fino ad ora... ma non basta: anche se uso le mie tile che sono 24x40, vengono comunque spaziate di 32x32 pixel, quindi il risultato è questo: image

(considera solo le pareti in alto a sinistra e in alto a destra).

Ho provato a rimediare ridimensionando a 32x32 le mie tile, ma ovviamente il risultato è indecente:

image

Invece i parametri di hitbox non li ho proprio capiti; visivamente, questa definizione come a cosa corrisponde?

    "modelMovingObject":{
      "image":"tiles", "width":32, "height":32,
      "hitbox":{ "width":16, "height":6, "x":8, "y":5 },
kesiev commented 1 year ago

Il codice che arrangia i tile parte da https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L159 e arriva a https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L195:

{ "set":{ "layer":0 } },
  {
    "times":5,
    "execute":[
      { "set":{ "counter":0 } },
      {
        "times":15,
        "execute":[
          { "set":{ "counter2":0 } },
          {
            "times":9,
            "execute":[
              { "set":{ "tile":{ "_":[ "this", "room", { "_":[ "this", "layer" ] }, { "_":[ "this", "counter" ] }, { "_":[ "this", "counter2" ] } ] } } },
              {
                "when":{ "_":[ "this", "tile", "and", { "_":[ "this", "tile", "isNotEqualTo", "." ] } ] },
                "execute":{
                  "when":{ "_":[ "stencil", { "_":[ "this", "tile" ] } ] },
                  "execute":{
                    "object":{
                      "set":{ "_":[ "stencil", { "_":[ "that", "tile" ] } ] },
                      "x":{ "_":[ "that", "counter2", "*", 32, "+", { "_":[ "that", "counter", "%", 2, "*", 16 ] }, "-", 16 ] }, "y":{ "_":[ "that", "counter", "*", 8, "+", 56 ] },
                      "execute":{ "_":[ "stencil", "codeSetZIndex" ] },
                      "zPos":{ "_":[ "that", "layer", "*", 16 ] }
                    }
                  }
                }
              },
              { "sum":1, "to":{ "_":[ "this", "counter2" ] } }
            ]
          },
          { "sum":1, "to":{ "_":[ "this", "counter" ] } }
        ]
      },
      { "sum":1, "to":{ "_":[ "this", "layer" ] } }
    ]
  }
],

Questo ciclo scorre gli strati sovrapposti (layer), la coordinata x (counter) e la coordinata y (counter2). La riga https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L179 effettivamente calcola le coordinate del tile:

"x":{ "_":[ "that", "counter2", "*", 32, "+", { "_":[ "that", "counter", "%", 2, "*", 16 ] }, "-", 16 ] }, "y":{ "_":[ "that", "counter", "*", 8, "+", 56 ] },

Cambiando la dimensione dei tile probabilmente dovrai cambiare anche questi valori. Circa le hitbox https://github.com/kesiev/Wright/blob/master/tapes/isocat/tape.json#L110 :

"modelTile":{
  "image":"tiles", "width":32, "height":32,
  "hitbox":[ { "width":8, "height":12, "x":12, "y":2 }, { "width":18, "height":8, "x":7, "y":4 } ],
  "zSubindex":0
},

Rettangolo rosso: { "width":8, "height":12, "x":12, "y":2 } Rettangolo blu: { "width":18, "height":8, "x":7, "y":4 }

image

La composizione dei due rettangoli costituisce la hitbox. Come vedi compone una sorta di croce nella parte "superiore" del blocco.

jumpjack commented 1 year ago

Scusa ma non riesco a "tradurre" questa sintassi in quella standard javascript; mi viene più o meno una cosa del genere, ma non sono per niente sicuro, dove trovo spiegata la tua sintassi?

for (layer = 0; layer < 5; layer++) {
    for (counter= 0; counter <15 ; counter++) {
        for (counter2= 0; counter2 < 9; counter2++) {
             tile = room[layer,counter, counter2]            
             if ((tile) && (tile !=  "." )) {
                                if (stencil == tile) {
                    object = stencil[tile];
                    x = counter2 * 32 + counter%2 * 16 - 16;
                    y = counter * 8 + 56;
                    zPos = layer * 16;
                }
             }
        }
    }
}
kesiev commented 1 year ago

Wright non è pensato per risolvere calcoli difficili ma per farlo il più in fretta e semplicemente, per cui lo fa da sinistra a destra, un po' come le calcolatrici RPN.

Ad ogni modo ti ho preparato questo, risistemando un po' il tuo codice: https://gist.github.com/kesiev/e7cbdcaf7fddb3622a2535e2be3ec635

Disegna questo:

image

...che è il primo livello di Isocat:

image

jumpjack commented 1 year ago

Grazie, adesso vedo di capirci qualcosa. Ma usi un convertitore per scrivere in "Linguaggio JOSN", o fai a mano?