The issue is smooth animation of a physics cycle slower than the screen refresh, such as a 144Hz monitor and a 30 fps physics update.
The correct way to smooth object positions is to tween them based on delta time. However, you cannot move Transforms using physics and have to move the rigidbodies, which are only updated on FixedUpdate. Objects thus only move at 30 fps.
The RBs have interpolation options but these don’t work when spawning pooled objects where the position is interpolation between the new position and the old position.
I’m struggling to find how to solve this. At present, I spawn my objects one frame invisible and let the RB move to its starting position, and then the next FixedUpdate(), set it to visible. However, this is delaying the creation of my object so it’s no longer immediate.
But that doesn’t move the rigidbody. I was using that but then the collider was being left behind for one FixedUpdate and this meant false positive collisions when performing collider overlaps. then I discovered as per this thread:
What does this mean? Interpolation is just that, interpolation. The simulation steps and at the end it has an old and current position. For the following frames until the next simulation step, the Transform is updated per-frame. Position is lerped, rotation is slerped. Simple.
I have no idea what this means either. When you spawn it i.e. take it out of the pool and activate it, the body will be at the pose of the Transform there and then. When a Rigidbody(2D) is activated, its pose is set to the Transform i.e. it’s synced up because when inactive, the only pose state is the Transform. What you don’t want to do is activate it then set the Transform because that won’t be read until the simulation steps just like renderers are not notified that the Transform changes; they only know when they run too i.e. when they render.
In short, before you activate it, ensure all changes to the physics stuff are done. In your case, it sounds like ensuring the Transform is set before activating it.
I don’t see how this relates to high frame-rates though; this is just understanding that the physics isn’t running per-frame. You can, of course, run physics per-frame if you wish too. You quoted 2D physics but it’s not clear if you’re talking about 2D or 3D TBH.
I have an explosion at (-3,2). It ends and is pooled. Another explosion goes off at (6,7). I place the pooled object there, activate the gameobject, but the collider registers at (-3,2) for one frame. If I examine the object in the inspector, the transform at spawn is (6,7) but the centre of the collider is at (-3,2).
That’s not happening for me if I place the transform. That does work if I place the rigidbody at spawn, but then this body is interpolated from it’s old, prespawned position to the spawn position.
Okay, sounds like RB enable/disable is the answer.
Edit: What do you mean by ‘activate it’? Enable the Simulation for the rigidbody?
Also, how would one teleport an active object to a new position with interpolation enabled on the rigibody? Simply setting its position will interpolate to the new position. Would you have to disable interpolation, move it, and the next frame enable interpolation?
This just cannot be true. The Rigidbody2D when created has to be told what position, it gets this from the transform. Just the same as when you add a Rigidbody2D, it reads the transform.
You’re mixing words here and I don’t know what you mean. What does “place the rigidbody at spawn” mean? Can you use specific Unity actions like activate the GameObject or use Rigidbody2D.position or something?
But you said you’re doing that above when you said “I place the pooled object there, activate the gameobject**”** so I’m more confused now!
I just saw your edit. Activate is a Unity term related to the GameObject i.e. SetActive. You’re not taking a Rigidbody2D out the pool surely, you’re taking the GameObject out the pool so I’m referring to that being activated. When you do that, all the components are activated too.
I don’t understand what the simulation on or off has to do with activation or pooling. Turning the simulation on a Rigidbody2D on or off doesn’t change anything apart from it being simulated or not. It’s irrelvant if the whole GameObject is inactive TBH.
I don’t know why you need to do this if it’s related to the above.
Maybe just describe what you’re doing to the GameObject when its in the pool. Do you use SetActive(false) in the pool then SetActive(true) when out of it? Surely you must otherwise you’ll have things like renderers working. Take it out the pool, set its Transform and call SetActive(true) on the GameObject. Everything will be at the Transform pose.
Okay, thanks for that. Enabling the GameObject is what sets the starting condition of the RB. I can’t honestly say I know what I’ve done to fix my issues, but everything seems to be working now. I can only guess I was enabling a gameobject on spawn before setting its position and I’ve swapped that round. Need to tidy up my code now!
That still leaves the issue of teleporting a gameobject while it is active and has interpolation enabled on its RB. If one fixedupdate it’s at (-2,5) and the next I set the RB’s position to (3,7), the graphic will move over the intervening Updates to slide into place, no?
Again, clarity requried. In the scenario above, how are you setting the Rigidbody2D position (Rigidbody2D.position, Rigidbody2D.MovePosition or Transform.position = xxx) and are you always talking about doing so in the FixedUpdate which is just prior to the simulation step?
Simple test. Obj has a rigidbody2D and interpolation set to Interpolate. Fixed Timestep = 0.1, 10 fps fixedUpdate cycle. Updating the position every two seconds by a coroutine:
public class test : MonoBehaviour {
public GameObject obj;
Rigidbody2D _rb;
Transform _trans;
void Start(){
_rb = obj.GetComponent<Rigidbody2D>();
_trans = obj.transform;
InvokeRepeating("SetRandomPos", 0, 2);
}
void SetRandomPos() {
// _rb.MovePosition(Random.insideUnitCircle * 4);
_trans.position = Random.insideUnitCircle * 4;
}
}
If I use rb.position or rb.MovePosition, the object is tweened. If I use _trans.position, the object teleports, but the advice is “Don’t ever modify the Transform if using 2D physics components.”
So a different scenario then to what you asked before. Please, you have to understand that you keep asking different things but to you they are the same.
You don’t need these scenarios though. It doesn’t matter what the time-step is or FPS or A being a child or B or update every two seconds or what colliders or that it’s a Monday.
It’s as simple as:
You set the Transform. Doesn’t matter when. The Transform is updated but nothing else in Unity nor Physics knows about it. When the simulation runs, the Rigidbody2D will see the Transform change and be forced to instantly change to that position before the simulation runs. The simulation runs and the Rigidbody2D writes its position/rotation to the Transform.
You use Rigidbody2D.MovePosition. Nothing happens there and then. The Transform hasn’t changed. When the simulation runs, the Rigidbody2D has a temporary velocity calculated to move to that position. The simulation runs and Rigidbody2D moves/rotates. The Rigidbody2D writes its position/rotation to the Transform.
Interpolation is only setup when the simulation runs. It looks at the position/rotation of the Rigidbody2D and stores them as the last pose. The simulation runs and we have a current pose. The interpolation for the following frames, until the next simulation will interpolate.
If you write to Rigidbody2D.position or rotation during interpolation then the interpolation will stop until the next simulation step.
You are also taking this advice too far. This causes teleports and non-physical behaviour. You are then reading that, wanting to do non-physics behaviour per-frame or at an arbitrary frame which isn’t related to physics update and asking why you shouldn’t do it. That’s out of context.
Lots and lots of devs do this wrong. They poke around at the Transform position, set velocities, randomly use the Transform rotation and then ask, why is my physics not working or missing collision? Ths advice is, don’t modify the Transform.
If you want the Transform and the Rigidbody to both be instantly set to a position randomly in the world, independent of any simulation update or being completley ignorant of it and you are away you can cause overlaps this way then there’s nothing stopping you setting both the Transform and the Rigidbody2D. This doesn’t make the advice invalid though.
You are also allowed to set the physics to run per-frame. You can do that by going into the Physics 2D Settings and setting the Simulation mode to “Update”. That way, you get variable-rate physcis but interpolation is not required and completely ignored.
Much thanks for your time! One of the issues as a dev is advice is given piecemeal over the period of learning Unity and it doesn’t build into a cohesive picture until we’ve wrestled it into understanding. eg. Our first journey with Unity always begins with instantiating and destroying objects, but then we learn that’s really poor practice and we should be pooling!
It’s not always clear how the components fit together. For example, I am only using colliders for manual collision/overlap tests and I’m not using OnCollision/OnTrigger events, so I just added a Collider2D to my Transforms. I imagined every time I moved the transform the collider was just updated but they were getting left behind between object de/respawn. Then I read in your other thread that this is a Bad Idea as these triggers are assumed static and are reconstructed every frame! So then I added rigidbodies and moved these and my existing, beautifully smooth motion all went wonky.
Could I pester you for one last post on best practice? For people like me just wanting to use collision tests (collider overlap, ray cast, box cast, etc) and not have physics drive our motion or use physics events, how should we update our objects? Is it simply a case of adding a kinematic rb and collider to our objects, setting the Simulation Mode to “Update”, and move our transforms?
I totally understand and Unity is as much to blame for confusion as devs being confused. Best practices are not always something that’s as clear cut as it would seem to be. Sometimes it’s easier to state bad practices. Physics is a particular pain point because of the disconnection between render update and fixed-update. It’s there for a good reason, it’s not always clear of the implications.
I’m always available for pestering as long as you don’t mind my direct style of answering!
That’s exactly, to the letter how you should do it yes. If you want to explicitly move, use a Kinematic body. If you’re updating per-frame then interpolation is off and changes happen after the “Update” callback but before rendering.
Queries are always based upon the positions of Rigidbody2D. If you modify a Transform, it won’t affect positions. If you do "Rigidbody2D.position = " and then query, the query will work against that new position. If you use “MovePosition” then that will happen after the “Update” is called but before rendering.
You can also get contact information for Kinematic vs Static/Kinematic too if you turn on Rigidbody2D.useFullKinematicContacts. You obviously won’t get a collision response but you will get callbacks and you’ll be able to retrieve contacts, use “IsTouching” and “IsTouchingLayers” etc.
Sort of related but you can then have full control and can do overlap solving yourself. A rough example of that kind of move/slide and solve overlaps can be seen here: