{"id":331,"date":"2025-09-08T17:16:10","date_gmt":"2025-09-08T17:16:10","guid":{"rendered":"https:\/\/iotnoob.com\/wordpress\/?p=331"},"modified":"2025-09-10T02:45:32","modified_gmt":"2025-09-10T02:45:32","slug":"build-map-game-use-perlin-noise","status":"publish","type":"post","link":"https:\/\/iotnoob.com\/wordpress\/2025\/09\/08\/build-map-game-use-perlin-noise\/","title":{"rendered":"\u0e2a\u0e23\u0e49\u0e32\u0e07 MAP \u0e43\u0e19\u0e40\u0e01\u0e21\u0e2a\u0e4c\u0e14\u0e49\u0e27\u0e22 PERLIN NOISE"},"content":{"rendered":"\n<p>\u0e43\u0e2b\u0e49 AI \u0e2a\u0e23\u0e49\u0e32\u0e07\u0e15\u0e31\u0e27\u0e2d\u0e22\u0e48\u0e32\u0e07\u0e40\u0e25\u0e48\u0e19\u0e46\u0e2d\u0e31\u0e19\u0e19\u0e36\u0e07 \u0e40\u0e2d\u0e32\u0e44\u0e27\u0e49\u0e21\u0e32\u0e28\u0e36\u0e01\u0e29\u0e32\u0e2d\u0e35\u0e01\u0e17\u0e35<\/p>\n\n\n\n<p>\u0e27\u0e34\u0e18\u0e35\u0e19\u0e35\u0e49\u0e40\u0e17\u0e48\u0e32\u0e17\u0e35\u0e48\u0e23\u0e39\u0e49 \u0e04\u0e37\u0e2d \u0e21\u0e31\u0e19\u0e44\u0e21\u0e48\u0e43\u0e0a\u0e48\u0e01\u0e32\u0e23\u0e2a\u0e23\u0e49\u0e32\u0e07 map \u0e40\u0e15\u0e23\u0e35\u0e22\u0e21\u0e44\u0e27\u0e49\u0e01\u0e48\u0e2d\u0e19 \u0e41\u0e15\u0e48\u0e40\u0e1b\u0e47\u0e19\u0e01\u0e32\u0e23\u0e2a\u0e23\u0e49\u0e32\u0e07 map \u0e15\u0e2d\u0e19\u0e17\u0e35\u0e48\u0e40\u0e23\u0e32\u0e17\u0e33\u0e07\u0e32\u0e19 \u0e14\u0e31\u0e07\u0e19\u0e31\u0e49\u0e19\u0e21\u0e31\u0e19\u0e44\u0e21\u0e48\u0e15\u0e49\u0e2d\u0e07 save \u0e2d\u0e30\u0e44\u0e23\u0e40\u0e22\u0e2d\u0e30 map \u0e2a\u0e32\u0e21\u0e32\u0e23\u0e16\u0e01\u0e27\u0e49\u0e32\u0e07\u0e43\u0e2b\u0e0d\u0e48\u0e44\u0e14\u0e49\u0e44\u0e21\u0e48\u0e08\u0e33\u0e01\u0e31\u0e14 \u0e40\u0e1b\u0e47\u0e19 infinity<br>\u0e41\u0e25\u0e49\u0e27\u0e01\u0e32\u0e23\u0e40\u0e25\u0e37\u0e48\u0e2d\u0e19\u0e0b\u0e49\u0e32\u0e22\u0e02\u0e27\u0e32\u0e01\u0e47\u0e44\u0e21\u0e48\u0e44\u0e14\u0e49\u0e17\u0e33\u0e43\u0e2b\u0e49\u0e2b\u0e19\u0e49\u0e32\u0e15\u0e32\u0e02\u0e2d\u0e07 map \u0e40\u0e1b\u0e25\u0e35\u0e48\u0e22\u0e19\u0e44\u0e1b\u0e08\u0e32\u0e01\u0e40\u0e14\u0e34\u0e21 \u0e41\u0e15\u0e48\u0e40\u0e1b\u0e47\u0e19\u0e01\u0e32\u0e23 generate map \u0e40\u0e1e\u0e34\u0e48\u0e21\u0e40\u0e02\u0e49\u0e32\u0e44\u0e1b\u0e40\u0e23\u0e37\u0e48\u0e2d\u0e22\u0e46<br>\u0e41\u0e15\u0e48\u0e15\u0e2d\u0e19\u0e19\u0e35\u0e49 \u0e16\u0e49\u0e32\u0e1b\u0e34\u0e14\u0e41\u0e25\u0e49\u0e27\u0e40\u0e1b\u0e34\u0e14\u0e43\u0e2b\u0e21\u0e48 map \u0e08\u0e30\u0e40\u0e1b\u0e25\u0e35\u0e48\u0e22\u0e19\u0e2b\u0e19\u0e49\u0e32\u0e15\u0e32\u0e44\u0e1b <\/p>\n\n\n\n<p>\u0e15\u0e48\u0e2d\u0e44\u0e1b\u0e04\u0e07\u0e15\u0e49\u0e2d\u0e07\u0e17\u0e33\u0e43\u0e2b\u0e49\u0e21\u0e31\u0e19 save state \u0e44\u0e14\u0e49 \u0e40\u0e27\u0e25\u0e32\u0e17\u0e35\u0e48\u0e40\u0e23\u0e32 quit \u0e08\u0e32\u0e01 application<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.KeyAdapter;\nimport java.awt.event.KeyEvent;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Random;\n\n\/**\n * \u0e04\u0e25\u0e32\u0e2a\u0e2b\u0e25\u0e31\u0e01\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e40\u0e01\u0e21\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e41\u0e1c\u0e19\u0e17\u0e35\u0e48\n * \u0e2a\u0e23\u0e49\u0e32\u0e07 JFrame \u0e41\u0e25\u0e30\u0e40\u0e1e\u0e34\u0e48\u0e21 GamePanel \u0e40\u0e02\u0e49\u0e32\u0e44\u0e1b\n *\/\npublic class MapGame {\n\n    public static void main(String[] args) {\n        \/\/ \u0e2a\u0e23\u0e49\u0e32\u0e07 Frame \u0e2b\u0e25\u0e31\u0e01\u0e02\u0e2d\u0e07\u0e42\u0e1b\u0e23\u0e41\u0e01\u0e23\u0e21\n        JFrame frame = new JFrame(\"Map Based Game - \u0e43\u0e0a\u0e49\u0e1b\u0e38\u0e48\u0e21\u0e25\u0e39\u0e01\u0e28\u0e23\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e40\u0e04\u0e25\u0e37\u0e48\u0e2d\u0e19\u0e17\u0e35\u0e48\");\n        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n        frame.setSize(800, 800);\n        frame.setLocationRelativeTo(null); \/\/ \u0e41\u0e2a\u0e14\u0e07\u0e2b\u0e19\u0e49\u0e32\u0e15\u0e48\u0e32\u0e07\u0e01\u0e25\u0e32\u0e07\u0e08\u0e2d\n\n        \/\/ \u0e2a\u0e23\u0e49\u0e32\u0e07\u0e41\u0e25\u0e30\u0e40\u0e1e\u0e34\u0e48\u0e21 GamePanel \u0e17\u0e35\u0e48\u0e40\u0e1b\u0e47\u0e19\u0e2b\u0e31\u0e27\u0e43\u0e08\u0e2b\u0e25\u0e31\u0e01\u0e02\u0e2d\u0e07\u0e40\u0e01\u0e21\n        GamePanel gamePanel = new GamePanel();\n        frame.add(gamePanel);\n\n        frame.setVisible(true);\n    }\n\n    \/**\n     * GamePanel \u0e17\u0e33\u0e2b\u0e19\u0e49\u0e32\u0e17\u0e35\u0e48\u0e27\u0e32\u0e14\u0e41\u0e1c\u0e19\u0e17\u0e35\u0e48\u0e41\u0e25\u0e30\u0e08\u0e31\u0e14\u0e01\u0e32\u0e23\u0e01\u0e32\u0e23\u0e04\u0e27\u0e1a\u0e04\u0e38\u0e21\n     *\/\n    static class GamePanel extends JPanel {\n\n        \/\/ --- \u0e04\u0e48\u0e32\u0e04\u0e07\u0e17\u0e35\u0e48\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e1b\u0e23\u0e31\u0e1a\u0e41\u0e15\u0e48\u0e07\u0e40\u0e01\u0e21 ---\n        private static final int TILE_SIZE = 16; \/\/ \u0e02\u0e19\u0e32\u0e14\u0e02\u0e2d\u0e07\u0e41\u0e15\u0e48\u0e25\u0e30\u0e44\u0e17\u0e25\u0e4c (pixel)\n        private static final int CHUNK_WIDTH = 32; \/\/ \u0e08\u0e33\u0e19\u0e27\u0e19\u0e44\u0e17\u0e25\u0e4c\u0e43\u0e19\u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19\u0e02\u0e2d\u0e07 1 chunk\n        private static final int CHUNK_HEIGHT = 32; \/\/ \u0e08\u0e33\u0e19\u0e27\u0e19\u0e44\u0e17\u0e25\u0e4c\u0e43\u0e19\u0e41\u0e19\u0e27\u0e15\u0e31\u0e49\u0e07\u0e02\u0e2d\u0e07 1 chunk\n        private static final int MOVE_SPEED = 10; \/\/ \u0e04\u0e27\u0e32\u0e21\u0e40\u0e23\u0e47\u0e27\u0e43\u0e19\u0e01\u0e32\u0e23\u0e40\u0e04\u0e25\u0e37\u0e48\u0e2d\u0e19\u0e17\u0e35\u0e48 (pixel)\n        private static final double NOISE_SCALE = 0.05; \/\/ \u0e2a\u0e40\u0e01\u0e25\u0e02\u0e2d\u0e07 Perlin noise (\u0e04\u0e48\u0e32\u0e22\u0e34\u0e48\u0e07\u0e19\u0e49\u0e2d\u0e22 \u0e41\u0e1c\u0e19\u0e17\u0e35\u0e48\u0e22\u0e34\u0e48\u0e07\u0e40\u0e23\u0e35\u0e22\u0e1a)\n        private static final double RESOURCE_NOISE_SCALE = 0.2; \/\/ \u0e2a\u0e40\u0e01\u0e25\u0e02\u0e2d\u0e07 noise \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e17\u0e23\u0e31\u0e1e\u0e22\u0e32\u0e01\u0e23\n        private static final double RESOURCE_THRESHOLD = 0.7; \/\/ \u0e04\u0e48\u0e32 noise \u0e17\u0e35\u0e48\u0e08\u0e30\u0e40\u0e23\u0e34\u0e48\u0e21\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e17\u0e23\u0e31\u0e1e\u0e22\u0e32\u0e01\u0e23 (0.0 - 1.0)\n\n        \/\/ --- \u0e15\u0e31\u0e27\u0e41\u0e1b\u0e23\u0e2a\u0e16\u0e32\u0e19\u0e30\u0e02\u0e2d\u0e07\u0e40\u0e01\u0e21 ---\n        private int cameraX = 0; \/\/ \u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e01\u0e25\u0e49\u0e2d\u0e07\u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19 (World Coordinate)\n        private int cameraY = 0; \/\/ \u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e01\u0e25\u0e49\u0e2d\u0e07\u0e41\u0e19\u0e27\u0e15\u0e31\u0e49\u0e07 (World Coordinate)\n\n        \/\/ Cache \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e40\u0e01\u0e47\u0e1a Chunk \u0e17\u0e35\u0e48\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e41\u0e25\u0e49\u0e27 Key \u0e04\u0e37\u0e2d\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e02\u0e2d\u0e07 Chunk, Value \u0e04\u0e37\u0e2d\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e44\u0e17\u0e25\u0e4c\u0e02\u0e2d\u0e07 Chunk \u0e19\u0e31\u0e49\u0e19\n        private final Map&lt;Point, int[][]> chunkCache = new HashMap&lt;>();\n        private final PerlinNoise noiseGenerator = new PerlinNoise();\n        private final PerlinNoise resourceNoiseGenerator = new PerlinNoise(new Random().nextInt()); \/\/ \u0e43\u0e0a\u0e49 seed \u0e41\u0e22\u0e01\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e17\u0e23\u0e31\u0e1e\u0e22\u0e32\u0e01\u0e23\n\n        public GamePanel() {\n            this.setFocusable(true); \/\/ \u0e17\u0e33\u0e43\u0e2b\u0e49 Panel \u0e19\u0e35\u0e49\u0e23\u0e31\u0e1a input \u0e08\u0e32\u0e01 keyboard \u0e44\u0e14\u0e49\n            this.setBackground(Color.BLACK);\n\n            \/\/ \u0e40\u0e1e\u0e34\u0e48\u0e21 KeyListener \u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e23\u0e31\u0e1a\u0e01\u0e32\u0e23\u0e01\u0e14\u0e1b\u0e38\u0e48\u0e21\n            this.addKeyListener(new KeyAdapter() {\n                @Override\n                public void keyPressed(KeyEvent e) {\n                    handleKeyPress(e.getKeyCode());\n                }\n            });\n        }\n\n        \/**\n         * \u0e08\u0e31\u0e14\u0e01\u0e32\u0e23\u0e01\u0e32\u0e23\u0e01\u0e14\u0e1b\u0e38\u0e48\u0e21\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e40\u0e04\u0e25\u0e37\u0e48\u0e2d\u0e19\u0e17\u0e35\u0e48\n         * @param keyCode \u0e23\u0e2b\u0e31\u0e2a\u0e02\u0e2d\u0e07\u0e1b\u0e38\u0e48\u0e21\u0e17\u0e35\u0e48\u0e16\u0e39\u0e01\u0e01\u0e14\n         *\/\n        private void handleKeyPress(int keyCode) {\n            switch (keyCode) {\n                case KeyEvent.VK_UP:\n                    cameraY -= MOVE_SPEED;\n                    break;\n                case KeyEvent.VK_DOWN:\n                    cameraY += MOVE_SPEED;\n                    break;\n                case KeyEvent.VK_LEFT:\n                    cameraX -= MOVE_SPEED;\n                    break;\n                case KeyEvent.VK_RIGHT:\n                    cameraX += MOVE_SPEED;\n                    break;\n            }\n            repaint(); \/\/ \u0e2a\u0e31\u0e48\u0e07\u0e43\u0e2b\u0e49\u0e27\u0e32\u0e14\u0e2b\u0e19\u0e49\u0e32\u0e08\u0e2d\u0e43\u0e2b\u0e21\u0e48\u0e2b\u0e25\u0e31\u0e07\u0e08\u0e32\u0e01\u0e40\u0e04\u0e25\u0e37\u0e48\u0e2d\u0e19\u0e17\u0e35\u0e48\n        }\n\n        \/**\n         * \u0e40\u0e21\u0e18\u0e2d\u0e14\u0e2b\u0e25\u0e31\u0e01\u0e17\u0e35\u0e48\u0e43\u0e0a\u0e49\u0e43\u0e19\u0e01\u0e32\u0e23\u0e27\u0e32\u0e14 Component \u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14\n         *\/\n        @Override\n        protected void paintComponent(Graphics g) {\n            super.paintComponent(g);\n\n            \/\/ \u0e04\u0e33\u0e19\u0e27\u0e13\u0e02\u0e2d\u0e1a\u0e40\u0e02\u0e15\u0e02\u0e2d\u0e07 Chunk \u0e17\u0e35\u0e48\u0e15\u0e49\u0e2d\u0e07\u0e27\u0e32\u0e14\u0e1a\u0e19\u0e2b\u0e19\u0e49\u0e32\u0e08\u0e2d\n            int startChunkX = (int) Math.floor((double) cameraX \/ (CHUNK_WIDTH * TILE_SIZE));\n            int startChunkY = (int) Math.floor((double) cameraY \/ (CHUNK_HEIGHT * TILE_SIZE));\n            int endChunkX = (int) Math.floor((double) (cameraX + getWidth()) \/ (CHUNK_WIDTH * TILE_SIZE));\n            int endChunkY = (int) Math.floor((double) (cameraY + getHeight()) \/ (CHUNK_HEIGHT * TILE_SIZE));\n            \n            \/\/ \u0e27\u0e19\u0e25\u0e39\u0e1b\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e27\u0e32\u0e14\u0e17\u0e38\u0e01 Chunk \u0e17\u0e35\u0e48\u0e21\u0e2d\u0e07\u0e40\u0e2b\u0e47\u0e19\n            for (int cy = startChunkY; cy &lt;= endChunkY; cy++) {\n                for (int cx = startChunkX; cx &lt;= endChunkX; cx++) {\n                    drawChunk(g, cx, cy);\n                }\n            }\n             \/\/ \u0e27\u0e32\u0e14\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e1b\u0e31\u0e08\u0e08\u0e38\u0e1a\u0e31\u0e19\u0e02\u0e2d\u0e07\u0e01\u0e25\u0e49\u0e2d\u0e07\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e01\u0e32\u0e23\u0e14\u0e35\u0e1a\u0e31\u0e01\n            g.setColor(Color.WHITE);\n            g.drawString(String.format(\"Position: (%d, %d)\", cameraX, cameraY), 10, 20);\n        }\n        \n        \/**\n         * \u0e27\u0e32\u0e14 Chunk 1 \u0e2d\u0e31\u0e19\u0e17\u0e35\u0e48\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07 (chunkX, chunkY)\n         * @param g Graphics object\n         * @param chunkX \u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07 Chunk \u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19\n         * @param chunkY \u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07 Chunk \u0e41\u0e19\u0e27\u0e15\u0e31\u0e49\u0e07\n         *\/\n        private void drawChunk(Graphics g, int chunkX, int chunkY) {\n            Point chunkPos = new Point(chunkX, chunkY);\n            int[][] tiles;\n\n            \/\/ \u0e15\u0e23\u0e27\u0e08\u0e2a\u0e2d\u0e1a\u0e27\u0e48\u0e32 Chunk \u0e19\u0e35\u0e49\u0e2d\u0e22\u0e39\u0e48\u0e43\u0e19 cache \u0e2b\u0e23\u0e37\u0e2d\u0e44\u0e21\u0e48\n            if (chunkCache.containsKey(chunkPos)) {\n                tiles = chunkCache.get(chunkPos); \/\/ \u0e16\u0e49\u0e32\u0e21\u0e35\u0e2d\u0e22\u0e39\u0e48\u0e41\u0e25\u0e49\u0e27 \u0e01\u0e47\u0e14\u0e36\u0e07\u0e08\u0e32\u0e01 cache\n            } else {\n                tiles = generateChunk(chunkX, chunkY); \/\/ \u0e16\u0e49\u0e32\u0e22\u0e31\u0e07\u0e44\u0e21\u0e48\u0e21\u0e35 \u0e01\u0e47\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e43\u0e2b\u0e21\u0e48\n                chunkCache.put(chunkPos, tiles); \/\/ \u0e41\u0e25\u0e49\u0e27\u0e40\u0e01\u0e47\u0e1a\u0e25\u0e07 cache\n            }\n\n            \/\/ \u0e27\u0e19\u0e25\u0e39\u0e1b\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e27\u0e32\u0e14\u0e17\u0e38\u0e01\u0e44\u0e17\u0e25\u0e4c\u0e43\u0e19 Chunk\n            for (int y = 0; y &lt; CHUNK_HEIGHT; y++) {\n                for (int x = 0; x &lt; CHUNK_WIDTH; x++) {\n                    int tileType = tiles[y][x];\n                    Color tileColor = getTileColor(tileType);\n\n                    \/\/ \u0e04\u0e33\u0e19\u0e27\u0e13\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e17\u0e35\u0e48\u0e08\u0e30\u0e27\u0e32\u0e14\u0e1a\u0e19\u0e2b\u0e19\u0e49\u0e32\u0e08\u0e2d\n                    int drawX = chunkX * CHUNK_WIDTH * TILE_SIZE + x * TILE_SIZE - cameraX;\n                    int drawY = chunkY * CHUNK_HEIGHT * TILE_SIZE + y * TILE_SIZE - cameraY;\n\n                    g.setColor(tileColor);\n                    g.fillRect(drawX, drawY, TILE_SIZE, TILE_SIZE);\n                }\n            }\n        }\n        \n        \/**\n         * \u0e2a\u0e23\u0e49\u0e32\u0e07\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e44\u0e17\u0e25\u0e4c\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a Chunk \u0e17\u0e35\u0e48\u0e01\u0e33\u0e2b\u0e19\u0e14\u0e42\u0e14\u0e22\u0e43\u0e0a\u0e49 Perlin Noise\n         * @param chunkX \u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07 Chunk \u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19\n         * @param chunkY \u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07 Chunk \u0e41\u0e19\u0e27\u0e15\u0e31\u0e49\u0e07\n         * @return 2D array \u0e02\u0e2d\u0e07 tile types\n         *\/\n        private int[][] generateChunk(int chunkX, int chunkY) {\n            int[][] tiles = new int[CHUNK_HEIGHT][CHUNK_WIDTH];\n            for (int y = 0; y &lt; CHUNK_HEIGHT; y++) {\n                for (int x = 0; x &lt; CHUNK_WIDTH; x++) {\n                    \/\/ \u0e04\u0e33\u0e19\u0e27\u0e13\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e44\u0e17\u0e25\u0e4c\u0e43\u0e19\u0e42\u0e25\u0e01\u0e08\u0e23\u0e34\u0e07 (World Coordinate)\n                    int worldX = chunkX * CHUNK_WIDTH + x;\n                    int worldY = chunkY * CHUNK_HEIGHT + y;\n\n                    \/\/ \u0e2a\u0e23\u0e49\u0e32\u0e07\u0e04\u0e48\u0e32 noise \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e20\u0e39\u0e21\u0e34\u0e1b\u0e23\u0e30\u0e40\u0e17\u0e28\n                    double elevation = noiseGenerator.eval(worldX * NOISE_SCALE, worldY * NOISE_SCALE);\n                    \n                    \/\/ \u0e01\u0e33\u0e2b\u0e19\u0e14\u0e1b\u0e23\u0e30\u0e40\u0e20\u0e17\u0e44\u0e17\u0e25\u0e4c\u0e15\u0e32\u0e21\u0e04\u0e48\u0e32 noise\n                    int tileType;\n                    if (elevation &lt; -0.4) tileType = 0; \/\/ Deep Water\n                    else if (elevation &lt; -0.2) tileType = 1; \/\/ Shallow Water\n                    else if (elevation &lt; -0.1) tileType = 2; \/\/ Sand\n                    else if (elevation &lt; 0.5) tileType = 3; \/\/ Grass\n                    else if (elevation &lt; 0.8) tileType = 4; \/\/ Rock\n                    else tileType = 5; \/\/ Snow\n\n                    \/\/ \u0e16\u0e49\u0e32\u0e40\u0e1b\u0e47\u0e19\u0e1e\u0e37\u0e49\u0e19\u0e2b\u0e0d\u0e49\u0e32 (Grass) \u0e43\u0e2b\u0e49\u0e25\u0e2d\u0e07\u0e2a\u0e38\u0e48\u0e21\u0e17\u0e23\u0e31\u0e1e\u0e22\u0e32\u0e01\u0e23\n                    if (tileType == 3) {\n                        double resourceValue = resourceNoiseGenerator.eval(worldX * RESOURCE_NOISE_SCALE, worldY * RESOURCE_NOISE_SCALE);\n                        \/\/ resourceValue \u0e08\u0e30\u0e21\u0e35\u0e04\u0e48\u0e32\u0e23\u0e30\u0e2b\u0e27\u0e48\u0e32\u0e07 -1 \u0e16\u0e36\u0e07 1 \u0e40\u0e23\u0e32\u0e08\u0e36\u0e07\u0e15\u0e49\u0e2d\u0e07\u0e1b\u0e23\u0e31\u0e1a\u0e43\u0e2b\u0e49\u0e2d\u0e22\u0e39\u0e48\u0e43\u0e19\u0e0a\u0e48\u0e27\u0e07 0-1\n                        if ((resourceValue + 1) \/ 2 > RESOURCE_THRESHOLD) {\n                           tileType = 6; \/\/ Resource\n                        }\n                    }\n\n                    tiles[y][x] = tileType;\n                }\n            }\n            return tiles;\n        }\n\n        \/**\n         * \u0e04\u0e37\u0e19\u0e04\u0e48\u0e32\u0e2a\u0e35\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e44\u0e17\u0e25\u0e4c\u0e41\u0e15\u0e48\u0e25\u0e30\u0e1b\u0e23\u0e30\u0e40\u0e20\u0e17\n         * @param tileType \u0e23\u0e2b\u0e31\u0e2a\u0e02\u0e2d\u0e07\u0e1b\u0e23\u0e30\u0e40\u0e20\u0e17\u0e44\u0e17\u0e25\u0e4c\n         * @return Color object\n         *\/\n        private Color getTileColor(int tileType) {\n            switch (tileType) {\n                case 0: return new Color(0, 0, 128); \/\/ Deep Water\n                case 1: return new Color(0, 100, 255); \/\/ Shallow Water\n                case 2: return new Color(240, 230, 140); \/\/ Sand\n                case 3: return new Color(34, 139, 34);  \/\/ Grass\n                case 4: return new Color(139, 137, 137); \/\/ Rock\n                case 5: return new Color(255, 250, 250); \/\/ Snow\n                case 6: return Color.RED; \/\/ Resource\n                default: return Color.BLACK;\n            }\n        }\n    }\n\n    \/**\n     * Perlin Noise Generator\n     * \u0e19\u0e35\u0e48\u0e04\u0e37\u0e2d\u0e01\u0e32\u0e23 \u03c5\u03bb\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u0e02\u0e2d\u0e07 \"Improved Perlin Noise\" \u0e42\u0e14\u0e22 Ken Perlin\n     * \u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e43\u0e2b\u0e49\u0e44\u0e1f\u0e25\u0e4c\u0e19\u0e35\u0e49\u0e17\u0e33\u0e07\u0e32\u0e19\u0e44\u0e14\u0e49\u0e14\u0e49\u0e27\u0e22\u0e15\u0e31\u0e27\u0e40\u0e2d\u0e07\u0e42\u0e14\u0e22\u0e44\u0e21\u0e48\u0e15\u0e49\u0e2d\u0e07\u0e1e\u0e36\u0e48\u0e07 library \u0e20\u0e32\u0e22\u0e19\u0e2d\u0e01\n     *\/\n     static class PerlinNoise {\n        private final int[] p = new int[512];\n\n        public PerlinNoise() {\n            this(new Random().nextInt());\n        }\n\n        public PerlinNoise(int seed) {\n            int[] permutation = new int[256];\n            for (int i = 0; i &lt; 256; i++) {\n                permutation[i] = i;\n            }\n            Random rand = new Random(seed);\n            for (int i = 255; i > 0; i--) {\n                int index = rand.nextInt(i + 1);\n                int temp = permutation[index];\n                permutation[index] = permutation[i];\n                permutation[i] = temp;\n            }\n            for (int i = 0; i &lt; 256; i++) {\n                p[i] = p[i + 256] = permutation[i];\n            }\n        }\n\n        public double eval(double x, double y) {\n            int X = (int) Math.floor(x) &amp; 255;\n            int Y = (int) Math.floor(y) &amp; 255;\n            x -= Math.floor(x);\n            y -= Math.floor(y);\n            double u = fade(x);\n            double v = fade(y);\n            int A = p[X] + Y;\n            int B = p[X + 1] + Y;\n            return lerp(v, lerp(u, grad(p[A], x, y), grad(p[B], x - 1, y)),\n                    lerp(u, grad(p[A + 1], x, y - 1), grad(p[B + 1], x - 1, y - 1)));\n        }\n\n        private static double fade(double t) {\n            return t * t * t * (t * (t * 6 - 15) + 10);\n        }\n\n        private static double lerp(double t, double a, double b) {\n            return a + t * (b - a);\n        }\n\n        private static double grad(int hash, double x, double y) {\n            int h = hash &amp; 15;\n            double u = h &lt; 8 ? x : y;\n            double v = h &lt; 4 ? y : h == 12 || h == 14 ? x : 0;\n            return ((h &amp; 1) == 0 ? u : -u) + ((h &amp; 2) == 0 ? v : -v);\n        }\n    }\n}\n<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"786\" height=\"793\" src=\"https:\/\/iotnoob.com\/wordpress\/wp-content\/uploads\/2025\/09\/image.png\" alt=\"\" class=\"wp-image-332\" srcset=\"https:\/\/iotnoob.com\/wordpress\/wp-content\/uploads\/2025\/09\/image.png 786w, https:\/\/iotnoob.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-297x300.png 297w, https:\/\/iotnoob.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-150x150.png 150w, https:\/\/iotnoob.com\/wordpress\/wp-content\/uploads\/2025\/09\/image-768x775.png 768w\" sizes=\"auto, (max-width: 786px) 100vw, 786px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\u0e43\u0e2b\u0e49 AI \u0e2a\u0e23\u0e49\u0e32\u0e07\u0e15\u0e31\u0e27\u0e2d\u0e22\u0e48\u0e32\u0e07\u0e40\u0e25\u0e48\u0e19\u0e46\u0e2d\u0e31\u0e19\u0e19\u0e36\u0e07 \u0e40\u0e2d\u0e32\u0e44\u0e27\u0e49\u0e21\u0e32\u0e28\u0e36\u0e01\u0e29\u0e32\u0e2d\u0e35\u0e01\u0e17\u0e35 \u0e27\u0e34\u0e18\u0e35\u0e19\u0e35\u0e49\u0e40\u0e17\u0e48\u0e32\u0e17\u0e35\u0e48\u0e23\u0e39\u0e49 \u0e04\u0e37\u0e2d \u0e21\u0e31\u0e19\u0e44\u0e21\u0e48\u0e43\u0e0a\u0e48\u0e01\u0e32\u0e23\u0e2a\u0e23\u0e49\u0e32\u0e07 map \u0e40\u0e15\u0e23\u0e35\u0e22\u0e21\u0e44\u0e27\u0e49\u0e01\u0e48\u0e2d\u0e19 \u0e41\u0e15\u0e48\u0e40\u0e1b\u0e47\u0e19\u0e01\u0e32\u0e23\u0e2a\u0e23\u0e49\u0e32\u0e07 map \u0e15\u0e2d\u0e19\u0e17\u0e35\u0e48\u0e40\u0e23\u0e32\u0e17\u0e33\u0e07\u0e32\u0e19 \u0e14\u0e31\u0e07\u0e19\u0e31\u0e49\u0e19\u0e21\u0e31\u0e19\u0e44\u0e21\u0e48\u0e15\u0e49\u0e2d\u0e07 save \u0e2d\u0e30\u0e44\u0e23\u0e40\u0e22\u0e2d\u0e30&hellip;<\/p>\n","protected":false},"author":1,"featured_media":338,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,4,2],"tags":[],"class_list":["post-331","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-game","category-java","category-programming"],"_links":{"self":[{"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/posts\/331","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/comments?post=331"}],"version-history":[{"count":1,"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/posts\/331\/revisions"}],"predecessor-version":[{"id":333,"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/posts\/331\/revisions\/333"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/media\/338"}],"wp:attachment":[{"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/media?parent=331"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/categories?post=331"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/iotnoob.com\/wordpress\/wp-json\/wp\/v2\/tags?post=331"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}