- Home /
minecraft style block placement
hello everybody, i am trying to make kind of a minecraft like block placment mecanic, i have the block placement half done, the main problem i have now is the fact that i have no idea on how to snap the block into a possition. if someone has any idea on ow to make this happen pls let me know. note that i am certainly not asking for code, simply an idea on how can this be done. thanks a lot for your help.
Answer by Jeremy2300 · Jan 23, 2014 at 03:41 PM
I found this tutorial really useful. It starts with a Minecraft like system, but takes it much further later on.
thanks dude, i was cracking my skull trying to make it work.
No problem. I went through that a few months ago. I have a pretty decent smooth terrain now (it was just a test for myself though, nothing worth showing off). But that tutorial was probably the most useful one I've found thus far on the subject.
Answer by will19 · Mar 04, 2020 at 08:51 AM
This is a simple way I came up with:
As you may have guessed, the idea is to cast a ray in the player camera's forward direction, and we are interested in the point of collision of this ray. Destroying a block is simple, we just identify the collider's gameObject, and destroy it, like this:
if (Input.GetKeyDown(KeyCode.Mouse0)) // left click --> destroy block
{
RaycastHit hitInfo;
if (Physics.Raycast(playerCam.transform.position, playerCam.transform.forward, out hitInfo, range, playerMask))
{
Destroy(hitInfo.collider.gameObject);
}
}
That's really all there is to it. Now, to place a block, it's slightly trickier, but not that bad: We have to find which face of the block the player is aiming at. For that, We cast a ray, identify the collider's gameObject, specifically its position (we call P) in world space (the idea is that the block's reference frame will lie right in the center of the block). Position P will have components x, y and z. The key here is that P lies on the face of the block (obviously), but this means one of the components of P finishes with .5. because in my case, the block has side length 1 unit. We look at the relative position between point P and the position of the center of the block. One of its >comonents will be -0.5f or 0.5f, and we just need to check will one! We write a method like this:
Vector3 SnappedPosition(Vector3 pointToSnap, Vector3 blockCenterPosition)
{
Vector3 relativePosition = pointToSnap - blockCenterPosition;
if (relativePosition.x == 0.5f) return blockCenterPosition + Vector3.right;
else if (relativePosition.x == -0.5f) return blockCenterPosition + Vector3.left;
else if (relativePosition.y == 0.5f) return blockCenterPosition + Vector3.up;
else if (relativePosition.y == -0.5f) return blockCenterPosition + Vector3.down;
else if (relativePosition.z == 0.5f) return blockCenterPosition + Vector3.forward;
else if (relativePosition.z == -0.5f) return blockCenterPosition + Vector3.back;
else return Vector3.zero; // error (should not occur)
}
This will return the position the block's center will lie at. Then we call this function after ray casting, like so:
if (Input.GetKeyDown(KeyCode.Mouse1)) // right click --> place block
{
RaycastHit hitInfo;
if (Physics.Raycast(playerCam.transform.position, playerCam.transform.forward, out hitInfo, range))
{
Vector3 instantiatePosition = SnappedPosition(hitInfo.point, hitInfo.collider.transform.position);
Instantiate(editingInfo.currentGameObject, instantiatePosition, Quaternion.identity);
}
}
The complete code (which should be attached to the player Game Onject) will look like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EditingTerrain : MonoBehaviour
{
public Camera playerCam;
public float range = 10f;
public EditingInfo editingInfo; // to retrieve the currently selected block from another script
LayerMask playerMask;
Vector3 SnappedPosition(Vector3 pointToSnap, Vector3 blockCenterPosition)
{
Vector3 relativePosition = pointToSnap - blockCenterPosition;
if (relativePosition.x == 0.5f) return blockCenterPosition + Vector3.right;
else if (relativePosition.x == -0.5f) return blockCenterPosition + Vector3.left;
else if (relativePosition.y == 0.5f) return blockCenterPosition + Vector3.up;
else if (relativePosition.y == -0.5f) return blockCenterPosition + Vector3.down;
else if (relativePosition.z == 0.5f) return blockCenterPosition + Vector3.forward;
else if (relativePosition.z == -0.5f) return blockCenterPosition + Vector3.back;
else return Vector3.zero; // error (should not occur)
}
void Start()
{
// to avoid collision with player camera during raycast
playerMask = ~ LayerMask.GetMask("Player"); // everything except the player mask
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0)) // left click --> destroy block
{
RaycastHit hitInfo;
if (Physics.Raycast(playerCam.transform.position, playerCam.transform.forward, out hitInfo, range, playerMask))
{
Destroy(hitInfo.collider.gameObject);
}
}
if (Input.GetKeyDown(KeyCode.Mouse1)) // right click --> place block
{
RaycastHit hitInfo;
if (Physics.Raycast(playerCam.transform.position, playerCam.transform.forward, out hitInfo, range))
{
Vector3 instantiatePosition = SnappedPosition(hitInfo.point, hitInfo.collider.transform.position);
Instantiate(editingInfo.currentGameObject, instantiatePosition, Quaternion.identity);
}
}
}
}
Hope that helps, even if I'm 6 years late.
Your answer
Follow this Question
Related Questions
Add object to another object's selected face 2 Answers
Minecraft block placing/ block building - how to? 2 Answers
MineCrafter Starter 1 Answer
Question about slideScrolling Voxels 0 Answers
Cubic terrain lags 1 Answer