浏览代码

integration of highmap, basic map generator, prevent map rendering
artifacts, registered new tiles and their renderers, updated texture
atlas

Kajetan Johannes Hammerle 5 年之前
父节点
当前提交
71c8298665

二进制
resources/tiles.png


二进制
resources/tiles.xcf


+ 2 - 2
src/pathgame/PathGame.java

@@ -5,7 +5,7 @@ import me.hammerle.snuviengine.api.Renderer;
 import pathgame.gameplay.Keys;
 import pathgame.rendering.TileMapRenderer;
 import pathgame.tilemap.TileMap;
-import pathgame.utils.TestUtils;
+import pathgame.tilemap.TileMapGenerator;
 import pathgame.gameplay.Player;
 import pathgame.rendering.PlayerRenderer;
 import pathgame.rendering.TileRenderer;
@@ -13,7 +13,7 @@ import pathgame.rendering.TileRenderer;
 public class PathGame implements IGame
 {
     private final TileMapRenderer mapRenderer = new TileMapRenderer();
-    private final TileMap map = TestUtils.getTestMap(33, 25);
+    private final TileMap map = TileMapGenerator.getMap(50, 50);
 
     private final PlayerRenderer playerRenderer = new PlayerRenderer();
     private final Player player = new Player();

+ 8 - 3
src/pathgame/rendering/TileMapRenderer.java

@@ -11,6 +11,10 @@ import pathgame.tilemap.TileMap;
  */
 public class TileMapRenderer
 {
+    // prevents rendering artifacts especially on different zoom levels
+    private final static float ERROR = 1.0f / 512.0F;
+    private final static float T_ERROR = 1.0f / 4096.0F;
+    
     private final Texture tileTexture = new Texture("resources/tiles.png");
     private final TextureRenderer textureRenderer = new TextureRenderer(20 * 20 * 2); // default to 20x20 map
     private float scale = 1.0f;
@@ -73,9 +77,10 @@ public class TileMapRenderer
                     continue;
                 }
                 textureRenderer.addRectangle(
-                        x * TileRenderer.TILE_SIZE, y * TileRenderer.TILE_SIZE,
-                        (x + 1) * TileRenderer.TILE_SIZE, (y + 1) * TileRenderer.TILE_SIZE,
-                        tt.getMinX(), tt.getMinY(), tt.getMaxX(), tt.getMaxY());
+                        x * TileRenderer.TILE_SIZE - ERROR, y * TileRenderer.TILE_SIZE - ERROR,
+                        (x + 1) * TileRenderer.TILE_SIZE + ERROR, (y + 1) * TileRenderer.TILE_SIZE + ERROR,
+                        tt.getMinX() + T_ERROR, tt.getMinY() + T_ERROR, 
+                        tt.getMaxX() - T_ERROR, tt.getMaxY() - T_ERROR);
             }
         }
         textureRenderer.build();

+ 13 - 4
src/pathgame/rendering/TileRenderer.java

