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
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 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 (incomingVec == new Vector3(0, -2, 0))
– foodigglerHmm thank you I will try that. What about the answer to [this question][1]? They seem to accept the answer but I dont really see any difference when I compare it to the code example of the questioner. [1]: http://answers.unity3d.com/questions/254003/instantiate-gameobject-with-parameters.html
– TPRammusJust some things you might need:
Meshes don’t have faces (from techincal view) they are made of triangles. So a cube-side is made of 2 triangles.
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...
– Bunny83understood, 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
– dju4icHere 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*.gameObject)*
{
Debug.Log("Object Hit = " + transforms*.gameObject.name + " Tri Index = " + hit.triangleIndex);*
return transforms*.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*.GetComponent();*
if (meshRenderer != null)
{
if (!meshRenderer.enabled)
{
MeshFilter meshFilter = obj*.GetComponent();*
if (_combinedMeshFilters.Contains(meshFilter))
{
_combinedMeshFilters.Remove(meshFilter);
combine = true;
}
meshRenderer.enabled = true;
meshRenderer.material = new Material(Shader.Find(“Standard”));
MeshCollider meshCollider = obj*.GetComponent();*
if (meshCollider == null)
obj*.AddComponent();*
}
}
}
if (combine)
CombineMeshes(gameObject);
}
///
for (int i = 0; i < obj.Length; i++)
{
MeshRenderer meshRenderer = obj*.GetComponent();*
if (meshRenderer != null)
{
if (meshRenderer.enabled)
{
_combinedMeshFilters.Add(obj*.GetComponent());*
MeshCollider meshCollider = obj*.GetComponent();*
if (meshCollider != null)
GameObject.DestroyImmediate(meshCollider);
combine = true;
}
}
}
if (combine)
CombineMeshes(gameObject);
}
///
foreach (Transform t in gameObject.transform)
if (t.GetComponent() != null)
objs.Add(t.gameObject);
return objs.ToArray();
}
///
if (obj.GetComponent() != null)
GameObject.DestroyImmediate(obj.GetComponent());
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.mesh = combinedMeshFilters*.sharedMesh;
combine.transform = _combinedMeshFilters.transform.localToWorldMatrix;
_combinedMeshFilters.gameObject.GetComponent().enabled = false;*
i++;
}
MeshFilter meshFilter = obj.transform.GetComponent();
if (meshFilter == null)
meshFilter = obj.AddComponent();
obj.transform.GetComponent().mesh = new Mesh();
obj.transform.GetComponent().mesh.CombineMeshes(combine, true, true);
obj.transform.gameObject.SetActive(true);_
// Add Mesh Renderer
MeshRenderer meshRenderer = obj.transform.GetComponent();
if (meshRenderer == null)
meshRenderer = obj.AddComponent();
// Add Mesh Collider
MeshCollider meshCollider = obj.transform.GetComponent();
if (meshRenderer != null)
GameObject.DestroyImmediate(meshCollider);
obj.AddComponent();
// Assign the Shared Material
meshRenderer.sharedMaterial = _sharedMaterial;
//Reset position
obj.transform.position = position;
}
}
Hmm...all the green reply for that Q shows is being able to use GetComponent after instantiating something. But that's already in the manual (and was when the Q was asked.) AND you're allowed to skip that line by directly instantiating by component (ex: public Rigidbody r1; ... Rigidbody r=Instatiate(r1);, which is also in the manual. But it's the internet. You can get 11 people somewhere out there to click on anything.
I know this topic is a bit old, but here’s my answer on this one. First, I define an array containing the six main normal vectors for a cube’s facets.
static Vector3[] sides = {
Vector3.down,
Vector3.forward,
Vector3.left,
Vector3.right,
Vector3.back,
Vector3.up
};
You can then use this code to detect which side was intersected by a given RaycastHit:
public int FaceIntersectingHit(RaycastHit hit) {
var result = new DieFace();
// RaycastHits are in world space; convert to local space - note that we
// normalize the result too because scale can affect the transformed vector
Vector3 localNormal = transform.InverseTransformVector(hit.normal).normalized;
// There may be rounding errors in the result, so round to the nearest integer
Vector3 incoming = new Vector3(
Mathf.Round(localNormal.x),
Mathf.Round(localNormal.y),
Mathf.Round(localNormal.z)
);
// Compare against our list of faces to see which is hit
for (int i = 0; i < sides.Length; i++) {
var side = sides[i];
if (incoming == side) {
return i+1;
}
}
return 0;
}
Note that my method returns an integer based on the array but adds one to its value, because I’m using this to detect the facet of a six-sided die.
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.
– Bunny83Hey @Clicksurfer . I did this a long time ago, so my memory of all the details isn't great. However I was also using HLAPI in conjunction and this still worked. I was able to achieve it by defining a new network topology at runtime. Just copy/paste the code above into Start and it should hopefully get you somewhere. However as Unity is pulling support for UNET now I would advise moving on to a new API like Photon. I wish I had used Photon to begin with, it's so much easier and doesn't have bandwidth limitations you run into with Unity's relay servers.
– Glicknork