├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── roboto_regular.ttf ├── thumbnail.png ├── tilesource_1.png └── tilesource_2.png ├── example ├── camera.go ├── camera.script ├── collection.collection ├── font_1.font ├── go.go ├── go.script ├── gui.gui ├── gui.gui_script ├── h_str.lua ├── tilemap.tilemap ├── tilesource_1.tilesource └── tilesource_2.tilesource ├── game.project └── input └── game.input_binding /.gitattributes: -------------------------------------------------------------------------------- 1 | # Defold Protocol Buffer Text Files (https://github.com/github/linguist/issues/5091) 2 | *.animationset linguist-language=JSON5 3 | *.atlas linguist-language=JSON5 4 | *.camera linguist-language=JSON5 5 | *.collection linguist-language=JSON5 6 | *.collectionfactory linguist-language=JSON5 7 | *.collectionproxy linguist-language=JSON5 8 | *.collisionobject linguist-language=JSON5 9 | *.cubemap linguist-language=JSON5 10 | *.display_profiles linguist-language=JSON5 11 | *.factory linguist-language=JSON5 12 | *.font linguist-language=JSON5 13 | *.gamepads linguist-language=JSON5 14 | *.go linguist-language=JSON5 15 | *.gui linguist-language=JSON5 16 | *.input_binding linguist-language=JSON5 17 | *.label linguist-language=JSON5 18 | *.material linguist-language=JSON5 19 | *.mesh linguist-language=JSON5 20 | *.model linguist-language=JSON5 21 | *.particlefx linguist-language=JSON5 22 | *.render linguist-language=JSON5 23 | *.sound linguist-language=JSON5 24 | *.sprite linguist-language=JSON5 25 | *.spinemodel linguist-language=JSON5 26 | *.spinescene linguist-language=JSON5 27 | *.texture_profiles linguist-language=JSON5 28 | *.tilemap linguist-language=JSON5 29 | *.tilesource linguist-language=JSON5 30 | 31 | # Defold JSON Files 32 | *.buffer linguist-language=JSON 33 | 34 | # Defold GLSL Shaders 35 | *.fp linguist-language=GLSL 36 | *.vp linguist-language=GLSL 37 | 38 | # Defold Lua Files 39 | *.editor_script linguist-language=Lua 40 | *.render_script linguist-language=Lua 41 | *.script linguist-language=Lua 42 | *.gui_script linguist-language=Lua 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.internal 2 | /build 3 | .externalToolBuilders 4 | .DS_Store 5 | Thumbs.db 6 | .lock-wscript 7 | *.pyc 8 | .project 9 | .cproject 10 | builtins -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 White Box Dev 2 | 3 | This software is provided 'as-is', without any express or implied warranty. 4 | In no event will the authors be held liable for any damages arising from the use of this software. 5 | 6 | Permission is granted to anyone to use this software for any purpose, 7 | including commercial applications, and to alter it and redistribute it freely, 8 | subject to the following restrictions: 9 | 10 | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 11 | If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 12 | 13 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 14 | 15 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Diamond Square 2 | 3 | Example of the diamond square algorithm and procedural generation. 4 | 5 | Watch the reference video: 6 | https://www.youtube.com/watch?v=4GuAV1PnurU 7 | 8 | Play with the interactive HTML5 demo: 9 | https://whiteboxdev.github.io/bundles/example-diamond-square/index.html 10 | 11 | Please click the ☆ button on GitHub if this repository is useful or interesting. Thank you! 12 | 13 | ![alt text](https://github.com/whiteboxdev/example-diamond-square/blob/main/assets/thumbnail.png?raw=true) 14 | 15 | ## Controls 16 | 17 | | Control | Description | 18 | | ------- | ----------- | 19 | | Left Click | Generate a new map. | 20 | | Right Click | Scroll across the map. | 21 | | 1 | Use grayscale graphics. | 22 | | 2 | Use colored graphics. | 23 | | 3 | Decrease the random scalar. | 24 | | 4 | Increase the random scalar. | 25 | -------------------------------------------------------------------------------- /assets/roboto_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteboxdev/example-diamond-square/136cf99659b89f8ea62a0412bcada07e0e39aafd/assets/roboto_regular.ttf -------------------------------------------------------------------------------- /assets/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteboxdev/example-diamond-square/136cf99659b89f8ea62a0412bcada07e0e39aafd/assets/thumbnail.png -------------------------------------------------------------------------------- /assets/tilesource_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteboxdev/example-diamond-square/136cf99659b89f8ea62a0412bcada07e0e39aafd/assets/tilesource_1.png -------------------------------------------------------------------------------- /assets/tilesource_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteboxdev/example-diamond-square/136cf99659b89f8ea62a0412bcada07e0e39aafd/assets/tilesource_2.png -------------------------------------------------------------------------------- /example/camera.go: -------------------------------------------------------------------------------- 1 | components { 2 | id: "script" 3 | component: "/example/camera.script" 4 | position { 5 | x: 0.0 6 | y: 0.0 7 | z: 0.0 8 | } 9 | rotation { 10 | x: 0.0 11 | y: 0.0 12 | z: 0.0 13 | w: 1.0 14 | } 15 | } 16 | embedded_components { 17 | id: "camera" 18 | type: "camera" 19 | data: "aspect_ratio: 1.0\n" 20 | "fov: 0.7854\n" 21 | "near_z: 0.1\n" 22 | "far_z: 1000.0\n" 23 | "auto_aspect_ratio: 0\n" 24 | "orthographic_projection: 0\n" 25 | "orthographic_zoom: 1.0\n" 26 | "" 27 | position { 28 | x: 0.0 29 | y: 0.0 30 | z: 0.0 31 | } 32 | rotation { 33 | x: 0.0 34 | y: 0.0 35 | z: 0.0 36 | w: 1.0 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /example/camera.script: -------------------------------------------------------------------------------- 1 | local h_str = require "example.h_str" 2 | 3 | local scroll = false 4 | 5 | function init(self) 6 | msg.post("#", h_str.acquire_input_focus) 7 | msg.post("#camera", h_str.acquire_camera_focus) 8 | msg.post("@render:", h_str.use_fixed_fit_projection, { near = -1, far = 1 }) 9 | end 10 | 11 | function on_input(self, action_id, action) 12 | if scroll and not action_id then 13 | go.set_position(go.get_position() - vmath.vector3(action.screen_dx, action.screen_dy, 0)) 14 | end 15 | if action.pressed then 16 | if action_id == h_str.button_right then 17 | scroll = true 18 | end 19 | elseif action.released then 20 | if action_id == h_str.button_right then 21 | scroll = false 22 | end 23 | end 24 | end -------------------------------------------------------------------------------- /example/collection.collection: -------------------------------------------------------------------------------- 1 | name: "collection" 2 | instances { 3 | id: "go" 4 | prototype: "/example/go.go" 5 | position { 6 | x: 0.0 7 | y: 0.0 8 | z: 0.0 9 | } 10 | rotation { 11 | x: 0.0 12 | y: 0.0 13 | z: 0.0 14 | w: 1.0 15 | } 16 | scale3 { 17 | x: 1.0 18 | y: 1.0 19 | z: 1.0 20 | } 21 | } 22 | instances { 23 | id: "camera" 24 | prototype: "/example/camera.go" 25 | position { 26 | x: 0.0 27 | y: 0.0 28 | z: 0.0 29 | } 30 | rotation { 31 | x: 0.0 32 | y: 0.0 33 | z: 0.0 34 | w: 1.0 35 | } 36 | scale3 { 37 | x: 1.0 38 | y: 1.0 39 | z: 1.0 40 | } 41 | } 42 | scale_along_z: 0 43 | -------------------------------------------------------------------------------- /example/font_1.font: -------------------------------------------------------------------------------- 1 | font: "/assets/roboto_regular.ttf" 2 | material: "/builtins/fonts/font.material" 3 | size: 32 4 | antialias: 1 5 | alpha: 1.0 6 | outline_alpha: 1.0 7 | outline_width: 1.0 8 | shadow_alpha: 0.0 9 | shadow_blur: 0 10 | shadow_x: 0.0 11 | shadow_y: 0.0 12 | extra_characters: "" 13 | output_format: TYPE_BITMAP 14 | all_chars: false 15 | cache_width: 0 16 | cache_height: 0 17 | render_mode: MODE_SINGLE_LAYER 18 | -------------------------------------------------------------------------------- /example/go.go: -------------------------------------------------------------------------------- 1 | components { 2 | id: "tilemap" 3 | component: "/example/tilemap.tilemap" 4 | position { 5 | x: 0.0 6 | y: 0.0 7 | z: 0.0 8 | } 9 | rotation { 10 | x: 0.0 11 | y: 0.0 12 | z: 0.0 13 | w: 1.0 14 | } 15 | } 16 | components { 17 | id: "script" 18 | component: "/example/go.script" 19 | position { 20 | x: 0.0 21 | y: 0.0 22 | z: 0.0 23 | } 24 | rotation { 25 | x: 0.0 26 | y: 0.0 27 | z: 0.0 28 | w: 1.0 29 | } 30 | } 31 | components { 32 | id: "gui" 33 | component: "/example/gui.gui" 34 | position { 35 | x: 0.0 36 | y: 0.0 37 | z: 0.0 38 | } 39 | rotation { 40 | x: 0.0 41 | y: 0.0 42 | z: 0.0 43 | w: 1.0 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/go.script: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- LICENSE 3 | -------------------------------------------------------------------------------- 4 | 5 | -- Copyright (c) 2024 White Box Dev 6 | 7 | -- This software is provided 'as-is', without any express or implied warranty. 8 | -- In no event will the authors be held liable for any damages arising from the use of this software. 9 | 10 | -- Permission is granted to anyone to use this software for any purpose, 11 | -- including commercial applications, and to alter it and redistribute it freely, 12 | -- subject to the following restrictions: 13 | 14 | -- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 15 | -- If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 16 | 17 | -- 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 18 | 19 | -- 3. This notice may not be removed or altered from any source distribution. 20 | 21 | -------------------------------------------------------------------------------- 22 | -- INFORMATION 23 | -------------------------------------------------------------------------------- 24 | 25 | -- GitHub: https://github.com/whiteboxdev/example-diamond-square 26 | 27 | ---------------------------------------------------------------------- 28 | -- DEPENDENCIES 29 | ---------------------------------------------------------------------- 30 | 31 | local h_str = require "example.h_str" 32 | 33 | ---------------------------------------------------------------------- 34 | -- CONSTANTS 35 | ---------------------------------------------------------------------- 36 | 37 | local height_nil = 0 38 | local height_min = 1 39 | local height_max = 16 40 | local height_map_size = 129 41 | 42 | ---------------------------------------------------------------------- 43 | -- PROPERTIES 44 | ---------------------------------------------------------------------- 45 | 46 | go.property("tilesource_1", resource.tile_source("/example/tilesource_1.tilesource")) 47 | go.property("tilesource_2", resource.tile_source("/example/tilesource_2.tilesource")) 48 | 49 | local height_map = {} 50 | local random_scalar_start = 8 51 | local random_scalar = random_scalar_start 52 | 53 | ---------------------------------------------------------------------- 54 | -- FUNCTIONS 55 | ---------------------------------------------------------------------- 56 | 57 | local function draw() 58 | for i = 1, height_map_size do 59 | for j = 1, height_map_size do 60 | tilemap.set_tile("#tilemap", "layer1", j, i, height_map[i][j]) 61 | end 62 | end 63 | end 64 | 65 | local function round(value) 66 | local result = math.abs(math.ceil(value) - value) > math.abs(value - math.floor(value)) and math.floor(value) or math.ceil(value) 67 | if result < height_min then 68 | return height_min 69 | end 70 | if result > height_max then 71 | return height_max 72 | end 73 | return result 74 | end 75 | 76 | local function random() 77 | return math.random(-1, 1) * random_scalar 78 | end 79 | 80 | local function init_height_map() 81 | height_map = {} 82 | for i = 1, height_map_size do 83 | height_map[i] = {} 84 | for j = 1, height_map_size do 85 | height_map[i][j] = height_nil 86 | end 87 | end 88 | end 89 | 90 | local function diamond_square() 91 | init_height_map() 92 | random_scalar = random_scalar_start 93 | height_map[1][1] = math.random(height_min, height_max) 94 | height_map[1][height_map_size] = math.random(height_min, height_max) 95 | height_map[height_map_size][1] = math.random(height_min, height_max) 96 | height_map[height_map_size][height_map_size] = math.random(height_min, height_max) 97 | local chunk_size = height_map_size - 1 98 | while chunk_size > 1 do 99 | local chunk_size_half = chunk_size / 2 100 | for y = 1, height_map_size - 1, chunk_size do 101 | for x = 1, height_map_size - 1, chunk_size do 102 | height_map[y + chunk_size_half][x + chunk_size_half] = round((height_map[y][x] + height_map[y][x + chunk_size] + height_map[y + chunk_size][x] + height_map[y + chunk_size][x + chunk_size]) / 4 + random()) 103 | end 104 | end 105 | for y = 1, height_map_size, chunk_size_half do 106 | for x = (y + chunk_size_half) % chunk_size, height_map_size, chunk_size do 107 | -- Line 111 below is only required because Lua's arrays are 1-indexed. 108 | -- In 0-indexed languages, the modulus used on line 108 above works without correction. 109 | if x == 0 then x = chunk_size end 110 | local sum = 0 111 | local count = 0 112 | if x - chunk_size_half > 0 then 113 | sum = sum + height_map[y][x - chunk_size_half] 114 | count = count + 1 115 | end 116 | if x + chunk_size_half <= height_map_size then 117 | sum = sum + height_map[y][x + chunk_size_half] 118 | count = count + 1 119 | end 120 | if y - chunk_size_half > 0 then 121 | sum = sum + height_map[y - chunk_size_half][x] 122 | count = count + 1 123 | end 124 | if y + chunk_size_half <= height_map_size then 125 | sum = sum + height_map[y + chunk_size_half][x] 126 | count = count + 1 127 | end 128 | height_map[y][x] = round(sum / count + random()) 129 | end 130 | end 131 | chunk_size = chunk_size / 2 132 | random_scalar = math.max(random_scalar / 2, 0.1) 133 | end 134 | end 135 | 136 | function init(self) 137 | msg.post("#", h_str.acquire_input_focus) 138 | math.randomseed(os.clock() * 100000000000) 139 | diamond_square() 140 | draw() 141 | end 142 | 143 | function on_input(self, action_id, action) 144 | if action.pressed then 145 | if action_id == h_str.button_left then 146 | diamond_square() 147 | draw() 148 | elseif action_id == h_str.one then 149 | go.set("#tilemap", "tile_source", self.tilesource_1) 150 | elseif action_id == h_str.two then 151 | go.set("#tilemap", "tile_source", self.tilesource_2) 152 | elseif action_id == h_str.three then 153 | random_scalar_start = random_scalar_start - 1 154 | if random_scalar_start < 0 then 155 | random_scalar_start = 0 156 | else 157 | msg.post("#gui", h_str.update_random_scalar, { value = random_scalar_start }) 158 | diamond_square() 159 | draw() 160 | end 161 | elseif action_id == h_str.four then 162 | random_scalar_start = random_scalar_start + 1 163 | if random_scalar_start > height_max then 164 | random_scalar_start = height_max 165 | else 166 | msg.post("#gui", h_str.update_random_scalar, { value = random_scalar_start }) 167 | diamond_square() 168 | draw() 169 | end 170 | end 171 | end 172 | end -------------------------------------------------------------------------------- /example/gui.gui: -------------------------------------------------------------------------------- 1 | script: "/example/gui.gui_script" 2 | fonts { 3 | name: "font_1" 4 | font: "/example/font_1.font" 5 | } 6 | background_color { 7 | x: 0.0 8 | y: 0.0 9 | z: 0.0 10 | w: 0.0 11 | } 12 | nodes { 13 | position { 14 | x: 0.0 15 | y: 0.0 16 | z: 0.0 17 | w: 1.0 18 | } 19 | rotation { 20 | x: 0.0 21 | y: 0.0 22 | z: 0.0 23 | w: 1.0 24 | } 25 | scale { 26 | x: 1.0 27 | y: 1.0 28 | z: 1.0 29 | w: 1.0 30 | } 31 | size { 32 | x: 1280.0 33 | y: 44.0 34 | z: 0.0 35 | w: 1.0 36 | } 37 | color { 38 | x: 0.0 39 | y: 0.0 40 | z: 0.0 41 | w: 1.0 42 | } 43 | type: TYPE_BOX 44 | blend_mode: BLEND_MODE_ALPHA 45 | texture: "" 46 | id: "background" 47 | xanchor: XANCHOR_LEFT 48 | yanchor: YANCHOR_BOTTOM 49 | pivot: PIVOT_SW 50 | adjust_mode: ADJUST_MODE_STRETCH 51 | layer: "" 52 | inherit_alpha: true 53 | slice9 { 54 | x: 0.0 55 | y: 0.0 56 | z: 0.0 57 | w: 0.0 58 | } 59 | clipping_mode: CLIPPING_MODE_NONE 60 | clipping_visible: true 61 | clipping_inverted: false 62 | alpha: 0.75 63 | template_node_child: false 64 | size_mode: SIZE_MODE_MANUAL 65 | custom_type: 0 66 | enabled: true 67 | visible: true 68 | material: "" 69 | } 70 | nodes { 71 | position { 72 | x: 10.0 73 | y: 2.0 74 | z: 0.0 75 | w: 1.0 76 | } 77 | rotation { 78 | x: 0.0 79 | y: 0.0 80 | z: 0.0 81 | w: 1.0 82 | } 83 | scale { 84 | x: 1.0 85 | y: 1.0 86 | z: 1.0 87 | w: 1.0 88 | } 89 | size { 90 | x: 200.0 91 | y: 100.0 92 | z: 0.0 93 | w: 1.0 94 | } 95 | color { 96 | x: 1.0 97 | y: 1.0 98 | z: 1.0 99 | w: 1.0 100 | } 101 | type: TYPE_TEXT 102 | blend_mode: BLEND_MODE_ALPHA 103 | text: "Random Scalar = 8" 104 | font: "font_1" 105 | id: "random_scalar" 106 | xanchor: XANCHOR_LEFT 107 | yanchor: YANCHOR_BOTTOM 108 | pivot: PIVOT_SW 109 | outline { 110 | x: 0.0 111 | y: 0.0 112 | z: 0.0 113 | w: 1.0 114 | } 115 | shadow { 116 | x: 1.0 117 | y: 1.0 118 | z: 1.0 119 | w: 1.0 120 | } 121 | adjust_mode: ADJUST_MODE_FIT 122 | line_break: false 123 | layer: "" 124 | inherit_alpha: true 125 | alpha: 1.0 126 | outline_alpha: 1.0 127 | shadow_alpha: 1.0 128 | template_node_child: false 129 | text_leading: 1.0 130 | text_tracking: 0.0 131 | custom_type: 0 132 | enabled: true 133 | visible: true 134 | material: "" 135 | } 136 | material: "/builtins/materials/gui.material" 137 | adjust_reference: ADJUST_REFERENCE_PARENT 138 | max_nodes: 512 139 | -------------------------------------------------------------------------------- /example/gui.gui_script: -------------------------------------------------------------------------------- 1 | local h_str = require "example.h_str" 2 | 3 | function on_message(self, message_id, message, sender) 4 | if message_id == h_str.update_random_scalar then 5 | gui.set_text(gui.get_node(h_str.random_scalar), "Random Scalar = " .. message.value) 6 | end 7 | end -------------------------------------------------------------------------------- /example/h_str.lua: -------------------------------------------------------------------------------- 1 | local h_str = {} 2 | 3 | h_str.acquire_camera_focus = hash("acquire_camera_focus") 4 | h_str.use_fixed_fit_projection = hash("use_fixed_fit_projection") 5 | h_str.button_right = hash("button_right") 6 | h_str.button_left = hash("button_left") 7 | h_str.acquire_input_focus = hash("acquire_input_focus") 8 | h_str.one = hash("one") 9 | h_str.two = hash("two") 10 | h_str.three = hash("three") 11 | h_str.four = hash("four") 12 | h_str.update_random_scalar = hash("update_random_scalar") 13 | h_str.random_scalar = hash("random_scalar") 14 | 15 | return h_str -------------------------------------------------------------------------------- /example/tilesource_1.tilesource: -------------------------------------------------------------------------------- 1 | image: "/assets/tilesource_1.png" 2 | tile_width: 16 3 | tile_height: 16 4 | tile_margin: 0 5 | tile_spacing: 0 6 | collision: "" 7 | material_tag: "tile" 8 | extrude_borders: 2 9 | inner_padding: 0 10 | sprite_trim_mode: SPRITE_TRIM_MODE_OFF 11 | -------------------------------------------------------------------------------- /example/tilesource_2.tilesource: -------------------------------------------------------------------------------- 1 | image: "/assets/tilesource_2.png" 2 | tile_width: 16 3 | tile_height: 16 4 | tile_margin: 0 5 | tile_spacing: 0 6 | collision: "" 7 | material_tag: "tile" 8 | extrude_borders: 2 9 | inner_padding: 0 10 | sprite_trim_mode: SPRITE_TRIM_MODE_OFF 11 | -------------------------------------------------------------------------------- /game.project: -------------------------------------------------------------------------------- 1 | [bootstrap] 2 | main_collection = /example/collection.collectionc 3 | 4 | [script] 5 | shared_state = 1 6 | 7 | [display] 8 | width = 1280 9 | height = 720 10 | 11 | [android] 12 | input_method = HiddenInputField 13 | 14 | [project] 15 | title = Diamond Square 16 | version = 1.0.0 17 | publisher = White Box Dev 18 | developer = White Box Dev 19 | 20 | [graphics] 21 | default_texture_min_filter = nearest 22 | default_texture_mag_filter = nearest 23 | 24 | [tilemap] 25 | max_tile_count = 16641 26 | 27 | [html5] 28 | show_fullscreen_button = 0 29 | scale_mode = no_scale 30 | cssfile = /builtins/manifests/web/dark_theme.css 31 | 32 | -------------------------------------------------------------------------------- /input/game.input_binding: -------------------------------------------------------------------------------- 1 | key_trigger { 2 | input: KEY_1 3 | action: "one" 4 | } 5 | key_trigger { 6 | input: KEY_2 7 | action: "two" 8 | } 9 | key_trigger { 10 | input: KEY_3 11 | action: "three" 12 | } 13 | key_trigger { 14 | input: KEY_4 15 | action: "four" 16 | } 17 | mouse_trigger { 18 | input: MOUSE_BUTTON_RIGHT 19 | action: "button_right" 20 | } 21 | mouse_trigger { 22 | input: MOUSE_BUTTON_LEFT 23 | action: "button_left" 24 | } 25 | --------------------------------------------------------------------------------