To get the point where two lines intersect, we will do some maths. To the mathematicians who will come across this post, I’m truly sorry for the heart attacks or strokes you may experience by reading this post.
Ok, let’s take a look on the figure:
Figure 1
First, sorry, I was too lazy to make a proper figure using computer tools so I just put a scan. XD
Next, here are the definitions:
& : the two lines,
, : the arbitrary starting points of the two lines,
, : the arbitrary points which tells the direction of the two lines,
: the intersection point,
: the origin point.
Kewl. Now, what we want is the intersection point between those two lines. In other words, we want to know the position which starts from either lines’ arbitrary starting point, added by the direction of the line multiplied by a scalar value. So in our figure 1, the position is:
the position added by the components of multiplied by an unknown which I named
the position added by the components of multiplied by an unknown which I named
In this case, it is clear that so it will be easy to check if our final formula is correct. 🙂
At the point of intersection, we know that:
… which gives us:
But we can’t use this statement exactly like this to solve our equation as we cannot multiply and divide vectors in this raw format. Also we need to reduce the unkowns count to 1. So we will separate our equation into two equations with the magic of matrices (which I don’t understand well at the moment), one for the x component and one for the y:
To make our equation more readable, we will use some shorthands:
… so:
From this point, we can reduce the unknown count. In my case, I have chosen to keep instead of :
And finally, you have to check if . This will happen if your two lines are parallel or if there is one line defined as a point such as or ; no solution exists in those cases.
Use a single BoxCollider for all your planes. For example, if you have multiple aligned planes, remove their Collider component (Box, Mesh, whichever they have) and on only one of the planes, add a BoxCollider and adjust its center and size values in the component’s inspector to encapsulate all the planes.
Pros
Simple.
Cons
Supports only rectangular surfaces.
Method 2: generated colliders
If you are rolling your ball on a non rectangular surface, you will need to find a way to generate a mesh collider for all your planes. For this, choose one of the following:
the easy way: look for a plugin online or on the Asset Store,
Pros
Just works.
Cons
Uses noticeable CPU power when updating (baking) the colliding mesh in real time. Update sparingly.
Method 3: ramps as bridges
Create a set of meshes from a 3D software such as Blender to make invisible ramps which will be placed partly underground between your planes. They have to be large enough to make the transitions as smooth as possible. The height between the top of the bridge and the ground (the planes) should be approximately the value defined by the Default Contact Offset value in the Physics Manager.
Pros
No real improvement.
Cons
The ball may jump a little, especially at high speed.
Doesn’t work with small tiling (or when your successive planes are small): the longer the tiles, the longer bridges can be.
Requires a lot of testing.
Requires 3D software usage.
The result is not consistent.
Requires good workflow / toolchain.
Method 4: make custom extended planes’ colliders
This one should not work very well.
Create in a 3D software a planar mesh. Then, on its edges, extrude towards outside and lower down slightly the new edges. To put the words into image:
Make them intersect, and hopefully the bouncing will be invisible.
Pros
Quite simple.
Cons
The ball may jump a little, especially at high speed.
Requires a lot of testing.
Requires 3D software usage.
The result is not consistent.
Requires good workflow / toolchain.
Method 5: turn slightly your planes’ colliders
Make your planes’ colliders slightly rotated so that, in the direction of movement, the end of a collider is slightly above the next plane’s collider. The height should be approximately the value defined by the Default Contact Offset value in the Physics Manager and hopefully no bouncing will occur.
Pros
Works flawlessly.
Cons
You will see the ball flying and falling a few units from one plane to another.
Method 6: do everything by script
Maybe the Physics is not what is the best for your gameplay. Write your own system with accelerations, collision detection. This is the old-fashioned way and is the choice of a lot of developers! ^^
Pros
Works flawlessly.
Permits game design driven gameplay and not by physics.
Cons
Not using the PhysX forces and gravity.
Requires to work (omg! 😉 ) to simulate fake physics.
Method 7: Make your ball much larger
By using a greater ball (x10, x100), this could lead to less edge detection.
Pros
May work.
Cons
The scale of the simulation would change: if you make everything at the same scale as the ball, objects falling by gravity will look like they fall in slow motion.
The result is not consistent.
Method 8: collision layers and raycast
This one is pretty cool.
Keep single BoxColliders for each plane. Set the layer of the plane prefab to SinglePlanes (create the layer).
Make a big Unity cube with a collider which encapsulates all the planes. Set the layer of the cube to ContinuousPlane.
Create two layers: OnAPlane and NotOnAPlane.
Set the ball prefab’s layer to OnAPlane.
In Physics Manager, set the collision matrix so that:
NotOnAPlane and ContinuousPlane are not collidable (unchecked),
OnAPlane and SinglePlanes are not collidable (unchecked).
On each Update(), do a raycast from the center of the ball towards Vector3.down on the layer SinglePlanes:
If the raycast returns false, the center of the ball is not on a plane. So now, we change the layer of the ball to NotOnAPlane. The ball will start to fall through the hole.
If the raycast returns true, set the layer of the ball to OnAPlane.
For how to define a layer, please check the manual.
Pros
Works efficiently with dynamic floor layout.
You will learn how to deal with layers and Physics.
Cons
No real flaws.
Additional Information
Methods above may be combined.
You can adjust the physics project settings and / or set the physics materials to reduce the bounciness of your objects.
Make sure the thickness of the planes collision is not 0f. Make them 1f large or more.
There is a possibility to reduce the bounces, but I am not recommending it (may cause jittery and physics artifacts): set the Default Contact Offset to 0.0001. Again, I am not recommending it!
All of this post could be useless when the default PhysX embedded in Unity will be upgraded.
I originally posted this post as an answer on the Unity Answers website but none of the above methods have been considered as valid by the OP. Hence the removal from the answers website.
Try to avoid naming your MonoBehaviour methods Main(). These would be triggered between Awake() and Start(). This Main() method supports IEnumerator flavors as much as Awake() and alike! But as useful as it could be, I would not recommend to use it as there is no official documentation entry in the manual. And usually, you should not need this method.
Évitez de nommer Main() les méthodes se situant dans vos MonoBehaviour. Celles-ci seraient déclenchées entre Awake() et Start(). Cette méthode Main() supporte la version en IEnumerator autant que Awake() et les autres ! Mais aussi utile que pourrait être cette méthode, je ne la recommanderais pas à l’usage puisqu’il n’existe aucune documentation officielle dans le manuel. Et normalement, vous ne devriez pas avoir recours à cette méthode.
Awake() is fired, then Main() and finally Start(). But don’t use Main()!
Plantage de l’éditeur Unity sur la re-sérialisation en texte
Lorsque vous avez un gros projet Unity entre vos mains et que vous décidez de forcer la sérialisation en texte (Project Settings > Editor > Asset Serialization > Mode: Force Text), il se peut que vous rencontriez un problème de mémoire insuffisante qui fait crasher Unity. Lors du processus de « re-serialisation », Unity charge tous vos assets dans la RAM pour recréer les structures de données du format binaire vers le format texte. Puis arrive le moment tant redouté : l’éditeur n’arrive plus à allouer de la mémoire et crashe !
Ceci est dû pour l’une des deux raisons suivantes :
l’incapacité d’Unity à allouer la mémoire nécessaire due à la limitation des applications 32-bit.
si vous êtes sur Unity 5, bien que l’éditeur soit 64-bit, il n’y a pas assez de mémoire sur votre PC.
Quel que soit le cas, pas de panique ! Vos données n’ont pas été corrompues par le crash vu que le travail se faisait uniquement en RAM. Néanmoins, il se peut que vos derniers changements apportés au projet se soient évanouis dans la nature (parfois, il faut fermer l’éditeur proprement pour s’assurer que des changements sont sauvegardés sur le disque).
Comment remédier à ce problème ?
Pour ma part, la recherche de solution et la résolution m’ont pris un peu plus d’une heure. J’ai passé pas mal de temps sur les forums sans trouver de réelle réponse précise qui n’implique pas le devoir de redéfinir des valeurs et des références qui ont disparu lors de la conversion. Mais de mon côté, j’ai pu trouver une méthode qui permet de faire la conversion sans perte de valeurs et de références !
Je suis trop fort !
Voici donc mon pas à pas :
Déjà, partez d’un projet stable, sans erreur. Corrigez vos bugs avant de convertir les assets en texte.
Archivez votre projet quelque part. Ben oui, c’est important d’archiver avant de faire de opérations dangereuses.
Dans l’éditeur, dans la fenêtre Project, sélectionnez tous vos assets puis exportez-les dans un unitypackage via Export Package…
L’export peut prendre plusieurs dizaines de secondes, voire minutes, selon la taille du projet (mon package faisait 750 Mo !)
Mettez votre package pas trop loin, on va s’en resservir souvent pendant le processus.
Supprimez tous vos assets dans Project ! Quand je vous disais d’archiver le projet, ce n’était pas pour rien…
Définissez Project Settings > Editor > Asset Serialization > Mode: Force Text
Double-cliquez sur votre unitypackage depuis l’explorateur et attendez le chargement qui peut prendre du temps.
Désélectionnez tout puis sélectionnez uniquement une partie du package pour l’import.
Le but est d’importer petit à petit les assets. À chaque import, Unity va re-sérialiser en texte.
Si l’import plante (et donc que Unity crash pour out of memory), c’est parce que vous avez pris trop de fichiers d’un coup. Dans ce cas, réimportez à nouveau en prenant moins d’assets.
Vous constaterez très probablement que la console vous signale des erreurs pour classe manquante. Dans ce cas, identifiez un asset ou un groupe d’asset qui contient la classe manquante et importez-le. Très important : lorsque vous avez réglé les problèmes de classes manquantes, il faut réimporter tous les assets à partir desquels l’erreur est apparue dans la console, toujours petit à petit (avec les mêmes sélections), qui sont déjà importés pour recréer les variables et les références qui ont pu se briser.
Pour vous aider dans le processus, je vous conseille d’avoir la fenêtre du Gestionnaire des tâches pour voir la taille que prend une sélection d’assets en import pour mieux découper les imports.
Une fois que tout est importé, faites un test. Il ne devrait rien manquer si vous avez tout bien importé / réimporté / réréimporté / …
Si vous avez des problèmes de NullPointerException ou des incohérences de comportement dans le test, identifiez l’asset qui lève cette exception ou l’incohérence puis réimportez-le. Ne faites surtout pas la réassignation vous-même, le réimport est censé corriger les problèmes de références manquantes (Missing) et les valeurs qui n’ont pas été bien importées.
Le plus long dans le processus a été, pour moi, d’attendre l’ouverture du unitypackage à chaque import. C’est pourquoi vous devez bien comprendre comment sont rangés vos assets pour bien découper vos imports. Je pense que le mieux est d’importer du plus générique au plus spécifique. Par exemple, importer les scripts des plugins sur lesquels s’appuie votre code, puis petit à petit, importer les prefabs et assets jusqu’à arriver à ceux utilisés dans les scènes. Les scènes doivent d’ailleurs être importés en dernier, il s’agit du bout de la chaîne.
Voilà, j’espère que ça servira à quelqu’un. De mon côté, ça m’a permis de travailler avec Mercurial.
Tout récemment, j’ai acquis une licence de Unity Pro. Pour ceux qui ne connaissent pas, il s’agit d’une solution logicielle permettant de produire et diffuser rapidement et simplement du contenu interactif en 2D et 3D. De cette manière, je pourrai enfin vous faire partager des expériences ludiques grâce à une solution efficace et prometteuse.
Comme certaines de mes connaissances, j’effectue ainsi une transition de Virtools Dev vers Unity, sachant que je n’ai pu utiliser Virtools Dev que lors de mes cours à ISART Digital et durant mon contrat à SoBuzzy/Serious Factory.
Je vais vous épargner la comparaison Unity vs. Virtools, mais je dois vous dire que j’apprécie certaines fonctionnalités de Unity, absentes de Virtools telles que le blocage du pointeur de la souris, indispensable pour du jeu en vue subjective !
Bref, j’espère pouvoir démarrer quelque chose de sympathique avec Unity !