Pagine    Articoli    Prodotti    Forum    Cerca  
Nickname

Password


Non sei registrato?
Registrati a GPI qui!

Puoi anche attivare un vecchio utente GPI e chiedere una nuova password.
I Team

Mappa Team
I nostri utenti

Mappa Utenti
  AHug: A Hex Unity Game - Component oriented GUI
Pubblicato da Dario Oliveri il 2013-11-24 15:04:01

Per chi se lo fosse perso nello scorso articolo ho fatto vedere come si può renderizzare una griglia di esagoni in modo efficiente.

 

Oggi volevo fare un articolo più corposo, non toccheremo direttamente gli esagoni, ma getteremo le basi per la logica del nostro gioco, si tratta sempre di come organizzare il gioco, ma a livello di codice (sento che verrò pesantemente criticato Risatona da chi è esperto in Unity, ovviamente aggiornerò l'articolo se ho detto qualche castroneria).

 

Organizzazione base:

Per oggi serviranno 3 folders aggiuntivi (eh mi piace avere tanti folders a portata di mano e nessun sotto-folder, poi ovviamente potete fare come più siete comodi Sorridente ): Behaviours, Components, Extensions

 

Una breve overview:

Behaviours: sono i moduli base e "generici" del nostro gioco. Quelli che riutilizzeremo di più e fungeranno da fondamenta per i futuri components. Sono quelli con maggiori possibilità di essere riutilizzati in futuro (con o senza modifiche) e quindi i più importanti.

Components: questi sono i moduli specifici del nostro gioco, possono essere ad esempio estensioni dei Behaviours generici e contengono codice che è difficile che possa essere riutilizzato in futuro. Diciamo pure che inizia tutto da questo folder e ogni tanto sposto qualcosa verso Behaviours.

Extensions: codice aggiuntivo, tipicamente usato per colmare lacune di Unity/MonoDevelop o per sopperire in maniera comoda alle esigenze particolari del nostro gioco. ( mi viene immediato pensare di estendere le classi vettore 2D/3D di unity per supportare le "coordinate esagonali e la conversione fra i vari tipi di coordinate" )

 

Components & Behaviours:

Non voglio perdermi in troppa teoria sui MonoBehaviours, però cerchiamo di fare un minimo di mente locale.

 

 

Cliccando su un qualunque gameObject possiamo vederne i componenti, questo particolare gameObject ha 4 componenti. 

Tipicamente si crea una classe Singleton da cui la maggior parte della logica del gioco funziona, tuttavia se si riesce a muovere un po di codice sui vari components si potrebbbero semplificare alcune cose

 

Pro: Usando un approccio components oriented ci si ritrova ad assemblare la logica del gioco, quasi come dei lego. Ovviamente ci sarà sempre da aggiungere codice a mano, ma almeno la struttura base c'è già.

 

Contro: se si esagera esce fuori un pastrocchio totale da cui è difficile districarsi.

 

Un ottimo esempio dell'utilizzo dei componenti è  NGUI. Vi permette di creare una GUI basata sui components, assemblando i menù, imparentando gameObjects e aggiungendogli componenti. NGUI è potentissimo, ma ha lo svantaggio di essere enorme e ci potrebbe volere un po a padroneggiarlo, senza contare che combinazioni non previste di componenti potrebbero dare qualche rompicapo.

 

Iniziamo a mettere insieme i tasselli:

 

1)Grazie a PhysX abbiamo a disposizione i seguenti eventi in maniera abbastanza ottimizzata:

 

OnCollisionEnter 	
OnCollisionExit 	
OnCollisionStay
OnControllerColliderHit
OnMouseDown 	
OnMouseDrag 	
OnMouseEnter 	
OnMouseExit 	
OnMouseOver 	
OnMouseUp 	
OnMouseUpAsButton
OnParticleCollision

 

2)Se vogliamo che un oggetto faccia qualcosa quando viene cliccato ci basta implementare "OnMouseUpAsButton" (e deve avere un collider component attaccato inoltre!)

 

