Devlog Refuge: Optimized Mouse Interaction 🖱️and short AFK

Ah, the mouse! That tiny, insignificant peripheral that somehow wields absolute power over my Refuge project. After a few clumsy attempts and raycasts lost in the void, I finally have a robust and optimized implementation. Because, honestly, after watching my survivors completely ignore my clicks or float above the ground like they had discovered the secret to levitation, it was about time to bring some order to this mess!
The Objective 🎯
From the start, the goal was clear: create a clean and efficient mouse interaction system without turning every click into a detective case to figure out where my selection had gone. I needed smooth hover detection, precise clicks, and above all, something that wouldn’t drag performance into the abyss.
So, I set out to find a solution that balanced clarity, performance, and maintainability. Also, I wanted to avoid unnecessary memory allocations—because in a world where optimization is king, every millisecond saved means delaying the zombie apocalypse just a little longer!
The Great MouseEvents Overhaul 🛠️
Enter the MouseEvents
class, the guardian of all mouse interactions. This little gem now ensures reliable detection of interactive objects, well-placed clicks, and an efficient grid position update system.
But wait, there’s more! I also had to think about optimizations. So I revamped the raycasting logic, introducing a static buffer to avoid allocating objects with every request. The result? Smooth and optimized interaction handling with zero wasted resources.
Under the Hood đź”§
Instead of creating a new array with every call to Physics.RaycastAll
, I opted for Physics.RaycastNonAlloc
. This small tweak prevents unnecessary allocations and keeps performance in check. Here’s how it works:
private static readonly RaycastHit[] HitsBuffer = new RaycastHit[5];
public static GameObject GetObjectUnderMouse(this LayerMask mask, UnityEngine.Camera camera)
{
Vector3 mousePos = Input.mousePosition;
if (float.IsInfinity(mousePos.x) || float.IsInfinity(mousePos.y) || mousePos.x < 0 || mousePos.y < 0 || mousePos.x > Screen.width || mousePos.y > Screen.height)
{
return null;
}
Ray ray = camera.ScreenPointToRay(mousePos);
int size = Physics.RaycastNonAlloc(ray, HitsBuffer, Mathf.Infinity, mask);
GameObject closestObject = null;
float closestDistance = Mathf.Infinity;
for (int i = 0; i < size; i++)
{
var hit = HitsBuffer[i];
if (hit.distance < closestDistance)
{
closestDistance = hit.distance;
closestObject = hit.collider.gameObject;
}
}
return closestObject;
}
With this approach, only the closest object is considered, ensuring performance remains top-notch. Simple, yet effective!
Smarter Component Retrieval 🎩
Another notable improvement: TryGetComponentInParent
. Previously, finding a component up the hierarchy was an absolute nightmare, involving tedious manual checks and convoluted code. Now, a single method does the job, allowing me to retrieve components from parent objects effortlessly.
What’s Next? 📅
I’ll be away for a few days, off to the hospital for some routine check-ups. Nothing serious, don’t worry! But unfortunately, hospitals have an unreasonable policy against bringing in a PC loaded with Unity projects. (Honestly, they act like I’m going to accidentally code an AI that escapes into their medical systems.) So, no development for me during this time—but hey, at least I’ll have plenty of time to plan what’s next!
When I return, I’ll be dropping a new devlog about the GOAP system I wrapped up in the last sprint. This will be a deep dive into how my survivors make decisions intelligently (or at least, that’s the goal) in this unforgiving world.
If all goes well, I’ll also tackle Refuge’s user interface—because managing a post-apocalyptic shelter is cool and all, but if the menus are a mess, I might as well be sending my survivors into the wasteland blindfolded.
Conclusion 🚀
Thanks to these improvements, mouse interactions are now smooth and precise. No more clicking the same spot fifteen times, hoping something finally reacts! Beyond avoiding unnecessary slowdowns, this overhaul drastically simplifies the code and makes adding new interactions a breeze.
For now, I’ll see if my survivors finally stop ignoring me when I tell them to go scavenge for supplies. Stay tuned for the next devlog! 👋
Ah, la souris ! Ce petit périphérique insignifiant mais qui contrôle pourtant tout ce qui se passe dans mon projet Refuge. Après quelques essais maladroits et des raycasts perdus dans l'espace infini, voici enfin une implémentation robuste et optimisée. Car oui, après avoir vu mes survivants ignorer royalement mes clics ou flotter au-dessus du sol comme s’ils avaient découvert la lévitation, il était temps de mettre de l'ordre dans cette gestion des interactions !
Objectif 🎯
Dès le début, l’idée était simple : avoir une gestion de la souris propre et efficace, sans que chaque clic se transforme en une enquête policière pour savoir où est passée ma sélection. Il fallait que la détection du survol soit fluide, que les clics soient précis et surtout, que tout ça tourne sans trop peser sur les performances.
J’ai donc planché sur une solution qui assure un bon équilibre entre clarté, performance et maintenabilité. Le but était aussi d’éviter de spammer la mémoire avec des allocations inutiles. Parce que bon, dans un monde où l’optimisation est reine, chaque milliseconde gagnée, c’est une apocalypse zombie retardée de quelques instants !
La refonte de MouseEvents 🛠️
J’ai donc mis au point une classe MouseEvents
qui gère tout ce qui touche à la souris : du survol des objets interactifs aux clics bien placés. Elle permet d’avoir une détection fiable, tout en intégrant un système de mise à jour efficace de la position sur la grille du jeu.
Mais ce n’est pas tout ! Il fallait aussi penser aux optimisations. J’ai donc retravaillé les raycasts en intégrant un buffer statique pour éviter d’instancier des objets à chaque requête. Résultat : une gestion fluide et optimisée, sans gaspillage de ressources.
Un regard sous le capot đź”§
Plutôt que de créer un tableau à chaque appel de Physics.RaycastAll
, j’ai préféré utiliser Physics.RaycastNonAlloc
. Ce petit changement a permis d'éviter les allocations inutiles et d'améliorer les performances. Voici comment ça fonctionne :
private static readonly RaycastHit[] HitsBuffer = new RaycastHit[5];
public static GameObject GetObjectUnderMouse(this LayerMask mask, UnityEngine.Camera camera)
{
Vector3 mousePos = Input.mousePosition;
if (float.IsInfinity(mousePos.x) || float.IsInfinity(mousePos.y) || mousePos.x < 0 || mousePos.y < 0 || mousePos.x > Screen.width || mousePos.y > Screen.height)
{
return null;
}
Ray ray = camera.ScreenPointToRay(mousePos);
int size = Physics.RaycastNonAlloc(ray, HitsBuffer, Mathf.Infinity, mask);
GameObject closestObject = null;
float closestDistance = Mathf.Infinity;
for (int i = 0; i < size; i++)
{
var hit = HitsBuffer[i];
if (hit.distance < closestDistance)
{
closestDistance = hit.distance;
closestObject = hit.collider.gameObject;
}
}
return closestObject;
}
Avec ce code, on s’assure que seuls les objets les plus proches sont pris en compte et que la performance reste optimale. C’est simple, mais efficace !
Une gestion plus maline des composants 🎩
Autre amélioration notable : TryGetComponentInParent
. Avant, retrouver un composant dans la hiérarchie parentale relevait du casse-tête, avec des vérifications manuelles et du code inutilement alambiqué. Désormais, une seule méthode permet de parcourir les parents d’un objet et d’y récupérer un composant sans prise de tête.
Et après ? 📅
Je vais devoir m'absenter quelques jours, direction l'hôpital pour quelques examens. Rien de grave, rassurez-vous ! Mais malheureusement, ils ont une politique très stricte contre l’importation de PC remplis de projets Unity (à croire qu’ils ont peur que je code une IA qui s’échappe dans leur système). Bref, pas de développement pour moi pendant ce temps-là , mais ça me laissera l'occasion de réfléchir à la suite.
À mon retour, je publierai un nouvel article sur l'implémentation de mon système GOAP, que j'ai terminé lors du sprint précédent. Ce sera l'occasion de détailler comment mes survivants prennent leurs décisions intelligemment (ou pas) dans cet univers impitoyable.
Si tout se passe bien, j'aborderai aussi l'interface utilisateur de Refuge, qui est l'objectif du sprint en cours. Parce que gérer un abri post-apo, c'est cool, mais encore faut-il avoir des menus clairs pour ne pas perdre ses survivants entre deux clics !
Conclusion 🚀
Grâce à ces améliorations, les interactions souris sont désormais fluides et précises. Plus besoin de cliquer quinze fois au même endroit en espérant que quelque chose réagisse ! En plus d’éviter les ralentissements, cette refonte simplifie énormément le code et permet d’ajouter facilement de nouvelles interactions.
D’ici là , je vais voir si mes survivants arrêtent enfin de m’ignorer quand je leur demande d’aller chercher des ressources. À suivre dans le prochain devlog ! 👋