Skip to content

Commit

Permalink
tmx transpiler
Browse files Browse the repository at this point in the history
  • Loading branch information
SalvatorePreviti authored and bencoder committed Sep 4, 2019
1 parent 7871f50 commit 1f38616
Show file tree
Hide file tree
Showing 16 changed files with 569 additions and 203 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Expand Up @@ -245,7 +245,7 @@
"yoda": 2
},
"parserOptions": {
"ecmaVersion": 8
"ecmaVersion": 9
},
"env": {
"es6": true,
Expand Down
20 changes: 10 additions & 10 deletions .vscode/settings.json
@@ -1,12 +1,12 @@
{
"editor.tabSize": 4,
"editor.detectIndentation": false,
"editor.formatOnSave": true,
"eslint.autoFixOnSave": true,
"eslint.validate": [
{ "language": "javascript", "autoFix": true },
{ "language": "javascriptreact", "autoFix": true },
{ "language": "typescript", "autoFix": true },
{ "language": "typescriptreact", "autoFix": true }
]
"editor.tabSize": 2,
"editor.detectIndentation": false,
"editor.formatOnSave": true,
"eslint.autoFixOnSave": true,
"eslint.validate": [
{ "language": "javascript", "autoFix": true },
{ "language": "javascriptreact", "autoFix": true },
{ "language": "typescript", "autoFix": true },
{ "language": "typescriptreact", "autoFix": true }
]
}
35 changes: 35 additions & 0 deletions levels-compiler/index.js
@@ -0,0 +1,35 @@
#!/usr/bin/env node

const path = require('path')
const fs = require('fs')
const tmxToLevel = require('./tmxToLevel')
const prettier = require('prettier')

const levelsFolder = path.resolve(__dirname, '../src/levels')
const outputLevelsFilePath = path.resolve(__dirname, '../src/levels.js')

const levelNames = fs
.readdirSync(levelsFolder)
.filter(name => name.endsWith('.tmx'))
.map(name => path.basename(name, '.tmx'))
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))

console.log(`Compiling ${levelNames.length} levels from ${levelsFolder} to ${outputLevelsFilePath}`)

const levels = []
for (let levelIndex = 0; levelIndex < levelNames.length; ++levelIndex) {
const levelName = levelNames[levelIndex]
console.log('>', levelIndex, levelName)
const xml = fs.readFileSync(path.resolve(levelsFolder, `${levelName}.tmx`), 'utf8')
const level = tmxToLevel(xml, levelIndex)
levels.push(level)
}

const output = `// autogenerated file
const levels = ${JSON.stringify(levels)}
`

const outputFormatted = prettier.format(output, { filepath: outputLevelsFilePath })
fs.writeFileSync(outputLevelsFilePath, outputFormatted)

console.log('ok.')
56 changes: 56 additions & 0 deletions levels-compiler/tmx.js
@@ -0,0 +1,56 @@
const xmlParser = require('fast-xml-parser')

function tmxParse(xmlText) {
return xmlParser.parse(xmlText, {
allowBooleanAttributes: true,
ignoreAttributes: false,
arrayMode: false,
attributeNamePrefix: '',
parseAttributeValue: true,
parseNodeValue: true,
trimValues: true,
ignoreNameSpace: true
})
}

exports.tmxParse = tmxParse

function tmxArray(itemOrArray) {
if (itemOrArray === null || itemOrArray === undefined) {
return []
}
if (Array.isArray(itemOrArray)) {
return itemOrArray.filter(x => x !== undefined && x !== null)
}
return [itemOrArray]
}

exports.tmxArray = tmxArray

function tmxObjectProperties(object, result = {}) {
for (const properties of tmxArray(object.properties)) {
for (const item of tmxArray(properties.property)) {
result[item.name] = item.value
}
}
return result
}

exports.tmxObjectProperties = tmxObjectProperties

function tmxPolygonPoints(text, objectX = 0, objectY = 0) {
const array = text.split(' ').map(point => {
const [x, y] = point.split(',').map(parseFloat)
return { x: Math.round(x + objectX), y: Math.round(y + objectY) }
})
// Insert first element at the end to close the polygon
const first = array[0]
const last = array[array.length - 1]
if (first && first !== last && (first.x !== last.x || first.y !== last.y)) {
array.push(first)
}

return array
}

exports.tmxPolygonPoints = tmxPolygonPoints
66 changes: 66 additions & 0 deletions levels-compiler/tmxToLevel.js
@@ -0,0 +1,66 @@
const { tmxParse, tmxArray, tmxObjectProperties, tmxPolygonPoints } = require('./tmx')

function tmxToLevel(xmlText, id) {
const level = {
id,
walls: [],
doors: [],
switches: [],
start: { x: 0, y: 0 },
end: { x: 10, y: 10 }
}

const objectTypeMapping = {
wall(object) {
for (const polygon of tmxArray(object.polygon)) {
level.walls.push(tmxPolygonPoints(polygon.points, object.x, object.y))
}
},

door(object, properties) {
level.doors.push({
...properties,
name: object.name,
polygon: tmxPolygonPoints(object.polygon.points, object.x, object.y),
open: !!properties.open
})
},

switch(object, properties) {
level.switches.push({
...properties,
x: object.x,
y: object.y,
name: object.name,
targets: `${properties.target || ''}`.split(','),
type: properties.type || 'momentary',
pressed: 0
})
},

start(object) {
level.start.x = Math.round(object.x)
level.start.y = Math.round(object.y)
},

end(object) {
level.end.x = Math.round(object.x)
level.end.y = Math.round(object.y)
}
}

const xml = tmxParse(xmlText)
for (const objectGroup of tmxArray(xml.map.objectgroup)) {
for (const object of tmxArray(objectGroup.object)) {
if (typeof objectTypeMapping[object.type] === 'function') {
objectTypeMapping[object.type](object, tmxObjectProperties(object))
} else {
console.warn(`Warning, unknown object type "${object.type}". id:${object.id}`)
}
}
}

return level
}