void OnMouseUpAsButton(){
	Debug.Log("object pressed!");
}

3)Tuttavia questo può non bastarci, in fondo ci piacciono gli effetti di transizione dei menù etc. Per questo motivo mi appoggerò ad un ottima libreria di Tweening esterna. HOTween:)

 

4)Ora (ispirandoci in parte a NGUI e in parte al sistema di GUI che ho abbozzato per il mio engine in C++) vedremo come realizzare un semplice oggetto cliccabile che abbia anche un effetto di transizione.

 

HOTween:

(immagine cliccabile)

 

Per aggiungere HOTween al vostro progetto vi basta scaricare lo ZIP e scompattarlo dove volete (all'interno della cartella Assets... io ad esempio l'ho messo dentro Assets/HOTween). HOTween è estremamente semplice da usare ed è molto performante.

 

Cosa fa un TweenEngine? molto semplice, fa "variare" dei parametri seguendo delle curve/percorsi. A completare il set di utilità di HOTween c'è la possibilità di eseguire Callbacks alla fine delle animazioni.

 

A cosa può servire? un pò a tutto, alcuni esempi:

 

- Far comparire del testo che fluttua nel vostro menù introduttivo del gioco

- Far muovere un fuoco d'artificio lungo una traiettoria a spirale e poi farlo scoppiare alla fine attivando un particle emitter

- Far muovere un agente governato da IA lungo dei WayPoints, al termine di ogni waypoint, una callback permetterà all'agente di prendere una decisione su cosa fare successivamente.

 

GET STARTED WITH HOTween

 

Clickable Widget

 

Mettiamo insieme il tutto, e creiamo un pulsante cliccabile (onMouseUpAsButton), animato (HOTween) basato su poche ma semplici componenti.

 

Ingredienti (download di tutto in fondo all'articolo):

 

- Assets/Behaviours/Clickable.cs:

Questo componente gestisce la logica del pulsante.

 

- Assets/Behaviours/Widget.cs:

Questo componente è una classe da cui deriviamo per implementare la grafica, una volta che la grafica vi stufa potete sostituirla con altra grafica più bella.

 

- Assets/Extensions/MakeSureIsAloneExtension.cs:

Verifica che del componente voluto ci sia una sola istanza appiccicata al nostro gameObject.

 

- Assets/Behaviours/Command.cs:

 

using UnityEngine;
using System.Collections;

// Derive from Command and implement Execute.
public class Command : MonoBehaviour {
	public virtual void Execute(){
		Debug.Log ("Need to override this.");
	}
}

 

Interfaccia da implementare per creare comandi/azioni che verranno eseguite chiamando "Execute()".

 

Creiamo ora lo script:

- Assets/Components/MyNiceButton.cs

 

using UnityEngine;
using System.Collections;

public class MyNiceButton : Widget {

	// Per animare il pulsante abbiamo bisogno di 2 textures diverse..
	public Texture2D frontTexture;
	public Texture2D backTexture;
	public Shader	 shader; //..e uno shader (trovat il codice più giu')
	
	void Start () {
		// Stiamo agendo sui Tween che si trovano in Widget.cs
		middleTween.Prop("pression", 0.4f);
		downTween.Prop("pression", 0.1f);
		upTween.Prop("pression",1.0f);
		tweenDownTime =0.15f;
		tweenMiddleTime = 0.10f;
		tweenUpTime = 0.2f;

		// Andiamo ad usare lo shader e le textures
		renderer.material = new Material (shader);
		renderer.material.SetTexture("_MainTex",frontTexture);
		renderer.material.SetTexture("_BgTex",backTexture);
	}

	void Update () {
		//Aggiorniamo la transizione tra le textures usando il parametro "pression"
		renderer.material.SetFloat("_Transition",1-pression);
	}
}

 

 

Per completezza vi metto 2 comandi eseguibili:

- Assets/Components/Command1.cs

using UnityEngine;
using System.Collections;

public class Command1 : Command {

	public override void Execute(){
		Debug.Log ("Button Pressed");
	}
}

 

- Assets/Components/Command2.cs

using UnityEngine;
using System.Collections;

public class Command2 : Command {
	
	public override void Execute(){
		Debug.Log ("Button Released");
	}
}

 

Mettere insieme i pezzi:

 

Ora creiamo un gameObject vuoto, lo useremo per il pulsante

 

Aggiungiamo come componente lo script "MyNiceButton.cs", in automatico vi ritroverete alcuni altri components necessari.

 

Ovviamente per ora ci basta un pulsante quadrato, pertanto andiamo a caricare una mesh

quadrata! :)

 

