Boolean устанавливается в true, даже не доходя до строки, устанавливающей логическое значение true - PullRequest
1 голос
/ 18 марта 2020

A normal level (picture 1) Нормальный уровень (рисунок 1)

The squares are tiles and the red dots are vertices (picture 2) Квадраты - это плитки и красные точки - это вершины (рисунок 2)

Я пытаюсь создать набор блоков (серых предметов), которые можно уничтожить (удалить), чтобы вода могла через них go. Как показано на рисунке, это работает большую часть времени, некоторые блоки уже удалены, и вода течет через промежутки. Проблема в том, что это не работает все время. Иногда, когда блок снят, вода не заполняет пробел, и в воде появляется дыра.

Код

public class WaterManager(){

    //level is the map, it is the parent containing the tile mesh and the water
    public Node level;
    Mesh water = new Mesh();
    Geometry geo;
    Vector3f[] vertices;
    //subdivision is used so the mesh is more detailed, a subdivision of 2 means there are 9 vertices per tile (cube) as shown on picture 2 
    public int subdivision = 2;
    //The amount of vertices on the x and z-axis
    int xVertices, zVertices;
    //The size of one tile, this is 10 in my case
    float cubeSize;
    //The amount of tiles on the x and z-axis
    int xCubes, zCubes;
    List<Integer> triangles = new ArrayList<>();
    
    List<Vector3f> emptyCubes = new ArrayList<>();
    List<Vector3f> newEmptyCubes = new ArrayList<>();
    Dictionary<Vector3f, Tile> tiles = new Hashtable<Vector3f, Tile>();

    public void Loop(Vector3f startPos){
        
        newEmptyCubes.clear();
        emptyCubes.clear();
        
        boolean loop = true;
        
        List<Vector3f> temp = new ArrayList<>();
        
        //This is the first check to get all the connected blocks that should be filled with water
        //including the block clicked on
        GetConnectedEmptyTiles(startPos, newEmptyCubes);
        
        //If there is more then 1 block which should be filled than loop through all the blocks
        //and get the ones connected to those that should be filled with water
        if (newEmptyCubes.size() > 1){
            do{
                for(Vector3f cube : newEmptyCubes){
                    GetConnectedEmptyTiles(cube, temp);
                }
                emptyCubes.addAll(newEmptyCubes);
                newEmptyCubes.clear();
                if (temp.size() <= 0)
                    loop = false;
                newEmptyCubes.addAll(temp);
                temp.clear();
            
            }while(loop);
        } else emptyCubes.addAll(newEmptyCubes);
        
        //This creates the mesh
        PaintEmptyTiles();        
    }

