package elm_playground_gamekits
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Genre kits for Playground games: platformers, racing, shoot 'em ups, fighting and more
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.6.tar.gz
md5=7c636383d146d30ac6f2fa234a6253c8
sha512=c79f3823c5f8f57e5038eb640d487c61168b84aa07c61999d6622ef9fd0c890e2b03b4c6a7cdbbe9352a49e25dda00ac7bb14693cee8e3d7beeed251351a2af0
doc/src/elm_playground_gamekits.kit_heightmap/Heightmap.ml.html
Source file Heightmap.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143(* Claude Code * * Copyright (C) 2026 Yoann Padioleau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * (LGPL) as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. *) type t = { size : int; cells : float array; top : float; sea : float } (*****************************************************************************) (* Making it up *) (*****************************************************************************) (* every step keeps the low 30 bits: those of a product are the same * whether it was computed on 32 bits (the web) or 63 (native) *) let random (seed : int) (i : int) (j : int) : float = let mask = 0x3FFFFFFF in let h = ((seed * 0x27d4eb2d) + (i * 0x165667b1) + (j * 0x1b873593)) land mask in let h = h lxor (h lsr 15) in let h = (h * 0x2c1b3c6d) land mask in let h = h lxor (h lsr 12) in let h = (h * 0x297a2d39) land mask in let h = h lxor (h lsr 15) in (float_of_int h /. float_of_int mask *. 2.) -. 1. (* Diamond-square, on a grid that wraps around (the cell after the last * is the first: no edges to special-case), [step] halved each time: * * a . . . b a . . . b a . e . b * . . . . . . . . . . . . . . . * . . . . . -> . . m . . -> h . m . f * . . . . . . . . . . . . . . . * d . . . c d . . . c d . g . c * the diamond: the square: e, f, g, h, the * m, a b c d's average of the 4 points around * average + bump (the next squares' m's too) + bump *) let diamond_square (seed : int) (size : int) (roughness : float) : float array = let a = Array.make (size * size) 0. in let index i j = ((j land (size - 1)) * size) + (i land (size - 1)) in let get i j = a.(index i j) in let set i j v = a.(index i j) <- v in let rec go step bump = if step > 1 then begin let h = step / 2 in for y = 0 to (size / step) - 1 do for x = 0 to (size / step) - 1 do let i = x * step and j = y * step in let corners = get i j +. get (i + step) j +. get i (j + step) +. get (i + step) (j + step) in set (i + h) (j + h) ((corners /. 4.) +. (bump *. random seed (i + h) (j + h))) done done; for y = 0 to (size / h) - 1 do for x = 0 to (size / h) - 1 do (* the edges' middles: an odd number of halves from the corner *) if (x + y) land 1 = 1 then begin let i = x * h and j = y * h in let around = get (i - h) j +. get (i + h) j +. get i (j - h) +. get i (j + h) in set i j ((around /. 4.) +. (bump *. random seed i j)) end done done; go h (bump *. roughness) end in go size 1.; a let generate ~(seed : int) ~(size : int) ~(top : float) ~(roughness : float) : t = let a = diamond_square seed size roughness in let lo = Array.fold_left Float.min infinity a and hi = Array.fold_left Float.max neg_infinity a in (* 0..1, then lowered by the squared distance to the middle (0 there, * 1 at an edge's middle): the island *) let half = float_of_int size /. 2. in let island = Array.mapi (fun k h -> let dx = (float_of_int (k mod size) -. half) /. half and dy = (float_of_int (k / size) -. half) /. half in ((h -. lo) /. (hi -. lo)) -. (1.5 *. ((dx *. dx) +. (dy *. dy)))) a in let high = Array.fold_left Float.max neg_infinity island in let sea = top /. 5. in (* 0 (and less) the sea's level, [high] the top *) { size; top; sea; cells = Array.map (fun h -> Float.max sea (sea +. (h /. high *. (top -. sea)))) island } (*****************************************************************************) (* Asking *) (*****************************************************************************) let cell (t : t) (i : int) (j : int) : float = if i < 0 || j < 0 || i >= t.size || j >= t.size then t.sea else t.cells.((j * t.size) + i) let height (t : t) (x : float) (y : float) : float = let i = Float.to_int (Float.floor x) and j = Float.to_int (Float.floor y) in let fx = x -. Float.floor x and fy = y -. Float.floor y in let mix a b f = a +. ((b -. a) *. f) in mix (mix (cell t i j) (cell t (i + 1) j) fx) (mix (cell t i (j + 1)) (cell t (i + 1) (j + 1)) fx) fy let clear (t : t) ((x1, y1, z1) : float * float * float) ((x2, y2, z2) : float * float * float) : bool = let n = Float.to_int (Float.hypot (x2 -. x1) (y2 -. y1)) + 1 in let above k = let f = float_of_int k /. float_of_int n in z1 +. ((z2 -. z1) *. f) > height t (x1 +. ((x2 -. x1) *. f)) (y1 +. ((y2 -. y1) *. f)) in List.for_all above (List.init (n + 1) Fun.id) (*****************************************************************************) (* Colors *) (*****************************************************************************) type kind = Sea | Sand | Grass | Forest | Rock | Snow let kinds = [ Sea; Sand; Grass; Forest; Rock; Snow ] let kind (t : t) (i : int) (j : int) : kind = let h = cell t i j in (* how high between the sea and the top, 0..1 *) let f = (h -. t.sea) /. (t.top -. t.sea) in if h <= t.sea then Sea else if f < 0.04 then Sand else if f < 0.35 then Grass else if f < 0.6 then Forest else if f < 0.82 then Rock else Snow let light (t : t) (i : int) (j : int) : int = let slope = cell t i j -. cell t (i - 1) j in let steep = t.top /. 200. in (* going up eastward: the slope faces west, the sun *) if slope > steep then 0 else if slope < -.steep then 2 else 1 let color (k : kind) (light : int) : int * int * int = let r, g, b = match k with | Sea -> (40, 90, 170) | Sand -> (214, 196, 136) | Grass -> (86, 156, 64) | Forest -> (42, 104, 46) | Rock -> (128, 116, 104) | Snow -> (236, 238, 244) in let f = match (k, light) with Sea, _ -> 1. | _, 0 -> 1.18 | _, 1 -> 1. | _ -> 0.72 in let c x = min 255 (Float.to_int (float_of_int x *. f)) in (c r, c g, c b)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>