0
\$\begingroup\$

I am trying to build a Tetris 3D game in Unity but I am stuck at getting the different blocks to interact (to detect each other, to sit one on top of the other rather than going through each other). I have set the ground with a box collider and the spwaned blocks come in with rigidbodies and trigger colliders.

This works for them to nicely settle on the ground but when I try to sit a block on top of another block they both have kinematic rigidbodies and the collision detection doesn't work and they end up overlapping. The problem is if I remove the rigidbody of the already settled block then it will go through the ground.

Any idea how to get 2 spawned objects to detect each other?

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

public class moveBlock : MonoBehaviour
{    
    public static float speed = 2;
    public GameObject[] blocks;
    public static List<GameObject> blocksSpawned = new List<GameObject>();
    public static List<Rigidbody> blocksRBSpawned = new List<Rigidbody>();
    public static bool triggerPlatform = true;
    Rigidbody rb;

    void Update()
    {
        Vector3 input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
        Vector3 direction = input.normalized;
        Vector3 velocity = direction * speed;
        Vector3 moveAmount = velocity * Time.deltaTime;

        if (triggerPlatform)
        {
            blocksSpawned.Add((GameObject)Instantiate(blocks[Random.Range(0, 7)], new Vector3(0, 6, 0), Quaternion.Euler(Vector3.right)));
            rb = blocksSpawned[blocksSpawned.Count - 1].GetComponent<Rigidbody>();
            blocksRBSpawned.Add(rb);
            triggerPlatform = false;
        }
        /*if (!triggerPlatform)
        {
            Destroy(blocksRBSpawned[blocksRBSpawned.Count - 1]);
        }*/
        if (blocksSpawned[blocksSpawned.Count - 1] != null)
        {
            blocksSpawned[blocksSpawned.Count - 1].transform.Translate(Vector3.down * Time.deltaTime*speed, Space.World);
            blocksSpawned[blocksSpawned.Count - 1].transform.Translate(moveAmount);
        }
    }
}

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

public class trigger : MonoBehaviour
{    
    private void OnTriggerEnter(Collider other)
    {
        moveBlock.triggerPlatform = true;
    }
}

enter image description here

\$\endgroup\$
7
  • 1
    \$\begingroup\$ You're making the common mistake of bypassing the physics engine with Transform.Translate, then still expecting physics to work. If you want physical behaviour, you need to manipulate your rigidbodies with velocities, forces, or (if you're careful) MovePosition() calls. \$\endgroup\$
    – DMGregory
    Jul 20, 2020 at 16:48
  • \$\begingroup\$ @DMGregory He's using kinematic Rigidbodies; isn't manually moving the objects acceptable in this case? \$\endgroup\$
    – Kevin
    Jul 21, 2020 at 0:50
  • \$\begingroup\$ Not quite, because OP also wants to fire collision events. Kinematic bodies won't fire OnCollisionEnter events when they touch static or kinematic bodies, and if the colliders are set to be triggers the collision won't stop the bodies' movement. Even in that case, MovePosition would be preferable to Translate. \$\endgroup\$
    – DMGregory
    Jul 21, 2020 at 0:56
  • \$\begingroup\$ @mavish Kinematic Rigidbodies don't behave like Rigidbodies in most ways. They ignore forces, as I assume you've already noticed since you implemented your own gravity manually. They aren't affected by collisions with other Rigidbodies, and as DMGregory noted they won't fire OnCollisionEnter if they collide with another kinematic Rigidbody. There are only a few highly specific scenarios where it really makes sense to use kinematic Rigidbodies. If you want your objects to fall and collide using the normal physics engine, uncheck "Is Kinematic". \$\endgroup\$
    – Kevin
    Jul 21, 2020 at 1:11
  • \$\begingroup\$ @mavish If you want to use your own gravity code, you should also uncheck "use gravity". If you want to make sure the physics engine will only move the blocks down and never sideways, check the "Freeze Position" boxes for "X" and "Z". \$\endgroup\$
    – Kevin
    Jul 21, 2020 at 1:14

1 Answer 1

1
\$\begingroup\$

From your screenshot I see that you are using kinematic Rigidbodies. Kinematic Rigidbodies don't behave like Rigidbodies in most ways.

  • They ignore forces, as I assume you've already noticed since you implemented your own gravity manually.
  • They aren't moved or otherwise physically affected by collisions with non-kinematic Rigidbodies
  • As DMGregory noted, they won't fire OnCollisionEnter if they intersect with another kinematic Rigidbody. As far as the physics engine is concerned, two kinematic Rigidbodies cannot collide with one another.

There are only a few highly specific scenarios where it really makes sense to use kinematic Rigidbodies.

If you want your objects to fall and collide using the normal physics engine, uncheck "Is Kinematic".

If you want to keep using your own gravity code, you'll need to also uncheck "Use gravity". If you go that route, you should move the objects in FixedUpdate() instead of Update() since the former is in step with the physics engine and is a safer place to move physics objects. As DMGregory noted, Rigidbody.MovePosition() is a safer function to use for manually moving physics objects. Also, if you keep using your own gravity code, you should disable the MoveBlock component once it lands; otherwise it's going to waste CPU cycles trying to move downward for every fixed update for the rest of the game.

If you use standard (non-kinematic) Rigidbodies and want to ensure that the physics engine is only allowed to move the objects directly downward (preventing any lateral motion), check the boxes under "Freeze Position" for "X" and "Z". This will ensure that the physics engine only moves the Rigidbody along the vertical (y) axis. I believe you're still free to manually move it along the X and Z axes from your code.

Alternatively you could throw out the physics engine, remove the Rigidbody components, and write your own code for determining when the blocks have landed; however, I'd expect that to be more involved than using the physics engine correctly.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .