0
votes

I know the title isnt very explanatory, but here's my problem:

I have a player (merely a cube with a rigidbody, a collider and a movement script), and I have a floor made of small 1 by 1 by 1 cubes (cubes with box colliders).

For some reason unknown to me, when my player cube falls and tries to collide horizontally with the floor, he just phases through... But want him to get blocked by the cubes just like it does vertically. Any help would be greatly appreciated ;)

heres how the scene looks like

heres a cube object

heres the player object

Here's a gif of the player going through the floor

Here's my c# player movement script (I know its very bad, but I prefer to put this here just in case its linked to my problem) :

void ApplyMovement()
{        

 transform.position += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

}

If you need any more info to help me just tell me, I'll provide it as fast as I can.

3
Do you attach the rigidbody component for both your cube and player?MT-FreeHK
No, I only added a ribidbody to the player. I already tried adding a rigidbody to the cubes, but to no avail.Thomas Bergeron
Let's see the rest of your PlayerMovement script. Directly manipulating transform.position leads to issues like this (you should instead be either applying forces or manipulating the velocity of the Rigidbody so the physics engine can do its thing). And FWIW, you wont need Rigidbody components on the floor. That's for allowing the physics engine to manipulate an GameObject's movement and the BoxColllider they already have is sufficient for them to act as a static "floor."Foggzie

3 Answers

1
votes
  1. The value of

    new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))
    

    is framerate-dependent. This means the faster the framerate the faster your object will move. This is usually not what you want. Instead use Time.deltaTime

    // Adjust the speed in the inspector
    public float speedMultiplicator = 1;
    
    //...
    
    new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * speedMultiplicator * Time.deltaTime
    

    to get a framerate-independent movement. Also see the example in Input.GetAxis.

  2. When dealing with RigidBody never change the transform.position (and rotation) directly!

    If you would want to make the RigidBody jump to a certain position rather use

    rigidBody.position = transform.position + ...;
    

    However what you want is a smooth movement in order to keep the collision detection intact. So you should use RigidBody.MovePosition instead

    rigidBody.MovePosition(transform.position + ...);
    

    You don't have to deal with force etc.

  3. Also add a RigidBody component to the floor objects. Even ifnthe object is not moving this improves the collision detection (at the cost of performance in the Physics engine ofcourse). And since the objects are not supposed to move set

    • isKinematic -> true
    • use Gravity -> false

    you can also set freeze position and freeze rotation.

  4. On both floor and player objects set Collision Detection -> Continous Dynamic.
    This improves the collision detection and looks for collisions also between frames.
    Be aware, however, that dynamic detection is quite expensive so use it only if there is still trouble with too fast objects.

  5. On the player you might want to also use interpolate as well.

  6. Finally

    Note that continuous collision detection is intended as a safety net to catch collisions in cases where objects would otherwise pass through each other, but will not deliver physically accurate collision results, so you might still consider decreasing the fixed Time step value in the TimeManager inspector to make the simulation more precise, if you run into problems with fast moving objects.

For more information see the RigidBody manual and the Colliders manual

0
votes

I recreated the scenario you described on my end. I put your "ApplyMovement" code in "Update". I was basically able to reproduce your results.

It seems to me that the issue might be Freezing Position X/Z on the Player. I think since you are doing that, you're telling the Rigidbody component that it is not allowed to modify the X/Z positions of the objects as part of it's collision resolution and physics simulation. When I turn those two off, I get results that are (I think) closer to what you're looking for.

One note: your "ApplyMovement" code is frame-locked, meaning your player will move at different speeds at different frame rates. To solve this, you'd need to multiply your Input.GetAxis values by Time.deltaTime.

Also, if your player moves too fast, it'll still be able to pass through collisions and cause odd behavior, so be sure to limit the max movement rate of the player to some reasonable value.

0
votes

You should be applying a force to the Rigidbody of the character instead of directly manipulating the transform.position (this is preventing the physics engine from resolving the collisions). You're also freezing the X and Z position on the Rigidbody; you don't want that because it entirely prevents the Rigidbody from manipulating those values.

Instead of transform.postion += ... first get a reference to the Rigidbody somewhere in your script (best done in an Awake() method):

private Rigidbody _body;
private void Awake() {
    _body = GetComponent<Rigidbody>();
}

Then make sure the vector built from your inputs is being applied to the object's "movement," not its position:

Vector3 inputVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
// You can multiply this vector by a float to adjust "speed"

_body.ApplyForce(inputVector, ForceMode.VelocityChange);

Finally, you should read up on the different ForceMode options and decide which one fits your preferences: https://docs.unity3d.com/ScriptReference/ForceMode.html

Don't forget this should happen in a FixedUpdate(), not an Update() (all physics operations should be done in FixedUpdate())


As a side note, there is also the possibility your rigidbodies still up moving too quickly and passing through each-other. Even when you're using forces and velocities, this is possible so if your run into this case down the line, investigate Collision Detection Modes. TLDR; they're settings for performance vs accuracy trade-offs.