[Résolu][MY-AL] Positionner des objets 2d par rapport aux autres

Pour les scripts écrits en C#
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
Avatar de l’utilisateur
Greg
Messages : 156
Inscription : 08 Mai 2017 15:22

[Résolu][MY-AL] Positionner des objets 2d par rapport aux autres

Message par Greg » 25 Juin 2017 00:12

Coucou,

alors pour le principe, je veux pouvoir 'acheter' une 'membrane' et qu'elle se positionne par rapports aux autres. Le top serait de le faire pendant le start.
le deuxième truc top serait d'éviter aussi les 'chevauchements' pendant l'update mais j'ai bien peur que ça devienne vite trop gourmand.

pour l'idée :
Image

pour l'instant je n'y parviens pas dans le start et fais tout dans l'update comme ceci :

Code : Tout sélectionner

        // Debug Position X Y.
        foreach (GameObject otherMembrane in objectsManager.Membranes.ToArray())
        {
            if (otherMembrane == gameObject)
                return;

            // Check Distance.
            Vector3 distance = otherMembrane.transform.position - transform.position;

            // Assign Wanted Distance.
            float wantedDistance = transform.localScale.x + otherMembrane.transform.localScale.x;

            // Assign Position.
            if (distance.sqrMagnitude < wantedDistance * wantedDistance)
            {
                Vector3 randomPoint = Random.insideUnitCircle.normalized * (wantedDistance);

                transform.position = new Vector3(randomPoint.x + distanceIncrementer, randomPoint.y, transform.position.z);
                
                // Increment distance.
                distanceIncrementer++;
            }
        }
Mais bien évidemment, une boucle foreach sur une liste sur chaque membrane de la liste dans l'update...
A partir de la 6 ou 7 ème membrane en scène je commence à sérieusement ramer...

quelqu'un aurait une idée magique pour moi?! ^^
Dernière édition par Greg le 28 Juin 2017 15:09, édité 1 fois.
Mon jeu de développement cellulaire : MICROBIOME (encore quelques bugs...)
(merci bien à ceux qui passent mettre des étoiles ! ^^)

Avatar de l’utilisateur
Greg
Messages : 156
Inscription : 08 Mai 2017 15:22

Re: [MY-AL] Positionner des objets 2d par rapport aux autres

Message par Greg » 25 Juin 2017 12:37

Bon... j'ai grandement amélioré le problème en enlevant le foreach et en mettant le code dans un 'OnCollisionEnter2D -> if collision tag...'

Code : Tout sélectionner

    void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.tag == "Membrane")
        {          
            // Check Distance.
            Vector3 distance = collision.transform.position - transform.position;

            // Assign Wanted Distance.
            float wantedDistance = transform.localScale.x + collision.transform.localScale.x;

            // Assign Position.
            if (distance.sqrMagnitude < wantedDistance * wantedDistance + 2)
            {
                Vector3 randomPoint = Random.insideUnitCircle.normalized * (wantedDistance + 2);

                transform.position = new Vector3(randomPoint.x, randomPoint.y, transform.position.z);
            }
        }
    }
    
Toutefois, je met pas encore résolu parce que je trouve mon code un peu crade et mes membranes ont une peu plus tendances à 'danser' à la création. Donc si vous avez une astuce toujours, je suis preneur!

:merci:
Mon jeu de développement cellulaire : MICROBIOME (encore quelques bugs...)
(merci bien à ceux qui passent mettre des étoiles ! ^^)

Avatar de l’utilisateur
evereal
Messages : 109
Inscription : 06 Nov 2015 18:46

Re: [MY-AL] Positionner des objets 2d par rapport aux autres

Message par evereal » 26 Juin 2017 22:15

Salut,
Je trouvais l'idée intéressante du coup j'ai fait qq test
j'arrive a un comportement plutôt pas mal avec ce code ci :

