} // 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);
    }
Exemple #2
0
 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));
     }
 }
Exemple #3
0
    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()