Creazione di carte da gioco in modo dinamico utilizzando il codice per gli inceppamenti del gioco

Cosa starai creando

Questo tutorial è diverso dai miei tutorial precedenti poiché questo è orientato verso gli inceppamenti e la prototipazione dei giochi, in particolare i giochi di carte. Creeremo un mazzo di carte da gioco 2D in Unity senza usare arte puramente con codice.

1. Componenti di un mazzo di carte da gioco

Un mazzo di carte da gioco ha un totale di 52 carte con 13 carte ciascuna di 4 simboli diversi. Per crearne uno usando il codice, dovremo creare questi 4 simboli, la base rettangolare arrotondata per la carta e il disegno sul retro della carta.

Il disegno sul retro della carta può essere un modello astratto e ci sono molti modi per crearne uno. Creeremo un semplice motivo piastrellabile che verrà quindi affiancato per creare il design. Non avremo alcun design speciale per le carte A, K, Q e J.

2. Soluzioni alternative

Prima di iniziare, devo dire che ci sono soluzioni più facili là fuori che possiamo usare per creare un mazzo di carte. Alcuni di quelli sono elencati di seguito.

  1. L'ovvio è usare l'arte pre-renderizzata per tutti i disegni.
  2. Il meno ovvio è usare un font che contiene tutti i simboli necessari. Possiamo inoltre trasformare il suddetto carattere in un font bitmap per ridurre le chiamate di estrazione e aumentare le prestazioni.

La soluzione basata su font è la più veloce e semplice se vuoi fare prototipi veloci.

3. Creazione di trame durante il runtime

Il primo passo è imparare come creare un Texture2D usando il codice che può quindi essere usato per creare un folletto in Unity. Il codice seguente mostra la creazione di una trama vuota 256x256.

Texture2D texture = new Texture2D (256, 256, TextureFormat.ARGB4444, false); texture.filterMode = FilterMode.Trilinear; texture.wrapMode = TextureWrapMode.Clamp; texture.Apply ();

L'idea è di disegnare tutti i disegni sulla trama prima di usare il Applicare metodo. Possiamo disegnare disegni sulla trama pixel per pixel usando il SetPixel metodo, come mostrato di seguito.

texture.SetPixel (x, y, Color.white);

Ad esempio, se volessimo riempire l'intera trama con un colore, potremmo usare un metodo come questo.