Membrane.cs

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class Membrane : MonoBehaviour {

	private GameObject mere;

	// Use this for initialization
	void Start () {
		if (mere.transform.childCount == 0) {
			transform.position = mere.transform.position;
		} else if (mere.transform.childCount == 1) {
			Vector3 pos = transform.position;
			Vector3 kernelPos = mere.transform.GetChild (0).transform.position;
			float actualDist = Vector3.Distance (pos, kernelPos);
			float wantedDist = GetComponent<SphereCollider> ().radius + mere.transform.GetChild (0).GetComponent<SphereCollider> ().radius;
			transform.position = ((pos - kernelPos) * wantedDist / actualDist) + kernelPos;
		} else { //childCount > 1
			
			Transform nearest1 = mere.transform.GetChild (0);
			Transform nearest2 = mere.transform.GetChild (1);

			for (int i = 2; i < mere.transform.childCount; i++) {
				Transform candidat = mere.transform.GetChild (i);
				if (Vector3.Distance (transform.position, candidat.position) < Vector3.Distance (transform.position, nearest1.position))
					nearest1 = candidat;
				else if (Vector3.Distance (transform.position, candidat.position) < Vector3.Distance (transform.position, nearest2.position))
					nearest2 = candidat;
			}

			Vector3 pointA = nearest1.transform.position;
			Vector3 pointB = nearest2.transform.position;
			float wantedDistA = GetComponent<SphereCollider> ().radius + nearest1.GetComponent<SphereCollider> ().radius;
			float wantedDistB = GetComponent<SphereCollider> ().radius + nearest2.GetComponent<SphereCollider> ().radius;
			Vector3 intersect1;
			Vector3 intersect2;
			FindCircleCircleIntersections (pointA.x, pointA.y, wantedDistA, pointB.x, pointB.y, wantedDistB, out intersect1, out intersect2);
			// on choisi l'intersection la plus proche du point de spawn
			if (Vector3.Distance (intersect1, transform.position) > Vector3.Distance (intersect2, transform.position)) {
				transform.position = intersect2;
			} else {
				transform.position = intersect1;
			}
		}

		transform.SetParent(mere.transform);
	}

	public void setMere(GameObject newMere) {
		mere = newMere;
	}
	
	//
	// Find the points where the two circles intersect.
	//
	private int FindCircleCircleIntersections(
		float cx0, float cy0, float radius0,
		float cx1, float cy1, float radius1,
		out Vector3 intersection1, out Vector3 intersection2)
	{
		// Find the distance between the centers.
		float dx = cx0 - cx1;
		float dy = cy0 - cy1;
		double dist = Math.Sqrt(dx * dx + dy * dy);

		// See how many solutions there are.
		if (dist > radius0 + radius1)
		{
			// No solutions, the circles are too far apart.
			intersection1 = new Vector3(float.NaN, float.NaN,float.NaN );
			intersection2 = new Vector3(float.NaN, float.NaN, float.NaN);
			return 0;
		}
		else if (dist < Math.Abs(radius0 - radius1))
		{
			// No solutions, one circle contains the other.
			intersection1 = new Vector3(float.NaN, float.NaN,float.NaN );
			intersection2 = new Vector3(float.NaN, float.NaN, float.NaN);
			return 0;
		}
		else if ((dist == 0) && (radius0 == radius1))
		{
			// No solutions, the circles coincide.
			intersection1 = new Vector3(float.NaN, float.NaN,float.NaN );
			intersection2 = new Vector3(float.NaN, float.NaN, float.NaN);
			return 0;
		}
		else
		{
			// Find a and h.
			double a = (radius0 * radius0 -
				radius1 * radius1 + dist * dist) / (2 * dist);
			double h = Math.Sqrt(radius0 * radius0 - a * a);

			// Find P2.
			double cx2 = cx0 + a * (cx1 - cx0) / dist;
			double cy2 = cy0 + a * (cy1 - cy0) / dist;

			// Get the points P3.
			intersection1 = new Vector3(
				(float)(cx2 + h * (cy1 - cy0) / dist),
				(float)(cy2 - h * (cx1 - cx0) / dist), 0);
			intersection2 = new Vector3(
				(float)(cx2 - h * (cy1 - cy0) / dist),
				(float)(cy2 + h * (cx1 - cx0) / dist), 0);

			// See if we have 1 or 2 solutions.
			if (dist == radius0 + radius1) return 1;
			return 2;
		}
	}
}
Controler.cs
Petit controlleur pour les test

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controler : MonoBehaviour {
	[SerializeField] private GameObject myMembrane;
	[SerializeField] private GameObject mere;
	// Update is called once per frame
	void Update () {
		if (Input.GetKeyDown(KeyCode.Space)) {
			float x = Random.Range(-10f, 10f);
			float y = Random.Range(-10f, 10f);
			GameObject newMembrane = Instantiate(myMembrane, new Vector3(x, y, 0), Quaternion.identity);
			newMembrane.GetComponent<Membrane>().setMere (mere);
		}
	}
}
Image

Pour les explications ; Le gameObject Mothership (désolé j'ai craqué pour les noms) contiendra tout les GameObject membranes.
Il sert a la fois a les retrouver et également a donner une position pour le tout premier GameObject membrane.
Lorsqu'on fait apparaitre la première membrane, elle se place sur la position du mothership.
pour la seconde membrane, elle vient coller sa paroi contre la paroi de la première membrane en se rapprochant simplement linéairement.
pour la 3eme membrane, elle va se positionner au niveau de l'intersection des cercles défini par :
1) de la première membrane+rayon de la 3eme membrane
2) de la seconde membrane+rayon de la 3eme membrane
pour les suivant c'est pareil, sauf qu'ils vont vérifier quel sont les 2 membranes les plus proches de leur point d'apparition, puis calculer l'intersection des cercles basé sur ces 2 membranes.

Il reste un bug qui fait apparaitre une membrane pile sur une membrane déjà existante mais j'ai pas eu le temps de creuser davantage.
“La théorie, c'est quand on sait tout et que rien ne fonctionne. La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : Rien ne fonctionne... et personne ne sait pourquoi !”

Avatar de l’utilisateur
Greg
Messages : 156
Inscription : 08 Mai 2017 15:22

Re: [MY-AL] Positionner des objets 2d par rapport aux autres

