Quantcast
Channel: Answers by "hoekkii"
Viewing all articles
Browse latest Browse all 26

Answer by hoekkii

$
0
0
Readability is most of the time more important than efficiency, but first of all some feedback on your code:
You should initialize objects inside `Awake`.
Why don't you remove items from the list? This way it will only grow in size.
Why is the collider separated from the rigidbody? (the parent has the rigidbody...?) There could occur a null reference exception in the update loop because the parent doesn't need to have a rigidbody and will result in adding `null` to your rgbodiesIn list, but objectsIn does have a reference >>> Why do you have two Lists?
For efficiency you could cache the transform position at the beginning of `Update()`. Which brings me to why you do physics manipulation inside `Update` and not `FixedUpdate`? This causes irregularities at different frame-rates.

Some style feedback:
in `OnTriggerExit2D` you have an if statement inside an if statement, which as a reader can make reading quite 'chaotic', I would recommend instead of `if (objectsIn[i] != null) { ...` doing `if (objectsIn[i] == null) continue;` this way you relieve some of the "what objects could be passing this code...?".
Split long lines into shorter ones, the compiler is quite good at optimizing things.
Last note I know it is boring to do, but I really recommend adding comments.

Here is some code (note this is not tested in any way) #define DEBUG_FORCES using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Collider2D))] public class Attractor : MonoBehaviour { [SerializeField] float _force; /// /// Collection of rigidbodies that are inside the collider /// HashSet _rigidbodies; /// /// Initialize /// void Awake() { _rigidbodies = new HashSet(); } /// /// Called when a collider enters this collider /// void OnTriggerEnter2D(Collider2D other) { // Get the rigidbody and check if can proceed var obj = other.gameObject; var body = obj.GetComponent(); if (body == null) return; // Add rigidbody to the collection _rigidbodies.Add(body); } /// /// Called when a collider exits this collider /// void OnTriggerExit2D(Collider2D other) { // Get the rigidbody and check if can proceed var obj = other.gameObject; var body = obj.GetComponent(); if (body == null) return; // Remove rigidbody to the collection _rigidbodies.Remove(body); } /// /// Called when the object is being disabled /// Clear the rigidbody collection /// void OnDisable() { _rigidbodies.Clear(); } /// /// Called at a fixed time step /// void FixedUpdate() { // Cache the position var currentPosition = (Vector2)transform.position; // Apply force to all rigidbodies foreach (var body in _rigidbodies) { // Calculate the magnitude of the force by the rigidbody mass and the attractor force var forceMagnitude = body.mass * _force * Time.fixedDeltaTime; // Calculate the force by getting the delta position with the previously calculated magnitude var force = GetDirection(body, currentPosition) * forceMagnitude; // Apply body.AddForce(force); } } /// /// Get the relative position of body opposing to the point /// /// Normalized direction static Vector2 GetDirection(Rigidbody2D body, Vector2 point) { // Calculate the delta position var delta = body.position - point; return delta.normalized; } #if DEBUG_FORCES void Update() { foreach (var body in _rigidbodies) { var force = GetDirection(body, transform.position); Debug.DrawRay(body.transform.position, force, Color.red); } } #endif } If efficiency is all you want, You'll probably end up something like this (Note this is not tested in any way and quickly put together, so it could not be working) [RequireComponent(typeof(Collider2D))] public class AttractorEfficient : MonoBehaviour { const int Capacity = 64; [SerializeField] float _force; Affectee[] _affectees; int _firstFreeIndex; bool _firstFreeIndexOccupied; int _lastIndex; /// /// Initialize /// void Awake() { _affectees = new Affectee[Capacity]; _firstFreeIndex = 0; _lastIndex = -1; _firstFreeIndexOccupied = false; } /// /// Called when a collider enters this collider /// void OnTriggerEnter2D(Collider2D other) { var obj = other.gameObject; var body = obj.GetComponent(); if (body == null) return; var index = _firstFreeIndex; if (_firstFreeIndexOccupied) { for (index = 0; index < Capacity; ++index) if (!_affectees[index].Occupied) break; _firstFreeIndex = index; if (index > _lastIndex) { if (index == Capacity) return; // Or throw error _lastIndex = index; } } _firstFreeIndexOccupied = true; _affectees[index].Occupied = true; _affectees[index].Rigidbody = body; _affectees[index].Id = body.GetInstanceID(); } /// /// Called when a collider exits this collider /// void OnTriggerExit2D(Collider2D other) { var obj = other.gameObject; var body = obj.GetComponent(); if (body == null) return; var id = body.GetInstanceID(); for (var i = 0; i <= _lastIndex; ++i) if (_affectees[i].Occupied && _affectees[i].Id == id) { _affectees[i].Occupied = false; if (i < _firstFreeIndex || _firstFreeIndexOccupied) { _firstFreeIndex = i; _firstFreeIndexOccupied = false; } if (i == _lastIndex) for (--_lastIndex; _lastIndex >= 0; --_lastIndex) if (_affectees[_lastIndex].Occupied) break; return; } } /// /// Called at a fixed time step /// void FixedUpdate() { var currentPosition = (Vector2)transform.position; var mul = _force * Time.fixedDeltaTime; for (var i = 0; i <= _lastIndex; ++i) { if (!_affectees[i].Occupied) continue; var body = _affectees[i].Rigidbody; var force = body.position; force.x -= currentPosition.x; force.y -= currentPosition.y; force.Normalize(); var mulNet = mul * body.mass; force.x *= mulNet; force.y *= mulNet; body.AddForce(force); } } struct Affectee { public bool Occupied; public Rigidbody2D Rigidbody; public int Id; } }

Viewing all articles
Browse latest Browse all 26

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>