Créer un système de détection d'item sur Unity

post-thumb

Pourquoi ce projet ?

La réalisation de ce projet a pour but d’apprendre et expérimenter le C# sous Unity. Je voulais comprendre l’héritage et son potentiel qu’il regorgeait !

L’implémenter dans mes projets était une tâche difficile, je comprenais pourquoi l’utiliser, mais comment bien l’utiliser…

C’est pour cela que j’ai conçu ce projet pour pouvoir comprendre l’architecture et l’utilisation de celui-ci !

1ʳᵉ Réflexion générale

Avant de foncer dans le code comme un petit fou. Je me suis posé devant une feuille de papier et de ma petite tête pour réfléchir comment j’allais procéder.

Ma 1ʳᵉ réflexion était : “Si je dois trier mon inventaire, il faut bien que des items y entre et pour qu’ils y entrent, il faut les récupérer "

À partir de ce moment-là, j’ai commencé à réfléchir comment faire ce système de récupération d’item. Simplement, je clique sur une touche, par exemple “E” pour récupérer !

Non … Trop simple ! Certes le but est de faire un inventaire, mais autant faire un système de récupération pour expérimenter également !

Réflexion du système de détection

Un système de détection malléable serait l’idéal et il ne sera pas forcément dédié que pour ce système d’inventaire.

Et c’est à ce moment-là que je commence à arriver sur le terrain de l’héritage sans même le savoir !

Premier croquis de détection
Deuxième croquis de détection

Mise en œuvre du système de détection

Pour commencer, mon système de détection malléable, c’est-à-dire crée comme on le souhaite une détection d’un élément spécifique.

ParametreDetection

J’ai créé un Script se nomment “ParametreDetection” comportant un ScriptableObject. Le ScriptableObject va nous faciliter pour la création de nouveau paramètre directement dans l’inspecteur d’Unity.

[CreateAssetMenu(fileName = "New parametre", menuName = "Dectection Parameter")]
public class ParametreDetection : ScriptableObject
{
	[Range(1f,100f)]
	public float radius;

	[Range(0f,360f)]
	public float angleView;
	public DetectionElement detectionElement;
	public Color colorCircleDetection;
	public Color colorLineDetection;
}
Capture écran Unity Inventory System
Capture écran Unity Detection Controller

DetectionController

Une fois mes scripts paramétrés, j’ai fait le DetectionController me permettant de tout regrouper et permettre de détecter les éléments souhaités. Sauf qu’il me reste des choses à voir avant de passer à ce mastodonte.

Et là… je me suis dit : “Avant, il me faut un script pour identifier les différents éléments… Un Item ne peut pas être une ennemie ! Si ? Puis est-ce que l’objet voulu peut être pris ou non ?”

Commençons avec le script Identity, il va comporter une valeur d’une Énumération et va la retourner si nous avons besoin de la récupérer.

  • “Tu es un Item ?”
  • “Non. "
  • “Ah ! D’accord, je repasse plus tard.”

Pourquoi une Énumération ? J’ai choisi d’identifier mes objets avec un Enum pour récupérer l’identité de l’objet plus facilement.

Les Enums peuvent être utilisés dans les Switch ! On peut regarder très simplement la valeur de l’Enumération.

Je vous montre mon Énumération :

public enum DetectionElement
{
	enemy = 0,
	player = 1,
	item = 2,
	energy = 3,
	Element00 = 4,
}

Maintenant que mes objets sont Énumérés, il faut leur ajouter s’ils peuvent être pris ou non.

Interactable

Je me suis tout de suite rappeler la torture pour la vérification du type de l’objet récupéré avec un Raycast ou encore un Physics.OverlapSphere Je vous montre ? Attention à vous.


void Update()
{
	// Je crée une sphere et prend les éléments à l'intérieur 
	coll = Physics.OverlapSphere(transform.position, radius);

	for (int j = 0; j < coll.Length; j++)
	{
		Item item = coll[j].GetComponent<Item>();
		Enemy enemy = coll[j].GetComponent<Enemy>();
		Energy energy = coll[j].GetComponent<Energy>();
		
		if (item != null)
		{
			// Action();
		}
		if (enemy != null)
		{
			// Action();
		}
		if (energy != null)
		{
			// Action();
		}
		// Ect...
	}
}

Ceci n’est pas envisageable ! Si je ne possède qu’un type d’objet à récupérer, cela est correct, mais si je possède 35 types différents que je veux récupérer ! Bon courage…