module.exports = tmxToLevel
File renamed without changes.
File renamed without changes.
File renamed without changes.
55 changes: 55 additions & 0 deletions levels/level3.tmx
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.2.4" orientation="orthogonal" renderorder="right-down" width="30" height="30" tilewidth="32" tileheight="32" infinite="0" nextlayerid="5" nextobjectid="12">
<objectgroup id="3" name="features">
<object id="1" name="walls" type="wall" x="416" y="768">
<polygon points="0,192 0,-480 -96,-480 -96,-96 -32,-96 -32,32 -160,32 -160,-544 0,-544 0,-672 -224,-672 -224,64 -32,64 -32,192 -288,192 -288,-736 64,-736 64,-544 224,-544 224,32 96,32 96,-96 160,-96 160,-480 64,-480 64,192"/>
</object>
<object id="2" name="start" type="start" x="448" y="736">
<point/>
</object>
<object id="3" name="switch1" type="switch" x="448" y="480">
<properties>
<property name="target" value="door1"/>
<property name="type" value="momentary"/>
</properties>
<point/>
</object>
<object id="4" name="end" type="end" x="576" y="736">
<point/>
</object>
<object id="5" name="door1" type="door" x="416" y="288">
<properties>
<property name="open" type="bool" value="false"/>
<property name="test" value="123"/>
</properties>
<polygon points="0,128 64,128 0,128"/>
</object>
<object id="6" name="switch1" type="switch" x="320" y="736">
<properties>
<property name="target" value="door1"/>
<property name="type" value="momentary"/>
</properties>
<point/>
</object>
<object id="8" name="switch1" type="switch" x="448" y="576">
<properties>
<property name="target" value="door1"/>
<property name="type" value="momentary"/>
</properties>
<point/>
</object>
<object id="10" name="door1" type="door" x="554.489" y="437.33">
<properties>
<property name="open" type="bool" value="false"/>
</properties>
<polygon points="-138.489,74.6704 -74.4894,74.6704 -138.489,74.6704"/>
</object>
<object id="11" name="door1" type="door" x="544.932" y="561.647">
<properties>
<property name="open" type="bool" value="false"/>
</properties>
<polygon points="31.0682,14.3525 95.0682,14.3525 31.0682,14.3525"/>
</object>
</objectgroup>
<objectgroup id="4" name="Object Layer 2"/>
</map>
33 changes: 30 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 37 additions & 33 deletions package.json
@@ -1,35 +1,39 @@
{
"name": "js13k-2019",
"version": "1.0.0",
"description": "ghosts",
"main": "index.js",
"scripts": {
"zip": "node ./scripts/zip.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/bencoder/js13k-2019.git"
},
"keywords": [
"ghost",
"js13k"
],
"author": "Ben Clarks, Salvatore Previti",
"license": "ISC",
"bugs": {
"url": "https://github.com/bencoder/js13k-2019/issues"
},
"homepage": "https://github.com/bencoder/js13k-2019#readme",
"devDependencies": {
"archiver": "^3.1.1",
"eslint": "^6.3.0",
"eslint-config-prettier": "^6.1.0",
"html-minifier": "^4.0.0",
"mkdirp": "^0.5.1",
"prettier": "^1.18.2",
"prettysize": "^2.0.0",
"uglify-es": "^3.3.9",
"uglify-js": "^3.6.0"
}
"name": "js13k-2019",
"version": "1.0.0",
"description": "ghosts",
"main": "index.js",
"private": true,
"scripts": {
"levels": "node ./levels-compiler",
"zip": "node ./scripts/zip.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/bencoder/js13k-2019.git"
},
"keywords": [
"ghost",
"js13k"
],
"author": "Ben Clarks, Salvatore Previti",
"license": "ISC",
"bugs": {
"url": "https://github.com/bencoder/js13k-2019/issues"
},
"homepage": "https://github.com/bencoder/js13k-2019#readme",
"devDependencies": {
"archiver": "^3.1.1",
"eslint": "^6.3.0",
"eslint-config-prettier": "^6.2.0",
"html-minifier": "^4.0.0",
"mkdirp": "^0.5.1",
"prettier": "^1.18.2",
"prettysize": "^2.0.0",
"uglify-es": "^3.3.9"
},
"dependencies": {
"fast-xml-parser": "^3.12.20"
}
}
17 changes: 13 additions & 4 deletions src/index.html
@@ -1,9 +1,18 @@
<style>
body,html {padding:0; margin:0}
canvas {margin:0; width:100%; height:100%;}
body,
html {
padding: 0;
margin: 0
}

canvas {
margin: 0;
width: 100%;
height: 100%;
}
</style>
<canvas id="c">
</canvas>
<canvas id="c"></canvas>
<script src="levels.js"></script>
<script src="textures.js"></script>
<script src="vectors.js"></script>
<script src="collision.js"></script>
Expand Down

0 comments on commit 1f38616

Please sign in to comment.