- Home /
Detect face of cube clicked
Does anyone know a script where you can detect the face of an cube clicked and perform an action on it? Or can anyone write one that does that?
I'm guessing it's something to do with Raycasting.
Thanks
You have to be more specific. Other people write 1 page questions so you can understand what he want to do and where the problems are. You sound like you just asking for free code...
You have to do your stuff on your own. If you have problems you can ask a question.
Answer by Ultimationz · May 26, 2015 at 09:56 PM
You can detect the side of the cube via the following algo
public enum MCFace
{
None,
Up,
Down,
East,
West,
North,
South
}
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;
}
Demo Video Bellow: https://dl.dropboxusercontent.com/u/53593879/ShareX/2015/05/2015-05-26_20-20-16.mp4
Thanks for this. But, I noticed clicking on the underside of a block did not work, since it returned None.
To get GetHitFace to return Down, had to change the following...
if (inco$$anonymous$$gVec == new Vector3(0, -2, 0))
Answer by Bunny83 · Jun 11, 2011 at 12:24 PM
Just some things you might need:
Input.GetMouseButtonDown to detect the mousclick
Camera.main.ViewportPointToRay to get a ray from the center of your camera
Physics.Raycast to perform a raycast against the scene
RaycastHit.triangleIndex to retrieve the index of the triangle you've hit.
Mesh to get access to the actual mesh (vertices,triangles)
Take a closer look at RaycastHit. It provides a lot information (hitpoint, surfacenormal, uvposition, barycentric coordinates,...).
Meshes don't have faces (from techincal view) they are made of triangles. So a cube-side is made of 2 triangles.
Answer by dju4ic · Jun 11, 2011 at 04:16 PM
Using Raycasting: (I am also using a Mesh collider on a cube as opposed to the original box collider).. Hopefully this will save from the guessing game i had to go through. Remember though, this will only work for normal cubes of any size.
if (triIndex == 0 || triIndex == 1) {
Debug.Log ("Creating On: front - Of: " + myhit.collider.gameObject.name);
clone = Instantiate(toCreate, new Vector3 (xRndd, yRndd, (zRndd+1)), Quaternion.identity) as GameObject;
}
if (triIndex == 2 || triIndex == 3) {
Debug.Log ("Creating On: top - Of: " + myhit.collider.gameObject.name);
clone = Instantiate(toCreate, new Vector3 (xRndd, (yRndd+1), zRndd), Quaternion.identity) as GameObject;
}
if (triIndex == 4 || triIndex == 5) {
Debug.Log ("Creating On: back - Of: " + myhit.collider.gameObject.name);
clone = Instantiate(toCreate, new Vector3 (xRndd, yRndd, (zRndd-1)), Quaternion.identity) as GameObject;
}
if (triIndex == 6 || triIndex == 7) {
Debug.Log ("Creating On: bottom - Of: " + myhit.collider.gameObject.name);
clone = Instantiate(toCreate, new Vector3 (xRndd, (yRndd-1), zRndd), Quaternion.identity) as GameObject;
}
if (triIndex == 8 || triIndex == 9) {
Debug.Log ("Creating On: right - Of: " + myhit.collider.gameObject.name);
clone = Instantiate(toCreate, new Vector3 ((xRndd-1), yRndd, zRndd), Quaternion.identity) as GameObject;
}
if (triIndex == 10 || triIndex == 11) {
Debug.Log ("Creating On: left - Of: " + myhit.collider.gameObject.name);
clone = Instantiate(toCreate, new Vector3 ((xRndd+1), yRndd, zRndd), Quaternion.identity) as GameObject;
}
For that task it's a bit overkill to use the triangle index...
You can use the hit normal to get the direction the side is facing. No need for such an if chain (which should at least have "else if"). Also the hit normal works with any type of colliders and is much less code. But you can't say what the OP wants to do...
understood, I just ripped this out of some commented code i had, and have it modified for some non-absolute objects. There are definitely too many variables still open that need to be accounted for in the OP. Everything is in the examples on the scripting resource as well as other postings on here. Reading up on raycasting in general should get you in the right direction
Answer by GXMark · Jan 31, 2017 at 02:43 PM
Here is another example of using the following game object format
gameobject side0 side1 side_n
It combines meshes for shared materials. Built in face detection code with simple API
Initialise() Setup shared material for all sides SetSharedMaterial() The material that will be used for the shared material AddSelectables() Array of game objects e.g. side0, side1 which are selectable faces RemoveSelectables() Array of game objects which are deselected faces SelectableFaces() Returns the selectable faces DetectFace() Takes a raycast and mesh collider from some input manager and returns the gameobject hit
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FaceSelection : MonoBehaviour
{
private List<MeshFilter> _combinedMeshFilters = new List<MeshFilter>();
private Material _sharedMaterial = null;
// Use this for initialization
void Start ()
{
Initialize();
}
/*
void Update()
{
if (Input.GetKeyDown(KeyCode.Alpha1))
AddSelectables(new GameObject[] { GameObject.Find("Barrel_6Sided_5Mat/Side") });
if (Input.GetKeyDown(KeyCode.Alpha2))
AddSelectables(new GameObject[] { GameObject.Find("Barrel_6Sided_5Mat/Top") });
if (Input.GetKeyDown(KeyCode.Alpha3))
AddSelectables(new GameObject[] { GameObject.Find("Barrel_6Sided_5Mat/BevelTop") });
if (Input.GetKeyDown(KeyCode.Alpha4))
RemoveSelectables(new GameObject[] { GameObject.Find("Barrel_6Sided_5Mat/Side") });
if (Input.GetKeyDown(KeyCode.Alpha5))
RemoveSelectables(new GameObject[] { GameObject.Find("Barrel_6Sided_5Mat/Top") });
if (Input.GetKeyDown(KeyCode.Alpha6))
RemoveSelectables(new GameObject[] { GameObject.Find("Barrel_6Sided_5Mat/BevelTop") });
/*
if (Input.GetKeyDown(KeyCode.Alpha2))
AddSelectables(new GameObject[] { GameObject.Find("Cube/Back") });
if (Input.GetKeyDown(KeyCode.Alpha3))
AddSelectables(new GameObject[] { GameObject.Find("Cube/Top") });
if (Input.GetKeyDown(KeyCode.Alpha4))
AddSelectables(new GameObject[] { GameObject.Find("Cube/Bottom") });
if (Input.GetKeyDown(KeyCode.Alpha5))
AddSelectables(new GameObject[] { GameObject.Find("Cube/Left") });
if (Input.GetKeyDown(KeyCode.Alpha6))
AddSelectables(new GameObject[] { GameObject.Find("Cube/Right") });
if (Input.GetKeyDown(KeyCode.Alpha7))
RemoveSelectables(new GameObject[] { GameObject.Find("Cube/Front") });
if (Input.GetKeyDown(KeyCode.Alpha8))
RemoveSelectables(new GameObject[] { GameObject.Find("Cube/Back") });
if (Input.GetKeyDown(KeyCode.Alpha9))
RemoveSelectables(new GameObject[] { GameObject.Find("Cube/Top") });
if (Input.GetKeyDown(KeyCode.Alpha0))
RemoveSelectables(new GameObject[] { GameObject.Find("Cube/Bottom") });
if (Input.GetKeyDown(KeyCode.Minus))
RemoveSelectables(new GameObject[] { GameObject.Find("Cube/Left") });
if (Input.GetKeyDown(KeyCode.Equals))
RemoveSelectables(new GameObject[] { GameObject.Find("Cube/Right") });
}
*/
/// <summary>
/// Initialize all faces to a shared material
/// </summary>
public void Initialize()
{
_combinedMeshFilters.Clear();
foreach (Transform t in gameObject.transform)
if (t.GetComponent<MeshRenderer>() != null)
_combinedMeshFilters.Add(t.gameObject.GetComponent<MeshFilter>());
if (_sharedMaterial == null)
{
_sharedMaterial = new Material(Shader.Find("Standard"));
_sharedMaterial.color = Color.red;
}
CombineMeshes(gameObject);
}
/// <summary>
/// Set the shared material
/// </summary>
public void SetSharedMaterial(Material material)
{
_sharedMaterial = material;
CombineMeshes(gameObject);
}
public GameObject DetectFace(RaycastHit hit, MeshCollider meshCollider)
{
Transform[] transforms = gameObject.GetComponentsInChildren<Transform>();
for (int i=0; i< transforms.Length; i++)
{
if (hit.collider.gameObject == transforms[i].gameObject)
{
Debug.Log("Object Hit = " + transforms[i].gameObject.name + " Tri Index = " + hit.triangleIndex);
return transforms[i].gameObject;
}
}
/*
Mesh mesh = meshCollider.sharedMesh;
Vector3[] vertices = mesh.vertices;
int[] triangles = mesh.triangles;
Vector3 p0 = vertices[triangles[hit.triangleIndex * 3 + 0]];
Vector3 p1 = vertices[triangles[hit.triangleIndex * 3 + 1]];
Vector3 p2 = vertices[triangles[hit.triangleIndex * 3 + 2]];
Transform hitTransform = hit.collider.transform;
p0 = hitTransform.TransformPoint(p0);
p1 = hitTransform.TransformPoint(p1);
p2 = hitTransform.TransformPoint(p2);
Debug.DrawLine(p0, p1);
Debug.DrawLine(p1, p2);
Debug.DrawLine(p2, p0);*/
return null;
}
// Add selectable face objects
public void AddSelectables(GameObject[] obj)
{
bool combine = false;
for (int i = 0; i < obj.Length; i++)
{
MeshRenderer meshRenderer = obj[i].GetComponent<MeshRenderer>();
if (meshRenderer != null)
{
if (!meshRenderer.enabled)
{
MeshFilter meshFilter = obj[i].GetComponent<MeshFilter>();
if (_combinedMeshFilters.Contains(meshFilter))
{
_combinedMeshFilters.Remove(meshFilter);
combine = true;
}
meshRenderer.enabled = true;
meshRenderer.material = new Material(Shader.Find("Standard"));
MeshCollider meshCollider = obj[i].GetComponent<MeshCollider>();
if (meshCollider == null)
obj[i].AddComponent<MeshCollider>();
}
}
}
if (combine)
CombineMeshes(gameObject);
}
/// <summary>
/// Remove selectable face objects
/// </summary>
public void RemoveSelectables(GameObject[] obj)
{
bool combine = false;
for (int i = 0; i < obj.Length; i++)
{
MeshRenderer meshRenderer = obj[i].GetComponent<MeshRenderer>();
if (meshRenderer != null)
{
if (meshRenderer.enabled)
{
_combinedMeshFilters.Add(obj[i].GetComponent<MeshFilter>());
MeshCollider meshCollider = obj[i].GetComponent<MeshCollider>();
if (meshCollider != null)
GameObject.DestroyImmediate(meshCollider);
combine = true;
}
}
}
if (combine)
CombineMeshes(gameObject);
}
/// <summary>
/// Return selectable faces
/// </summary>
public GameObject[] SelectableFaces()
{
List<GameObject> objs = new List<GameObject>();
foreach (Transform t in gameObject.transform)
if (t.GetComponent<MeshRenderer>() != null)
objs.Add(t.gameObject);
return objs.ToArray();
}
/// <summary>
/// Combine meshes
/// </summary>
private void CombineMeshes(GameObject obj)
{
// Remove mesh and its renderer when all selectable faces are used
if (_combinedMeshFilters.Count == 0)
{
if (obj.GetComponent<MeshFilter>() != null)
GameObject.DestroyImmediate(obj.GetComponent<MeshFilter>());
if (obj.GetComponent<MeshRenderer>() != null)
GameObject.DestroyImmediate(obj.GetComponent<MeshRenderer>());
return;
}
// Zero transformation is needed because of localToWorldMatrix transform
Vector3 position = obj.transform.position;
obj.transform.position = Vector3.zero;
CombineInstance[] combine = new CombineInstance[_combinedMeshFilters.Count];
int i = 0;
while (i < _combinedMeshFilters.Count)
{
combine[i].mesh = _combinedMeshFilters[i].sharedMesh;
combine[i].transform = _combinedMeshFilters[i].transform.localToWorldMatrix;
_combinedMeshFilters[i].gameObject.GetComponent<MeshRenderer>().enabled = false;
i++;
}
MeshFilter meshFilter = obj.transform.GetComponent<MeshFilter>();
if (meshFilter == null)
meshFilter = obj.AddComponent<MeshFilter>();
obj.transform.GetComponent<MeshFilter>().mesh = new Mesh();
obj.transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine, true, true);
obj.transform.gameObject.SetActive(true);
// Add Mesh Renderer
MeshRenderer meshRenderer = obj.transform.GetComponent<MeshRenderer>();
if (meshRenderer == null)
meshRenderer = obj.AddComponent<MeshRenderer>();
// Add Mesh Collider
MeshCollider meshCollider = obj.transform.GetComponent<MeshCollider>();
if (meshRenderer != null)
GameObject.DestroyImmediate(meshCollider);
obj.AddComponent<MeshCollider>();
// Assign the Shared Material
meshRenderer.sharedMaterial = _sharedMaterial;
//Reset position
obj.transform.position = position;
}
}