    private void GetConnectedEmptyTiles(Vector3f pos, List<Vector3f> list){
        
        //The blocks connected to a given posistion including the given position
        Vector3f[] connectedTilesPlusPos = new Vector3f[]{
            new Vector3f(pos.x + cubeSize, pos.y, pos.z),
            new Vector3f(pos.x - cubeSize, pos.y, pos.z),
            new Vector3f(pos.x, pos.y, pos.z + cubeSize),
            new Vector3f(pos.x, pos.y, pos.z - cubeSize),
            pos
        };
        
        //If the removed block is not connected to water then it shouldn't be filled
        //with water
        boolean connectedToWater = false;
        
        List<Vector3f> tempList = new ArrayList<>();
        
        //Check if the given position exists
        if (tiles.get(pos) != null){
            System.out.println("tile has water: " + tiles.get(pos).water);
            //Loop through all the connected blocks including the given position
            //and if they should be filled with water than add them to tempList
           for(Vector3f tile : connectedTilesPlusPos){
               if (tiles.get(tile) != null){
                   //Check if there is a block at the position (tile), if there
                   // is not than it can be filled with water
                   if (tiles.get(tile).tileObj == null){
                       //Check if the position already has water in it **(this is were it goes wrong)**
                       if (tiles.get(tile).water == false){
                            tempList.add(tile);
                            tiles.get(tile).water = true;
                        } else connectedToWater = true;  //If there is already water attached to the
                       //the given position then it is connected to water
                    }
                }
            }
           if (!connectedToWater)
               tempList.clear();
           else list.addAll(tempList);
        }
    }
    private void PaintEmptyTiles(){
        for(Vector3f cube : emptyCubes){
            MakeTriangles(cube);
        }
        MakeMesh();        
    }
    public void MakeTriangles(Vector3f pos){
        //Gets an array of vertices that are used to create water at a given position as shown in picture 2
        Vector3f[] verticesToUse = GetVerticesForPosition(pos);
        
        List<Integer> indexes = new ArrayList<>();
        for(int i = 0; i < vertices.length; i++){
            for(Vector3f vert : verticesToUse){
                if (vertices[i].equals(vert)){
                    indexes.add(i);
                }
            }
        }
     
        int xVerticesSize = rowSize(indexes, tiles.get(pos));
        int zVerticesSize = (int)indexes.size() / xVerticesSize;
        int verticesLenght = (int)Math.round(Math.sqrt(vertices.length));//The amount of vertices in one row.
        int i = 0;
        for(int x = 0; x < xVerticesSize; x++){
            for (int z = 0; z < zVerticesSize; z++){
                
                int vert = indexes.get(i);
                
                if (indexes.contains(vert + verticesLenght + 1)){
                    //Creates a quad, since the water is build from small quads
                    triangles.add(vert);
                    triangles.add(vert + 1);
                    triangles.add(vert + verticesLenght + 1);
                    triangles.add(vert + verticesLenght + 1);
                    triangles.add(vert + verticesLenght);
                    triangles.add(vert);
                }
                
                i++;                
              
            }
        }
    }
        private Vector3f[] GetVerticesForPosition(Vector3f pos){
        
        List<Vector3f> tempVertices = new ArrayList<>();
        
        for (Vector3f vertex : vertices) {
            if (vertex != null){
                float distance = DistanceOnXAndZ(pos, vertex);
                float roundedDistance = roundedTo(distance, cubeSize / subdivision);
                if (distance < cubeSize || (roundedDistance <= cubeSize && vertex.y <= -100 )){
                    tempVertices.add(vertex);
                }
            }
        }
        
        Vector3f[] returnVertices = new Vector3f[tempVertices.size()];
        returnVertices = tempVertices.toArray(returnVertices);
        
        return returnVertices;
    }
    
    //This calculates the distance from a point to another point but only using the x and z-axis
    private float DistanceOnXAndZ(Vector3f origin, Vector3f target){
        float originX = origin.x;
        float originZ = origin.z;
        
        float targetX = target.x;
        float targetZ = target.z;
        
        float xDistance = targetX - originX;
        float zDistance = targetZ - originZ;
        
        float distance = (float)Math.sqrt((xDistance * xDistance) + (zDistance * zDistance));
        
        return distance;
    }
        private void MakeMesh(){
        water.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
        
        int[] tri = new int[triangles.size()];
        for(int i = 0; i < triangles.size(); i++){tri[i] = triangles.get(i);}
        
        water.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(tri));
        water.updateBound();
        
        geo = new Geometry("Water", water);
        Material mat = new Material(assetManager,
        "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geo.setMaterial(mat);
        level.attachChild(geo);
    }
}

//The tile Object
public class Tile {    

    //not used anymore, but not deleted yet
    public enum CellType {        
        LEFTORRIGHTSIDE, OTHER
    }
    public CellType cellType;
    
    //The cube the Tile contains, if there is no cube then this is null
    public Spatial tileObj;
    
    //True if the tile contains water, false if not
    public boolean water = false;
    
    public Tile(CellType type, Spatial obj){
        //Nothing is done with cellType
        cellType = type;
        tileObj = obj;
    }
    
}

Причина

Причина, по которой это происходит, до сих пор неизвестна, но я думаю, что это как-то связано с тем, что булево значение воды в Tile уже установлено на true когда в нем есть куб (серая вещь).

Что нужно знать

  • плитки - это список, содержащий все позиции, содержащие плитку, если он содержит блок, то tileObj не является нулевым Если в позиции содержится вода, то логическое значение воды должно быть истинным.
  • PaintEmptyTiles (), в L oop () - функция, которая создает воду me sh
  • Когда блок уничтожается нажатием на нее, вызывается функция L oop () и для tileObj в Tile в списке плиток устанавливается значение NULL
  • Плитка - это квадрат с серым блоком и водой. или ничего.
...