mirror of
https://github.com/maddievision/Celestial.git
synced 2024-08-14 23:55:37 +00:00
Add XML/JSON output script, JSON import script, JS viewer
This commit is contained in:
parent
664c684b79
commit
1685b32536
3 changed files with 461 additions and 2 deletions
10
json2map.rb
Normal file
10
json2map.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
require "./celeste_map_reader"
|
||||
require 'ruby2d'
|
||||
require 'pry'
|
||||
# fn = 'app/Content/Maps/1-ForsakenCity.bin'
|
||||
|
||||
ARGV.each do |fn|
|
||||
base = File.basename(fn, ".json")
|
||||
a = CelesteMapReader.new(fn, fmt: :json)
|
||||
a.write "bin/#{base}.bin"
|
||||
end
|
|
@ -1,9 +1,10 @@
|
|||
require "./celeste_map_reader"
|
||||
require 'ruby2d'
|
||||
|
||||
# fn = 'app/Content/Maps/1-ForsakenCity.bin'
|
||||
|
||||
ARGV.each do |fn|
|
||||
base = File.basename(fn, ".bin")
|
||||
a = CelesteMapReader.new(fn)
|
||||
File.open("#{File.basename(fn)}.xml", "wb") { |f| f.write a.root.inspect }
|
||||
File.open("#{base}.xml", "wb") { |f| f.write a.root.inspect }
|
||||
a.write_json("#{base}.json")
|
||||
end
|
||||
|
|
448
viewer.js
Normal file
448
viewer.js
Normal file
|
@ -0,0 +1,448 @@
|
|||
// Demo https://codepen.io/deltabouche/full/WJPbaQ/
|
||||
|
||||
// Requires p5.js and lodash
|
||||
|
||||
const MapBase = "http://localhost:3000/";
|
||||
|
||||
const Maps = [
|
||||
"0-Intro",
|
||||
"1-ForsakenCity",
|
||||
"1H-ForsakenCity",
|
||||
"1X-ForsakenCity",
|
||||
"2-OldSite",
|
||||
"2H-OldSite",
|
||||
"2X-OldSite",
|
||||
"3-CelestialResort",
|
||||
"3H-CelestialResort",
|
||||
"3X-CelestialResort",
|
||||
"4-GoldenRidge",
|
||||
"4H-GoldenRidge",
|
||||
"4X-GoldenRidge",
|
||||
"5-MirrorTemple",
|
||||
"5H-MirrorTemple",
|
||||
"5X-MirrorTemple",
|
||||
"6-Reflection",
|
||||
"6H-Reflection",
|
||||
"6X-Reflection",
|
||||
"7-Summit",
|
||||
"7H-Summit",
|
||||
"7X-Summit",
|
||||
"8-Epilogue",
|
||||
"9-Core",
|
||||
"9H-Core",
|
||||
"9X-Core"
|
||||
]
|
||||
|
||||
let state = {
|
||||
mapPath: "0-Intro",
|
||||
dataReady: false,
|
||||
camera: {
|
||||
x: 200,
|
||||
y: 200,
|
||||
scale: 1
|
||||
},
|
||||
levelCamera: {
|
||||
x: 5,
|
||||
y: 5
|
||||
},
|
||||
screen: {
|
||||
width: 1280,
|
||||
height: 720
|
||||
},
|
||||
map: null,
|
||||
thumbnails: [],
|
||||
levelIndex: -1,
|
||||
hoverLevel: -1
|
||||
};
|
||||
|
||||
const SolidColors = {
|
||||
"0": "#000000", //0
|
||||
"1": "#FF0000", //1
|
||||
"2": "#00FF00", //2
|
||||
"3": "#0000FF", //3
|
||||
"4": "#FF00FF", //4
|
||||
"5": "#FFFF00", //5
|
||||
"6": "#00FFFF", //6
|
||||
"7": "#888888", //7
|
||||
"g": "#FF00FF"
|
||||
};
|
||||
|
||||
function setupThumbnails() {
|
||||
const levels = childByName(state.map.root, 'levels');
|
||||
let visIndex = 0;
|
||||
_.each(levels.children, (lvl, lvlIndex) => {
|
||||
let pg = createGraphics(lvl.attributes.width, lvl.attributes.height);
|
||||
const solids = childrenByName(lvl, 'solids');
|
||||
_.each(solids, solid => {
|
||||
let tx = 0;
|
||||
let ty = 0;
|
||||
_.each(solid.attributes.innerText, v => {
|
||||
if (v == 10) {
|
||||
ty++;
|
||||
tx=0;
|
||||
return;
|
||||
}
|
||||
const tRect = {
|
||||
x: solid.attributes.offsetX + tx * 8 + 1,
|
||||
y: solid.attributes.offsetY + ty * 8 + 1,
|
||||
width: 7,
|
||||
height: 7
|
||||
}
|
||||
pg.noStroke();
|
||||
const color = SolidColors[String.fromCharCode(v)] || 200;
|
||||
pg.fill(color);
|
||||
pg.rect(tRect.x / 2, tRect.y/ 2, tRect.width/ 2, tRect.height/ 2);
|
||||
tx++;
|
||||
});
|
||||
});
|
||||
state.thumbnails.push(pg)
|
||||
});
|
||||
}
|
||||
|
||||
function resetCamera() {
|
||||
state.camera = { x: 200, y: 200, scale: 0.5 };
|
||||
}
|
||||
|
||||
function resetLevelCamera() {
|
||||
state.levelCamera = { x: 5, y: 5 };
|
||||
}
|
||||
|
||||
function loadMap(path) {
|
||||
state.dataReady = false;
|
||||
state.thumbnails = [];
|
||||
state.map = null;
|
||||
state.mapPath = path;
|
||||
state.levelIndex = -1;
|
||||
fetch(`${MapBase}/${state.mapPath}.json`).then(res => res.json()).then(json => {
|
||||
state.map = json;
|
||||
setupThumbnails();
|
||||
state.dataReady = true;
|
||||
addLevelSelect();
|
||||
resetCamera();
|
||||
})
|
||||
}
|
||||
|
||||
function loadLevel(idx) {
|
||||
if (idx >= 0) resetLevelCamera();
|
||||
state.levelIndex = parseInt(idx, 10);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
addMapSelect();
|
||||
let canvasElement = createCanvas(state.screen.width, state.screen.height).elt;
|
||||
canvasElement.addEventListener('contextmenu', event => { event.preventDefault(); });
|
||||
let context = canvasElement.getContext('2d');
|
||||
context.mozImageSmoothingEnabled = false;
|
||||
context.webkitImageSmoothingEnabled = false;
|
||||
context.msImageSmoothingEnabled = false;
|
||||
context.imageSmoothingEnabled = false;
|
||||
loadMap(state.mapPath);
|
||||
}
|
||||
|
||||
function childrenByName(el, name) {
|
||||
return _.filter(el.children, { name });
|
||||
}
|
||||
|
||||
function childByName(el, name) {
|
||||
return _.find(el.children, { name });
|
||||
}
|
||||
|
||||
function drawAxes() {
|
||||
stroke("#0000FF");
|
||||
line(state.camera.x, 0, state.camera.x, state.screen.height);
|
||||
line(0, state.camera.y, state.screen.width, state.camera.y);
|
||||
}
|
||||
|
||||
function drawHeadings() {
|
||||
text(state.map.root.package, 20, 20);
|
||||
}
|
||||
|
||||
function screenTransformRect(rect) {
|
||||
return {
|
||||
x: rect.x * state.camera.scale + state.camera.x,
|
||||
y: rect.y * state.camera.scale + state.camera.y,
|
||||
width: rect.width * state.camera.scale,
|
||||
height: rect.height * state.camera.scale
|
||||
}
|
||||
}
|
||||
|
||||
function screenLevelTransformRect(rect) {
|
||||
return {
|
||||
x: (rect.x + state.levelCamera.x * 8) * 2,
|
||||
y: (rect.y + state.levelCamera.y * 8) * 2,
|
||||
width: rect.width * 2,
|
||||
height: rect.height * 2
|
||||
}
|
||||
}
|
||||
|
||||
function pointInRect(x, y, rect) {
|
||||
return x > rect.x && x < rect.x + rect.width && y > rect.y && y < rect.y + rect.height;
|
||||
}
|
||||
|
||||
function rectIsVisible(rect) {
|
||||
return rect.x + rect.width > 0 && rect.y + rect.height > 0 && rect.x < state.screen.width && rect.y < state.screen.height
|
||||
}
|
||||
|
||||
function drawFillers() {
|
||||
const fillers = childByName(state.map.root, 'Filler');
|
||||
_.each(fillers.children, (fillRect) => {
|
||||
const drawRect = screenTransformRect({
|
||||
x: fillRect.attributes.x * 8,
|
||||
y: fillRect.attributes.y * 8,
|
||||
width: fillRect.attributes.w * 8,
|
||||
height: fillRect.attributes.h * 8
|
||||
});
|
||||
if (!rectIsVisible(drawRect)) return;
|
||||
stroke("#FF0000");
|
||||
fill("#330000");
|
||||
rect(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
});
|
||||
}
|
||||
|
||||
function drawLevels() {
|
||||
const levels = childByName(state.map.root, 'levels');
|
||||
let visIndex = 0;
|
||||
_.each(levels.children, (lvl, lvlIndex) => {
|
||||
fill(255);
|
||||
stroke(255);
|
||||
const drawRect = screenTransformRect(lvl.attributes);
|
||||
if (!rectIsVisible(drawRect)) return;
|
||||
// text(`${drawRect.x}, ${drawRect.y}, ${drawRect.width}, ${drawRect.height}`, 10, 80 + 20 * visIndex);
|
||||
visIndex++;
|
||||
image(state.thumbnails[lvlIndex], drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
noFill();
|
||||
if (pointInRect(mouseX, mouseY, screenTransformRect(lvl.attributes))) {
|
||||
text(lvl.attributes.name, 10, 80);
|
||||
stroke(255);
|
||||
state.hoverLevel = lvlIndex;
|
||||
} else {
|
||||
stroke(64);
|
||||
}
|
||||
rect(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
});
|
||||
}
|
||||
|
||||
function processInput() {
|
||||
if (state.levelIndex === -1) {
|
||||
if (keyIsDown(LEFT_ARROW)) {
|
||||
state.camera.x += 8;
|
||||
}
|
||||
if (keyIsDown(RIGHT_ARROW)) {
|
||||
state.camera.x -= 8;
|
||||
}
|
||||
if (keyIsDown(UP_ARROW)) {
|
||||
state.camera.y += 8;
|
||||
}
|
||||
|
||||
if (keyIsDown(DOWN_ARROW)) {
|
||||
state.camera.y -= 8;
|
||||
}
|
||||
} else {
|
||||
if (keyIsDown(LEFT_ARROW)) {
|
||||
state.levelCamera.x += 1;
|
||||
}
|
||||
if (keyIsDown(RIGHT_ARROW)) {
|
||||
state.levelCamera.x -= 1;
|
||||
}
|
||||
if (keyIsDown(UP_ARROW)) {
|
||||
state.levelCamera.y += 1;
|
||||
}
|
||||
|
||||
if (keyIsDown(DOWN_ARROW)) {
|
||||
state.levelCamera.y -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function keyPressed() {
|
||||
if (keyCode === 81) {
|
||||
state.camera.x *= 1.5;
|
||||
state.camera.y *= 1.5;
|
||||
state.camera.scale *= 1.5;
|
||||
}
|
||||
if (keyCode === 65) {
|
||||
state.camera.x /= 1.5;
|
||||
state.camera.y /= 1.5;
|
||||
state.camera.scale /= 1.5;
|
||||
}
|
||||
if (keyCode === 27) {
|
||||
let select = document.getElementById('level-select');
|
||||
select.value = -1;
|
||||
loadLevel(-1);
|
||||
}
|
||||
}
|
||||
|
||||
function mousePressed() {
|
||||
if (mouseButton === RIGHT) {
|
||||
if (state.hoverLevel >= 0) {
|
||||
let idx = state.hoverLevel;
|
||||
state.hoverLevel = -1;
|
||||
let select = document.getElementById('level-select');
|
||||
select.value = idx;
|
||||
loadLevel(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawHud() {
|
||||
text(`${mouseX}, ${mouseY}`, 10, 50);
|
||||
}
|
||||
|
||||
function drawLoading() {
|
||||
text("Loading...", state.screen.width / 2, state.screen.height / 2);
|
||||
}
|
||||
|
||||
function drawOverview() {
|
||||
drawAxes();
|
||||
drawHud();
|
||||
drawHeadings();
|
||||
drawFillers();
|
||||
drawLevels();
|
||||
}
|
||||
|
||||
function drawLevel() {
|
||||
const levels = childByName(state.map.root, 'levels');
|
||||
const level = levels.children[state.levelIndex];
|
||||
|
||||
// draw surrounding levels
|
||||
_.each(levels.children, (sLevel, i) => {
|
||||
if (i == state.levelIndex) return;
|
||||
const drawRect = screenLevelTransformRect({
|
||||
x: sLevel.attributes.x - level.attributes.x,
|
||||
y: sLevel.attributes.y - level.attributes.y,
|
||||
width: sLevel.attributes.width,
|
||||
height: sLevel.attributes.height
|
||||
});
|
||||
if (!rectIsVisible(drawRect)) return;
|
||||
if (pointInRect(mouseX, mouseY, drawRect)) {
|
||||
stroke(128, 128, 128, 255);
|
||||
tint(255, 192);
|
||||
state.hoverLevel = i;
|
||||
} else {
|
||||
stroke(128, 128, 128, 128);
|
||||
tint(255, 128);
|
||||
}
|
||||
image(state.thumbnails[i], drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
noFill();
|
||||
rect(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
tint(255, 255);
|
||||
});
|
||||
|
||||
|
||||
// noFill(64);
|
||||
// rect((state.levelCamera.x * 16) + 16, (state.levelCamera.y * 16) + 16, level.attributes.width * 2, level.attributes.height * 2);
|
||||
|
||||
const solids = childByName(level, 'solids');
|
||||
const solidMap = solids.attributes.innerText;
|
||||
let tx = 0;
|
||||
let ty = 0;
|
||||
|
||||
const levelDrawRect = screenLevelTransformRect({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: level.attributes.width,
|
||||
height: level.attributes.height
|
||||
})
|
||||
|
||||
image(state.thumbnails[state.levelIndex], levelDrawRect.x, levelDrawRect.y, levelDrawRect.width, levelDrawRect.height);
|
||||
|
||||
// _.each(solidMap, (v, i) => {
|
||||
// if (v === 10) {
|
||||
// ty++;
|
||||
// tx=0;
|
||||
// return;
|
||||
// }
|
||||
// const drawRect = screenLevelTransformRect({
|
||||
// x: tx * 8,
|
||||
// y: ty * 8,
|
||||
// width: 8,
|
||||
// height: 8
|
||||
// })
|
||||
// tx++;
|
||||
// if (!rectIsVisible(drawRect)) return;
|
||||
|
||||
// stroke(32);
|
||||
|
||||
// // const color = SolidColors[String.fromCharCode(v)] || 200;
|
||||
// // fill(color);
|
||||
|
||||
|
||||
// // rect(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
// fill(0);
|
||||
// text(String.fromCharCode(v), drawRect.x + 6, drawRect.y + 12);
|
||||
// });
|
||||
|
||||
const entities = childByName(level, 'entities');
|
||||
_.each(entities.children, entity => {
|
||||
const drawRect = screenLevelTransformRect({
|
||||
x: entity.attributes.x - (entity.attributes.originX || 0),
|
||||
y: entity.attributes.y - (entity.attributes.originY || 0),
|
||||
width: entity.attributes.width || 8,
|
||||
height: entity.attributes.height || 8
|
||||
})
|
||||
if (!rectIsVisible(drawRect)) return;
|
||||
stroke(255, 255, 255, 128);
|
||||
fill(255, 255, 255, 128);
|
||||
text(entity.name, drawRect.x, drawRect.y);
|
||||
stroke(255, 64, 64, 128);
|
||||
fill(64, 0, 0, 128);
|
||||
rect(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
|
||||
})
|
||||
stroke(128);
|
||||
noFill();
|
||||
rect(levelDrawRect.x, levelDrawRect.y, levelDrawRect.width, levelDrawRect.height);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
processInput();
|
||||
background(0);
|
||||
stroke(255);
|
||||
fill(255);
|
||||
if (state.dataReady) {
|
||||
if (state.levelIndex === -1) {
|
||||
drawOverview();
|
||||
} else {
|
||||
drawLevel();
|
||||
}
|
||||
} else {
|
||||
drawLoading();
|
||||
}
|
||||
}
|
||||
|
||||
function addMapSelect() {
|
||||
let mapSelectContainer = document.getElementById("map-select-container");
|
||||
let selectList = document.createElement("select");
|
||||
selectList.id = "map-select";
|
||||
mapSelectContainer.appendChild(selectList);
|
||||
_.each(Maps, mapName => {
|
||||
let option = document.createElement("option");
|
||||
option.value = mapName;
|
||||
option.text = mapName;
|
||||
selectList.appendChild(option);
|
||||
})
|
||||
selectList.addEventListener('change', function(){
|
||||
loadMap(this.value);
|
||||
});
|
||||
}
|
||||
|
||||
function addLevelSelect() {
|
||||
let levelSelectContainer = document.getElementById("level-select-container");
|
||||
levelSelectContainer.innerHTML = "";
|
||||
let selectList = document.createElement("select");
|
||||
selectList.id = "level-select";
|
||||
levelSelectContainer.appendChild(selectList);
|
||||
let defOption = document.createElement("option");
|
||||
defOption.value = -1;
|
||||
defOption.text = "Overview";
|
||||
selectList.appendChild(defOption);
|
||||
const levels = childByName(state.map.root, 'levels');
|
||||
_.each(levels.children, (lvl, idx) => {
|
||||
let option = document.createElement("option");
|
||||
option.value = idx;
|
||||
option.text = lvl.attributes.name;
|
||||
selectList.appendChild(option);
|
||||
})
|
||||
selectList.addEventListener('change', function(){
|
||||
loadLevel(this.value);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue