class Worldgen::PlateMap
A map that generates plates within a square map.
Attributes
size[R]
Public Class Methods
new(size)
click to toggle source
# File lib/worldgen/platemap.rb, line 87 def initialize size @size = size @plate_ids = nil @plates = nil end
Public Instance Methods
each_plate_point() { |x, y, plate_ids[y]| ... }
click to toggle source
Iterate across the entire map.
Usage:
each_plate_point do |x, y, plate_id| # do something with this information end
# File lib/worldgen/platemap.rb, line 129 def each_plate_point (0...@size).each do |x| (0...@size).each do |y| yield x, y, @plate_ids[x][y] end end end
generate_plates!(num_plates, verbose=true)
click to toggle source
Generate plates within this map.
Arguments:
-
num_plates - the number of plates to generate
-
verbose (default: true) - output logging while we're generating
# File lib/worldgen/platemap.rb, line 142 def generate_plates! num_plates, verbose=true @plate_ids = Array.new(@size) { Array.new(@size) { -1 }} # Initialize plates in random spots @plates = (0...num_plates).map do |plate_num| # Find an unoccupied point point = nil while point == nil x, y = rand(@size), rand(@size) point = [x, y] if @plate_ids[x][y] < 0 end x, y = point @plate_ids[x][y] = plate_num Plate.new.tap do |plate| plate.map = @plate_ids plate.id = plate_num plate.type = rand < 0.5 ? :continent : :ocean plate.seed = point end end num_points = self.num_points - num_plates valid_plates = @plates.select(&:has_frontier?) i = 0 while valid_plates.length > 0 if verbose and i % (num_points / 100) == 0 puts "#{i}/#{num_points} #{(i.fdiv(num_points) * 100).round}%" end # Find a plate with neighbours loop do idx = choose_plate valid_plates plate = valid_plates[idx] # absorb a point from the frontier value = plate.absorb_frontier! if not value valid_plates.delete_at idx break if valid_plates.length == 0 else # Did we just consume the last point of this plate? valid_plates.delete_at(idx) if not plate.has_frontier? break end end i += 1 end end
num_points()
click to toggle source
Get the number of points in the map.
# File lib/worldgen/platemap.rb, line 94 def num_points @size * @size end
to_height_map(sea_gap)
click to toggle source
Convert to a height map - very simple, just give the continents one height and the oceans another height. This is controlled by a single parameter, (({sea_gap})), which will be the difference between the continents height and oceans height.
# File lib/worldgen/platemap.rb, line 102 def to_height_map sea_gap raise "Sea gap should be between 0 and 1" if sea_gap < 0 or sea_gap > 1 plate_heights = @plates.map do |plate| if plate.type == :continent 0.5 + sea_gap / 2 else 0.5 - sea_gap / 2 end end map = HeightMap.new @size each_plate_point do |x, y, id| map[x, y] = plate_heights[id] end map end
Private Instance Methods
choose_plate(plates)
click to toggle source
Choose a plate randomly from a list of plates
# File lib/worldgen/platemap.rb, line 200 def choose_plate plates # Weighted choice based on frontier length - if we do it perfectly uniform # then we end up with plates that "compress" into small remaining places # which results in "snaky" plates and weird convergence points between # many plates # TODO: could probably pull weighted randoms into a different module total = plates.map(&:frontier_length).inject(&:+) # There is the possibility of #return 0 if total == 0 # TODO: using a uniform random generator here gives plates that are all # roughly the same size - kinda boring, maybe try using a non-uniform # distribution here point = rand(total) idx = 0 begin while point > plates[idx].frontier_length point -= plates[idx].frontier_length idx += 1 end rescue # TODO: fix this - once in a while we get an out of bounds problem here puts $! puts $!.backtrace.join("\n") puts "Point: #{point}" puts "Idx: #{idx}" puts "Total: #{total}" end idx end