TransWikia.com

Tetris block kinematic rigidbodies pass through one another with Transform.Translate

Game Development Asked on November 2, 2021

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

One Answer

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.

Answered by Kevin on November 2, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP