Smooth Algorithm for World Generator

Discussion in 'Spigot Plugin Development' started by DasDarki, Apr 26, 2017.

  1. Hi. I am trying to create a SideScroller in Minecraft. Therefor I created a World Generator that generates the 2D World. But one problem do I have the "Mountains" that will be created by my Generator are...yeah not mountains. They are like spikes. No I try to make a Smooth Algorithm that the Spike will more mountain like.
    Here a Picture of a Map:
    http://i.imgur.com/XObHCxG.png
    And here my Generator Class:
    Code (Text):

    public class Map {

        private GenerateProcess process;
        private World world;
        private int sX;
        private int sY;
        private int z;
        private int bX;
        private int bY;
       
        private List<MapBlock> blocks;
       
        public Map(Location loc){
            bX = loc.getBlockX() - 1;
            bY = loc.getBlockY() - 1;
            sX = loc.getBlockX();
            sY = loc.getBlockY();
            z = loc.getBlockZ();
            world = loc.getWorld();
            generateBorder();
        }
       
        public Map generate(){
            process = new GenerateProcess();
            for(int y = sY; y <= (sY + MapVars.MAX_HEIGTH); y++){
                for(int x = sX; x <= (sX + MapVars.MAX_WIDTH); x++){
                    process.currentX = x - sX;
                    process.currentY = y - sY;
                    MapBlock block = MapRandom.generateMapBlock(sX, sY, process);
                    process.endingBlocks.add(block);
                }
            }
            blocks = process.endingBlocks;
            for(MapBlock block : blocks){
                setBlockSync(new Location(world, block.getPosition().getX(), block.getPosition().getY(), z),
                        block.isSolid() ? Material.LAPIS_BLOCK : Material.AIR);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                }
            }
            return this;
        }
       
        public List<MapBlock> getAllBlocks(){
            return blocks;
        }
       
        public MapBlock getBlockAt(Point p){
            for(MapBlock block : blocks)
                if(block.getPosition().equals(p))
                    return block;
            return null;
        }
       
        private void generateBorder(){
            new Thread(new Runnable() {
               
                @Override
                public void run() {
                    for(int x = bX; x <= (bX + MapVars.MAX_WIDTH + 2); x++){
                        for(int y = bY; y <= (bY + MapVars.MAX_HEIGTH + 2); y++){
                            Location loc = new Location(world, x, y, z);
                            setBlockSync(loc, Material.COAL_BLOCK);
                            try {
                                Thread.sleep(1);
                            } catch (InterruptedException e) {
                            }
                        }
                    }
                    generate();
                }
            }).start();
        }
       
        private void setBlockSync(Location loc, Material mat){
            new BukkitRunnable() {
               
                @Override
                public void run() {
                    loc.getBlock().setType(mat);
                }
            }.runTask(ShellCraft.getInstance());
        }
    }
     
    And the Class which the Generator uses:
    Code (Text):
    public class MapRandom {
       
        public static MapBlock generateMapBlock(int sX, int sY, GenerateProcess process){
            int cY = process.currentY;
            int cX = process.currentX;
            if(cY == 0){
                return new MapBlock(MapBlockType.SOLID, new Point(cX + sX, cY + sY));
            }else{
                Point underPoint = new Point(cX + sX, cY + sY-1);
                MapBlock underBlock = process.getBlock(underPoint);
                if(underBlock == null)
                    return new MapBlock(MapBlockType.AIR, new Point(cX + sX, cY + sY));
                if(!underBlock.isSolid())
                    return new MapBlock(MapBlockType.AIR, new Point(cX + sX, cY + sY));
                if(cY < MapVars.LESS_AREA){
                    Random random = new Random();
                    float f = random.nextFloat();
                    if(f <= 0.95)
                        return new MapBlock(MapBlockType.SOLID, new Point(cX + sX, cY + sY));
                    else
                        return new MapBlock(MapBlockType.AIR, new Point(cX + sX, cY + sY));
                }else{
                    if(cY < MapVars.SKY_Y){
                        Random random = new Random();
                        int i = random.nextInt(3);
                        if(i == 0 || i == 2)
                            return new MapBlock(MapBlockType.SOLID, new Point(cX + sX, cY + sY));
                        else
                            return new MapBlock(MapBlockType.AIR, new Point(cX + sX, cY + sY));
                    }else{
                        return new MapBlock(MapBlockType.AIR, new Point(cX + sX, cY + sY));
                    }
                }
            }
        }

    }
    I hope u can help me
     
    • Agree Agree x 2
  2. I assume at the moment it just picks a random height within the range of possible heights but what you need is for the height to vary depending on the height that came before it and only increase or decrease by a smaller random amount so that you get slopes instead of bar charts.
     
  3. Ok. But what means the Value and how do I use this in my Plugin?
     
  4. Ah I know what u mean...
     
  5. I'd like to do it on my own and not with an library...I did it nearly...but the only thing is the smoothing
     
  6. Try looking into perlin noise. I used that to generate some pretty neat terrain! :) If it's too complicated for you you can do something like this:
    Set a start height. Place a block there and fill everything underneath. On the next block, either descrease height by 1, increase by 1, or don't do anything with it. Again place a block there and fill up underneath. This is the result:
    [​IMG]
    https://i.gyazo.com/8ad4aac0bf53a77bb9b54497f8a15f93.gif
    It generates okayish terrain. You don't have much variation and you'll have to add biomes to keep it a bit interesting.
     
  7. I wouldn't say that I am the best in Java but I'd like a Challenge and honestly this
    is a litte bit boring and too easy. Ok. I try it with Perlin Noise.
     
  8. But now is the question how do I do side scroller worlds with it? And how do I use it or what should I do with the floats?
     
  9. Just quickly pointing out that Bukkit has built-in noise classes that don't require NMS. Includes simplex octave, simplex noise, perlin octave and perlin noise.

    I prefer the Simplex octave generator; no particular reason (I heard it was faster than Perlin, too? but I don't really know; haven't tested). Pretty easy to use, too.

    Now, I admit I have no idea about the performance of Bukkit's implementations; I'd love if someone pointed out whether a library could be a lot faster or not.
     
  10. That is nice but I dont know what the doubles mean that the methods return.
     
  11. The height for the location you put in.
     
  12. Ok now I understand this. But how do I use this to generate a 2D SideScrolling Map. I dont understand this the noise method returns only one double so one Location how do I generate a Map!? Maybe I am stupid, or I am stucking or something else
     
  13. For each x coordinate, run the method, it returns a y value for the specified x value. Together they form a coordinate. It's the highest point, so fill everything under it.
     
  14. Ok tried it. But it only genrates a very flat map...between two blocks
     
  15. You are thinking in the right direction. What you need is interpolation (finding values between points).
    Interpolating random values will create an octave. Stack many octaves with different frequencies and amplitudes on each other and you will get perlin noise.
     
    • Agree Agree x 1