allow for creating new tiles
(does not yet add to game data)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
$(document).ready(function() {
|
||||
// todo define things like 16x16, 128x128 etc. as constants?
|
||||
// also script debounce/throttle times
|
||||
const animationTime = 400; // defined in bitsy.js
|
||||
|
||||
var bitsyData = {};
|
||||
|
||||
@@ -27,6 +28,8 @@ $(document).ready(function() {
|
||||
|
||||
var tiles = [];
|
||||
|
||||
var tileMatchThreshold = 0;
|
||||
|
||||
var croptions = {
|
||||
url: 'https://i.imgur.com/ThQZ94v.jpg',
|
||||
viewport: {width: 128, height: 128, type: 'square'},
|
||||
@@ -87,6 +90,19 @@ $(document).ready(function() {
|
||||
return _.first(_.sortBy(colourOptions, 'difference'));
|
||||
}
|
||||
|
||||
function newTileName() {
|
||||
var tileNames = _.map(bitsyData.tiles, 'name');
|
||||
|
||||
var i = 1; // start with 1 as 0 is an implicit tile
|
||||
|
||||
while (tileNames.indexOf(i.toString(36)) > -1) {
|
||||
i++;
|
||||
}
|
||||
|
||||
// base 36 = 0-9a-z
|
||||
return i.toString(36);
|
||||
}
|
||||
|
||||
function handleBitsyGameData() {
|
||||
bitsyData = {};
|
||||
|
||||
@@ -127,15 +143,16 @@ $(document).ready(function() {
|
||||
|
||||
// get tiles
|
||||
|
||||
bitsyData.tiles = {};
|
||||
bitsyData.tiles = [];
|
||||
|
||||
// tile 0 (background colour only) is implicit in bitsy rather than being stored in the game data
|
||||
// so, make our own version
|
||||
bitsyData.tiles[0] = {
|
||||
name: 0,
|
||||
bitmap: _.chunk(_.split(_.repeat(0, 64), ''), 8)
|
||||
};
|
||||
|
||||
bitsyData.tiles.push({
|
||||
name: "0",
|
||||
bitmap: _.chunk(_.times(64, _.constant(0)), 8),
|
||||
new: false // this could also be used to stop it from being added to the game data, wooo
|
||||
});
|
||||
|
||||
// todo: handle animated tiles properly instead of discarding the second animation frame
|
||||
var tiles = input.match(/TIL (.*)\n([01]{8}\n){8}(>\n([01]{8}\n){8})?/g); // everything after > is an optional second animation frame
|
||||
|
||||
@@ -144,9 +161,14 @@ $(document).ready(function() {
|
||||
|
||||
tile = tile.replace(/TIL .*\n/, '');
|
||||
|
||||
var bitmap = tile.match(/[01]/g);
|
||||
var bitmap = _.map(tile.match(/[01]/g), _.toInteger);
|
||||
|
||||
var newTile = {name: name};
|
||||
var newTile = {
|
||||
name: name,
|
||||
new: false
|
||||
};
|
||||
|
||||
// todo make this agnostic? i.e. tile.frames = _.chunk(bitmap, 64)
|
||||
|
||||
if (bitmap.length === 64) { // normal tile
|
||||
newTile.bitmap = _.chunk(bitmap, 8);
|
||||
@@ -155,7 +177,7 @@ $(document).ready(function() {
|
||||
newTile.secondAnimationFrame = _.chunk(_.takeRight(bitmap, 64), 8);
|
||||
}
|
||||
|
||||
bitsyData.tiles[name] = newTile;
|
||||
bitsyData.tiles.push(newTile);
|
||||
});
|
||||
|
||||
if (_.find(bitsyData.palettes, {'id': palette.id})) {
|
||||
@@ -172,7 +194,7 @@ $(document).ready(function() {
|
||||
palette = _.first(_.sortBy(bitsyData.palettes, 'id'));
|
||||
}
|
||||
|
||||
renderResult();
|
||||
renderDebounced();
|
||||
|
||||
// update palette picker
|
||||
$('tr.palette').remove();
|
||||
@@ -210,7 +232,7 @@ $(document).ready(function() {
|
||||
}
|
||||
}
|
||||
|
||||
var renderResult = _.debounce(function() {
|
||||
function render() {
|
||||
$croppie.croppie('result', {
|
||||
type: 'rawcanvas',
|
||||
size: 'viewport'
|
||||
@@ -232,10 +254,10 @@ $(document).ready(function() {
|
||||
|
||||
var targetColour = getClosestColour(pixel, palette);
|
||||
|
||||
if (targetColour.name === "background") { // ?! why is this reversed?
|
||||
monochrome.push(1);
|
||||
if (targetColour.name === "background") {
|
||||
monochrome.push(0);
|
||||
} else { // tile
|
||||
monochrome.push(0)
|
||||
monochrome.push(1)
|
||||
}
|
||||
|
||||
rawData[i ] = targetColour.red;
|
||||
@@ -262,23 +284,16 @@ $(document).ready(function() {
|
||||
pseudoTile.push(
|
||||
_.slice(monochrome[(tileY * 8) + y], (tileX * 8), (tileX * 8) + 8)
|
||||
);
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
var tilesForMatch = bitsyData.tiles;
|
||||
|
||||
_.each(tilesForMatch, function(tile) {
|
||||
tile.match = 0;
|
||||
// if we want to always create new tiles, don't bother trying to check matches
|
||||
if (tileMatchThreshold < 64) {
|
||||
_.each(tilesForMatch, function(tile) {
|
||||
tile.match = 0;
|
||||
|
||||
_.each(tile.bitmap, function(row, y) {
|
||||
_.each(row, function(pixel, x) {
|
||||
if (parseInt(pixel) === parseInt(pseudoTile[y][x])) {
|
||||
tile.match++;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (tile.secondAnimationFrame) {
|
||||
_.each(tile.secondAnimationFrame, function(row, y) {
|
||||
_.each(tile.bitmap, function(row, y) {
|
||||
_.each(row, function(pixel, x) {
|
||||
if (parseInt(pixel) === parseInt(pseudoTile[y][x])) {
|
||||
tile.match++;
|
||||
@@ -286,62 +301,100 @@ $(document).ready(function() {
|
||||
});
|
||||
});
|
||||
|
||||
tile.match /= 2;
|
||||
}
|
||||
});
|
||||
if (tile.secondAnimationFrame) {
|
||||
_.each(tile.secondAnimationFrame, function(row, y) {
|
||||
_.each(row, function(pixel, x) {
|
||||
if (parseInt(pixel) === parseInt(pseudoTile[y][x])) {
|
||||
tile.match++;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var bestMatch = _.first(_.sortBy(tilesForMatch, 'match'));
|
||||
tile.match /= 2;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// if best match is under threshold
|
||||
// what if there are several equally good matches?
|
||||
// find highest match amount and find all of them
|
||||
var bestMatchAmount = _.last(_.sortBy(tilesForMatch, ['match'])).match;
|
||||
var bestMatches = _.filter(tilesForMatch, {'match': bestMatchAmount});
|
||||
|
||||
// sort by name in ascending order
|
||||
// earlier names are preferable
|
||||
var bestMatch = _.first(_.sortBy(bestMatches, 'name'));
|
||||
|
||||
if (tileMatchThreshold === 64 || bestMatch.match <= tileMatchThreshold) {
|
||||
// turn pseudo-tile into a real tile and add it to the tile data
|
||||
|
||||
room.push(bestMatch.name);
|
||||
|
||||
var name = newTileName();
|
||||
|
||||
bitsyData.tiles.push({
|
||||
name: name,
|
||||
bitmap: pseudoTile,
|
||||
new: true
|
||||
});
|
||||
|
||||
room.push(name);
|
||||
|
||||
// issue with this approach:
|
||||
// what if a tile we add late in the loop is a better match for an earlier "good enough" match?
|
||||
// this would also cause different results if the user were to add the same room several times
|
||||
// we could keep iterating until the room no longer changes
|
||||
} else {
|
||||
room.push(bestMatch.name);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
room = _.chunk(room, 16);
|
||||
|
||||
// write room to output
|
||||
|
||||
imageData = document.getElementById("room-output").getContext('2d').getImageData(0, 0, 128, 128);
|
||||
rawData = imageData.data;
|
||||
|
||||
_.each(room, function(row, tileY) {
|
||||
_.each(row, function(tileName, tileX) {
|
||||
if (_.get(bitsyData, 'tiles.' + tileName + '.bitmap')) {
|
||||
_.each(bitsyData.tiles[tileName].bitmap, function(row, y) {
|
||||
_.each(row, function(pixel, x) {
|
||||
var position = (((tileY * 8) + y) * 128) + ((tileX * 8) + x);
|
||||
var tile = _.find(bitsyData.tiles, {'name' : tileName});
|
||||
|
||||
position *= 4; // 4 values (rgba) per pixel
|
||||
_.each(tile.bitmap, function(row, y) {
|
||||
_.each(row, function(pixel, x) {
|
||||
var position = (((tileY * 8) + y) * 128) + ((tileX * 8) + x);
|
||||
|
||||
if (parseInt(pixel) === 0) {
|
||||
var pixelColour = palette.background;
|
||||
} else {
|
||||
var pixelColour = palette.tile;
|
||||
}
|
||||
position *= 4; // 4 values (rgba) per pixel
|
||||
|
||||
rawData[position ] = pixelColour.red;
|
||||
rawData[position + 1] = pixelColour.green;
|
||||
rawData[position + 2] = pixelColour.blue;
|
||||
rawData[position + 3] = 255;
|
||||
});
|
||||
var pixelColour = {};
|
||||
|
||||
switch(parseInt(pixel)) {
|
||||
case 0: pixelColour = palette.background; break;
|
||||
case 1: pixelColour = palette.tile; break;
|
||||
default: console.log("error");
|
||||
}
|
||||
|
||||
rawData[position ] = pixelColour.red;
|
||||
rawData[position + 1] = pixelColour.green;
|
||||
rawData[position + 2] = pixelColour.blue;
|
||||
rawData[position + 3] = 255;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('room-output').getContext('2d').putImageData(imageData, 0, 0);
|
||||
});
|
||||
}, 30);
|
||||
}
|
||||
|
||||
$croppie.on('update', renderResult);
|
||||
var renderDebounced = _.debounce(render, 30);
|
||||
|
||||
// make this not debounced but called every n milliseconds
|
||||
$('#brightness').on('change', renderResult);
|
||||
$croppie.on('update', renderDebounced);
|
||||
|
||||
$('#brightness').on('change', renderDebounced);
|
||||
|
||||
$('#brightness').on('dblclick', function() {
|
||||
$(this).val(0);
|
||||
renderResult();
|
||||
|
||||
renderDebounced();
|
||||
});
|
||||
|
||||
$('label[for="brightness"]').on('click touchdown', function() {
|
||||
@@ -375,7 +428,20 @@ $(document).ready(function() {
|
||||
// sprite colour is not currently used
|
||||
}
|
||||
|
||||
renderResult();
|
||||
renderDebounced();
|
||||
});
|
||||
|
||||
$(document).on('change', '#threshold', function() {
|
||||
var newValue = parseInt($(this).val());
|
||||
|
||||
if (newValue < tileMatchThreshold) {
|
||||
// set tiles back to default
|
||||
bitsyData.tiles = _.filter(bitsyData.tiles, ['new', false]);
|
||||
}
|
||||
|
||||
tileMatchThreshold = newValue;
|
||||
|
||||
renderDebounced();
|
||||
});
|
||||
|
||||
$('#save').on('click touchend', function() {
|
||||
|
||||
@@ -74,10 +74,12 @@ input {
|
||||
background-color: #d3cbd0;
|
||||
color: #594a54;
|
||||
}
|
||||
#brightness,
|
||||
#threshold {
|
||||
#brightness {
|
||||
width: 256px;
|
||||
}
|
||||
#threshold {
|
||||
width: 150px;
|
||||
}
|
||||
#brightness + label,
|
||||
#threshold + label {
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -95,13 +95,20 @@ textarea, input {
|
||||
color: @dark;
|
||||
}
|
||||
|
||||
#brightness {
|
||||
width: 256px;
|
||||
}
|
||||
|
||||
#threshold {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
#brightness, #threshold {
|
||||
+ label{
|
||||
.centre;
|
||||
}
|
||||
|
||||
// todo make this match the croppie slider or vice versa
|
||||
width: 256px;
|
||||
}
|
||||
|
||||
#imageUpload {
|
||||
|
||||
Reference in New Issue
Block a user