Quad.Obj

 

Aggiungiamo al nostro gameObject altri 2 componenti essenziali "Mesh Filter" e "Mesh Renderer"

 

Andiamo ad utilizzare il nostro quadrato come collider e come renderer:

 

E non dimentichiamo lo Shader e le Textures! :)

 

NiceButton.shader:

Shader "Custom/NiceButton" {
	Properties {
		_MainTex("FrontTexture (RGB)", 2D) = "white" {}
		_BgTex  ("BackgroundTexture (RGB)", 2D) = "white" {}
		_Transition("Animation Transition", Float) = 0
	}
	SubShader {
		Lighting Off
		ZWrite Off
		Blend SrcAlpha OneMinusSrcAlpha
	
		Tags { "Queue"="Transparent" "RenderType"="Transparent" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert

		sampler2D _MainTex;
		sampler2D _BgTex;
		float _Transition;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			half4 c2 = tex2D (_BgTex, IN.uv_MainTex);
			o.Albedo = lerp(c.rgb,c2.rgb,_Transition);
			o.Alpha = c.a;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}

 

 

Due immagini qualunque (ricordatevi di importarle come: Texture type Advanced -> RGBA32):

 

 

Come sempre il buon vecchio Drag n'Drop in Unity risolve molti problemi:

 

 

Ora che abbiamo fatto tutta questa fatica per costruirci il nostro pulsante, possiamo andare a creare un Prefab in modo da avere il pulsante già pronto all'utilizzo.

 

Ora ogni volta che vi serve un pulsante non vi basta che istanziarlo e implementare un Command per decidere cosa fare quando il pulsante viene schiacciato.

 

 

Perchè tutto queste complicazioni?

 

- Se non vi piace la grafica vi basta cambiare MyNiceButton (sia in un singolo pulsante che nel prefab per aggiornarli tutti, ad esempio potete aggiungere un effetto di "highlight" quando il mouse passa sopra al pulsante)

- La logica del pulsante è completamente separata dalla grafica.

- Basta fare un package con il prefab e lo avete pronto in tutti i progetti

- Ovviamente potete animare qualunque cosa, un forziere una porta etc.

 

Per caricare un livello cliccando un pulsante:

using UnityEngine;
using System.Collections;

public class LoadCreditsScene : Command {

	public override void Execute(){
		Application.LoadLevel ("credits");
	}
}

 

Ultime note:

Il pulsante che ho creato è brutto :), non ha "testo", non è ridimensionabile (a meno di cambiare la scale della sua Transform), ovviamente la grafica la dovete mettere voi derivando da Widget :P. Il codice che ho messo era per fare un esempio semplice e veloce.

 

Potete anche animarlo, vi basta aggiungere un Tween per farlo fluttuare.

 

 

Opzioni del pulsante:

Switch (pulsante che si alterna tra On e Off ad ogni click)

come impostare le opzioni:

 

schemino di funzionamento:

 

Ad ogni click si alterna tra "Pressed" e "Released" chiamando di conseguenza gli eventi/commands che avete impostato.

Pulsante classico (torna su da solo):

come impostare le opzioni:

 

schemino di funzionamento:

Ad ogni click ritorna sempre nello stato Released (passando temporaneamente da Pressed e attivandone comunque il rispettivo Command/Event).

 

 

 

L'occorrente per questo articolo:

 

 

Campagne crowfunding

Just One Line
Siamo presenti su

     
Copyright ©2016 - Manifesto - Privacy - Termini di Servizio - Community - Collaboratori - Contattaci