Minecraft block snapping(in a non-minecraft environment)

Hello,

I found this post about making minecraft blocks snap together:
My problem is that this only works when the ground is made up of cubes. I’m trying to make a game that has a regular ground that I can create blocks on top of. It looks like the reason this script works because it figures out the normal of a block and then it can then snap it to another normal of another block.
Is there someway to do this in a similar fashion but preternaturally snapping vertexes instead of normals? So that way I can snap my blocks to anything and not just normals.
Thoughts anyone?

 var blockLayer : LayerMask = 1;
    var range : float = Mathf.Infinity;
    var hit : RaycastHit;
    
function Update () {
    if (Input.GetMouseButtonDown(0))
        Build();
    if (Input.GetMouseButtonDown(1))
        Erase();
}

function Build() {
    if (HitBlock()) {
        var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.transform.position = hit.transform.position + hit.normal;
    }
}

function Erase() {
    if (HitBlock())
        Destroy(hit.transform.gameObject);
}

function HitBlock() : boolean {
    return Physics.Raycast(transform.position, transform.forward, hit, range, blockLayer);
}

As @Fattie says you would use a grid instead. Here’s a modified script which uses a grid, takes the collider size of the object to instantiate into account and instantiate at mouse position instead of the forward direction. You would also want to use two types of layers where you can spawn at certain places and destroy the instantiated objects.

What this script lacks is checking if the space is occupied already by an object. You would use the grid, hit position and perhaps a physics overlapsphere to check that.

#pragma strict

var spawnAreas : LayerMask; //Layers where you can spawn objects, make sure to fill this out
var destroyableObjects : LayerMask; //Objects that is ok to destroy, make sure to fill this out
var spawnPrefab : GameObject; //The object you want to spawn, in case you didn't assign the script creates a primitive
var grid : Vector3 = Vector3(1,1,1); //The grid you want to instantiate objects by
var colliderSize : Vector3 = Vector3(1,1,1); //The collider size of the object
var cam : Camera; //The camera you're using, in case you didn't assign one the script assigns the Main Camera
private var range : float = 100.0; //Don't use infinity, use the camera's far clipping plane if you need to
private var hit : RaycastHit;

function Start () {
	cam = Camera.main;
}

function Update () {
    if (Input.GetMouseButtonDown(0))
        Build();
    if (Input.GetMouseButtonDown(1))
        Erase();
}

function Build () {
	if (HitBlock(spawnAreas)) {
		if (spawnPrefab==null) {
			//In case you didn't have a prefab we spawn a primitive
			spawnPrefab = GameObject.CreatePrimitive(PrimitiveType.Cube);
			spawnPrefab.transform.position = Grid(hit.point);
		} else {
			//You have a prefab, let's spawn it
			var spawnObject = Instantiate(spawnPrefab, Grid(hit.point), Quaternion.identity);
		}
	}
}

function Erase () {
	if (HitBlock(destroyableObjects))
		Destroy(hit.transform.gameObject);
}

function HitBlock (mask : LayerMask) : boolean {
	var ray = cam.ScreenPointToRay (Input.mousePosition);
	return Physics.Raycast(ray, hit, range, mask);
}

function Grid (pos : Vector3) : Vector3 {
	return Vector3(Mathf.Round(pos.x/grid.x)*grid.x-(colliderSize.x/2), Mathf.Round(pos.y/grid.y)*grid.y+(colliderSize.y/2), Mathf.Round(pos.z/grid.z)*grid.z-(colliderSize.z/2));
}

It isn’t perfect but something to get started from hopefully.