Message par Greg » 27 Juin 2017 01:37

j'viens de voir le message et d'essayer!
Ouep ça marche bien et c'est marrant ^^

j'avoue que y'a un peu des portions de codes de fou furieux :malin2:

Code : Tout sélectionner

         // Find a and h.
         double a = (radius0 * radius0 -
            radius1 * radius1 + dist * dist) / (2 * dist);
         double h = Math.Sqrt(radius0 * radius0 - a * a);

         // Find P2.
         double cx2 = cx0 + a * (cx1 - cx0) / dist;
         double cy2 = cy0 + a * (cy1 - cy0) / dist;

         // Get the points P3.
         intersection1 = new Vector3(
            (float)(cx2 + h * (cy1 - cy0) / dist),
            (float)(cy2 - h * (cx1 - cx0) / dist), 0);
         intersection2 = new Vector3(
            (float)(cx2 - h * (cy1 - cy0) / dist),
            (float)(cy2 + h * (cx1 - cx0) / dist), 0);
C'est vrai que j'ai pas préciser mais j'avais déjà une arborescence de GO et tout... mais j'dois pouvoir adapter.

Dans l'absolu, mon problème est surtout ce 'bug' justement... J'ai un peu le même et c'est pourquoi je multiplie les checks dans un update ou onCollision mais c'est désastreux pour mon physic framerate et j'espère pouvoir déployer sur mobile un jour.

En tout cas merci bien! :merci:
cette méthode à le mérite de fonctionner dans le start donc je verrais demain avec les idées plus claires si j'y pige mieux!
Mon jeu de développement cellulaire : MICROBIOME (encore quelques bugs...)
(merci bien à ceux qui passent mettre des étoiles ! ^^)

Avatar de l’utilisateur
Greg
Messages : 156
Inscription : 08 Mai 2017 15:22

Re: [MY-AL] Positionner des objets 2d par rapport aux autres

Message par Greg » 28 Juin 2017 15:02

Bon alors pour mettre déjà bien cassez la tête là-dessus...

Il s'avère que j'ai eu et ai quelques soucis avec le bout de code d'evereal.
Avec mon niveau math fin de 3ème et ma formation au code à base de tuto youtube, ce code reste pour moi hardcore! ^^

Déjà, étant plutôt en fin de projet, je suis soumis à une trop longue liste de contraintes (hiérarchie, gameplay, 2d, méthodes de mouvements, rescale...) pour les exposer sur le forum mais que je dois prendre en contre lors de l'implémentation de la méthode.

Ensuite, parce qu'étant en 2d, j'utilise des CircleCollider2D au lieu des SphereCollider et il fonctionne pas pareil apparemment.
Un sphereCollider basé sur un mesh filter sphère aura toujours un radius de 0.5 pour un scale de 1.
Alors qu'un circleCollider aura un radius variable en fonction du sprite qui lui est associé.

Et enfin parce que si j'ai bien compris le code au final... il créé une grille virtuelle de la taille adéquate inclinée à 45 degrée, et place les sphères comme il faut dedans en se servant de leur radius.
Pour ce faire, il revient un peu à prendre les 2 sphères les plus proche. Tire un trait entre elle puis tire un 2ème trait perpendiculaire partant du centre du 1er trait et place la nouvelle sphère à la bonne distance sur celui-ci.

Plusieurs problèmes à ceci.
Si on rescale une sphère (même la 1ère), son radius ne bouge pas et donc les suivantes seront placées dans la spère 'plus grande' en suivant la grille de départ qui n'as pas bougée.
Si on déplace n'importe quelle sphère à partir du moment ou on en à 2, on se cogne encore des "Input position is { NaN, NaN, NaN }".
Et surtout si on dessine le chemin parcouru par le code pour remplir la grille, il l'a remplie en dessinant une spirale et du coup y repasse par certaines cases (d'où le bug de positionnement d'origine).


Mais quand même du coup vu que ma hiérarchie est :

Cells
> Cell1
>> Membrane
>> CellChild1
>> CellChild2
> Cell2
>> Membrane
>> CellChild1
>> CellChild2
etc

Cells et Cell sont des emptys et ne sont soumis à rien.
Les enfants des Cells sont soumis aux déplacements, scaling etc.


Je pense qu'il faut que je mixe les deux idées!

1- Que je parvienne à placer les cells dans une grille virtuelle (en me basant sur le code d'evereal)
2 - Que je parvienne à décaler mes enfants en fonction des offsets des membranes les plus proches (en me basant sur le code d'evereal et le mien)
3 - Et que je peaufine en déboguant la position des enfants dans leur start (en me basant sur mon code)

Bref, c'est loin d'être fait mais je met résolu parce que je sais pas quand j'y parviendrais et aurait le temps de m'en occuper -_-

Merci pour l'aide et/ou la lecture

:merci:
Mon jeu de développement cellulaire : MICROBIOME (encore quelques bugs...)
(merci bien à ceux qui passent mettre des étoiles ! ^^)

Répondre

Revenir vers « (C#) CSharp »