3 February 2014

Генератор космических кораблей из арматуры

JavaScriptGame developmentCanvas
Доброго времени на вашей стороне планеты, Хабр.
Сегодня на хабре прямо день космических кораблей, столько интересных статей про последнюю битву в EVE Online, ну а я в свободное время я продолжаю делать свою двухмерную космическую игру и после длительного перерыва взялся за генератор кораблей. Пусть корабли и не такие шикарные как в EVE, зато свои.



Кому интересно как такой рендер на канве сделать, прошу под кат.

Вступление


Для начала нужно сказать для чего нужен такой генератор. Причин несколько:
  • Спрайты кораблей нужны, а рисовать я толком не умею, но компьютер умеет
  • Очень хотелось сделать в игре пилотам возможность создавать свои чертежи кораблей, без однотипного набора кораблей на рынке
  • Я всегда смотрел на красивые концепты различной техники которые делают художники, и мне хотелось хотя бы чуть-чуть приблизится к такому уровню
  • Ну и это просто интересно

Что должен уметь генератор:
  • На основе JSON данных(основанных на vessel specification, о которой далее) генерить картинку корабля, на прозрачном фоне, для вставку в игру
  • Генерить красивый рендер, который можно скачать, залить, и запостить на где-нибудь на форумах
  • Выдавать конфиг корабля, который также можно скопипастить на форумы, и другой человек может поглядеть что там за дарвинский пепелац сорудили =)

Теперь поподробней о этой vessel specification, которая видна на рендере сверху. Технически она описывает как именно должны собираться корабли и из чего. С точки зрения бэкстори это что-то вроде ГОСТ'а, который придуман чтобы стандартизировать производство кораблей коммерческими компаниями. С точки зрения геймплея это попытка сделать какой-то общий дизайн кораблей, который не позволит создать тайловый редактор (когда по клеточкам рисуются корабли). Конечно общий дизайн это довольно условно, потому что редактирование конфига позволяет менять очень немало.
Из чего же составляются корабли по этому «ГОСТ'у»? Основой являются линии(line), линия это набор секций(section), которые располагаются параллельно друг другу. Секция — это компонент плюс два блока, которые скрепляют несколько секций в линию. Компонент же может быть много чем, это может быть просто скрепления, которые нужны только для увеличения прочности конструкции, не значительно увеличивающие её массу, или грузовым блоком, или блоком управления, или двигателем, или платформой для установки вооружения и так далее.
Думаю я уже достаточно рассказал о том, что такое генератор кораблей, давайте теперь посмотрим как же он собственно генерит эти рендеры.

Шаг 0 — Готовим холсты и краски


Для начала нам нужно настроить три канвы, #backCanvs, #mainCanvas и #topCanvas.

<canvas id="backCanvas"  width="640" height="480"></canvas>	
<canvas id="mainCanvas"  width="640" height="480"></canvas>	
<canvas id="topCanvas"  width="640" height="480"></canvas>

Вот функция инициализации, в ней использован очень известный трюк, с установкой разрешения канвы, больше чем её визуальные размеры.

//Вызываем функцию инициализации слоев
var canvasSize = { width: Math.floor(window.innerWidth*3.5),
                   height: Math.floor(window.innerHeight*3.5) };
var cssSize = { width: window.innerWidth, height: window.innerHeight };

shipGen.layerInit(["#backCanvas", "#mainCanvas", "#topCanvas"], canvasSize, cssSize);
//Сама функция
shipGen.layerInit = function(canvases, canvasSize, cssSize) {
	shipGen.config.canvasSize = canvasSize;
	shipGen.config.cssSize = cssSize;
    //Если слои есть, очищаем их и удаляем
	for(var i in shipGen.layers) {
		shipGen.layers[i].clearRect(0, 0, canvasSize.width, canvasSize.height)
	}
	shipGen.layers = [];
	for(var i in canvases) {
		shipGen.layers.push($(canvases[i]).attr("width", canvasSize.width)
		                .attr("height", canvasSize.height)
		                .css("width", cssSize.width)
		                .css("height", cssSize.height).get(0).getContext("2d"));
	}
}


Шаг 0.5 — Готовим кисточки


Теперь нужно сделать второе, и самое важное — конфиги.
Как я уже говорил сам конфиг корабля записываем в JSON формате, который потом парсится в Javascript Object, но ещё есть настройки самой рисовалки:

