ruby-perlin-2D-map-generator 0.0.4 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +104 -40
- data/lib/CLI/command.rb +101 -8
- data/lib/ansi_colours.rb +3 -0
- data/lib/biome.rb +20 -10
- data/lib/building.rb +20 -0
- data/lib/flora_generator.rb +28 -0
- data/lib/map.rb +33 -1
- data/lib/map_config.rb +53 -8
- data/lib/map_tile_generator.rb +1 -0
- data/lib/pathfinding/a_star_finder.rb +70 -0
- data/lib/pathfinding/grid.rb +78 -0
- data/lib/pathfinding/priority_queue.rb +73 -0
- data/lib/poisson_disk_sampling/sample_area.rb +43 -0
- data/lib/poisson_disk_sampling/sampler.rb +108 -0
- data/lib/road_generator.rb +70 -0
- data/lib/tile.rb +80 -16
- data/lib/town_generator.rb +154 -0
- metadata +37 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8bef2e8554e39c0e315b940f4a98a8927348ae576a7f12168c86c74f969c241b
|
4
|
+
data.tar.gz: b3debfe8269979c1f1f0be2a8def6a86de9fcd2a8ad6f548295113068ec04566
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c91f9810eda61b360e26b31944820b2587ff9e6a10776cdc84347475470573b381853e63b629781fbc0f18eb9fc33299fad31e2a436ef7f7a66d67db8dbb2ea2
|
7
|
+
data.tar.gz: 8c12388e0e7965165557bc5680f030d6d2da9a42e35cc066fbff2390de0e6076c2318e7d62000d17026fa91206adb1ff631eff0ff6af5d670ef81e3d206e45a0
|
data/README.md
CHANGED
@@ -3,16 +3,18 @@
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/ruby-perlin-2D-map-generator.svg)](https://badge.fury.io/rb/ruby-perlin-2D-map-generator)
|
4
4
|
![CI Status](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/actions/workflows/main.yml/badge.svg)
|
5
5
|
![CodeQL](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/workflows/CodeQL/badge.svg)
|
6
|
+
<a href="https://codeclimate.com/github/matthewstyler/ruby-perlin-2D-map-generator/test_coverage"><img src="https://api.codeclimate.com/v1/badges/b99aae29d02b7a8a4cc6/test_coverage" /></a>
|
7
|
+
<a href="https://codeclimate.com/github/matthewstyler/ruby-perlin-2D-map-generator/maintainability"><img src="https://api.codeclimate.com/v1/badges/b99aae29d02b7a8a4cc6/maintainability" /></a>
|
6
8
|
[![Downloads](https://img.shields.io/gem/dt/ruby-perlin-2D-map-generator.svg?style=flat)](https://rubygems.org/gems/ruby-perlin-2D-map-generator)
|
7
9
|
|
8
|
-
A gem that procedurally generates seeded and customizable 2D map using perlin noise.
|
10
|
+
A gem that procedurally generates seeded and customizable 2D map with optional roads and towns using perlin noise.
|
9
11
|
|
10
12
|
Include the gem in your project, or use the executable from the command line.
|
11
13
|
|
12
14
|
Map can be rendered in console using ansi colors or returned as 2D array of hashes describing each tile and binome. Completely customizable, use the --help option for full usage details.
|
13
15
|
|
14
16
|
|
15
|
-
![2D-maps](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/assets/4560901/
|
17
|
+
![2D-maps](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/assets/4560901/6234ebc1-f3bd-48b5-9b78-4d286d2c8d6e)
|
16
18
|
|
17
19
|
|
18
20
|
# Installation
|
@@ -34,6 +36,7 @@ gem install ruby-perlin-2D-map-generator
|
|
34
36
|
See Command line Usage for full customization, below are some examples. Alter the temperature, moisture or elevation seeds to alter these maps:
|
35
37
|
|
36
38
|
- Plains with random terrain evens: `ruby-perlin-2D-map-generator render`
|
39
|
+
- Plains with random terrain events and two roads: `ruby-perlin-2D-map-generator render --roads=2`
|
37
40
|
- Desert (increase temperature, decrease moisture): `ruby-perlin-2D-map-generator render --temp=100 --moisture=-100`
|
38
41
|
- Mountainous with lakes (increase elevation, increase moisture) `ruby-perlin-2D-map-generator render --elevation=25 --moisture=25`
|
39
42
|
- Islands (decreaes elevation, increase moisture): `ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25`
|
@@ -44,21 +47,42 @@ See Command line Usage for full customization, below are some examples. Alter th
|
|
44
47
|
--width=int The width of the generated map (default 128)
|
45
48
|
--height=int The height of the generated map (default 128)
|
46
49
|
|
50
|
+
--roads=int Add this many roads through the map,
|
51
|
+
starting and ending at edges
|
52
|
+
(default 0)
|
53
|
+
--towns=int Add this randomly sized towns
|
54
|
+
(default 0)
|
47
55
|
--hs=int The seed for a terrains height perlin generation
|
48
56
|
(default 10)
|
49
57
|
--ms=int The seed for a terrains moist perlin generation
|
50
58
|
(default 300)
|
51
59
|
--ts=int The seed for a terrains temperature perlin generation
|
52
60
|
(default 3000)
|
61
|
+
--rs=int The seed for generating roads
|
62
|
+
(default 100)
|
53
63
|
|
54
|
-
--elevation=float Adjust each generated elevation by this percent (
|
64
|
+
--elevation=float Adjust each generated elevation by this percent (-100 -
|
55
65
|
100) (default 0.0)
|
56
|
-
--moisture=float Adjust each generated moisture by this percent (
|
66
|
+
--moisture=float Adjust each generated moisture by this percent (-100 -
|
57
67
|
100) (default 0.0)
|
58
|
-
--temp=float Adjust each generated temperature by this percent (
|
68
|
+
--temp=float Adjust each generated temperature by this percent (-100
|
59
69
|
- 100) (default 0.0)
|
60
70
|
```
|
61
71
|
|
72
|
+
## Roads and the heuristic
|
73
|
+
Roads can be generated by providing a positive integer to the `roads=` argument. Roads are randomly seeded to begin
|
74
|
+
and start at an axis (but not the same axis).
|
75
|
+
|
76
|
+
A* pathfinding with a priority queue is used to generate the roads. The heuristic uses manhattan distance, and favours existing roads and similar elevations in adjacent tiles.
|
77
|
+
|
78
|
+
Roads can be configured to include/exclude generating paths thorugh water, mountains and flora.
|
79
|
+
|
80
|
+
Tiles containing roads are of type `road`, those without are of type `terrain`.
|
81
|
+
|
82
|
+
The `--roads_to_make` option allows you to specify multiple pairs of coordinates to attempt to build paths, subject to the heuristic and other option constraints. Expects a a single list, but must be sets of 4, example of two roads: `--roads_to_make=0,0,50,50,0,0,75,75`
|
83
|
+
|
84
|
+
## Towns
|
85
|
+
With Poisson Disk Sampling, towns can be generated randomly or with a provided x,y coordinate used as a centroid with radius. The result will be tiles that contain `Building` `items`. Buildings in a town are connected by roads, and additionally towns are connected to other towns by roads.
|
62
86
|
# Generate without rendering
|
63
87
|
|
64
88
|
```irb
|
@@ -112,7 +136,7 @@ $ ruby-perlin-2D-map-generator --help
|
|
112
136
|
```bash
|
113
137
|
Usage: ruby-perlin-2D-map-generator [OPTIONS] (DESCRIBE | RENDER)
|
114
138
|
|
115
|
-
Generate a seeded customizable procedurally generated 2D map.
|
139
|
+
Generate a seeded customizable procedurally generated 2D map with optional roads.
|
116
140
|
Rendered in the console using ansi colours, or described as a 2D array of
|
117
141
|
hashes with each tiles information.
|
118
142
|
|
@@ -128,40 +152,74 @@ Keywords:
|
|
128
152
|
coordinate tile details
|
129
153
|
|
130
154
|
Options:
|
131
|
-
--elevation=float
|
132
|
-
|
133
|
-
--fhx=float
|
134
|
-
|
135
|
-
--fhy=float
|
136
|
-
|
137
|
-
--fmx=float
|
138
|
-
|
139
|
-
--fmy=float
|
140
|
-
|
141
|
-
--ftx=float
|
142
|
-
|
143
|
-
--fty=float
|
144
|
-
|
145
|
-
--gf=bool
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
--
|
151
|
-
|
152
|
-
--
|
153
|
-
|
154
|
-
--
|
155
|
-
|
156
|
-
--
|
157
|
-
|
158
|
-
--
|
159
|
-
|
160
|
-
--
|
161
|
-
|
162
|
-
--
|
163
|
-
|
164
|
-
--
|
155
|
+
--elevation=float Adjust each generated elevation by
|
156
|
+
this percent (-100 - 100) (default 0.0)
|
157
|
+
--fhx=float The frequency for height generation
|
158
|
+
across the x-axis (default 2.5)
|
159
|
+
--fhy=float The frequency for height generation
|
160
|
+
across the y-axis (default 2.5)
|
161
|
+
--fmx=float The frequency for moist generation
|
162
|
+
across the x-axis (default 2.5)
|
163
|
+
--fmy=float The frequency for moist generation
|
164
|
+
across the y-axis (default 2.5)
|
165
|
+
--ftx=float The frequency for temp generation
|
166
|
+
across the x-axis (default 2.5)
|
167
|
+
--fty=float The frequency for temp generation
|
168
|
+
across the y-axis (default 2.5)
|
169
|
+
--gf=bool Generate flora, significantly affects
|
170
|
+
performance
|
171
|
+
--height=int The height of the generated map
|
172
|
+
(default 128)
|
173
|
+
-h, --help Print usage
|
174
|
+
--hs=int The seed for a terrains height perlin
|
175
|
+
generation (default 10)
|
176
|
+
--moisture=float Adjust each generated moisture by
|
177
|
+
this percent (-100 - 100) (default 0.0)
|
178
|
+
--ms=int The seed for a terrains moist perlin
|
179
|
+
generation (default 300)
|
180
|
+
--oh=int Octaves for height generation
|
181
|
+
(default 3)
|
182
|
+
--om=int Octaves for moist generation (default
|
183
|
+
3)
|
184
|
+
--ot=int Octaves for temp generation (default
|
185
|
+
3)
|
186
|
+
--ph=float Persistance for height generation
|
187
|
+
(default 1.0)
|
188
|
+
--pm=float Persistance for moist generation
|
189
|
+
(default 1.0)
|
190
|
+
--pt=float Persistance for temp generation
|
191
|
+
(default 1.0)
|
192
|
+
--road_exclude_flora_path=bool Controls if roads will run tiles
|
193
|
+
containing flora
|
194
|
+
--road_exclude_mountain_path=bool Controls if roads will run through
|
195
|
+
high mountains
|
196
|
+
--road_exclude_water_path=bool Controls if roads will run through
|
197
|
+
water
|
198
|
+
--roads=int Add this many roads through the map,
|
199
|
+
starting and ending at edges (default
|
200
|
+
0)
|
201
|
+
--roads_to_make ints Attempt to create a road from a start
|
202
|
+
and end point (4 integers), can be
|
203
|
+
supplied multiple paths
|
204
|
+
(default [])
|
205
|
+
--rs=int The seed for generating roads
|
206
|
+
(default 100)
|
207
|
+
--temp=float Adjust each generated temperature by
|
208
|
+
this percent (-100 - 100) (default 0.0)
|
209
|
+
--town_seed=int The seed for generating towns
|
210
|
+
(default 500)
|
211
|
+
--towns=int Add this many randomly sized towns
|
212
|
+
throughout the map
|
213
|
+
(default 0)
|
214
|
+
--towns_to_make ints Attempt to create a town at given x,y
|
215
|
+
coordinate, with z points and v radius
|
216
|
+
(4 integers). Can be supplied multiple
|
217
|
+
towns.
|
218
|
+
(default [])
|
219
|
+
--ts=int The seed for a terrains temperature
|
220
|
+
perlin generation (default 3000)
|
221
|
+
--width=int The width of the generated map
|
222
|
+
(default 128)
|
165
223
|
|
166
224
|
Examples:
|
167
225
|
Render with defaults
|
@@ -169,6 +227,12 @@ Examples:
|
|
169
227
|
|
170
228
|
Render with options
|
171
229
|
$ ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25 --hs=1
|
230
|
+
|
231
|
+
Render with roads
|
232
|
+
$ ruby-perlin-2D-map-generator render --roads=2
|
233
|
+
|
234
|
+
Render with 5 roads, 1 provided road, 10 random towns and 1 provided town
|
235
|
+
$ ruby-perlin-2D-map-generator render --roads=5 --roads_to_make=0,0,50,50 --towns=10 --towns_to_make=5,5,10,3
|
172
236
|
|
173
237
|
Describe tile [1, 1]
|
174
238
|
$ ruby-perlin-2D-map-generator describe coordinates=1,1
|
data/lib/CLI/command.rb
CHANGED
@@ -12,7 +12,7 @@ module CLI
|
|
12
12
|
|
13
13
|
no_command
|
14
14
|
|
15
|
-
desc 'Generate a seeded customizable procedurally generated 2D map. Rendered in the console ' \
|
15
|
+
desc 'Generate a seeded customizable procedurally generated 2D map with optional roads. Rendered in the console ' \
|
16
16
|
' using ansi colours, or described as a 2D array of hashes with each tiles information.'
|
17
17
|
|
18
18
|
example 'Render with defaults',
|
@@ -21,6 +21,9 @@ module CLI
|
|
21
21
|
example 'Render with options',
|
22
22
|
' $ ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25 --hs=1'
|
23
23
|
|
24
|
+
example 'Render with roads',
|
25
|
+
' $ ruby-perlin-2D-map-generator render --roads=2'
|
26
|
+
|
24
27
|
example 'Describe tile [1, 1]',
|
25
28
|
' $ ruby-perlin-2D-map-generator describe coordinates=1,1'
|
26
29
|
end
|
@@ -41,6 +44,24 @@ module CLI
|
|
41
44
|
desc 'Used with the describe command, only returns the given coordinate tile details'
|
42
45
|
end
|
43
46
|
|
47
|
+
option :roads_to_make do
|
48
|
+
arity one
|
49
|
+
long '--roads_to_make ints'
|
50
|
+
convert :int_list
|
51
|
+
validate ->(v) { v >= 0 }
|
52
|
+
desc 'Attempt to create a road from a start and end point (4 integers), can be supplied multiple paths'
|
53
|
+
default MapConfig::DEFAULT_ROADS_TO_MAKE
|
54
|
+
end
|
55
|
+
|
56
|
+
option :towns_to_make do
|
57
|
+
arity one
|
58
|
+
long '--towns_to_make ints'
|
59
|
+
convert :int_list
|
60
|
+
validate ->(v) { v >= 0 }
|
61
|
+
desc 'Attempt to create a town at given x,y coordinate, with z points and v radius (4 integers). Can be supplied multiple towns.'
|
62
|
+
default MapConfig::DEFAULT_TOWNS_TO_MAKE
|
63
|
+
end
|
64
|
+
|
44
65
|
option :height_seed do
|
45
66
|
long '--hs int'
|
46
67
|
# or
|
@@ -210,7 +231,7 @@ module CLI
|
|
210
231
|
long '--temp float'
|
211
232
|
long '--temp=float'
|
212
233
|
|
213
|
-
desc 'Adjust each generated temperature by this percent (
|
234
|
+
desc 'Adjust each generated temperature by this percent (-100 - 100)'
|
214
235
|
convert ->(val) { val.to_f / 100.0 }
|
215
236
|
validate ->(val) { val >= -1.0 && val <= 1.0 }
|
216
237
|
default MapConfig::DEFAULT_TEMP_ADJUSTMENT
|
@@ -220,7 +241,7 @@ module CLI
|
|
220
241
|
long '--elevation float'
|
221
242
|
long '--elevation=float'
|
222
243
|
|
223
|
-
desc 'Adjust each generated elevation by this percent (
|
244
|
+
desc 'Adjust each generated elevation by this percent (-100 - 100)'
|
224
245
|
convert ->(val) { val.to_f / 100.0 }
|
225
246
|
validate ->(val) { val >= -1.0 && val <= 1.0 }
|
226
247
|
default MapConfig::DEFAULT_HEIGHT_ADJUSTMENT
|
@@ -230,12 +251,83 @@ module CLI
|
|
230
251
|
long '--moisture float'
|
231
252
|
long '--moisture=float'
|
232
253
|
|
233
|
-
desc 'Adjust each generated moisture by this percent (
|
254
|
+
desc 'Adjust each generated moisture by this percent (-100 - 100)'
|
234
255
|
convert ->(val) { val.to_f / 100.0 }
|
235
256
|
validate ->(val) { val >= -1.0 && val <= 1.0 }
|
236
257
|
default MapConfig::DEFAULT_MOIST_ADJUSTMENT
|
237
258
|
end
|
238
259
|
|
260
|
+
option :roads do
|
261
|
+
long '--roads int'
|
262
|
+
long '--roads=int'
|
263
|
+
|
264
|
+
desc 'Add this many roads through the map, starting and ending at edges'
|
265
|
+
convert Integer
|
266
|
+
validate ->(val) { val >= 0 }
|
267
|
+
default MapConfig::DEFAULT_NUM_OF_ROADS
|
268
|
+
end
|
269
|
+
|
270
|
+
option :road_seed do
|
271
|
+
long '--rs int'
|
272
|
+
long '--rs=int'
|
273
|
+
|
274
|
+
desc 'The seed for generating roads'
|
275
|
+
convert Integer
|
276
|
+
default MapConfig::DEFAULT_ROAD_SEED
|
277
|
+
end
|
278
|
+
|
279
|
+
option :road_exclude_water_path do
|
280
|
+
long '--road_exclude_water_path bool'
|
281
|
+
long '--road_exclude_water_path=bool'
|
282
|
+
|
283
|
+
desc 'Controls if roads will run through water'
|
284
|
+
convert :bool
|
285
|
+
default MapConfig::DEFAULT_ROAD_EXCLUDE_WATER_PATH
|
286
|
+
end
|
287
|
+
|
288
|
+
option :road_exclude_mountain_path do
|
289
|
+
long '--road_exclude_mountain_path bool'
|
290
|
+
long '--road_exclude_mountain_path=bool'
|
291
|
+
|
292
|
+
desc 'Controls if roads will run through high mountains'
|
293
|
+
convert :bool
|
294
|
+
default MapConfig::DEFAULT_ROAD_EXCLUDE_MOUNTAIN_PATH
|
295
|
+
end
|
296
|
+
|
297
|
+
option :road_exclude_flora_path do
|
298
|
+
long '--road_exclude_flora_path bool'
|
299
|
+
long '--road_exclude_flora_path=bool'
|
300
|
+
|
301
|
+
desc 'Controls if roads will run tiles containing flora'
|
302
|
+
convert :bool
|
303
|
+
default MapConfig::DEFAULT_ROAD_EXCLUDE_FLORA_PATH
|
304
|
+
end
|
305
|
+
|
306
|
+
option :town_seed do
|
307
|
+
long '--town_seed int'
|
308
|
+
long '--town_seed=int'
|
309
|
+
|
310
|
+
desc 'The seed for generating towns'
|
311
|
+
convert Integer
|
312
|
+
default MapConfig::DEFAULT_TOWN_SEED
|
313
|
+
end
|
314
|
+
|
315
|
+
option :towns do
|
316
|
+
long '--towns int'
|
317
|
+
long '--towns=int'
|
318
|
+
|
319
|
+
desc 'Add this many randomly sized towns throughout the map'
|
320
|
+
convert Integer
|
321
|
+
validate ->(val) { val >= 0 }
|
322
|
+
default MapConfig::DEFAULT_NUM_OF_TOWNS
|
323
|
+
end
|
324
|
+
|
325
|
+
option :verbose do
|
326
|
+
arity one
|
327
|
+
long '--verbose'
|
328
|
+
desc 'Used with the render command, outputs loading information'
|
329
|
+
end
|
330
|
+
|
239
331
|
flag :help do
|
240
332
|
short '-h'
|
241
333
|
long '--help'
|
@@ -259,10 +351,11 @@ module CLI
|
|
259
351
|
map = Map.new(map_config: MapConfig.new(
|
260
352
|
width: params[:width],
|
261
353
|
height: params[:height],
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
354
|
+
all_perlin_configs: MapConfig::AllPerlinConfigs.new(perlin_height_config, perlin_moist_config, perlin_temp_config),
|
355
|
+
generate_flora: params[:generate_flora],
|
356
|
+
road_config: MapConfig::RoadConfig.new(*params.to_h.slice(:road_seed, :roads, :road_exclude_water_path, :road_exclude_mountain_path, :road_exclude_flora_path, :roads_to_make).values),
|
357
|
+
town_config: MapConfig::TownConfig.new(*params.to_h.slice(:town_seed, :towns, :towns_to_make).values),
|
358
|
+
verbose: params[:verbose]
|
266
359
|
))
|
267
360
|
case params[:command]
|
268
361
|
when 'render' then map.render
|
data/lib/ansi_colours.rb
CHANGED
data/lib/biome.rb
CHANGED
@@ -32,6 +32,10 @@ class Biome
|
|
32
32
|
TAIGA_TERRAIN.include?(self)
|
33
33
|
end
|
34
34
|
|
35
|
+
def high_mountain?
|
36
|
+
HIGH_MOUNTAIN.include?(self)
|
37
|
+
end
|
38
|
+
|
35
39
|
def flora_available
|
36
40
|
!flora_range.nil?
|
37
41
|
end
|
@@ -132,6 +136,12 @@ class Biome
|
|
132
136
|
TAIGA_COAST
|
133
137
|
].freeze
|
134
138
|
|
139
|
+
HIGH_MOUNTAIN = [
|
140
|
+
SNOW,
|
141
|
+
ROCKS,
|
142
|
+
MOUNTAIN
|
143
|
+
].freeze
|
144
|
+
|
135
145
|
LAND_TERRAIN = (ALL_TERRAIN - WATER_TERRAIN).freeze
|
136
146
|
|
137
147
|
class << self
|
@@ -141,21 +151,21 @@ class Biome
|
|
141
151
|
case elevation
|
142
152
|
when 0.95..1
|
143
153
|
SNOW
|
144
|
-
when 0.9
|
154
|
+
when 0.9...0.95
|
145
155
|
ROCKS
|
146
|
-
when 0.8
|
156
|
+
when 0.8...0.9
|
147
157
|
if moist < 0.9
|
148
158
|
MOUNTAIN
|
149
159
|
else
|
150
160
|
SHOAL
|
151
161
|
end
|
152
|
-
when 0.7
|
162
|
+
when 0.7...0.8
|
153
163
|
if moist < 0.9
|
154
164
|
MOUNTAIN_FOOT
|
155
165
|
else
|
156
166
|
SHOAL
|
157
167
|
end
|
158
|
-
when 0.6
|
168
|
+
when 0.6...0.7
|
159
169
|
if moist < 0.8
|
160
170
|
if desert_condition?(moist, temp)
|
161
171
|
STEPPE_DESERT
|
@@ -169,7 +179,7 @@ class Biome
|
|
169
179
|
else
|
170
180
|
SHOAL
|
171
181
|
end
|
172
|
-
when 0.3
|
182
|
+
when 0.3...0.6
|
173
183
|
if desert_condition?(moist, temp)
|
174
184
|
DESERT
|
175
185
|
elsif taiga_condition?(moist, temp)
|
@@ -177,7 +187,7 @@ class Biome
|
|
177
187
|
else
|
178
188
|
VALLEY
|
179
189
|
end
|
180
|
-
when 0.2
|
190
|
+
when 0.2...0.3
|
181
191
|
if desert_condition?(moist, temp)
|
182
192
|
DEEP_DESERT
|
183
193
|
elsif taiga_condition?(moist, temp)
|
@@ -185,25 +195,25 @@ class Biome
|
|
185
195
|
else
|
186
196
|
DEEP_VALLEY
|
187
197
|
end
|
188
|
-
when 0.15
|
198
|
+
when 0.15...0.2
|
189
199
|
if taiga_condition?(moist, temp)
|
190
200
|
TAIGA_COAST
|
191
201
|
else
|
192
202
|
COASTLINE
|
193
203
|
end
|
194
|
-
when 0.05
|
204
|
+
when 0.05...0.15
|
195
205
|
if taiga_condition?(moist, temp)
|
196
206
|
ICE
|
197
207
|
else
|
198
208
|
SHOAL
|
199
209
|
end
|
200
|
-
when 0.025
|
210
|
+
when 0.025...0.05
|
201
211
|
if taiga_condition?(moist, temp)
|
202
212
|
ICE
|
203
213
|
else
|
204
214
|
OCEAN
|
205
215
|
end
|
206
|
-
when 0.0
|
216
|
+
when 0.0...0.025
|
207
217
|
if taiga_condition?(moist, temp)
|
208
218
|
ICE
|
209
219
|
else
|
data/lib/building.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tile_item'
|
4
|
+
|
5
|
+
#
|
6
|
+
# Represents a building item on a tile
|
7
|
+
#
|
8
|
+
class Building < TileItem
|
9
|
+
TOWN_RENDER_PRIORITY = DEFAULT_RENDER_PRIORITY + 1
|
10
|
+
|
11
|
+
HOUSE = "\u{1F3E0}"
|
12
|
+
|
13
|
+
def initialize(render_symbol)
|
14
|
+
super self, render_symbol: render_symbol, render_priority: TOWN_RENDER_PRIORITY
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.random_town_building(_seed)
|
18
|
+
Building.new(HOUSE)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Generates flora for the given tiles
|
5
|
+
#
|
6
|
+
class FloraGenerator
|
7
|
+
attr_reader :tiles
|
8
|
+
|
9
|
+
def initialize(tiles)
|
10
|
+
@tiles = tiles
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate(config)
|
14
|
+
return unless config.generate_flora
|
15
|
+
|
16
|
+
puts 'generating flora...' if config.verbose
|
17
|
+
tiles.each do |row|
|
18
|
+
row.each do |tile|
|
19
|
+
next unless tile.biome.flora_available
|
20
|
+
|
21
|
+
range_max_value = tiles[(tile.y - tile.biome.flora_range)...(tile.y + tile.biome.flora_range)]&.map do |r|
|
22
|
+
r[(tile.x - tile.biome.flora_range)...(tile.x + tile.biome.flora_range)]
|
23
|
+
end&.flatten&.map(&:height)&.max
|
24
|
+
tile.add_flora if range_max_value == tile.height
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/map.rb
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'map_tile_generator'
|
4
4
|
require 'map_config'
|
5
|
+
require 'road_generator'
|
6
|
+
require 'town_generator'
|
7
|
+
require 'flora_generator'
|
5
8
|
|
6
9
|
class Map
|
7
10
|
attr_reader :config
|
@@ -30,6 +33,35 @@ class Map
|
|
30
33
|
# rubocop:enable Naming/MethodParameterName:
|
31
34
|
|
32
35
|
def tiles
|
33
|
-
@tiles
|
36
|
+
return @tiles if @tiles
|
37
|
+
|
38
|
+
generate_tiles
|
39
|
+
generate_flora
|
40
|
+
generate_roads
|
41
|
+
generate_towns
|
42
|
+
|
43
|
+
@tiles
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def generate_tiles
|
49
|
+
@tiles = MapTileGenerator.new(map: self).generate
|
50
|
+
end
|
51
|
+
|
52
|
+
def generate_flora
|
53
|
+
FloraGenerator.new(@tiles).generate(config)
|
54
|
+
end
|
55
|
+
|
56
|
+
def generate_roads
|
57
|
+
road_generator = RoadGenerator.new(@tiles)
|
58
|
+
road_generator.generate_num_of_random_roads(config.road_config)
|
59
|
+
road_generator.generate_roads_from_coordinate_list(config.road_config.roads_to_make, config.verbose)
|
60
|
+
end
|
61
|
+
|
62
|
+
def generate_towns
|
63
|
+
town_generator = TownGenerator.new(@tiles, seed: config.town_config.town_seed)
|
64
|
+
town_generator.generate_random_towns(config.town_config)
|
65
|
+
town_generator.generate_towns_from_coordinate_list(config.town_config)
|
34
66
|
end
|
35
67
|
end
|
data/lib/map_config.rb
CHANGED
@@ -25,25 +25,57 @@ class MapConfig
|
|
25
25
|
DEFAULT_TEMP_X_FREQUENCY = 2.5
|
26
26
|
DEFAULT_TEMP_ADJUSTMENT = 0.0
|
27
27
|
|
28
|
+
DEFAULT_ROAD_SEED = 100
|
29
|
+
DEFAULT_NUM_OF_ROADS = 0
|
30
|
+
DEFAULT_ROAD_EXCLUDE_WATER_PATH = true
|
31
|
+
DEFAULT_ROAD_EXCLUDE_MOUNTAIN_PATH = true
|
32
|
+
DEFAULT_ROAD_EXCLUDE_FLORA_PATH = true
|
33
|
+
DEFAULT_ROADS_TO_MAKE = [].freeze
|
34
|
+
|
35
|
+
DEFAULT_TOWN_SEED = 500
|
36
|
+
DEFAULT_NUM_OF_TOWNS = 0
|
37
|
+
DEFAULT_TOWNS_TO_MAKE = [].freeze
|
38
|
+
|
39
|
+
DEFAULT_VERBOSE = false
|
40
|
+
|
28
41
|
PERLIN_CONFIG_OPTIONS = %i[width height noise_seed octaves x_frequency y_frequency persistance adjustment].freeze
|
29
|
-
|
42
|
+
ALL_PERLIN_CONFIGS = %i[perlin_height_config perlin_moist_config perlin_temp_config].freeze
|
43
|
+
ROAD_CONFIG_OPTIONS = %i[road_seed roads road_exclude_water_path road_exclude_mountain_path road_exclude_flora_path roads_to_make verbose].freeze
|
44
|
+
TOWN_CONFIG_OPTIONS = %i[town_seed towns towns_to_make verbose].freeze
|
30
45
|
|
31
|
-
|
46
|
+
PerlinConfig = Struct.new(*PERLIN_CONFIG_OPTIONS)
|
47
|
+
AllPerlinConfigs = Struct.new(*ALL_PERLIN_CONFIGS)
|
48
|
+
RoadConfig = Struct.new(*ROAD_CONFIG_OPTIONS)
|
49
|
+
TownConfig = Struct.new(*TOWN_CONFIG_OPTIONS)
|
32
50
|
|
33
|
-
|
34
|
-
height: DEFAULT_TILE_COUNT, generate_flora: DEFAULT_GENERATE_FLORA)
|
35
|
-
raise ArgumentError unless perlin_height_config.is_a?(PerlinConfig) && perlin_moist_config.is_a?(PerlinConfig)
|
51
|
+
attr_reader :generate_flora, :perlin_height_config, :perlin_moist_config, :perlin_temp_config, :width, :height, :road_config, :town_config, :verbose
|
36
52
|
|
53
|
+
# rubocop:disable Metrics/ParameterLists:
|
54
|
+
def initialize(all_perlin_configs: default_perlin_configs, width: DEFAULT_TILE_COUNT,
|
55
|
+
height: DEFAULT_TILE_COUNT, generate_flora: DEFAULT_GENERATE_FLORA, road_config: default_road_config, town_config: default_town_config, verbose: DEFAULT_VERBOSE)
|
56
|
+
validate(all_perlin_configs)
|
37
57
|
@generate_flora = generate_flora
|
38
|
-
@perlin_height_config = perlin_height_config
|
39
|
-
@perlin_moist_config = perlin_moist_config
|
40
|
-
@perlin_temp_config = perlin_temp_config
|
58
|
+
@perlin_height_config = all_perlin_configs.perlin_height_config
|
59
|
+
@perlin_moist_config = all_perlin_configs.perlin_moist_config
|
60
|
+
@perlin_temp_config = all_perlin_configs.perlin_temp_config
|
41
61
|
@width = width
|
42
62
|
@height = height
|
63
|
+
@road_config = road_config
|
64
|
+
@town_config = town_config
|
65
|
+
@verbose = verbose
|
66
|
+
town_config.verbose = verbose
|
67
|
+
road_config.verbose = verbose
|
43
68
|
end
|
69
|
+
# rubocop:enable Metrics/ParameterLists:
|
44
70
|
|
45
71
|
private
|
46
72
|
|
73
|
+
def validate(all_perlin_configs)
|
74
|
+
unless all_perlin_configs.perlin_height_config.is_a?(PerlinConfig) && all_perlin_configs.perlin_moist_config.is_a?(PerlinConfig) && all_perlin_configs.perlin_temp_config.is_a?(PerlinConfig)
|
75
|
+
raise ArgumentError
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
47
79
|
def default_perlin_height_config
|
48
80
|
PerlinConfig.new(DEFAULT_TILE_COUNT, DEFAULT_TILE_COUNT, DEFAULT_HEIGHT_SEED, DEFAULT_HEIGHT_OCTAVES,
|
49
81
|
DEFAULT_HEIGHT_X_FREQUENCY, DEFAULT_HEIGHT_Y_FREQUENCY, DEFAULT_HEIGHT_PERSISTANCE, DEFAULT_HEIGHT_ADJUSTMENT)
|
@@ -58,4 +90,17 @@ class MapConfig
|
|
58
90
|
PerlinConfig.new(DEFAULT_TILE_COUNT, DEFAULT_TILE_COUNT, DEFAULT_TEMP_SEED, DEFAULT_TEMP_OCTAVES,
|
59
91
|
DEFAULT_TEMP_X_FREQUENCY, DEFAULT_TEMP_Y_FREQUENCY, DEFAULT_TEMP_PERSISTANCE, DEFAULT_TEMP_ADJUSTMENT)
|
60
92
|
end
|
93
|
+
|
94
|
+
def default_road_config
|
95
|
+
RoadConfig.new(DEFAULT_ROAD_SEED, DEFAULT_NUM_OF_ROADS, DEFAULT_ROAD_EXCLUDE_WATER_PATH, DEFAULT_ROAD_EXCLUDE_MOUNTAIN_PATH, DEFAULT_ROAD_EXCLUDE_FLORA_PATH, DEFAULT_ROADS_TO_MAKE,
|
96
|
+
DEFAULT_VERBOSE)
|
97
|
+
end
|
98
|
+
|
99
|
+
def default_town_config
|
100
|
+
TownConfig.new(DEFAULT_TOWN_SEED, DEFAULT_NUM_OF_TOWNS, DEFAULT_TOWNS_TO_MAKE, DEFAULT_VERBOSE)
|
101
|
+
end
|
102
|
+
|
103
|
+
def default_perlin_configs
|
104
|
+
AllPerlinConfigs.new(default_perlin_height_config, default_perlin_moist_config, default_perlin_temp_config)
|
105
|
+
end
|
61
106
|
end
|