#Bro what I tried so hard to get smooth movement how’d you do it
1 messages · Page 1 of 1 (latest)
For this
well for one it looks like they're using the gridless entity flag, which would be problematic when placing them by hand
- No gridless flag. In fact, there are no changes to existing prototypes at all.
- The movement for grid-based entities isn't actually smooth. It only looks that way because the velocity is very high.
- It is very performance heavy though. Especially for entities without
unit_number(so e.g. trees/rocks)
Source code for reference: https://github.com/k2aj/fq-core/blob/master/fq-core/runtime/motion.lua
How the motion works (simplified version):
- Any entity can have a
MotionComponentattached to it. MotionComponentis basically a table which stores a velocity vector (vx,vy)- Whenever the mod applies knockback to an entity, it looks up the
MotionComponentattached to that entity and adds the knockback vector to the velocity vector in thatMotionComponent. - Every tick I loop through all the
MotionComponentsand their associated entities:- I simulate motion by teleporting the entity to
{x=x+vx, y=y+vy}wherex,yis the position of the entity andvx,vyis the velocity vector from the attachedMotionComponent - Then I simulate drag by multiplying
vx,vyby 0.9 (this is why moving entities stop smoothly)
- I simulate motion by teleporting the entity to
The actual, ugly version:
The above simplified version causes entities to phase through walls because LuaEntity.teleport() doesn't care where you teleport something.
- To avoid that I use
LuaSurface.find_non_colliding_position()to check if the location where I teleport the entity is already occupied by something.- If the teleport location is occupied, I remove the
MotionComponentfrom the entity (which stops the movement). - Except that doesn't actually work correctly, because for small velocities
find_non_colliding_position()always fails, because it thinks the entity would collide with itself. - To avoid that I teleport the entity 100 tiles away before calling
find_non_colliding_position(), then teleport it back.
- If the teleport location is occupied, I remove the
- Except at high velocities that doesn't help either, because the entity could e.g. end up on one side of a wall at tick
N, then on another side of the same wall at tickN+1. So wall phasing would still happen.- To avoid that I don't apply the relative teleportation by
{+vx, +vy}all at once, but do it in multiple small steps instead.
- To avoid that I don't apply the relative teleportation by
Also a bunch of optimisations:
- Entities never have more than one motion component (to reduce lag). Any additional knockback/recoil just increases the velocity vector on the existing motion component.
- I remove the
MotionComponentfrom an entity if the velocity vector gets too low due to drag. (otherwise they would accumulate until you get lagged to death).