0
\$\begingroup\$

I've got a 3D cube in a scene, and rotatable using arrow keys. This is what it looks like, imagine that the boxes are left, right, up, and down.

enter image description here

Unlike other questions, I am not casting a ray cast at the cube directly, though I am trying to do this to figure out what face is facing the camera.

I want to be able to figure out what face is facing the camera, and when the arrows are what trigger the movement 90' in a given direction.

Once I listen for the arrows moving left or right, I try to cast a Raycast directly at the cube - but it doesn't seem to hit anything or make a difference if I use a 2D or 3D raycast. My scene is in 2D, but my cube is 3D. What am I doing wrong?

Here is my code:

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

public enum MCFace
{
    None,
    Up,
    Down,
    East,
    West,
    North,
    South
}

public class CubeHandling : MonoBehaviour
{
    private void OnEnable()
    {
        TouchScreenManager.SignalButton += CheckCubeFace;
    }

    private void OnDisable()
    {
        TouchScreenManager.SignalButton -= CheckCubeFace;
    }

    void CheckCubeFace(GameObject arrow)
    {
        if (arrow.name == "Left" || arrow.name == "Right")
        {
            // now cast another raycast at the cube
            var position = new Vector3(gameObject.transform.position.x, gameObject.transform.position.y, 0);
            Ray ray = Camera.main.ScreenPointToRay(gameObject.transform.position);

            Physics.Linecast(Camera.main.transform.position, position, out RaycastHit hit);
            Debug.Log("the ray is: " + ray + " and the hit is  " + hit);

            var face = GetHitFace(hit);
            Debug.Log(face);
        }
    }

    public MCFace GetHitFace(RaycastHit hit)
    {
        Vector3 incomingVec = hit.normal - Vector3.up;

        if (incomingVec == new Vector3(0, -1, -1))
            return MCFace.South;

        if (incomingVec == new Vector3(0, -1, 1))
            return MCFace.North;

        if (incomingVec == new Vector3(0, 0, 0))
            return MCFace.Up;

        if (incomingVec == new Vector3(1, 1, 1))
            return MCFace.Down;

        if (incomingVec == new Vector3(-1, -1, 0))
            return MCFace.West;

        if (incomingVec == new Vector3(1, -1, 0))
            return MCFace.East;

        return MCFace.None;
    }
}

Edit: I have now transformed the normal into the object's local space, which seems to be working. However, note that my arrows are meant to do the following - left and right will move the block both sides on the y axis. Up and down will move it on the x axis.

However, there now appears to be a problem synching up all of the movements so the faces stay consistent no matter what order the arrows are pressed in.

If the front-facing side is "West", and I press the left arrow, I will see the following movement:

West > North > East > South

However, if I now press the right arrow, it does this:

South > West > South > East > North, etc.

I am not sure why it would repeat itself, and indicate faces out of order.

This may be to do with how I am rotating my cube:

IEnumerator RotateCube(GameObject UI)
    {
        float timeElapsed = 0;
        Quaternion startRotation = cube.transform.rotation;
        Quaternion targetRotation = cube.transform.rotation;

        if (gameObject.name == "Up" || gameObject.name == "Down")
        {
            targetRotation *= Quaternion.Euler(angleRotation, 0, 0); // this rotation depends on the face. sometimes it'll be rotating on the y-axis, other times on the z. 
        } else
        {
            targetRotation *= Quaternion.Euler(0, angleRotation, 0);
        }

        while (timeElapsed < lerpDuration)
        {
            cube.transform.rotation = Quaternion.Slerp(startRotation, targetRotation, timeElapsed / lerpDuration);
            timeElapsed += Time.deltaTime;
            yield return null;
        }
        cube.transform.rotation = targetRotation;
    }

\$\endgroup\$
5
  • \$\begingroup\$ You can't use a 2D physics system to get a hit on a 3D collider. You'd need to use the 3D physics system for that. \$\endgroup\$
    – DMGregory
    Commented Nov 3, 2022 at 17:37
  • \$\begingroup\$ I've tried that too. For some reason, it keeps returning "South." I have tried debugging by laying a quad on one surface to follow the texture. and rotating the block, it looks like the surface keeps turning up on the block facing the camera. I have followed this gamedev.stackexchange.com/questions/203171/… to create the cube, I wonder if that might affect it somehow? \$\endgroup\$ Commented Nov 3, 2022 at 17:56
  • \$\begingroup\$ You're shooting a ray at the face that's pointing toward the camera. Since the camera is "South" of the cube, you will always get a normal that points sourth in worldspace. Your raycast couldn't give you anything else. Did you mean to transform the normal into the object's local space, to determine which way the side faces in the original cube mesh? \$\endgroup\$
    – DMGregory
    Commented Nov 3, 2022 at 20:05
  • \$\begingroup\$ Right, how silly of me. Yes, that's exactly what I was trying to do, but I'm not sure how to do that. \$\endgroup\$ Commented Nov 3, 2022 at 20:48
  • \$\begingroup\$ If you're willing to change your enum layout, you could use the solution shown here. \$\endgroup\$
    – DMGregory
    Commented Nov 3, 2022 at 23:26

1 Answer 1

1
\$\begingroup\$
MCFace GetSideFacing(Transform cube, Vector3 direction) {
    var localDirection = cube.InverseTransformDirection(direction);

    var positive = Vector3.Scale(localDirection, localDirection);

    if (positive.x > positive.y) {
        if (positive.x > positive.z) {
            return localDirection.x > 0 ?
                   MCFace.East : MCFace.West;
        } else {
            return localDirection.z > 0 ?
                   MCFace.North : MCFace.South;
        }
    } else {
        if (positive.y > positive.z) {
            return localDirection.y > 0 ?
                   MCFace.Up : MCFace.Down;
        } else {
            return localDirection.z > 0 ?
                   MCFace.North : MCFace.South;
        }
    }

}

Now you can skip the raycast and just call:

GetSideFacing(cube.transform,
     Camera.main.transform.position - cube.position);

Of course, since you're controlling this cube in 90 degree increments, you could also just keep track of which face is pointing which way as part of your rotation logic.

\$\endgroup\$
12
  • \$\begingroup\$ Thanks very much for this - for the var positive = Vector3.scale, did you mean to pass the same arguments in twice? Or did you mean localDirection, direction? \$\endgroup\$ Commented Nov 6, 2022 at 14:47
  • \$\begingroup\$ I did indeed mean what I wrote. This squares each component so you get positive values throughout, and it's less typing than taking the absolute value for each one. ;) \$\endgroup\$
    – DMGregory
    Commented Nov 6, 2022 at 15:19
  • \$\begingroup\$ I understand, thank you! One question, it does work when I implement this of course, which is great. However, if I turn it in 90 degree increments to the left, and then suddenly turn it back to the right with the other arrow, it then messes up the order - all the faces seem to get jumbled up. I'm not sure if I should keep a record of the face somewhere, but I'm not sure why that would even happen. Would you know what I might be doing wrong? \$\endgroup\$ Commented Nov 6, 2022 at 15:21
  • \$\begingroup\$ I don't have a reproducible test case to try, so I can't comment until you share enough information to reproduce the problem. I'll need a symptom more specific than "seem to get jumbled up" - what output do you expect, and what output do you get instead? \$\endgroup\$
    – DMGregory
    Commented Nov 6, 2022 at 15:26
  • \$\begingroup\$ Apologies. I've added more information above, and will try to edit the question even more so you might have more insight into this. \$\endgroup\$ Commented Nov 6, 2022 at 15:33

You must log in to answer this question.

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