lines: [], //Сюда помещаются распарсеный JSON-конфиг
config: { //Настройки для отрисовки
    factor: 15, //Маштабирование
    factorRandLight: 3, //Нужно для распределения лампочек
    angle: 0, //Угол поворота корабля
    canvasSize: {}, //Размеры канвы
    designName: "", //Название
    authorName: "" //Автор
},
counters: { //Различные счетчики, которые подсчитываются в процессе отрисовки или рядом
    heightShip: 0, //Длина корабля
	hull: 0, //Показатель прочности корпуса
	linesCount: 0, //Сколько всего линий
	sectionsCount: 0, //Сколько всего секций
	totalMass: 0, //Суммарная масса корабля
},
data: { //Собираем данные по конкретным компонентам
	engines: [],
	blocks: [],
	pipes: [],
	cargos: []
}

Конфиг корабля мы задаем так:

try {
  if(localStorage["config"]) {
    shipGen.lines = JSON.parse(localStorage["config"]); 
  }
  else {
    shipGen.lines = JSON.parse($("#text").val()); 
  }
  
}
catch(e) {
  alert("Error parse config");
}

Привожу в пример небольшой конфг конфига корабля. Сначала описывается массив всех линий(в данном случае их три), для каждой линии указывается смещение следующей линии, и перечисляются секции, в данном случае их по две на линию.
Скрытый текст
[
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 8,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 10,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 8,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    }
]


Всё готово, начинаем писать.

Шаг 1 — Пишем звезды на первом холсте


Не только звезды, но и небольшую туманность. Это делается двумя функциями:

shipGen.render.nebula(Math.random(), canvasSize.width, canvasSize.height);
shipGen.render.stars(Math.random(), canvasSize.width, canvasSize.height);

Не вижу смысла приводить большие куски кода рисования фона, кто хочет может посмотреть в коде, а заголовок статьи всё-таки имеет подстроку «корабли», вот к ним и перейдем.
Но тем не менее у нас уже получилось что-то такое:



Шаг 2 — Пишем космический аппарат на втором холсте


Здесь уже интересней, нам нужно отрисовать в каждой линии, каждую секцию, и блоки скрепляющий секции. Основная функция выглядит так, всё с подробными комментариями:

shipGen.process = function() {
	//Берем #mainCanvas
	var ctx = shipGen.layers[1];
	//Смещаем и поворачиваем контекст
	ctx.translate(shipGen.config.canvasSize.width/2, shipGen.config.canvasSize.height/2);
	ctx.rotate(shipGen.config.angle);
	//Записываем количество линий
	shipGen.counters.linesCount = shipGen.lines.length;
	//Вспомогательная переменная, отмеряющая насколько мы сместились по X координате
	//в процессе отрисовки линий
	var lenShiftX = 0;
	for (var i = 0; i < shipGen.counters.linesCount; i++) {

		ctx.save();
		//Берем данные о секциях
		var sections = shipGen.lines[i].sections;
		//Крутим цикл по каждому компоненту секции
		for(var component in sections) {
			//В процессе подсчитываем суммарное количество секций в кораблей
	  		shipGen.counters.sectionsCount += 1  
	  		//Берем набор параметров компонента, добавляем к нему некоторые служебные данные и вызываем отрисовку компонента
	  		shipGen.selectComponent(sections[component], {lenShiftX: lenShiftX, blockTopW: sections[component].blockW2, blockBottomW: sections[component].blockW1 } );
		}
		ctx.restore();
		lenShiftX += shipGen.lines[i].nextLineX;
		//Смещаем отрисовку вправо, для того чтобы рядом нарисовать следующую паралелльную линию
		ctx.translate(shipGen.lines[i].nextLineX, 0);
	}
}


Функцией selectComponent отрисовываем в нужном месте сначала первый блок, потом вызываем функцию рисования конкретного компонента, потом рисуем закрывающий блок:

...
shipGen.block(obj.blockW1, obj.blockH1);
...
shipGen.components[obj.name](obj);
...
shipGen.block(obj.blockW1, obj.blockH1);
...

Каждый компонент рисуется своей функцией, банальными moveTo/LineTo/rect/fill/stroke. Просто представляем как должен выглядеть компонент и последовательно вызываем функции по нужным координатам. Вот несколько примеров:
Pipe'ы и блоки:



Двигатели:



Грузовые блоки:



