1
\$\begingroup\$

I'm making a building game similar to minecraft, except you can place other types of objects as well. I am right now building the functionality of placing cubes. I'm using unity. here's my code.

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

public class Player : MonoBehaviour
{
    Camera cam;
    [SerializeField] GameObject brick;
    float pointX;
    float pointY;
    float pointZ;

// Start is called before the first frame update
void Start()
{
    cam = FindObjectOfType<Camera>();
}

// Update is called once per frame
void Update()
{
    Ray ray = cam.ScreenPointToRay(Input.mousePosition);
    RaycastHit hitInfo;


    if(Physics.Raycast(ray, out hitInfo))
    {
        if(Input.GetMouseButtonDown(0))
        {
            pointX = hitInfo.point.x;
            int roundedX = Mathf.RoundToInt(pointX);
            pointY = hitInfo.point.y;
            int roundedY = Mathf.RoundToInt(pointY);
            pointZ = hitInfo.point.z;
            int roundedZ = Mathf.RoundToInt(pointZ);
            Vector3 clickedPlace = new Vector3(roundedX, roundedY, roundedZ);

            Instantiate(brick, clickedPlace, transform.rotation);
        }

    }
}
}

the brick variable is assigned to a prefab which s 1 unit by 1 unit. this code works when placing the brick on the ground or on top of another block, but it only has a 50% chance of working when clicking on one side of the brick like you can do on minecraft. Sometimes the block will be placed right on top of another block, and sometimes it will be placed above the block and in front of it. does anyone know a way to fix this? I tried making the collider on the block bigger, but it didn't work.

\$\endgroup\$
  • \$\begingroup\$ I assume that your blocks are 1 unit large and their centers are on integer coordinates? So if you have a block on coordinates 3.0 : 3.0 : 3.0 would have a collider ranging from 2.5 : 2.5 : 2.5 to 3.5 : 3.5 : 3.5? \$\endgroup\$ – Philipp Sep 15 at 17:42
  • \$\begingroup\$ Yes, my blocks are 1 unit large, and their centers are on integer coordinates. actually, each block has an empty as it's parent so that when they spawn they don't spawn halfway through the ground. p.s, thanks for editing the question, it's clearer now. \$\endgroup\$ – Millard Sep 15 at 18:10
  • \$\begingroup\$ why did you remove your answer? \$\endgroup\$ – Millard Sep 15 at 19:26
  • \$\begingroup\$ Because you wrote that it didn't work. We don't want wrong answers on this website. \$\endgroup\$ – Philipp Sep 15 at 20:25
  • \$\begingroup\$ not sure why it didn't, it felt like it should have. \$\endgroup\$ – Millard Sep 15 at 21:26
4
\$\begingroup\$

Just rounding the coordinates alone won't work.

You need to figure out which block the ray collided with (the coordinates), and then which face of the block, the ray intersected.

From there, you can get the surface normal of that block face. Using that normal vector, you can then compute the next integer coordinate of where the block should be placed.

For example, if you are looking at the top of a block (assuming Y axis is "up"), the surface normal should be (0,1,0). If your blocks are all unit size of 1, then you can just add that surface normal to the position of the intersected block to get the placement coordinate:

if(Physics.Raycast(ray, out hitInfo))
{
    if(Input.GetMouseButtonDown(0))
    {
        pointX = hitInfo.point.x;
        int roundedX = Mathf.RoundToInt(pointX);
        pointY = hitInfo.point.y;
        int roundedY = Mathf.RoundToInt(pointY);
        pointZ = hitInfo.point.z;
        int roundedZ = Mathf.RoundToInt(pointZ);
        // The rounding may cause some issues: You will likely
        // need some logic to compute the coordinates of the *nearest* block
        Vector3 clickedBlock = new Vector3(roundedX, roundedY, roundedZ);
        Vector3 newBlock = clickedBlock + hitInfo.normal;

        Instantiate(brick, newBlock, transform.rotation);
    }
}
\$\endgroup\$
  • \$\begingroup\$ thanks, the rounding has a few issues, but it's a lot better. \$\endgroup\$ – Millard Sep 16 at 18:32
  • \$\begingroup\$ You might be able to query the hitInfo for the entity, and get it's position from there, but I can't be sure as Unity/C# isn't actually my thing \$\endgroup\$ – Ian Young Sep 16 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.