Voilà,
J'ai tout repris, la déco, les commandes et le gameplay.
Pour les commandes j'ai essayé de regrouper les commandes clavier chère à Boubouk
et celles que je préfère.
Soit les touches du clavier pour déplacer le player et le déplacement de la souris pour l'orienter, ça c'est pour Boubouk,
et la touche gauche de la souris pour avancer et la droite pour reculer, c'est ce que je préfère.
La touche Ctrl gauche ou le bouton central de la souris permettent de libérer le curseur pour avoir accès aux UI ou autre.
Il faut réutiliser le ctrl ou la souris pour revenir au mode normal du jeu.
Voici le lien pour essayer :
Enigmatics
help!!! c'est loin d'être terminé, ce n'est juste qu'un aperçu pour la déco et les commandes.
Mais si vous l'avez essayé vous aurez peut-être constaté qu'il y a un problème pour le drag and drop des pièces du puzzle.
Ce problème me bloque depuis plusieurs jours. On arrive à sélectionner et déplacer sans problèmes certaines pièces et d'autres pas. Et ce n'est pas toujours les mêmes qui ont le problème.
Ci joint les scripts qui me semblent concernés. Je les ai commenté pour essayer d'être le plus clair possible.
A savoir que le script "Btn" je l'ai conçu pour qu'il puisse convenir à toutes les éventualités des objets sur lesquels le joueur peut avoir une action. C'est pour ça qu'il est un peu long et complexe. Mais je n'arrive pas à comprendre pourquoi ça fonctionne très bien dans certains cas et pas dans d'autres.
Si quelqu'un pouvait avoir la patience et la gentillesse d'y jeter un oeil, peut-être trouvera-t-il un idée de solution.
Code : Tout sélectionner
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
[ExecuteInEditMode]
public class Btn : MonoBehaviour
{
[Foldout("Apparence", true)]
[Tooltip("La couleur par défaut de l'objet")]
[SerializeField] Color col_Defaut = Colors.Yellow;
[Tooltip("La couleur quand le curseur entre dans l'objet")]
[SerializeField] Color col_Enter = Colors.Orange;
[Tooltip("La couleur quand il y a clic l'objet")]
[SerializeField] Color col_Press = Colors.Red;
[Tooltip("La couleur quand l'objet est désactivé")]
[SerializeField] Color col_Inactif = Colors.Gray;
[Tooltip("La couleur imposée à l'objet")]
[SerializeField] Color color = Color.clear;
[Tooltip("sorting order")]
[SerializeField] int order = 1;
[Foldout("Mesh", true)]
[Tooltip("l'ID du matériel du mesh à colorer")]
public int id_mat = 0;
[Foldout("Sprite", true)]
[Tooltip("le sprite à appliquer au SpriteRenderer")]
[SerializeField] Sprite sprite;
[Foldout("Symbole", true)]
[Tooltip("le sprite à appliquer au Symbole")]
[SerializeField] Sprite symbole;
[Tooltip("la dimension du sprite du Symbole")]
[SerializeField] Color col_Symb = Color.clear;
[Tooltip("la dimension du sprite du Symbole")]
[SerializeField] Vector2 size_symb = new Vector2(0.025f, 0.025f);
[Tooltip("la rotation du sprite du Symbole")]
[SerializeField] float rot_symb;
[Foldout("Texte", true)]
[Tooltip("le texte du Tmp_Text")]
[SerializeField] string text;
[Tooltip("la couleur du texte du Tmp_Text")]
[SerializeField] Color col_text = Color.yellow;
[Foldout("Les Events", true)]
[Tooltip("L'objet à appeler")]
public GameObject target;
[Tooltip("la distance maximum de la caméra ver l'objet pour déclencher les actions")]
[SerializeField] float distance = 5f;
[Tooltip("Le mode à utiliser quand le curseur entre dans le bouton")]
public Mode mode_enter = Mode.Vise;
[Tooltip("Le mode à utiliser quand le curseur sort du bouton")]
public Mode mode_exit = Mode.Normal;
[Tooltip("Si le bouton est actif ou non")]
[SerializeField] bool actif = true;
[Tooltip("Pour appeler la fonction 'Btn_Active' dans 'Objet'")]
[SerializeField] bool active = false;
[Tooltip("Pour appeler la fonction 'Btn_Desactive' dans 'Objet'")]
public bool desactive = false;
[Tooltip("S'il faut appeler la fonction Btn_Enter")]
public bool enter = false;
[Tooltip("S'il faut appeler la fonction Btn_Left_Down")]
public bool leftDown = false;
[Tooltip("S'il faut appeler la fonction Btn_Center_Down")]
public bool centerDown = false;
[Tooltip("S'il faut appeler la fonction Btn_Right_Down")]
public bool rightDown = false;
[Tooltip("S'il faut appeler la fonction Btn_Left_Up")]
public bool leftUp = false;
[Tooltip("S'il faut appeler la fonction Btn_Center_Up")]
public bool centerUp = false;
[Tooltip("S'il faut appeler la fonction Btn_Right_Up")]
public bool rightUp = false;
[Tooltip("S'il faut appeler la fonction Btn_Exit")]
public bool exit = false;
[Tooltip("S'il faut appeler la fonction Btn_Dragging")]
public bool drag = false;
[Tooltip("S'il faut appeler la fonction Btn_Drag_Start")]
public bool dragStart = false;
[Tooltip("S'il faut appeler la fonction Btn_Dragging")]
public bool dragDragging = false;
[Tooltip("S'il faut appeler la fonction Btn_Drag_End")]
public bool dragEnd = false;
[Tooltip("Les boutons à désactiver en cas de drag (Se met à jour automatiquement si vide)")]
[SerializeField] List<Btn> voisins;
internal bool pose;
bool _actif;
public bool Actif
{
get { return _actif; }
set
{
_actif = value;
actif = value;
GetComponent<Collider>().enabled = value;
Colore_Btn(col_Defaut);
if (value)
{
if (active) target.SendMessage("Btn_Active", this);
}
else
{
if (desactive) target.SendMessage("Btn_Desactive", this);
}
}
}
Color _color;
//Pour imposer une couleur. Tant que Color est différent de Clear c'est cette couleur qui sera utilisée
public Color Color
{
get { return _color; }
set
{
_color = value;
if (value == Color.clear)
Colore_Btn(col_Defaut);
else
Colore_Btn(value);
}
}
Sprite _sprite;
//Pour appliquer un sprite si le bouton est un sprite renderer
public Sprite Sprite
{
get { return _sprite; }
set
{
_sprite = value;
if (transform.GetComponent<SpriteRenderer>())
{
transform.GetComponent<SpriteRenderer>().sprite = value;
transform.GetComponent<SpriteRenderer>().color = col_Defaut;
}
}
}
//Pour appliquer un sprite au symbole affiché au dessus du bouton s'il existe
public void Symbole(Sprite sprite, Color? color = null, Vector2? size = null, float rot = 0)
{
if (transform.Find("Symbole"))
{
if (color == null) color = Color.white;
if (size == null) size = new Vector2(0.025f, 0.025f);
SpriteRenderer render = transform.Find("Symbole").GetComponent<SpriteRenderer>();
render.sprite = sprite;
render.color = (Color)color;
render.size = (Vector2)size;
render.transform.localEulerAngles = new Vector3(0, 0, rot);
}
}
//Pour appliquer un texte sur le bouton s'il y a lieu
public string txt
{
get { return _txt; }
set
{
_txt = value;
foreach (Transform item in transform)
{
if (item.name == "Tmp_Text")
{
item.GetComponent<TextMeshPro>().color = _colTxt;
item.GetComponent<TextMeshPro>().text = value;
}
}
}
}
Color _colTxt;
//La couleur du texte
public Color Col_Txt
{
get { return _colTxt; }
set
{
_colTxt = value;
foreach (Transform item in transform)
{
if (item.name == "Tmp_Text")
{
item.GetComponent<TextMeshPro>().color = value;
}
}
}
}
string _txt;
//Pour appliquer un texte sur le bouton s'il y a lieu et sa couleur
public void Texte(string texte, Color? color = null)
{
if (color == null) color = _colTxt;
_txt = texte;
_colTxt = (Color)color;
foreach (Transform item in transform)
{
if (item.name == "Tmp_Text")
{
item.GetComponent<TextMeshPro>().color = _colTxt;
item.GetComponent<TextMeshPro>().text = texte;
}
}
}
int _order;
//Pour régler le sorting order des sprites du bouton
public int Order
{
get { return _order; }
set
{
_order = value;
if (transform.Find("Fond"))
transform.Find("Fond").GetComponent<SpriteRenderer>().sortingOrder = value;
if (transform.GetComponent<SpriteRenderer>())
transform.GetComponent<SpriteRenderer>().sortingOrder = value + 1;
if (transform.Find("Symbole"))
transform.Find("Symbole").GetComponent<SpriteRenderer>().sortingOrder = value + 2;
if (transform.Find("Tmp_Text"))
transform.Find("Tmp_Text").GetComponent<TextMeshPro>().sortingOrder = value + 2;
}
}
//Initialisation du bouton en mode édition
private void Initialise_Btn() //Corrigé en public au lieu de private
{
Actif = actif;
Order = order;
if (color != Color.clear) Color = color;
Sprite = sprite;
Colore_Btn(col_Defaut);
Symbole(symbole, col_Symb, size_symb, rot_symb);
Texte(text, col_text);
if (drag)
{
if (voisins == null || voisins.Count == 0)
{
voisins = new List<Btn>();
foreach (Transform item in transform.parent)
{
if (item.GetComponent<Btn>())
{
if (item != transform)
voisins.Add(item.GetComponent<Btn>());
}
}
}
}
else
voisins = null;
}
//Pour appliquer la couleur courante
private void Colore_Btn(Color col)
{
if (transform.GetComponent<SpriteRenderer>())
{
if (_color != Color.clear)
transform.GetComponent<SpriteRenderer>().color = _color;
else
transform.GetComponent<SpriteRenderer>().color = !_actif? col_Inactif: col;
}
if (transform.GetComponent<MeshRenderer>())
{
if (_color != Color.clear)
transform.Color(_color, id_mat);
else
transform.Color(!_actif ? col_Inactif : col, id_mat);
}
}
//A la création du bouton
private void Awake()
{
Initialise_Btn();
}
bool dans; //true quand le curseur est dans le bouton
bool ok; //true quand le player est assez proche du bouton
bool dragging; //true quand le bouton est en cours de drag
Vector3 start; //la position d'origine du bouton au départ du drag
Vector3 offset; //la différence de position du curseur et du centre du bouton
//Quand le curseur entre dans le bouton
void OnMouseEnter()
{
//s'il n'est pas actif ou s'il est en pose ou si c'est le mode UI : on sort
if (!_actif || pose || Manager.Instance.mode == Mode.UI) return;
//sinon on signale que le curseur est dans le bouton
dans = true;
}
//Quand le curseur sort du bouton
void OnMouseExit()
{
//s'il n'est pas actif ou s'il est en pose ou si c'est le mode UI : on sort
if (!_actif || pose || Manager.Instance.mode == Mode.UI) return;
//si on est en cours d'un drag : on sort
if (dragging) return;
//on signale que le curseur n'est plus dans le bouton
dans = false;
//qu'il n'est plus à la bonne distance
ok = false;
//on remet le couleur par défaut
Colore_Btn(col_Defaut);
//on reinitialise le mode
Manager.Instance.mode = mode_exit ;
//et on appelle la fonction "Btn_Exit" dans l'objet target si exit est à true
if (exit) target.SendMessage("Btn_Exit", this);
}
private void Update()
{
//si on est en mode editeur
if (!Application.isPlaying)
{
//on initialise le bouton pour le mettre à jour lors des changements
Initialise_Btn();
}
else
{
//s'il n'est pas actif ou s'il est en pose ou si c'est le mode UI : on sort
if (!_actif || pose || Manager.Instance.mode == Mode.UI) return;
//Si on est en cours de drag
if (dragging)
{
//Tant que le bouton gauche de la souris est pressé
if (Input.GetMouseButton(0))
{//Envoie un rayon vers le curseur
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
//si le rayon rencontre quelque chose
if (Physics.Raycast(ray, out hit))
{
//on récupère la local position z du bouton
float z = transform.localPosition.z;
//on repositionne le bouton
transform.position = hit.point - offset;
//on rectifie la position z
Vector3 p = transform.localPosition;
p.z = z;
transform.localPosition = p;
//on appelle le fonction "Btn_Dragging" du target si dragDragging est à true
if (dragDragging) target.SendMessage("Btn_Dragging", hit.point);
}
}
//si le bouton gauche de la souris est relaché
else
{
//on active le mode_enter
Manager.Instance.mode = mode_enter;
//on corrige le sorting order des sprites
Order = order;
//on arrete le drag
dragging = false;
//on sort du curseur
dans = false;
//on desactive les voisins en cas de drag
foreach (Btn item in voisins)
item.pose = false;
//on appelle la fonction "Btn_Drag_End" du target si dragEnd est activé
if (dragEnd)
target.SendMessage("Btn_Drag_End", this);
//si dragEnd n'est pas activé
else
{
//on replace le le bouton au départ
transform.position = start;
//et on sort du bouton
OnMouseExit();
}
}
}
//si on n'est pas en cours de drag
else
{
//si le curseur est dans le bouton
if (dans)
{
//si le bouton est actif et qu'il n'est pas en pose
if (_actif && !pose)
{
//on calcule la distance horizontale avec la caméra
float dist = Camera.main.transform.Distance(transform, 0);
//si on n'était pas à bonne distance
if (!ok)
{
//et que la distance actuelle est plus petite que la distance maxi
if (dist < distance)
{
//on signale que la distance c'est ok
ok = true;
//on colore le bouton avec la couleur enter
Colore_Btn(col_Enter);
//on passe au mode enter
Manager.Instance.mode = mode_enter;
//On appelle la fonction "Btn_Enter" de l'objet target si enter est activé
if (enter) target.SendMessage("Btn_Enter", this);
}
}
//si on est assez prêt du bouton
else
{
//si le player s'est trop éloigné
if (dist > distance)
{
//on signale que la distance n'est pas ok
ok = false;
//on remet la couleur par défaut
Colore_Btn(col_Defaut);
//on passe au mode exit
Manager.Instance.mode = mode_exit;
//On appelle la fonction "Btn_Exit" de l'objet target si exit est activé
if (exit) target.SendMessage("Btn_Exit", this);
}
//si le player est assez prêt
else
{
//si le player avance on sort
if (Player.Instance.avance) return;
//si drag est active, si on n'est pas en mode dragging et si on appuye sur le bouton gauche de la souris
if (drag && !dragging && Input.GetMouseButtonDown(0))
{
//on met en pose tous les voisins
foreach (Btn item in voisins)
item.pose = true;
//on applique le mode stop
Manager.Instance.mode = Mode.Stop;
//on augmentre le sortig order pour passer afficher le le bouton devant les autres
Order = order + 3;
//on récupère la position d'origine du bouton
start = transform.position;
//et on calcule la différence de position entre la position du curseur et du bouton
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
offset = hit.point - start;
//on active le dragging
dragging = true;
//si dragStart est activé on appelle la fonction "Btn_Drag_Start" de l'objet cible
if (dragStart) target.SendMessage("Btn_Drag_Start", this);
}
//si on n'est pas en mode drag
else
//on active le mode_enter choisi
Manager.Instance.mode = mode_enter;
//on appelle la fonction "Btn_Left_Down" si leftDown est actif et on appuye sur le btn gauche de la souris
if (leftDown && Input.GetMouseButtonDown(0)) target.SendMessage("Btn_Left_Down", this);
//on appelle la fonction "Btn_Right_Down" si rightDown est actif et on appuye sur le btn droit de la souris
if (rightDown && Input.GetMouseButtonDown(1)) target.SendMessage("Btn_Right_Down", this);
//on appelle la fonction "Btn_Center_Down" si centertDown est actif et on appuye sur le btn central de la souris
if (centerDown && Input.GetMouseButtonDown(2)) target.SendMessage("Btn_Center_Down", this);
//on appelle la fonction "Btn_Left_Up" si leftUp est actif et on relache le btn gauche de la souris
if (leftUp && Input.GetMouseButtonUp(0)) target.SendMessage("Btn_Left_Up", this);
//on appelle la fonction "Btn_Right_Up" si rightUp est actif et on relache le btn droit de la souris
if (rightUp && Input.GetMouseButtonUp(1)) target.SendMessage("Btn_Right_Up", this);
//on appelle la fonction "Btn_Center_Up" si centerUp est actif et on relache le btn central de la souris
if (centerUp && Input.GetMouseButtonUp(2)) target.SendMessage("Btn_Center_Up", this);
}
}
}
//si le bouton n'est pas actif ou en pose
else
{
//on applique le mode exit spécifié
Manager.Instance.mode = mode_exit;
}
}
}
}
}
}
Code : Tout sélectionner
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Hexa_Puzzle : MonoBehaviour
{
public List<Transform> pos_exter; //les positions des pièces à l'extérieur de la grille
public List<Transform> pos; //les positions des pièces dans la grille
public List<Btn> pieces; //les pièces du puzzle
public List<Sprite> sprites; //les sprites pour l'affichage UI
public List<Transform> niches; //les transform parent pour les pièces du puzzle dans les niches du labyrinthe
public List<Image> images; //les images UI de l'inventaire
public List<int> id_piece; //l'index des pièces pour les niches et l'inventaire
public List<int> id_image; //l'index des images
public Porte porte; //la porte à ouvrir
public bool reussi; //si le défi est reussi
//pour initialise le puzlle au départ quand le labyrinthe est construit
public void Initialise(List<Transform> niches)
{
//on recupère les niches du labyrinthe
this.niches = niches;
//on initialise la liste des pièces qui vont aller dans les niches
id_piece = new List<int>();
for (int i = 0; i < 3; i++)
{
recommence:
//un index de pièce au hazard
int v = UnityEngine.Random.Range(0, pieces.Count);
//si on à déjà tiré cette pièce au sort on recommence
if (id_piece.Contains(v)) goto recommence;
//on positionne la pièce dans la niche
pieces[v].transform.parent = niches[i];
pieces[v].transform.localPosition = new Vector3(0, 0, 0);
pieces[v].transform.localEulerAngles = Vector3.zero;
//on change les propriété de la pièce pour qu'elle réagisse au clic et pas au drag
pieces[v].leftUp = true;
pieces[v].drag = false;
pieces[v].dragEnd = false;
pieces[v].Initialise_Btn(); //Correction apportée pour régler les problèmes
//on ajoute l'index de la pièce à la liste
id_piece.Add(v);
}
}
//quand on clique sur une pièce
public void Btn_Left_Up(Btn btn)
{
//on récupère l'index de la pièce
int v = pieces.IndexOf(btn);
int i = id_piece.IndexOf(v);
//on affiche l'image de l'inventaire en fonction de la pièce cliquée
images[i].sprite = sprites[v];
images[i].gameObject.SetActive(true);
//on repositionne la pièce dans le puzzle
pieces[v].transform.parent = transform;
pieces[v].transform.localPosition = pos_exter[v].transform.localPosition;
pieces[v].transform.localEulerAngles = new Vector3(-90, 0, 0);
//on restaure les actions de drag et clic
pieces[v].leftUp = false;
pieces[v].drag = true;
pieces[v].dragEnd = true;
pieces[v].Initialise_Btn(); //Correction apportée pour régler les problèmes
//et on rend la pièce inactive pour que le joueur les sélectionne dans l'inventaire pour les réactiver
pieces[v].gameObject.SetActive(false);
//et on passe au mode normal car ça ne se fait pas automatiquement car désactivé
Manager.Instance.mode = Mode.Normal;
}
//Quand le joueur clique sur une image de l'inventaire
public void Clic_Image(int i)
{
//on récupère l'index de la pièce
int v = id_piece[i];
//on active la pièce
pieces[v].gameObject.SetActive(true);
//on désactive l'image
images[i].gameObject.SetActive(false);
}
//quand le joueur termine le drag d'une pièce
public void Btn_Drag_End(Btn btn)
{
//pour une grande distance au départ
float d = 1000;
//l'index de la "pos" le plus proche
int p = -1;
//l'index de la "pos_exter" la plus proche
int e = -1;
//recherche la pos_exter la plus proche
for (int i = 0; i < pos_exter.Count; i++)
{
float dist = Vector3.Distance(btn.transform.localPosition, pos_exter[i].localPosition);
if (dist < d)
{
d = dist;
e = i;
}
}
//recherche la pos piece la plus proche
for (int i = 0; i < pos.Count; i++)
{
float dist = Vector3.Distance(btn.transform.localPosition, pos[i].localPosition);
if (dist < d)
{
d = dist;
p = i;
e = -1;
}
}
//s'il n'y a pas de pos pièces plus pr0che on ramène la piece sur la pos_exter la plus proche
if (e > -1)
btn.transform.localPosition = pos_exter[e].transform.localPosition;
//sinon positionne la pièce sur la pos_pièce la plus proche
else if (p > -1)
btn.transform.localPosition = pos[p].transform.localPosition;
Controle();
}
private void Controle()
{
reussi = false;
//on parcours toutes les pièces
for (int i = 0; i < pos.Count; i++)
{
//si une pièce n'est pas à sa place : on sort
if (pieces[i].transform.localPosition != pos[i].transform.localPosition)
return;
}
//puzzle réussi
reussi = true;
//on débloque et ouvre la porte
porte.Bloque = false;
porte.Ouvre();
//on désactive toutes les pièces
foreach (Btn item in pieces)
{
item.Actif = false;
}
//et on active le mode normal
Manager.Instance.mode = Mode.Normal;
}
}
Edité quelques minutes après le premier envoi : Il semblerai que le simple fait de poser la question ici m'éclaire pour trouver la solution. J'ai modifié les scripts et ajouté un petit commentaire pour montrer mes erreurs.
J'attends quand même vos commentaires en ce qui concerne la déco et les commandes
Merci