Генерируем случайные острова на Instead

Решил наваять карту по которой будет бродить герой новой игры. Крупный такой остров например. Но на одной и той же карте конечно скучно будет бродить, надо сгенерировать песочницу же. Взял и сделал.

Пётр сказал что видит тут зайца.
Перед вами кривой код генерирующий остров среди моря на карте размером 50х50, код тяжелый и вероятно неоптимальный. Хотя результат неплохой. Держите вот готовый и рабочий main.lua:
-- $Name:Генерация острова$
-- $Version:0.01$
-- $Name(ru):Генерация острова$
instead_version "2.4.1"

require "xact"			-- подключаем модуль xact
require "hideinv"		-- подключаем модуль hideinv
require "para"			-- догадайтесь, что мы подключили в этот раз ;)
require "dash"			-- подключаем dash
require "quotes"		-- подключаем quotes

game.codepage="UTF-8";

game.act = 'Не получается.';
game.inv = 'Хм, странная штука.';
game.use = 'Не сработает.';

global {
map = 'box:500x500,gray,255';
array = {};
a = 50;
b = 50;
x = 0;
y = 0;
};

---Начало---------------------------------------------------------------------------------------------------------------

main = room {
	forcedsc = true;
	nam = 'генерация карты';
	pic = function()
		return(map);
	end;
	obj = {'mapgen'};
};

mapgen = obj {
	nam = 'map';
	dsc = '{сгенерировать карту}';
	act = function()
--заливаю море
		for a = 1, 50 do
			array[a] = {};
			for b = 1, 50 do
				array[a][b] = 0;
			end;
		end;
--раскидываю горы ближе к центру поля
		a = rnd(30) + 10;
		b = rnd(30) + 10;
		array[a][b] = 1;
--строим горы	
		local i = 0;
		for i = 0, 250 do
-- тут задается случайное смещение следующей горы относительно предыдущей, вместо rnd(3) можно вписать другое значение, случайное или нет. 250 проходов по циклу тоже получены методом научного тыка.
			if rnd(2) == 1 then a = a + rnd(3); else a = a - rnd(3); end;
			if rnd(2) == 1 then b = b + rnd(3); else b = b - rnd(3); end;
--оставим немного места, некрасиво, когда суша примыкает к краям карты
			if a < 4 or a > 46 then a = rnd(30) + 10; end;
			if b < 4 or b > 46 then b = rnd(30) + 10; end;
			array[a][b] = 1;
		end;
--растим траву вокруг гор
		i = 0;
		for a = 2, 49 do
			for b = 2, 49 do
				if array[a][b] == 0 then
					if array[a+1][b] == 1 or array[a-1][b] == 1 or array[a][b+1] == 1 or array[a][b-1] == 1 or array[a+1][b+1] == 1 or array[a+1][b-1] == 1 or array[a-1][b+1] == 1 or array[a-1][b-1] == 1 then
						array[a][b] = 2;
					end;
				end;
			end;
		end;
--сносим одиночные горы
		i = 0;
		for a = 2, 49 do
			for b = 2, 49 do
				if array[a][b] == 1 then
					if array[a+1][b] == 2 and array[a-1][b] == 2 and array[a][b+1] == 2 and array[a][b-1] == 2 then
						array[a][b] = 2;
					end;
				end;
			end;
		end;

--сыпем песок вокруг травы
		i = 0;
		for a = 2, 49 do
			for b = 2, 49 do
				if array[a][b] == 0 then
					if array[a+1][b] == 2 or array[a-1][b] == 2 or array[a][b+1] == 2 or array[a][b-1] == 2 or array[a+1][b+1] == 2 or array[a+1][b-1] == 2 or array[a-1][b+1] == 2 or array[a-1][b-1] == 2 then
						array[a][b] = 3;
					end;
				end;
			end;
		end;
--упс, много песка насыпали, оставим только по берегам
		i = 0;
		for a = 2, 49 do
			for b = 2, 49 do
				if array[a][b] == 3 then
					if array[a+1][b] ~= 0 and array[a-1][b] ~= 0 and array[a][b+1] ~= 0 and array[a][b-1] ~= 0 and array[a+1][b+1] ~= 0 and array[a+1][b-1] ~= 0 and array[a-1][b+1] ~= 0 and array[a-1][b-1] ~= 0 then
						array[a][b] = 2;
					end;
				end;
			end;
		end;

--рисуем карту
		for a = 1, 50 do
			for b = 1, 50 do
				x = a*10 - 10;
				y = b*10 - 10;
				if array[a][b] == 1 then
					map = map..'box:10x10,gray,255@'..x..','..y..';';
				elseif array[a][b] == 2 then
					map = map..'box:10x10,green,255@'..x..','..y..';';
				elseif array[a][b] == 3 then
					map = map..'box:10x10,yellow,255@'..x..','..y..';';
				else
					map = map..'box:10x10,blue,255@'..x..','..y..';';
				end;
			end;
		end;
		return true;
	end;
}
Ну и на закуску еще пара скриншотов, для рисования я использовал тупо квадраты залитые нужной краской типа box:50x50,blue,255, но далее конечно пристрою сюда текстурки посимпатичнее.
Скриншот выше показывает что получается если не убирать лишний песок.

Вносим предложения по коду, а то проц грузит при генерации неплохо.

8 комментариев

techniX
Если инициализировать переменные map и array внутри mapgen:

mapgen = obj {
	nam = 'map';
	dsc = '{сгенерировать карту}';
	act = function()
            map = 'box:500x500,gray,255';
            array = {};

	    for a = 1, 50 do
            ...
то будет работать заметно быстрее при повторном запуске генерации :)
epoxa
Я так понимаю, что
here().pic = map
потеряется после восстановления из сохранёнки.
Irremann
Исправил пример, там должно быть норм.
epoxa
И мне кажется, что пейзаж без удаления лишнего песка естественнее выглядит.
Oreolek
Палим название игры :-) код хороший, но горы получаются какими-то ущельями. Можно взять кривые Безье (квадратичных хватит) и сыпать горы при помощи них, так горы будут соединены, как хребет, а не вырастать случайно.

Ещё стоит не сыпать песок вокруг воды внутри леса, это же озёра.

P.S. А зачем вообще такой огромный остров? 50x50 = 2500, это очень сложно сделать достаточно разнообразным и интересным одному человеку.
Комментарий отредактирован: 19 января 2017, 14:40 (4 раза)
esse
No Man Island. К такой генерации карты еще бы сюжет хороший и персонажей. Или будет рогалик?
techniX
Irremann, тебе может быть интересно :)
www.sibylmoon.com/a-procedurally-generated-wilderness/
Там автор описывает свой подход к процедурной генерации описаний локаций. Как по мне, выглядит очень интересно.