privateRoid PaintRectangle (Texture2D texture, Rect rectBounds, Color color) for (int i = (int) rectBounds.x; i

Una volta che abbiamo un Texture2D creato, possiamo usarlo per creare un folletto per essere visualizzato sullo schermo.

Sprite sprite = Sprite.Create (texture, new Rect (0.0f, 0.0f, texture.width, texture.height), new Vector2 (0.5f, 0.5f), 1);

La parte complicata di tutto questo è la creazione dei disegni necessari sulla trama.

4. Creazione della forma del cuore

Quando si tratta della creazione della forma del cuore, ci sono molti approcci diversi che potremmo usare, tra cui alcune equazioni complicate e un semplice mix di forme. Useremo il metodo di miscelazione delle forme come mostrato di seguito, in particolare quello con il triangolo.

Come hai osservato, possiamo usare due cerchi e un quadrato o un triangolo per creare la forma del cuore di base. Ciò significa che mancherebbe quelle curve extra belle ma si adatterebbe perfettamente al nostro scopo.

Dipingere un cerchio

Cerchiamo alcune equazioni per dipingere un cerchio. Per un cerchio con centro all'origine e al raggio r, l'equazione per il punto (X, y) sul cerchio è X2 + y2 = r2. Ora se il centro del cerchio è a (HK) allora l'equazione diventa  (X-h)2 + (Y-k)2 = r2. Quindi, se abbiamo un rettangolo quadrato di delimitazione, possiamo scorrere tutti i punti all'interno di quel rettangolo e determinare quali punti rientrano nel cerchio e quali no. Possiamo facilmente creare il nostro PaintCircle metodo basato su questa comprensione, come mostrato di seguito.

private void PaintCircle (trama Texture2D, raggio float, punto medio Vector2, colore Colore) Rect circleBounds = new Rect (); circleBounds.x = Mathf.Clamp (midPoint.x- (raggio), 0, risoluzione); circleBounds.y = Mathf.Clamp (midPoint.y- (raggio), 0, risoluzione); circleBounds.width = Mathf.Clamp (2 * raggio, 0, risoluzione); circleBounds.height = Mathf.Clamp (2 * raggio, 0, risoluzione); float iValue; for (int i = (int) circleBounds.x; imidPoint.x-iValue && i

Una volta che abbiamo il PaintCircle metodo, possiamo procedere a creare il nostro cuore come mostrato di seguito.

void PaintHearts (trama Texture2D) // 2 cerchi sul raggio float superiore = risoluzione * 0.26f; Vector2 mid = new Vector2 (raggio, risoluzione-raggio); PaintCircle (texture, raggio, metà, Color.red); mid = new Vector2 (risoluzione-raggio, risoluzione-raggio); PaintCircle (texture, raggio, metà, Color.red); // triangolo in basso float width = resolution * 0.58f; int endJ = (int) (risoluzione * 0.65f); int startJ = (int) (risoluzione * 0.1f); float delta = (larghezza / fineJ); float midI = resolution * 0.5f; per (int i = 0; i(Midi-(delta * (j-startJ))) && i<(midI+(delta*(j-startJ)))) texture.SetPixel(i, j, Color.red);    

La variabile risoluzione è la larghezza e l'altezza della trama.

5. Creazione della forma del diamante

Discuteremo due modi per disegnare la forma del diamante.

Dipingere un diamante semplice

Il più semplice è estendere il codice utilizzato per il triangolo e aggiungere un triangolo invertito in alto per creare la forma necessaria, come mostrato di seguito.

 void PaintDiamond (texture Texture2D) float width = resolution * 0.35f; per (int i = 0; imetà J) j = risoluzione-j; if (i> (Midi-(delta * j)) && i<(midI+(delta*j))) isValid=true;  else if(i>(Midi-(delta * j)) && i<(midI+(delta*j))) isValid=true;   return isValid;  PaintDiamond(texture);

Dipingere un diamante Curvy

Il secondo è usare un'altra equazione per creare una versione migliore e sinuosa della nostra forma a diamante. Useremo questo per creare il design di piastrellatura per il lato posteriore della nostra carta. L'equazione per un cerchio deriva dall'equazione originale di un'ellisse, che è (X / a)2 + (Y / b)2 = r2.

Questa equazione è la stessa di quella del cerchio quando le variabili un e B sono entrambi 1. L'equazione dell'ellisse può quindi essere estesa in un'equazione di superellisse per forme simili semplicemente cambiando la potenza, (X / a)n + (Y / b)n = rn. Cosi quando n è 2 abbiamo l'ellisse e per altri valori di n avremo forme diverse, una delle quali è il nostro diamante. Possiamo usare l'approccio utilizzato per arrivare al PaintCircle metodo per arrivare al nostro nuovo PaintDiamond metodo.

private void PaintDiamond (texture Texture2D, Rect rectBounds, Vector2 midPoint, Colore color, float n = 0.8f) float iValue; int a = (int) (rectBounds.width / 2); int b = (int) (rectBounds.height / 2); float nRoot = 1 / n; delta mobile; float partialOne; rectBounds.width = Mathf.Clamp (rectBounds.x + rectBounds.width, 0, risoluzione); rectBounds.height = Mathf.Clamp (rectBounds.y + rectBounds.height, 0, risoluzione); rectBounds.x = Mathf.Clamp (rectBounds.x, 0, risoluzione); rectBounds.y = Mathf.Clamp (rectBounds.y, 0, risoluzione); for (int i = (int) rectBounds.x; imidPoint.x-iValore && i

Dipingere un rettangolo arrotondato

La stessa equazione può essere utilizzata per creare la nostra forma base della carta rettangolare arrotondata variando il valore di n.

private void PaintRoundedRectangle (Texture2D texture) for (int i = 0; imid.x-iValue && i

Dipingere un disegno di piastrellatura

Usando questo PaintDiamond metodo, possiamo disegnare cinque diamanti per creare la trama piastrellatura per il design sul retro della nostra carta.

Il codice per disegnare il disegno della piastrellatura è il seguente.

 private void PaintTilingDesign (Texture2D texture, int tileResolution) Vector2 mid = new Vector2 (tileResolution / 2, tileResolution / 2); float size = 0.6f * tileResolution; PaintDiamond (texture, nuova Rect (dimensione medio / 2, dimensione media / 2, dimensione, dimensione), metà, Colore.rosso); mid = new Vector2 (0,0); PaintDiamond (texture, nuova Rect (dimensione medio / 2, dimensione media / 2, dimensione, dimensione), metà, Colore.rosso); mid = new Vector2 (tileResolution, 0); PaintDiamond (texture, nuova Rect (dimensione medio / 2, dimensione media / 2, dimensione, dimensione), metà, Colore.rosso); mid = new Vector2 (tileResolution, tileResolution); PaintDiamond (texture, nuova Rect (dimensione medio / 2, dimensione media / 2, dimensione, dimensione), metà, Colore.rosso); mid = new Vector2 (0, tileResolution); PaintDiamond (texture, nuova Rect (dimensione medio / 2, dimensione media / 2, dimensione, dimensione), metà, Colore.rosso); 

6. Creazione della forma di picche

La forma a picche è solo la vibrazione verticale della nostra forma a cuore insieme a una forma di base. Questa forma base sarà la stessa anche per le mazze. La figura seguente illustra come possiamo usare due cerchi per creare questa forma base.

Il PaintSpades il metodo sarà come mostrato di seguito.

void PaintSpades (texture Texture2D) // 2 cerchi sul raggio medio del galleggiante = risoluzione * 0,26f; Vector2 mid = new Vector2 (raggio, risoluzione-2,2f * raggio); PaintCircle (texture, raggio, metà, Color.black); mid = new Vector2 (raggio di risoluzione, raggio di risoluzione 2.2f *); PaintCircle (texture, raggio, metà, Color.black); // triangolo in alto float width = resolution * 0.49f; int startJ = (int) (risoluzione * 0,52f); float delta = (width / (resolution-startJ)); float midI = resolution * 0.5f; int alteratoJ; raggio = risoluzione * 0.5f; float midJ = risoluzione * 0.42f; float iValue; per (int i = 0; i(Midi-(delta * alteredJ)) && i<(midI+(delta*alteredJ))) texture.SetPixel(i, j, Color.black);   //bottom stalk for (int k=0;kmid.x + iValue) mid = new Vector2 (risoluzione, metàJ); iValue = (Mathf.Sqrt (radius * radius - ((k-mid.y) * (k-mid.y)))); // + mid.x; se io

7. Creazione della forma dei fiori

A questo punto, sono sicuro che puoi capire quanto è diventato facile creare la forma dei bastoni. Tutto ciò di cui abbiamo bisogno sono due cerchi e la forma base che abbiamo creato per la forma di picche.

Il PaintClubs il metodo sarà come mostrato di seguito.

 void PaintClubs (texture Texture2D) int raggio = (int) (risoluzione * 0,24f); // 3 cerchi Vector2 mid = new Vector2 (risoluzione * 0,5f, risoluzione-raggio); PaintCircle (texture, raggio, metà, Color.black); mid = new Vector2 (risoluzione * 0,25f, risoluzione- (2,5f * raggio)); PaintCircle (texture, raggio, metà, Color.black); mid = new Vector2 (risoluzione * 0,75f, risoluzione- (2,5f * raggio)); PaintCircle (texture, raggio, metà, Color.black); // raggio del gambo di base = (int) (risoluzione * 0,5f); float midY = risoluzione * 0.42f; int stalkHeightJ = (int) (risoluzione * 0.65f); float iValue; per (int i = 0; imid.x + iValue) mid = new Vector2 (risoluzione * 1.035f, midY); iValue = (Mathf.Sqrt (radius * radius - ((j-mid.y) * (j-mid.y)))); // + mid.x; se io

8. Trame di imballaggio

Se esplori i file sorgente di Unity per questo progetto, troverai a TextureManager classe che fa tutto il sollevamento pesante. Una volta che abbiamo creato tutte le trame necessarie, il TextureManager la classe usa il PackTextures metodo per combinarli in una singola trama, riducendo così il numero di chiamate di disegno richieste quando usiamo queste forme.

Rect [] packedAssets = packedTexture.PackTextures (allGraphics, 1);

Usando il packedAssets array, possiamo recuperare i riquadri di delimitazione delle singole trame dalla trama master denominata packedTexture.

public Rect GetTextureRectByName (string textureName) textureName = textureName.ToLower (); int textureIndex; Rect textureRect = new Rect (0,0,0,0); if (textureDict.TryGetValue (textureName, out textureIndex)) textureRect = ConvertUVToTextureCoordinates (packedAssets [textureIndex]);  else Debug.Log ("no such texture" + textureName);  return textureRect;  private Rect ConvertUVToTextureCoordinates (Rect rect) return new Rect (rect.x * packedTexture.width, rect.y * packedTexture.height, rect.width * packedTexture.width, rect.height * packedTexture.height); 

Conclusione

Con tutti i componenti necessari creati, possiamo procedere alla creazione del nostro mazzo di carte in quanto è solo questione di disporre correttamente le forme. Possiamo utilizzare l'interfaccia utente di Unity in composito o possiamo creare le carte come trame individuali. Puoi esplorare il codice di esempio per capire come ho usato il primo metodo per creare i layout delle carte.

Possiamo seguire lo stesso metodo per creare qualsiasi tipo di arte dinamica in fase di runtime in Unity. La creazione di arte in fase di esecuzione è un'operazione che richiede prestazioni, ma deve essere eseguita una volta sola se salviamo e riutilizziamo tali trame in modo efficiente. Imballando le risorse create dinamicamente in una singola trama, otteniamo anche i vantaggi dell'utilizzo di un atlante di texture.

Ora che abbiamo il nostro mazzo di carte da gioco, fammi sapere quali giochi hai intenzione di creare con esso.