Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question I would like a cube that when user clicks one side of the cube, it spawns another cube on that side

Discussion in 'Scripting' started by TFK_001, Aug 3, 2023.

  1. TFK_001

    TFK_001

    Joined:
    Dec 30, 2018
    Posts:
    6
    As the title states, how would I make it so that if you click on one side of a cube, another cube spawns flush to that cube, similar to the CAD mockup I have in the attached image. I am relatively new to Unity and do not know how to go about this issue.

    I know what I need to do, just not how to implement it via Unity. I know that I need to
    1) detect a click and know what side is clicked
    2) spawn a new cube with click detectors on all sides except those which already have cubes
    3) delete the click detectors that overlap placed cubes

    I just don't know what unity classes should be used to add this.
     
  2. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    You would need a raycast from camera to mouse position, that gives variables of hitposition and the object clicked. Assuming the (hit)cube prefab has it's position as the center, you would subtract hitPosition minus (hit)cube position then round that(direction), and Instantiate a new cube prefab at that position times 2 from (hit)cube.

    Excuse my poor pseudo code, I'm just thinking aloud.. I'll play around with my thought and see if I can get it to work right.
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    I'm curious why your screenshot is titled "the root of human idiocy" but I'll leave that aside for now.

    In the general sense, everything @wideeyenow_unity suggests above is exactly what you need.

    Anything beyond that is ... well, extra features.

    Steps to success:

    - detect click on a cube
    - use the RaycastHit info to find what it was (and hence where it was)
    - use the RaycastHit normal to offset by one cube chunk
    - spawn afresh

    You don't even need to "delete click detectors" because the previous cube will be "buried"
     
  4. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    510
    Put this on a camera:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class AddCube : MonoBehaviour
    4. {
    5.     void Update()
    6.     {
    7.         if (Input.GetMouseButtonDown(0))
    8.         {
    9.             Ray ray=Camera.main.ScreenPointToRay(Input.mousePosition);
    10.             if (Physics.Raycast(ray,out RaycastHit hit,500f))
    11.             {
    12.                 GameObject obj=Instantiate(hit.transform.gameObject,hit.transform.position+hit.normal,hit.transform.rotation);
    13.             }
    14.         }
    15.     }
    16. }
     
  5. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    Yup, he's got it ^^^.

    I was still trying to figure how to round the difference yet with negative values. :mad: But yup, normals.. lol

    Edit: I already told myself, multiply by 2.. ::facepalm::
     
    Last edited: Aug 3, 2023
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Zulo, Zulo, Zulo!!! Deep respect there, my friend. Very nicely done. WOW!!!

    Here was my much more complicated but still sorta easy to use effort:



    It's all in my MakeGeo project as ClickToAddCubes.cs

    https://github.com/kurtdekker/makegeo/blob/master/makegeo/Assets/ClickToAddCubes/ClickToAddCubes.cs

    MakeGeo is presently hosted at these locations:

    https://bitbucket.org/kurtdekker/makegeo

    https://github.com/kurtdekker/makegeo

    https://gitlab.com/kurtdekker/makegeo

    https://sourceforge.net/p/makegeo
     
    ijmmai and zulo3d like this.
  7. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    Not to steal any thunder from zulo3d, but I wondered myself, what might be the question on this later:

    What if the cube was oddly scaled, or more than just (1,1,1)? this:
    Code (CSharp):
    1. public class AddCube : MonoBehaviour
    2. {
    3.     void Update()
    4.     {
    5.         if (Input.GetMouseButtonDown(0))
    6.         {
    7.             Ray ray=Camera.main.ScreenPointToRay(Input.mousePosition);
    8.             if (Physics.Raycast(ray,out RaycastHit hit,500f))
    9.             {
    10.                 Vector3 sideVector = new Vector3(
    11.                     hit.transform.localScale.x * hit.normal.x,
    12.                     hit.transform.localScale.y * hit.normal.y,
    13.                     hit.transform.localScale.z * hit.normal.z);
    14.                 Instantiate(hit.transform.gameObject,
    15.                     hit.transform.position + sideVector, hit.transform.rotation);
    16.             }
    17.         }
    18.     }
    19. }
     
    zulo3d likes this.
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    I dunno but...

    :)
     
    wideeyenow_unity likes this.
  9. TFK_001

    TFK_001

    Joined:
    Dec 30, 2018
    Posts:
    6
    Exactly what I was looking for, thanks! I will be using this for something larger than 1x1 cubes but I think upscaling this will be a fun learning challenge for me.

    I was originally using that cad file to model a collision I was in to show how my idiocy caused an accident, then decided to repurpose it to showcase this.
     
  10. TFK_001

    TFK_001

    Joined:
    Dec 30, 2018
    Posts:
    6
    Modified the code so it works with any rectangular/hexagonal/octagonal
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class AddCube : MonoBehaviour
    4. {
    5.     void Update()
    6.     {
    7.         if (Input.GetMouseButtonDown(0))//if user clicks
    8.         {
    9.             Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//where user clicks
    10.             bool cast = Physics.Raycast(ray, out RaycastHit hit, 500f);
    11.            
    12.             if (cast && hit.transform.gameObject.CompareTag("Room"))//if user clicks an object, duplicate it along that face
    13.             {
    14.                 if (hit.normal.x != 0)
    15.                 {
    16.                     Instantiate(hit.transform.gameObject, hit.transform.position + hit.normal * hit.transform.localScale.x, hit.transform.rotation);
    17.                 }else if (hit.normal.y != 0)
    18.                 {
    19.                     Instantiate(hit.transform.gameObject, hit.transform.position + hit.normal * hit.transform.localScale.y, hit.transform.rotation);
    20.                 }
    21.                 else
    22.                 {
    23.                     Instantiate(hit.transform.gameObject, hit.transform.position + hit.normal * hit.transform.localScale.z, hit.transform.rotation);
    24.                 }
    25.             }
    26.         }
    27.     }
    28. }
    prisms:
     
  11. TFK_001

    TFK_001

    Joined:
    Dec 30, 2018
    Posts:
    6
    almost certainly a better way than if else chains but it works
     
  12. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    lol, I knew that question was going to pop up, that's why a few posts ago I threw it out there:
    Code (CSharp):
    1. public class AddCube : MonoBehaviour
    2. {
    3.     void Update()
    4.     {
    5.         if (Input.GetMouseButtonDown(0))
    6.         {
    7.             Ray ray=Camera.main.ScreenPointToRay(Input.mousePosition);
    8.             if (Physics.Raycast(ray,out RaycastHit hit,500f))
    9.             {
    10.                 Vector3 sideVector = new Vector3(
    11.                     hit.transform.localScale.x * hit.normal.x,
    12.                     hit.transform.localScale.y * hit.normal.y,
    13.                     hit.transform.localScale.z * hit.normal.z);
    14.                 Instantiate(hit.transform.gameObject,
    15.                     hit.transform.position + sideVector, hit.transform.rotation);
    16.             }
    17.         }
    18.     }
    19. }
    Because "hitting" the cube will return it's size, and position. So you only need to change the position, in relevance, as the "Instantiate" will duplicate the cube being hit. Tested this function with a cube scale (2,2,2) and (1,2,3) and saw no issues.

    However if you want certain functionality with different size/side hits, than for sure you'll need "if-else if-else" statements. :)