} // end Adjust() private Voxel CreateSubstanceBlock(Vector3 position, Substance substance, VoxelFace faceTemplate) { if (!substance.defaultPaint.IsEmpty()) { faceTemplate = substance.defaultPaint; } Voxel voxel = VoxelAt(position, true); if (!voxel.IsEmpty()) { if (voxel.substance == substance) { return(voxel); } return(null); // doesn't work } voxel.substance = substance; for (int faceI = 0; faceI < 6; faceI++) { Voxel adjacentVoxel = VoxelAt(position + Voxel.DirectionForFaceI(faceI), false); if (adjacentVoxel == null || adjacentVoxel.substance != substance) { // create boundary voxel.faces[faceI] = faceTemplate; } else { // remove boundary adjacentVoxel.faces[Voxel.OppositeFaceI(faceI)].Clear(); voxel.faces[faceI].Clear(); } } return(voxel); }
public Vector3 DirectionFrom(Transform transform) { if (entityRef.entity != null) { direction = NO_DIRECTION; // older versions had default direction as 0 EntityComponent c = entityRef.component; if (c != null) { return((c.transform.position - transform.position).normalized); } return(Vector3.zero); } else if (direction == NO_DIRECTION) { return(Vector3.zero); } else if (direction == RANDOM) { return(randomDirection); } else if ((direction & LOCAL_BIT) != 0) { return(transform.TransformDirection(Voxel.DirectionForFaceI(direction & ~LOCAL_BIT))); } else { return(Voxel.DirectionForFaceI(direction)); } }
private void ReadVoxel(JSONObject voxelObject, VoxelArray voxelArray, List <Material> materials, List <Substance> substances) { if (voxelObject["at"] == null) { return; } Vector3 position = ReadVector3(voxelObject["at"].AsArray); Voxel voxel = null; if (!editor) { // slightly faster -- doesn't add to octree voxel = voxelArray.InstantiateVoxel(position); } else { voxel = voxelArray.VoxelAt(position, true); } if (voxelObject["s"] != null) { voxel.substance = substances[voxelObject["s"].AsInt]; } if (voxelObject["f"] != null) { foreach (JSONNode faceNode in voxelObject["f"].AsArray) { JSONObject faceObject = faceNode.AsObject; if (fileWriterVersion == 0) { // faces were oriented differently. Get voxel for each face int faceI = faceObject["i"].AsInt; voxel = voxelArray.VoxelAt(position + Voxel.DirectionForFaceI(faceI), true); } ReadFace(faceObject, voxel, materials); } } if (voxelObject["e"] != null) { foreach (JSONNode edgeNode in voxelObject["e"].AsArray) { ReadEdge(edgeNode.AsObject, voxel); } } voxel.UpdateVoxel(); }
public void SurfaceSelectFloodFill(Voxel voxel, int faceI, Substance substance) { if (voxel == null) { return; } if (voxel.substance != substance) { return; } VoxelFace face = voxel.faces[faceI]; if (face.IsEmpty()) { return; } if (face.addSelected || face.storedSelected) // stop at boundaries of stored selection { return; } SelectFace(voxel, faceI); Vector3 position = voxel.transform.position; for (int sideNum = 0; sideNum < 4; sideNum++) { int sideFaceI = Voxel.SideFaceI(faceI, sideNum); SurfaceSelectFloodFill(voxel, sideFaceI, substance); Vector3 newPos = position + Voxel.DirectionForFaceI(sideFaceI); SurfaceSelectFloodFill(VoxelAt(newPos, false), faceI, substance); newPos += Voxel.DirectionForFaceI(faceI); SurfaceSelectFloodFill(VoxelAt(newPos, false), Voxel.OppositeFaceI(sideFaceI), substance); } if (selectMode != SelectMode.SURFACE) { selectionBounds = voxel.GetFaceBounds(faceI); } else { selectionBounds.Encapsulate(voxel.GetFaceBounds(faceI)); } selectMode = SelectMode.SURFACE; SetMoveAxes(position + new Vector3(0.5f, 0.5f, 0.5f) - Voxel.OppositeDirectionForFaceI(faceI) / 2); }
// return false if object could not be placed public bool PlaceObject(ObjectEntity obj) { Vector3 createPosition = selectionBounds.center; int faceNormal = GetSelectedFaceNormal(); Vector3 createDirection = Voxel.DirectionForFaceI(faceNormal); if (faceNormal != -1) { createPosition += createDirection / 2; } else { faceNormal = 3; createDirection = Vector3.up; } createPosition -= new Vector3(0.5f, 0.5f, 0.5f); // don't create the object at the same location of an existing object // keep moving in the direction of the face normal until an empty space is found while (true) { Voxel voxel = VoxelAt(createPosition, false); if (voxel != null && voxel.substance == null && !voxel.faces[Voxel.OppositeFaceI(faceNormal)].IsEmpty()) { return(false); // blocked by wall. no room to create object } if (voxel == null || voxel.objectEntity == null) { break; } createPosition += createDirection; } obj.position = VoxelArray.Vector3ToInt(createPosition); obj.InitObjectMarker(this); AddObject(obj); unsavedChanges = true; // select the object. Wait one frame so the position is correct StartCoroutine(SelectNewObjectCoroutine(obj)); return(true); }
public Vector3 DirectionFrom(Vector3 point) { if (entityRef.entity != null) { direction = -1; // older versions had default direction as 0 EntityComponent c = entityRef.component; if (c != null) { return((c.transform.position - point).normalized); } return(Vector3.zero); } else if (direction == -1) { return(Vector3.zero); } else { return(Voxel.DirectionForFaceI(direction)); } }
public void Adjust(Vector3 adjustDirection) { MergeStoredSelected(); // now we can safely look only the addSelected property and the selectedThings list // and ignore the storedSelected property and the storedSelectedThings list int adjustDirFaceI = Voxel.FaceIForDirection(adjustDirection); int oppositeAdjustDirFaceI = Voxel.OppositeFaceI(adjustDirFaceI); int adjustAxis = Voxel.FaceIAxis(adjustDirFaceI); bool negativeAdjustAxis = adjustDirFaceI % 2 == 0; // sort selectedThings in order along the adjustDirection vector selectedThings.Sort(delegate(Selectable a, Selectable b) { // positive means A is greater than B // so positive means B will be adjusted before A Vector3 aCenter = a.bounds.center; Vector3 bCenter = b.bounds.center; float diff = 0; switch (adjustAxis) { case 0: diff = bCenter.x - aCenter.x; break; case 1: diff = bCenter.y - aCenter.y; break; case 2: diff = bCenter.z - aCenter.z; break; } if (negativeAdjustAxis) { diff = -diff; } if (diff > 0) { return(1); } if (diff < 0) { return(-1); } if (a is VoxelFaceReference && b is VoxelFaceReference) { var aFace = (VoxelFaceReference)a; var bFace = (VoxelFaceReference)b; if (aFace.faceI == oppositeAdjustDirFaceI) { if (bFace.faceI != oppositeAdjustDirFaceI) { return(-1); // move one substance back before moving other forward } else if (bFace.faceI == oppositeAdjustDirFaceI) { return(1); } } } return(0); }); // HashSets prevent duplicate elements var voxelsToUpdate = new HashSet <Voxel>(); bool createdSubstance = false; bool temporarilyBlockPushingANewSubstance = false; for (int i = 0; i < selectedThings.Count; i++) { Selectable thing = selectedThings[i]; if (thing is ObjectMarker) { var obj = ((ObjectMarker)thing).objectEntity; Vector3Int objNewPos = obj.position + Vector3ToInt(adjustDirection); MoveObject(obj, objNewPos); Voxel objNewVoxel = VoxelAt(objNewPos, false); if (objNewVoxel != null && objNewVoxel.substance == null && !objNewVoxel.faces[oppositeAdjustDirFaceI].IsEmpty() && !objNewVoxel.faces[oppositeAdjustDirFaceI].addSelected) { // carve a hole for the object if it's being pushed into a wall objNewVoxel.faces[oppositeAdjustDirFaceI].addSelected = true; selectedThings.Insert(i + 1, new VoxelFaceReference(objNewVoxel, oppositeAdjustDirFaceI)); } continue; } else if (!(thing is VoxelFaceReference)) { continue; } VoxelFaceReference faceRef = (VoxelFaceReference)thing; Voxel oldVoxel = faceRef.voxel; Vector3 oldPos = oldVoxel.transform.position; Vector3 newPos = oldPos + adjustDirection; Voxel newVoxel = VoxelAt(newPos, true); int faceI = faceRef.faceI; int oppositeFaceI = Voxel.OppositeFaceI(faceI); bool pushing = adjustDirFaceI == oppositeFaceI; bool pulling = adjustDirFaceI == faceI; if (pulling && (!newVoxel.faces[oppositeFaceI].IsEmpty()) && !newVoxel.faces[oppositeFaceI].addSelected) { // usually this means there's another substance. push it away before this face if (substanceToCreate != null && newVoxel.substance == substanceToCreate) { // substance has already been created there! // substanceToCreate has never existed in the map before Adjust() was called // so it must have been created earlier in the loop // remove selection oldVoxel.faces[faceI].addSelected = false; selectedThings[i] = new VoxelFaceReference(null, -1); voxelsToUpdate.Add(oldVoxel); } else { newVoxel.faces[oppositeFaceI].addSelected = true; selectedThings.Insert(i, new VoxelFaceReference(newVoxel, oppositeFaceI)); i -= 1; // need to move the other substance out of the way first temporarilyBlockPushingANewSubstance = true; } continue; } VoxelFace movingFace = oldVoxel.faces[faceI]; movingFace.addSelected = false; Substance movingSubstance = oldVoxel.substance; bool blocked = false; // is movement blocked? Voxel newSubstanceBlock = null; if (pushing) { for (int sideNum = 0; sideNum < 4; sideNum++) { int sideFaceI = Voxel.SideFaceI(faceI, sideNum); if (oldVoxel.faces[sideFaceI].IsEmpty()) { // add side Vector3 sideFaceDir = Voxel.DirectionForFaceI(sideFaceI); Voxel sideVoxel = VoxelAt(oldPos + sideFaceDir, true); int oppositeSideFaceI = Voxel.OppositeFaceI(sideFaceI); // if possible, the new side should have the properties of the adjacent side Voxel adjacentSideVoxel = VoxelAt(oldPos - adjustDirection + sideFaceDir, false); if (adjacentSideVoxel != null && !adjacentSideVoxel.faces[oppositeSideFaceI].IsEmpty() && movingSubstance == adjacentSideVoxel.substance) { sideVoxel.faces[oppositeSideFaceI] = adjacentSideVoxel.faces[oppositeSideFaceI]; sideVoxel.faces[oppositeSideFaceI].addSelected = false; } else { sideVoxel.faces[oppositeSideFaceI] = movingFace; } voxelsToUpdate.Add(sideVoxel); } } if (!oldVoxel.faces[oppositeFaceI].IsEmpty()) { blocked = true; } oldVoxel.Clear(); if (substanceToCreate != null && !temporarilyBlockPushingANewSubstance) { newSubstanceBlock = CreateSubstanceBlock(oldPos, substanceToCreate, movingFace); } } else if (pulling && substanceToCreate != null) { newSubstanceBlock = CreateSubstanceBlock(newPos, substanceToCreate, movingFace); oldVoxel.faces[faceI].addSelected = false; blocked = true; } else if (pulling) { if (movingSubstance == null && newVoxel != null && newVoxel.objectEntity != null) { // blocked by object oldVoxel.faces[faceI].addSelected = false; selectedThings[i] = new VoxelFaceReference(null, -1); voxelsToUpdate.Add(oldVoxel); continue; } for (int sideNum = 0; sideNum < 4; sideNum++) { int sideFaceI = Voxel.SideFaceI(faceI, sideNum); int oppositeSideFaceI = Voxel.OppositeFaceI(sideFaceI); Voxel sideVoxel = VoxelAt(newPos + Voxel.DirectionForFaceI(sideFaceI), false); if (sideVoxel == null || sideVoxel.faces[oppositeSideFaceI].IsEmpty() || movingSubstance != sideVoxel.substance) { // add side // if possible, the new side should have the properties of the adjacent side if (!oldVoxel.faces[sideFaceI].IsEmpty()) { newVoxel.faces[sideFaceI] = oldVoxel.faces[sideFaceI]; newVoxel.faces[sideFaceI].addSelected = false; } else { newVoxel.faces[sideFaceI] = movingFace; } } else { // delete side sideVoxel.faces[oppositeSideFaceI].Clear(); voxelsToUpdate.Add(sideVoxel); } } Voxel blockingVoxel = VoxelAt(newPos + adjustDirection, false); if (blockingVoxel != null && !blockingVoxel.faces[oppositeFaceI].IsEmpty()) { if (movingSubstance == blockingVoxel.substance) { blocked = true; blockingVoxel.faces[oppositeFaceI].Clear(); voxelsToUpdate.Add(blockingVoxel); } } oldVoxel.faces[faceI].Clear(); } else // sliding { oldVoxel.faces[faceI].addSelected = false; if (newVoxel.faces[faceI].IsEmpty() || newVoxel.substance != movingSubstance) { blocked = true; } } if (!blocked) { // move the face newVoxel.faces[faceI] = movingFace; newVoxel.faces[faceI].addSelected = true; newVoxel.substance = movingSubstance; selectedThings[i] = new VoxelFaceReference(newVoxel, faceI); } else { // clear the selection; will be deleted later selectedThings[i] = new VoxelFaceReference(null, -1); if (pulling && substanceToCreate == null) { newVoxel.substance = movingSubstance; } } if (newSubstanceBlock != null) { createdSubstance = true; if (!newSubstanceBlock.faces[adjustDirFaceI].IsEmpty()) { newSubstanceBlock.faces[adjustDirFaceI].addSelected = true; selectedThings.Insert(0, new VoxelFaceReference(newSubstanceBlock, adjustDirFaceI)); i += 1; } } voxelsToUpdate.Add(newVoxel); voxelsToUpdate.Add(oldVoxel); temporarilyBlockPushingANewSubstance = false; } // end for each selected face foreach (Voxel voxel in voxelsToUpdate) { VoxelModified(voxel); } for (int i = selectedThings.Count - 1; i >= 0; i--) { Selectable thing = selectedThings[i]; if ((thing is VoxelFaceReference) && ((VoxelFaceReference)thing).voxel == null) { selectedThings.RemoveAt(i); } } selectionChanged = true; if (substanceToCreate != null && createdSubstance) { substanceToCreate = null; } AutoSetMoveAxesEnabled(); } // end Adjust()