JSFiddle - React, Tailwind, and code Playground

Basic terrain builder for rpgGame

by jcubed111

HTML

<div id="newPopup" class="">
  Width: <input type="text" id="w" value="20"> <br/>
  Height: <input type="text" id="h" value="20"> <br/>
  <button onclick="init()">Go</button><br/><br/>
  Or open from a file: <input type="file" id="opener" />
</div>
<div id="view">
  <canvas id="display" oncontextmenu="return false;"></canvas>
</div>
<div id="controls">
  <div id="selector_air" class="selector cell air active" onClick="setType('air')"></div>
  <div id="selector_solid" class="selector cell solid" onClick="setType('solid')"></div>
  <div id="selector_solidSW" class="selector cell solidSW" onClick="setType('solidSW')"></div>
  <div id="selector_solidSE" class="selector cell solidSE" onClick="setType('solidSE')"></div>
  <div id="selector_solidNW" class="selector cell solidNW" onClick="setType('solidNW')"></div>
  <div id="selector_solidNE" class="selector cell solidNE" onClick="setType('solidNE')"></div>
  <div id="selector_upperscore" class="selector cell upperscore" onClick="setType('upperscore')"></div>
  <div id="selector_slash" class="selector cell slash" onClick="setType('slash')"></div>
  <div id="selector_backslash" class="selector cell backslash" onClick="setType('backslash')"></div>
  <div id="selector_upperscoreBackslash" class="selector cell upperscoreBackslash" onClick="setType('upperscoreBackslash')"></div>
  <div id="selector_upperscoreSlash" class="selector cell upperscoreSlash" onClick="setType('upperscoreSlash')"></div>
  <div id="descArea">
    Description: <input type="text" maxlength="128" id="desc" value="terrain" />
  </div>
  <div id="modeSwitchArea">
    <button onclick="setMode('terrain')">Edit Terrain</button>
    <button onclick="setMode('depth')">Edit Depth</button>
  </div>
  <input type="number" min=0 max=255 value=0 id="depthValue" size=3 />
  <button id="export" onclick="exportTerrain()">Export</button>
</div>

SCSS

body{
  padding: 5px;
}

#newPopup{
  position: fixed;
  top: 1px;
  left: 1px;
  right: 0;
  bottom: 0;
  padding: 50px;
  background: #f3f5f6;
  z-index: 2;
}

.hidden{
  display: none;
}

#view{
  position: fixed;
  top: 1px;
  right: 0;
  left: 1px;
  bottom: 50px;
  white-space: nowrap;
  background: #ccc;
  font-size: 0;
  z-index: 0;
}

#display{
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  
  -webkit-user-select: none;  /* Chrome all / Safari all */
  -moz-user-select: none;     /* Firefox all */
  -ms-user-select: none;      /* IE 10+ */
  -o-user-select: none;
  user-select: none;
}

.col{
  display: inline-block;
}

.cell{
  display: block;
  height: 25px;
  width: 25px;
  background: #fff;
  margin: 0 1px 1px 0;
  
  &:hover{
    opacity: 0.7;
  }
  
  &.solid{
    background: #0af;
  }
  
  &.solidNW{
    background: linear-gradient(135deg, #0af 0%, #0af 50%, #fff 50%, #fff 100%);
  }
  
  &.solidNE{
    background: linear-gradient(-135deg, #0af 0%, #0af 50%, #fff 50%, #fff 100%);
  }
  
  &.solidSW{
    background: linear-gradient(45deg, #0af 0%, #0af 50%, #fff 50%, #fff 100%);
  }
  
  &.solidSE{
    background: linear-gradient(-45deg, #0af 0%, #0af 50%, #fff 50%, #fff 100%);
  }
  
  &.upperscore{
    background: linear-gradient(to bottom, #0af 0%, #0af 10%, #fff 10%, #fff 100%);
  }
  
  &.slash{
    background: linear-gradient(-45deg, #fff 0%, #fff 45%, #0af 45%, #0af 55%, #fff 55%, #fff 100%);
  }
  
  &.backslash{
    background: linear-gradient(45deg, #fff 0%, #fff 45%, #0af 45%, #0af 55%, #fff 55%, #fff 100%);
  }
  
  &.upperscoreSlash{
    background: linear-gradient(to bottom, #0af 0%, #0af 10%, transparent 10%, transparent 100%),
    linear-gradient(-45deg, #fff 0%, #fff 45%, #0af 45%, #0af 55%, #fff 55%, #fff 100%);
  }
  
  &.upperscoreBackslash{
    background: linear-gradient(to bottom, #0af 0%, #0af 10%, transparent 10%, transparent 100%),
    linear-gradient(45deg, #fff 0%, #fff 45%, #0af 45%, #0af 55%,...

JavaScript

"use strict";

var dataArray = [];
var w;
var h;
var offsetX = 10;
var offsetY = 10;

var mode = "terrain"; // other options: "depth"


var cellTypes = [
	"air",
  "solid",
  "solidSW",
  "solidSE",
  "solidNW",
  "solidNE",
  "upperscore",
  "slash",
  "backslash",
  "upperscoreSlash",
  "upperscoreBackslash"
];

var drawType = cellTypes[0];
function setType(t) {
	drawType = t;
  $('.selector').removeClass('active');
  $('.selector.'+t).addClass('active');
}

function setMode(m) {
	mode = m;
  render();
}


function init(width, height) {
	w = width || +$('#w').val();
	h = height || +$('#h').val();
  
  for(let i=0; i<w; i++) {
  	dataArray[i] = [];
  	for(let j=0; j<h; j++) {
    	dataArray[i][j] = {
      	type: (j == 0 || j == h-1 || i == 0 || i == w-1) ? cellTypes[1] : cellTypes[0],
        z: 0,
      };
    }
  }
  
  $('#newPopup').addClass('hidden');
  $('#desc').val('terrain '+w+'x'+h);
  
  $("#display").attr('width', $("#view").width());
  $("#display").attr('height', $("#view").height());
  
  $("#display").on('mousedown', canvasMouseDown);
  $("#display").on('mouseup', canvasMouseUp);
  $("#display").on('mousemove', canvasMouseMove);
  
  window.addEventListener('resize', function () {
  	$("#display").attr('width', $("#view").width());
    $("#display").attr('height', $("#view").height());
    render();
  });
  
  render();
}

var mousePos = [0, 0];
var dragging = 0;

function canvasMouseDown(e) {
	mousePos = [e.offsetX, $("#display").height() - e.offsetY];
  switch(e.which) {
  	case 1: //left
    	dragging = 1;
      fill();
    	break;
    case 2: // middle
      dragging = 2;
      break;
    case 3: // right
      dragging = 3;
      fill();
      break;
  }
}

function canvasMouseUp(e) {
  dragging = 0;
}

function canvasMouseMove(e) {
  const oldX = mousePos[0]; const oldY = mousePos[1];
	mousePos = [e.offsetX, $("#display").height() - e.offsetY];
  switch(dragging) {
  	case 1: //left
    case 3: // right
      fill();
    	break;
    case...