Collisions do not interact properly

I’m in the game where I’m making a piston and physics are playing tricks on me. After pressing the button, the piston goes up and (it should) also raise the cube on it. But it does not happen … The cube will move next to it. I don’t know why this is happening because all objects have the required coliders.

I added a video, some of my code and information from the inspector.

Piston script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Piston : MonoBehaviour
{
    public float speed = 2f;

    [HideInInspector]
    public bool up = false;

    Vector3 pos = new Vector3();
    Vector3 velocity = Vector3.zero;
    Transform liftObj;

    float defaultPosition = -0.515f;
    float liftPosition = 2.475f;

    private void Start()
    {
        liftObj = transform.GetChild(0);
        liftObj.localPosition = velocity + new Vector3(0, 0.535f, 0);
        pos = liftObj.position;
    }

    private void Update()
    {
        liftObj.position = Vector3.SmoothDamp(liftObj.position, pos, ref velocity, speed * Time.deltaTime);
    }

    public void tooglePiston()
    {
        if (up == false)
        {
            pos.y = liftPosition;
            up = true;
        }
        else
        {
            pos.y = defaultPosition;
            up = false;
        }
    }
}

Cube

I will be grateful for your help : )

IMO this is caused by two things:

1) Transform changes + collision detection = :frowning:
If you want to use physics, you need to let the simulation to detect collisions in a proper way. For example, you can move the piston by setting the rigidbody velocity:

// I'm assuming you have a rigidbody reference already defined (rb)
private void FixedUpdate()
{
        var position = Vector3.SmoothDamp(liftObj.position, pos, ref velocity, speed * Time.deltaTime);
      
        // Use the displacement
        rb.velocity = (position - liftObj.position) / Time.deltaTime;

       // Or use the SmoothDamp velocity
       // rb.velocity = velocity;
}

This won’t probably fix the issue but it is a general good advice.

2) MoveCube.cs
I’m not sure what this script is doing. The cube y position seems to be limited somehow. Are you setting this value?
Even if you ignore 1), the cube should be pushed upwards a bit. Nevertheless, the video shows a very unnatural response to me.

1 Like

Thanks for the answer. I handled it myself somehow, but thanks anyway.

I solved the problem almost identically.

private void FixedUpdate()
    {
        Vector3 velocity = Vector3.zero;
        Vector3 pos;
        float pistonSpeed;

        if (cubeOnPiston && piston)
        {
            if (pistonUp)
            {
                pos = transform.position + new Vector3(0, 2.475f, 0);
            } else
            {
                pos = transform.position + new Vector3(0, -0.515f, 0);
            }

            pistonSpeed = piston.speed;

            transform.position = Vector3.SmoothDamp(transform.position, pos, ref velocity, pistonSpeed * Time.deltaTime);
        }
    }

To be clear, you should NOT be modifying the Transform. The Rigidbody or Rigidbody2D do this, it’s your proxy to the Transform. The Transform isn’t the pose the physics engine is using, that’s stored in the Rigidbody(2D) itself. The Transform is for visuals only, it’s not the authority here. Get changes done via the Rigidbody(2D) component.

A good example is interpolation. The Transform will be moving from the old Rigidbody position to the current one i.e. be historic. Reading it won’t give you the real position.

All you end up doing is causing overlaps that the physics engine has to then solve. This leads to jittering/fighting over positions etc.

If you want explicit positional control then it needs to be a Kinematic Rigidbody and you should be using Rigidbody.MovePosition.

It might be “solved” from your POV but that doesn’t mean it’s something you should be doing moving forward and won’t cause you problems. You are free of course to do it however you want.