Ayant réfléchi un petit moment sur la question, j’ai trouvé une solution adaptée à mon problème. Si je mets tout simplement un Script se nommant Interactable disant que mon objet peut être récupéré par le joueur. Alors Détection regarde que si les objets détectés possèdent ce script

Exemple :

void Update
{
	// Je crée une sphere et prend les éléments à l'intérieur 
	coll = Physics.OverlapSphere(transform.position,radius);    

	for (int j = 0; j < coll.Length; j++)  
	{  
		// J'assigne à interactable un Interactable qui va rechercher dans l'objet trouvé
		Interactable interactable = coll[j].GetComponent<Interactable>();
	}
}

Ça nous facilite la tâche ! On continue ?

Interaction

Tous mes objets ne sont pas forcément interactifs, mais ils peuvent être détectés. Par exemple des ennemies ! On peut les détecter, mais on ne peut pas interagir. Pour cela, j’ai conçu un script Interaction me permettant de sélectionner ce que le joueur peut ou non interagir.

public class Interaction : MonoBehaviour
{
	// Je choisis quels éléments détecter
	[SerializeField] private List<DetectionElement> _interactionElement;

	// Je retourne les éléments détectés
	public List<DetectionElement> GetInteractionElement()
	{
		return _interactionElement;
	}

}

Maintenant que j’ai tout mis en place, il me reste a développé le DetectionController

DetectionController

Mon DetectionController que va-t-il faire ?

  • Prendre tous mes “ParametreDetection” et appliquer leur paramètre : Taille du rayon de détection, l’angle de la détection, couleurs, etc…
  • Récupéré tous les objets par rapport au paramètre “ParametreDetection”
  • Vérification de mes objets collectés par rapport à la contrainte donnée par l’Interaction et du système en général de vision.
  • Ensuite, une fois que tout est vérifié et que nous avons bien nos objets, on procède à un tri par ordre de distance des objets par rapport au joueur.
  • Pour finir, nous allons mettre l’objet le plus près du joueur, celui que le joueur pourra prendre en priorité avant les autres.

Pour ne pas partir sans donnée de nouvel niveau visuel, je vous montre mon champ de vision et le système pour trier par ordre de distance.

Champ de vision :

void Update()
{
	/* Code précédent for(i =0... */ 

	
	// Ceci me permet de retourner si mon objet et dans l'angle
	if (!InRangeZone(parametreDetections[i].angleView, collDist))
	{

		if (elementDetected.ContainsKey(coll[j].gameObject))
		{

			elementDetected.Remove(coll[j].gameObject);
		}
	
		continue;
	}
	
	/* Suite NearestElement(... */
}


// Calcul de l'angle
public bool InRangeZone(float _angleInDegree, Vector3 _directionObject)
{

	if (Vector3.Angle (transform.forward, _directionObject) < _angleInDegree / 2)
	{
		return true;
	}

	return false;

}

Système pour trier par ordre de distance : myList.Sort() permet de trier dans l’ordre automatiquement selon son type.


public void NearestElement(float _dist)
{
	// Je transforme le Dictionary elementDetected en List
	var myList = elementDetected.ToList();

	myList.Sort((pair1, pair2) => pair1.Value.CompareTo(pair2.Value));

	if (myList[0].Key == null)
		return;

	interaction.SetObjectInteratable(myList[0].Key.GetComponent<Interactable>());

	if (myList[0].Value >= _dist)
		elementDetected.Remove(myList[0].Key);
}

Et nous allons finir sur la partie visuelle dans Editor. “DetectionEditor” va permettre d’afficher visuellement dans l’editor un cercle coloré, des traits coloré par rapport à l’angle de vision.

Résultat

Résumé du système de détection

ParametreDetection : Sert à paramétrer la détection d’objet

DetectionController : Il met en place la détection et la récupération des objets par rapport aux paramètres donné par les “ParametreDetection” Il traite les objets obtenus par une série de vérifications pour envoyer l’objet le plus proche du joueur dans une variable du script “Interaction”.

DetectionEditor : Gère la partie visuelle du système dans l’Editor.

Interaction : Il gère si le joueur veut interagir avec l’item le plus proche de lui stoker dans une variable. Ne retourne rien si la variable est nulle.

Interactable : Script permettant d’identifier si un objet peut être pris.

Tu pourrais aussi aimer