Ну и так далее, можно сделать много разных компонентов, что и нужно сделать, но пока для тестов нового формата кораблей достаточно и трех.
Финальный результат корабля, с конфигом:
Скрытый текст
[
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "4": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
              "name": "pipe",
              "blockW1": 10,
              "blockH1": 10,
              "blockW2": 10,
              "blockH2": 10,
              "width": 8,
              "height": 80,
              "color": {"r":20,"g":20,"b":20},
              "shift": 0, 
              "step": 35
          },
          "4": {
              "name": "pipe",
              "blockW1": 10,
              "blockH1": 10,
              "blockW2": 10,
              "blockH2": 10,
              "width": 8,
              "height": 80,
              "color": {"r":20,"g":20,"b":20},
              "shift": 0, 
              "step": 35
          }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "4": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            }
        }
    }
]




Шаг 3 — Пишем красивый текст на третьем холсте


Остался предпоследний этап, нужно офоромить характеристики корабля в виде красивого текста. Ну хотя бы чуть-чуть красивого.
И делаем это очень легко, просто меняем размеры шрифта, и смещаемся постепенно вниз по Y координате. Как раз таки используем данные из конфига об авторе, названии дизайна и другие. Кстати об авторе и названии дизайна, я сделал пока их статичными, потому что они будут вытащены при интеграции с игрой, а пока пусть будут Unnamed и Unknown.
//Вызов рисования текста
shipGen.render.text();
//Сама функция
shipGen.render.text = function() {
    var ctx = shipGen.layers[2];
    //Номер дизайна
    ctx.fillStyle = "#fff";
    ctx.strokeStyle = "#fff";
    ctx.font = "130pt Arial";
    ctx.fillText("Vessel Design " + shipGen.config.number, 220, 220);
    //Название формата
    ctx.font = "50pt Arial";
    ctx.fillText("Vessel specification of Tranquilla Community VSC-V3", 250, 320); 
    
    ctx.font = "40pt Arial";
    //Название дизайна
    ctx.fillText("Design name: " + shipGen.config.designName, 250, 420); 
    //Имя автора дизайна
    ctx.fillText("Author name: " + shipGen.config.authorName, 250, 520); 
    //Где мы делали этот дизайн
    ctx.fillText("Place: Tranq One IV Station 41 (1020; 1210)", 250, 620); 

    ctx.font = "35pt Arial";
    //Основные характеристики
    ctx.fillText("Mass: " + shipGen.counters.totalMass, 250, 750); 
    ctx.fillText("Hull: " + shipGen.counters.hull, 250, 800); 
    ctx.fillText("Lines count: " + shipGen.counters.linesCount , 250, 850); 
    ctx.fillText("Sections count: " + shipGen.counters.sectionsCount, 250, 900); 
    ctx.fillText("Block count: " + shipGen.data.blocks.length, 250, 950); 
    ctx.fillText("Pipe count: " + shipGen.data.pipes.length, 250, 1000);

    var lineY = 1150;
    //Характеристики компонентов
    for(var i in shipGen.data) {
      if(i == "blocks" || i == "pipes") continue;
      ctx.fillText(i.toString() + ":", 250, lineY - 50); 
      for (var v in shipGen.data[i]) {
        ctx.fillText(i.toString() + ": " + JSON.stringify(shipGen.data[i][v], "", 1).replace(/\"/g, ''), 250, lineY); 
        lineY += 50;
      }
      lineY+=100;
    }
}

Результат мы уже видели выше, привожу тоже самое для другого конфига.
Скрытый текст
[   {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 40,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 40,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
       {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 40,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    }
]




Шаг 4 — Открываем выставку


Последний этап, подключаем FileSaver.js, и пишем такую простую сохранялку, объединяя все слои.
$("#save-render").click(function(){
    var canvasMerge = $("<canvas width='"+canvasSize.width+"' height='"+canvasSize.height+"'></canvas>").get(0);
    var ctxMerge = canvasMerge.getContext("2d");

    ctxMerge.fillStyle = "#000";
    ctxMerge.fillRect(0, 0, canvasSize.width, canvasSize.height);
    ctxMerge.drawImage($("#backCanvas").get(0), 0, 0);
    ctxMerge.drawImage($("#mainCanvas").get(0), 0, 0);
    ctxMerge.drawImage($("#topCanvas").get(0), 0, 0);
    canvasMerge.toBlob(function(blob) {
      saveAs(blob, "render.png");
    });
});


Заключение


Для тех кто не хочет мучатся с ручным редактированием конфигов, а просто хочет посмотреть на кораблики, я здесь привожу несколько конфигов, которые я делал в процессе рарзработки. Чтобы поглядеть на них нужно нажать внизу на ссылку «Edit config», вставить в выбранный конфиг, и нажать также внизу «Apply».
Громадная шестилинейка
[   {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 40,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 40,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
       {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 40,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    }
]
	




Грузовой корабль
[
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
              "name": "pipe",
              "blockW1": 10,
              "blockH1": 10,
              "blockW2": 10,
              "blockH2": 10,
              "width": 8,
              "height": 80,
              "color": {"r":20,"g":20,"b":20},
              "shift": 0, 
              "step": 35
          },
          "4": {
              "name": "pipe",
              "blockW1": 10,
              "blockH1": 10,
              "blockW2": 10,
              "blockH2": 10,
              "width": 8,
              "height": 80,
              "color": {"r":20,"g":20,"b":20},
              "shift": 0, 
              "step": 35
          }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "4": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
              "name": "pipe",
              "blockW1": 10,
              "blockH1": 10,
              "blockW2": 10,
              "blockH2": 10,
              "width": 8,
              "height": 80,
              "color": {"r":20,"g":20,"b":20},
              "shift": 0, 
              "step": 35
          },
          "4": {
              "name": "pipe",
              "blockW1": 10,
              "blockH1": 10,
              "blockW2": 10,
              "blockH2": 10,
              "width": 8,
              "height": 80,
              "color": {"r":20,"g":20,"b":20},
              "shift": 0, 
              "step": 35
          }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "4": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            }
        }
    },
        {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
              "name": "pipe",
              "blockW1": 10,
              "blockH1": 10,
              "blockW2": 10,
              "blockH2": 10,
              "width": 8,
              "height": 80,
              "color": {"r":20,"g":20,"b":20},
              "shift": 0, 
              "step": 35
          },
          "4": {
              "name": "pipe",
              "blockW1": 10,
              "blockH1": 10,
              "blockW2": 10,
              "blockH2": 10,
              "width": 8,
              "height": 80,
              "color": {"r":20,"g":20,"b":20},
              "shift": 0, 
              "step": 35
          }
        }
    }
]




