Here is how my scene is designed:
Player on top of the lily pad
Player can pull pads and when they are close jump onto them. Lily pad is tied to one point using target joint, so whenever player stops pulling it, it returns to initial point. Player can freely move inside of current lily pad.
// LilyPad.cs
public class LilyPad : MonoBehaviour {
private Vector2 _targetPosition;
private Rigidbody2D _rb;
[SerializeField] private float speed;
[SerializeField] private float pullForce = 10f;
private bool _pull;
private Vector2 _seed;
private void Start() {
_rb = GetComponent<Rigidbody2D>();
_targetPosition = transform.position;
}
public void Pull(Vector2 target) {
_pull = true;
_targetPosition = target;
_force.relativeForce = Vector2.zero;
}
public void Leave() {
_pull = false;
}
private void FixedUpdate() {
if (_pull) {
var direction = (_targetPosition - (Vector2) transform.position).normalized;
_rb.AddForce(direction * pullForce);
}
}
}
There are Pull method to start pulling lily pad to player position and Leave to stop pulling.
// Jump.cs (on the player)
public class Jump : MonoBehaviour {
private LilyPad _currentPad;
private float startDistance, distance;
[SerializeField] private float maxJumpDistance = 4f;
private Transform root;
private Vector2 prevPosition;
private Rigidbody2D _rb;
private void Start() {
_rb = GetComponent<Rigidbody2D>();
_pc = GetComponent<PlayerController>();
PlayerController.systemActions.SkillsMap.skill2.started += HandleSkill;
}
private void HandleSkill(InputAction.CallbackContext callbackContext) {
if (!Selectable.selected) return;
if (Vector2.Distance(transform.position, _currentPad.transform.position) <= maxJumpDistance) {
transform.position = _currentPad.transform.position;
root = _currentPad.transform;
transform.SetParent(root);
prevPosition = root.position;
}
}
private void Update() {
// Translate variant
if (root) {
var movement = (Vector2) root.position - prevPosition;
prevPosition = root.position;
transform.Translate(movement);
}
// Pulling logic
if (!Selectable.selected) {
if (_currentPad) _currentPad.Leave();
_currentPad = null;
return;
}
if (_currentPad && Selectable.selected != _currentPad.gameObject) {
_currentPad.Leave();
return;
}
if (!(_currentPad = Selectable.selected.GetComponent<LilyPad>())) return;
if (PlayerController.systemActions.SkillsMap.skill1.IsPressed() && root.gameObject != _currentPad.gameObject)
_currentPad.Pull(transform.position);
else _currentPad.Leave();
}
private void FixedUpdate() {
// MovePosition variant
if (root) {
var movement = (Vector2) root.position - prevPosition;
prevPosition = root.position;
_rb.MovePosition(_rb.position + movement);
}
}
}
Here i have Update method for pulling and HandleSkill for jumping onto lily pad.
The problem is, i need player to move with current lily pad, when it returns by target joint, or any other source of movement (generated by rigidbody) that i can come with in future.
And i need also common player movement by wasd while he is on top of the moving lily pad.
To be clear, pads collider is now disabled for any interactions with a player.
I tried different ways of moving player, including rb2d.velocity and rb2d.MovePosition.
I of course can move player manually using transform.Translate, but that somehow causes slow movement speed when lily pad is moving too.
Also i tried make current pad a parent of player`s transform, but any rigidbody movement except MovePosition does not pass to children. So basically i need physics movement while object i stand on is moving too.