@@ -7,7 +7,7 @@ import pathgame.tilemap.Tiles;
 public class TileRenderer
 {
     /** The unscaled render size of a map tile. */
-    public final static float TILE_SIZE = 16;
+    public final static float TILE_SIZE = 32;
     
     private static TileTextureProvider[] tProviders = new TileTextureProvider[8];
     
@@ -15,7 +15,7 @@ public class TileRenderer
     {
         if(t.getId() >= tProviders.length)
         {
-            TileTextureProvider[] newTProviders = new TileTextureProvider[t.getId()];
+            TileTextureProvider[] newTProviders = new TileTextureProvider[tProviders.length * 2];
             System.arraycopy(tProviders, 0, newTProviders, 0, tProviders.length);
             tProviders = newTProviders;
         }
@@ -25,8 +25,17 @@ public class TileRenderer
     static
     {
         register(Tiles.GRASS, new StaticTextureProvider(TileTexture.fromTextureId(0)));
-        register(Tiles.HILL, new StaticTextureProvider(TileTexture.fromTextureId(1)));
-        register(Tiles.MOUNTAIN, new StaticTextureProvider(TileTexture.fromTextureId(2)));
+        register(Tiles.GRASS_WITH_STONE, new StaticTextureProvider(TileTexture.fromTextureId(1)));
+        register(Tiles.GRASS_WITH_6_BUSHES, new StaticTextureProvider(TileTexture.fromTextureId(2)));
+        register(Tiles.GRASS_WITH_3_BUSHES, new StaticTextureProvider(TileTexture.fromTextureId(3)));
+        register(Tiles.GRASS_WITH_FLOWERS, new StaticTextureProvider(TileTexture.fromTextureId(4)));
+        register(Tiles.GRASS_WITH_HILL, new StaticTextureProvider(TileTexture.fromTextureId(5)));
+        register(Tiles.GRASS_WITH_EARTH, new StaticTextureProvider(TileTexture.fromTextureId(6)));
+        register(Tiles.FOREST, new StaticTextureProvider(TileTexture.fromTextureId(7)));
+        register(Tiles.SHALLOW_WATER, new StaticTextureProvider(TileTexture.fromTextureId(8)));
+        register(Tiles.DEEP_WATER, new StaticTextureProvider(TileTexture.fromTextureId(9)));
+        register(Tiles.HILL, new StaticTextureProvider(TileTexture.fromTextureId(10)));
+        register(Tiles.MOUNTAIN, new StaticTextureProvider(TileTexture.fromTextureId(11)));
     }
     
     public static TileTexture getTileTexture(TileMap map, Tile t, int x, int y)

+ 55 - 134
src/pathgame/tilemap/HighMap.java

@@ -1,186 +1,107 @@
-package speedtester;
+package pathgame.tilemap;
 
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
 import java.util.Random;
-import javax.imageio.ImageIO;
 
 public class HighMap
 {
+    public static HighMap generate(int width, int height, float zoom)
+    {
+        HighMap map = new HighMap(width, height);
+        map.zoom(zoom);
+        return map;
+    }
+    
     private final int width;
     private final int height;
-    private float data[][];
-    private Random r = new Random(0);
+    private final float data[][];
+    private final Random r = new Random(0);
     
-    public HighMap(int width, int height)
+    private HighMap(int width, int height)
     {
         this.width = width;
         this.height = height;
         this.data = new float[width][height];
     }
     
-    public void smooth(int radius)
+    public float get(int x, int y)
     {
-        float[][] newData = new float[width][height];
-        
-        for(int x = 0; x < width; x++)
-        {
-            for(int y = 0; y < height; y++)
-            {
-                int div = 0;
-                float sum = 0;
-                for(int mx = -radius; mx <= radius; mx++)
-                {
-                    for(int my = -radius; my <= radius; my++)
-                    {
-                        if(x + mx >= 0 && x + mx < width && y + my >= 0 && y + my < height)
-                        {
-                            sum += data[x + mx][y + my];
-                            div++;
-                        }
-                    }
-                }
-                sum /= div;
-                newData[x][y] = sum;
-            }
-        }
-        data = newData;
+        return data[x][y];
     }
     
-    public void randomize(int bound)
+    private float[][] randomizeBase()
     {
+        float[][] base = new float[width][height];
         for(int x = 0; x < width; x++)
         {
             for(int y = 0; y < height; y++)
             {
-                data[x][y] = r.nextInt(bound);
+                base[x][y] = r.nextFloat();
             }
         }
+        return base;
     }
     
-    public BufferedImage export()
+    private float smooth(float[][] base, float x1, float y1)
     {
-        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
-        
-        float min = Float.MAX_VALUE;
-        float max = Float.MIN_VALUE;
-        
-        for(int x = 0; x < width; x++)
-        {
-            for(int y = 0; y < height; y++)
-            {
-                if(data[x][y] < min)
-                {
-                    min = data[x][y];
-                }
-                if(data[x][y] > max)
-                {
-                    max = data[x][y];
-                }
-            }
-        }
-        
-        float div = 255.0f / (max - min);
-        
-        for(int x = 0; x < width; x++)
-        {
-            for(int y = 0; y < height; y++)
-            {
-                int base = (int) ((data[x][y] - min) * div);
-                image.setRGB(x, y, 0xFF000000 | (base << 16) | (base << 8) | base);
-            }
-        }
+        // distance to next exact pixel
+        float fractX = x1 - (int) x1;
+        float fractY = y1 - (int) y1;
+
+        // neighbour pixel coords
+        int x2 = ((int) x1 + 1) % width;
+        int y2 = ((int) y1 + 1) % height;
         
-        return image;
+        // interpolate over all 4 pixels, strength varies with distance
+        float value = 0.0f;
+        value += (1 - fractX) * (1 - fractY) * base[(int) x1][(int) y1];
+        value += (1 - fractX) * fractY * base[(int) x1][(int) y2];
+        value += fractX * (1 - fractY) * base[(int) x2][(int) y1];
+        value += fractX * fractY * base[(int) x2][(int) y2];
+        return value;
     }
     
-    public void threshold(int levels)
+    private float turbulence(float[][] base, float x1, float y1, float factor)
     {
-        float[] values = new float[width * height];
-        int counter = 0;
-        for(int x = 0; x < width; x++)
+        float sum = 0.0f;
+        while(factor >= 1)
         {
-            for(int y = 0; y < height; y++)
-            {
-                values[counter++] = data[x][y];
-            }
-        }
-        Arrays.sort(values);
-        
-        float[] borders = new float[levels];
-        for(int i = 0; i < levels - 1; i++)
-        {
-            borders[i] = values[(int) (((i + 1.0f) / levels) * values.length)];
-        }
-        borders[borders.length - 1] = Float.MAX_VALUE;
-
-        for(int x = 0; x < width; x++)
-        {
-            for(int y = 0; y < height; y++)
-            {
-                for(int i = 0; i < borders.length; i++)
-                {
-                    if(data[x][y] < borders[i])
-                    {
-                        data[x][y] = i;
-                        break;
-                    }
-                }
-            }
+            sum += smooth(base, x1 / factor, y1 / factor) * factor;
+            factor *= 0.5f;
         }
+        return sum;
     }
     
-    public BufferedImage colorExport(int scale, int... colors)
+    private void zoom(float factor)
     {
-        BufferedImage image = new BufferedImage(width * scale, height * scale, BufferedImage.TYPE_4BYTE_ABGR);
+        float[][] base = randomizeBase();
         
-        float[] values = new float[width * height];
-        int counter = 0;
+        float min = Float.MAX_VALUE;
+        float max = Float.MIN_VALUE;
+    
         for(int x = 0; x < width; x++)
         {
             for(int y = 0; y < height; y++)
             {
-                values[counter++] = data[x][y];
+                float f = turbulence(base, x, y, factor);
+                data[x][y] = f;
+                if(f < min)
+                {
+                    min = f;
+                }
+                if(f > max)
+                {
+                    max = f;
+                }
             }
         }
-        Arrays.sort(values);
         
-        float[] borders = new float[colors.length];
-        for(int i = 0; i < colors.length - 1; i++)
-        {
-            borders[i] = values[(int) (((i + 1.0f) / colors.length) * values.length)];
-        }
-        borders[borders.length - 1] = Float.MAX_VALUE;
-
+        float f = 1.0f / (max - min);
         for(int x = 0; x < width; x++)
         {
             for(int y = 0; y < height; y++)
             {
-                for(int i = 0; i < borders.length; i++)
-                {
-                    if(data[x][y] < borders[i])
-                    {
-                        for(int mx = 0; mx < scale; mx++)
-                        {
-                            for(int my = 0; my < scale; my++)
-                            {
-                                image.setRGB(x * scale + mx, y * scale + my, colors[i]);
-                            }
-                        }
-                        break;
-                    }
-                }
+                data[x][y] = (data[x][y] - min) * f;
             }
         }
-
-        return image;
-    }
-    
-    public void save(int scale, String name) throws IOException
-    {
-        BufferedImage image = colorExport(scale, 0xFF131ec1, 0xFF131ee0, 0xFF39aa38, 0xFFa57c4d, 0xFF50463a);
-        ImageIO.write(image, "png", new File(name + ".png"));
     }
 }

+ 55 - 0
src/pathgame/tilemap/TileMapGenerator.java

@@ -0,0 +1,55 @@
+package pathgame.tilemap;
+
+import java.util.Random;
+import java.util.TreeMap;
+
+public class TileMapGenerator
+{
+    private static final TreeMap<Integer, Tile> GRASS_MAP = new TreeMap<>();
+    
+    static
+    {
+        GRASS_MAP.put(0, Tiles.GRASS);
+        GRASS_MAP.put(70, Tiles.GRASS_WITH_STONE);
+        GRASS_MAP.put(75, Tiles.GRASS_WITH_6_BUSHES);
+        GRASS_MAP.put(80, Tiles.GRASS_WITH_3_BUSHES);
+        GRASS_MAP.put(85, Tiles.GRASS_WITH_FLOWERS);
+        GRASS_MAP.put(90, Tiles.GRASS_WITH_HILL);
+        GRASS_MAP.put(95, Tiles.GRASS_WITH_EARTH);
+    }
+    
+    /** Returns a random test map.
+     *
+     * @param width the width of the map
+     * @param height the height of the map
+     * @return a random test map
+     */
+    public static TileMap getMap(int width, int height)
+    {
+        Random r = new Random();
+        
+        HighMap highMap = HighMap.generate(width, height, Math.min(width, height) * 0.125f);
+        
+        TileMap map = new TileMap(width, height);
+        for(int x = 0; x < width; x++)
+        {
+            for(int y = 0; y < height; y++)
+            {
+                switch((int) (highMap.get(x, y) * 5))
+                {
+                    case 0: map.setTile(x, y, Tiles.DEEP_WATER); break;
+                    case 1: map.setTile(x, y, Tiles.SHALLOW_WATER); break;
+                    case 2: map.setTile(x, y, randomGrass(r)); break;
+                    case 3: map.setTile(x, y, Tiles.FOREST); break;
+                    case 4: map.setTile(x, y, Tiles.FOREST); break;
+                }
+            }
+        }
+        return map;
+    }
+    
+    private static Tile randomGrass(Random r)
+    {
+        return GRASS_MAP.floorEntry(r.nextInt(100)).getValue();
+    }
+}

+ 16 - 0
src/pathgame/tilemap/Tiles.java

@@ -3,6 +3,22 @@ package pathgame.tilemap;
 public class Tiles
 {
     public final static Tile GRASS = new Tile();
+    public final static Tile GRASS_WITH_STONE = new Tile();
+    public final static Tile GRASS_WITH_6_BUSHES = new Tile();
+    public final static Tile GRASS_WITH_3_BUSHES = new Tile();
+    public final static Tile GRASS_WITH_FLOWERS = new Tile();
+    public final static Tile GRASS_WITH_HILL = new Tile();
+    public final static Tile GRASS_WITH_EARTH = new Tile();
+    
+    public final static Tile[] GRASS_VARIANTS = new Tile[]
+    {
+        GRASS, GRASS_WITH_STONE, GRASS_WITH_6_BUSHES, GRASS_WITH_3_BUSHES, 
+        GRASS_WITH_FLOWERS, GRASS_WITH_HILL, GRASS_WITH_EARTH
+    };
+    
+    public final static Tile FOREST = new Tile();
+    public final static Tile SHALLOW_WATER = new Tile();
+    public final static Tile DEEP_WATER = new Tile();
     public final static Tile HILL = new Tile();
     public final static Tile MOUNTAIN = new Tile();
 }

+ 0 - 34
src/pathgame/utils/TestUtils.java

@@ -1,34 +0,0 @@
-package pathgame.utils;
-
-import java.util.Random;
-import pathgame.tilemap.TileMap;
-import pathgame.tilemap.Tiles;
-
-public class TestUtils
-{
-    /** Returns a random test map.
-     *
-     * @param width the width of the map
-     * @param height the height of the map
-     * @return a random test map
-     */
-    public static TileMap getTestMap(int width, int height)
-    {
-        Random r = new Random();
-        
-        TileMap map = new TileMap(width, height);
-        for(int x = 0; x < width; x++)
-        {
-            for(int y = 0; y < height; y++)
-            {
-                switch(r.nextInt(3))
-                {
-                    case 0: map.setTile(x, y, Tiles.GRASS); break;
-                    case 1: map.setTile(x, y, Tiles.HILL); break;
-                    case 2: map.setTile(x, y, Tiles.MOUNTAIN); break;
-                }
-            }
-        }
-        return map;
-    }
-}