mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-06-06 19:29:48 +00:00
Update tiled export to create code to start timer scripts for animated tiles
This commit is contained in:
parent
2ef67e0a1c
commit
7d7a54a731
|
@ -2,15 +2,14 @@
|
||||||
* Read an exported Tiled project in JSON format and produce Merlin32 output files with
|
* Read an exported Tiled project in JSON format and produce Merlin32 output files with
|
||||||
* GTE-compatible setup code wrapped around it.
|
* GTE-compatible setup code wrapped around it.
|
||||||
*/
|
*/
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { abort } = require('process');
|
const process = require('process');
|
||||||
const process = require('process');
|
|
||||||
const StringBuilder = require('string-builder');
|
const StringBuilder = require('string-builder');
|
||||||
const parser = require('xml2json');
|
const parser = require('xml2json');
|
||||||
const png2iigs = require('./png2iigs');
|
const png2iigs = require('./png2iigs');
|
||||||
|
|
||||||
main(process.argv.slice(2)).then(
|
main(process.argv.slice(2)).then(
|
||||||
() => process.exit(0),
|
() => process.exit(0),
|
||||||
(e) => {
|
(e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -87,11 +86,100 @@ function getArg(argv, arg, fn, defaultValue) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function writeTileAnimations(filename, animations) {
|
||||||
|
const init = new StringBuilder();
|
||||||
|
const scripts = new StringBuilder();
|
||||||
|
|
||||||
|
// First step is some initialization code that copies the first animated
|
||||||
|
// tile data into the dynamic tile space
|
||||||
|
const initLabel = 'TileAnimInit';
|
||||||
|
init.appendLine(`${initLabel} ENT`);
|
||||||
|
init.appendLine();
|
||||||
|
for (const animation of animations) {
|
||||||
|
// Get the first tile of the animation
|
||||||
|
const firstTileId = animation.frames[0].tileId;
|
||||||
|
|
||||||
|
// Create code to copy it into the dynamic tile index location
|
||||||
|
init.appendLine(' ldx #' + firstTileId);
|
||||||
|
init.appendLine(' ldy #' + animation.dynTileId);
|
||||||
|
init.appendLine(' jsr CopyTileToDyn');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, create the scripts to change the tile data based on the configured ticks delays.
|
||||||
|
for (const animation of animations) {
|
||||||
|
// Get the animation frames
|
||||||
|
const frames = animation.frames;
|
||||||
|
|
||||||
|
// Look at the frames and get the number of ticks. We only support a uniform animation period.
|
||||||
|
const numTicks = frames.map(f => f.ticks).reduce((x, y) => Math.min(x, y),Infinity);
|
||||||
|
if (frames.some(f => f.ticks !== numTicks)) {
|
||||||
|
console.warn(`Animated tiles must have a uniform animation delay. Setting ticks to ${numTicks}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = `TileAnim_${animation.tileId}`;
|
||||||
|
init.appendLine(` lda #${label}`);
|
||||||
|
init.appendLine(` ldx #^${label}`);
|
||||||
|
init.appendLine(` ldy #${numTicks}`);
|
||||||
|
init.appendLine(` jsl StartScript`);
|
||||||
|
|
||||||
|
scripts.appendLine(label);
|
||||||
|
for (let i = 0; i < frames.length ; i += 1) {
|
||||||
|
const last = (i === (frames.length - 1));
|
||||||
|
const command = 'YIELD+SET_DYN_TILE' + (last ? '+JUMP' : '');
|
||||||
|
const jump = last ? `,-${frames.length - 1}` : '';
|
||||||
|
|
||||||
|
scripts.appendLine(` dw ${command},${frames[i].tileId},${animation.dynTileId}${jump}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init.appendLine(' rts');
|
||||||
|
|
||||||
|
fs.writeFileSync(filename, init.toString() + scripts.toString());
|
||||||
|
}
|
||||||
|
|
||||||
function writeTiles(filename, tiles) {
|
function writeTiles(filename, tiles) {
|
||||||
const tileSource = png2iigs.buildMerlinCodeForTiles(tiles);
|
const tileSource = png2iigs.buildMerlinCodeForTiles(tiles);
|
||||||
fs.writeFileSync(filename, tileSource);
|
fs.writeFileSync(filename, tileSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findAnimatedTiles(tileset) {
|
||||||
|
const animations = [];
|
||||||
|
let dynTileId = 0;
|
||||||
|
|
||||||
|
if (tileset.tile) {
|
||||||
|
for (const tile of tileset.tile) {
|
||||||
|
if (!tile.animation) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tileId = parseInt(tile.id, 10);
|
||||||
|
const frames = tile.animation.frame.map(f => {
|
||||||
|
const millis = parseInt(f.duration, 10);
|
||||||
|
const ticksPerMillis = 60. / 1000.;
|
||||||
|
return {
|
||||||
|
tileId: parseInt(f.tileid, 10),
|
||||||
|
ticks: Math.round(millis * ticksPerMillis),
|
||||||
|
millis
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
animations.push({
|
||||||
|
tileId,
|
||||||
|
dynTileId,
|
||||||
|
frames
|
||||||
|
});
|
||||||
|
|
||||||
|
dynTileId += 1;
|
||||||
|
if (dynTileId > 31) {
|
||||||
|
console.warn('Only 32 animated tiles are supported');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return animations;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command line arguments
|
* Command line arguments
|
||||||
*
|
*
|
||||||
|
@ -145,6 +233,8 @@ async function main(argv) {
|
||||||
let bg0TileSet = null;
|
let bg0TileSet = null;
|
||||||
|
|
||||||
for (const record of tileSets) {
|
for (const record of tileSets) {
|
||||||
|
console.log('Looking for animated tiles...');
|
||||||
|
const animations = findAnimatedTiles(record.tileset);
|
||||||
console.log(`Importing tileset "${record.tileset.name}"`);
|
console.log(`Importing tileset "${record.tileset.name}"`);
|
||||||
const tiles = await readTileSet(workdir, record.tileset);
|
const tiles = await readTileSet(workdir, record.tileset);
|
||||||
|
|
||||||
|
@ -152,7 +242,22 @@ async function main(argv) {
|
||||||
console.log(`Writing tiles to ${outputFilename}`);
|
console.log(`Writing tiles to ${outputFilename}`);
|
||||||
writeTiles(outputFilename, tiles);
|
writeTiles(outputFilename, tiles);
|
||||||
console.log(`Writing complete`);
|
console.log(`Writing complete`);
|
||||||
|
|
||||||
|
// Look for tiles with animation sequences. If found, this information need to be propagated
|
||||||
|
// to the tilemap export to mark those tile IDs as Dynamic Tiles.
|
||||||
|
//
|
||||||
|
// Exporting the "animations" actually created two code stubs; one to copy the first
|
||||||
|
// tile of the animation into the dynamic tile space during initialization and a second
|
||||||
|
// that created the timer callbacks that replace the tile data based on the time animation
|
||||||
|
// rate. We only have a VBL timer, so the animation time is rounded to the nearest
|
||||||
|
// 1/60 of a second.
|
||||||
|
if (animations.length > 0) {
|
||||||
|
console.log('Writing tile animation ');
|
||||||
|
const animationFilename = path.resolve(path.join(outdir, record.tileset.name + 'Anim.s'));
|
||||||
|
writeTileAnimations(animationFilename, animations);
|
||||||
|
console.log(`Writing complete`);
|
||||||
|
|
||||||
|
}
|
||||||
bg0TileSet = tiles;
|
bg0TileSet = tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user