Небольшой легкий кораблик
[
    {
        "nextLineX": 100,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 8,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 100,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 10,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 100,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 10,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 10,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 8,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    }
]




Тоже большой корабль, но плохо сделанный
[
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "cargo",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 50,
                "blockH2": 60,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "2": {
                "name": "cargo",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 50,
                "blockH2": 60,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "3": {
                "name": "cargo",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 50,
                "blockH2": 60,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            },
            "4": {
                "name": "cargo",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 50,
                "blockH2": 60,
                "width": 35,
                "height": 35,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                }
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 50,
                "blockH2": 60,
                "width": 15,
                "height": 70,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 40,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 50,
                "blockH2": 60,
                "width": 15,
                "height": 70,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 50,
                "blockH2": 60,
                "width": 15,
                "height": 70,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 30,
                "blockH2": 40,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 90,
                "width": 15,
                "height": 30,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    },
    {
        "nextLineX": 200,
        "sections": {
            "0": {
                "name": "engine",
                "blockW1": 0,
                "blockH1": 0,
                "blockW2": 20,
                "blockH2": 10,
                "width": 12,
                "height": 8,
                "color": {
                    "r": 25,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "widthLeft": 8,
                "widthRight": 8
            },
            "1": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 50,
                "blockH2": 60,
                "width": 15,
                "height": 70,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "2": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "3": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 10,
                "blockH2": 10,
                "width": 15,
                "height": 40,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            },
            "4": {
                "name": "pipe",
                "blockW1": 40,
                "blockH1": 10,
                "blockW2": 40,
                "blockH2": 10,
                "width": 15,
                "height": 80,
                "color": {
                    "r": 20,
                    "g": 20,
                    "b": 20
                },
                "shift": 0,
                "step": 35
            }
        }
    }
]




Весь код доступен как всегда на гитхабе: github.com/MagistrAVSH/ship-gen
Демо можно увидеть здесь: magistravsh.github.io/ship-gen
В следующий раз надеюсь уже написать об интеграции редактора с игрой, думаю это будет интересно.
Fly safe!
Tags:space shipsкосмические корабликосмосspace gamespace flightjust another space simjass2djscanvasспейс шипдизайнергенераторвсем надоели шутки про теги
Hubs: JavaScript Game development Canvas
+12
17.8k 64
Comments 25
Popular right now