Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions editor/extensions/src/apply-wheelsprung-fixes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/// <reference types="@mapeditor/tiled-api" />

import { ensureWindingOrder } from "./ensure-winding-order";
import { polylineToPolygon } from "./outline-polyline";
import { newPolygon } from "./new-polygon";


export function applyWheelsprungFixes(mapOrLayer) {
tiled.log("Running applyWheelsprungFixes:" + mapOrLayer);
Expand All @@ -23,6 +26,16 @@ export function applyWheelsprungFixes(mapOrLayer) {
);
object.polygon = ensureWindingOrder(object.polygon);
}

if (object.shape == MapObject.Polyline && object.selected) {
var polygon = polylineToPolygon(object.polygon, 4.0);
var newObject = newPolygon(object);
tiled.log("New object:" + newObject);
tiled.log("new polygon:" + polygon);
newObject.polygon = polygon;
mapOrLayer.addObject(newObject);
};

if(object.shape == MapObject.Ellipse && object.className == "DynamicObject") {
if(object.width != object.height) {
tiled.log("Ellipses not supported for Dynamic Objects. Making circular:" + object);
Expand Down
9 changes: 9 additions & 0 deletions editor/extensions/src/new-polygon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function newPolygon(oldObj) {
var object = new MapObject();
object.x = oldObj.x;
object.y = oldObj.y;
object.width = oldObj.width;
object.height = oldObj.height;
object.shape = MapObject.Polygon;
return object;
}
138 changes: 138 additions & 0 deletions editor/extensions/src/outline-polyline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
function getOffsets(a, b, thickness) {
var
dx = b.x - a.x,
dy = b.y - a.y,
len = Math.sqrt(dx * dx + dy * dy),
scale = thickness / (2 * len)
;
return {
x: -scale * dy,
y: scale * dx
};
}

function getIntersection(a1, b1, a2, b2) {

// directional constants
var
k1 = (b1.y - a1.y) / (b1.x - a1.x),
k2 = (b2.y - a2.y) / (b2.x - a2.x);



// if the directional constants are equal, the lines are parallel
if (Math.abs(k1 - k2)<0.00001) {
return;
}

// y offset constants for both lines
var m1 = a1.y - k1 * a1.x;
var m2 = a2.y - k2 * a2.x;

// compute x
var x = (m1 - m2) / (k2 - k1);

// use y = k * x + m to get y coordinate
var y = k1 * x + m1;

return { x:x, y:y };
}

function isArray(obj){
return (Object.prototype.toString.call(obj)==='[object Array]');
}

function me(points, thickness) {


//Convert points into json notation
var arr = [];
for (var i=0; i<points.length; i++){
var pt = points[i];
arr.push({
x: pt[0],
y: pt[1]
});
}
points = arr;



//Convert thickness into an array as needed
if (!isArray(thickness)){
var t = thickness;
thickness = [];
for (var i=0; i<points.length; i++){
thickness.push(t);
}
}



var
off, off2,
poly = [],
isFirst, isLast,
prevA, prevB,
interA, interB,
p0a, p1a, p0b, p1b
;

for (var i = 0, il = points.length - 1; i < il; i++) {
isFirst = !i;
isLast = (i === points.length - 2);


off = getOffsets(points[i], points[i+1], thickness[i]);
off2 = getOffsets(points[i], points[i+1], thickness[i+1]);

p0a = { x:points[i].x + off.x, y:points[i].y + off.y };
p1a = { x:points[i+1].x + off2.x, y:points[i+1].y + off2.y };

p0b = { x:points[i].x - off.x, y:points[i].y - off.y };
p1b = { x:points[i+1].x - off2.x, y:points[i+1].y - off2.y };


if (!isFirst) {
interA = getIntersection(prevA[0], prevA[1], p0a, p1a);
if (interA) {
poly.unshift(interA);
}
interB = getIntersection(prevB[0], prevB[1], p0b, p1b);
if (interB) {
poly.push(interB);
}
}

if (isFirst) {
poly.unshift(p0a);
poly.push(p0b);
}

if (isLast) {
poly.unshift(p1a);
poly.push(p1b);
}

if (!isLast) {
prevA = [p0a, p1a];
prevB = [p0b, p1b];
}
}


for (var i=0; i<poly.length; i++){
var pt = poly[i];
poly[i] = [pt.x, pt.y];
}
poly.push(poly[0]);

return poly;
}

export function polylineToPolygon(polygon, thickness) {
var points = polygon.map((pt) => [pt.x, pt.y]);
tiled.log("Running me:" + points);
var vertices = me(points, thickness);
return vertices.map((pt) => Qt.point(pt[0], pt[1]));
}
106 changes: 106 additions & 0 deletions editor/extensions/wheelsprung/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,103 @@
return vertices;
}

// src/outline-polyline.ts
function getOffsets(a, b, thickness) {
var dx = b.x - a.x, dy = b.y - a.y, len = Math.sqrt(dx * dx + dy * dy), scale = thickness / (2 * len);
return {
x: -scale * dy,
y: scale * dx
};
}
function getIntersection(a1, b1, a2, b2) {
var k1 = (b1.y - a1.y) / (b1.x - a1.x), k2 = (b2.y - a2.y) / (b2.x - a2.x);
if (Math.abs(k1 - k2) < 1e-5) {
return;
}
var m1 = a1.y - k1 * a1.x;
var m2 = a2.y - k2 * a2.x;
var x = (m1 - m2) / (k2 - k1);
var y = k1 * x + m1;
return { x, y };
}
function isArray(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
}
function me(points, thickness) {
var arr = [];
for (var i2 = 0; i2 < points.length; i2++) {
var pt = points[i2];
arr.push({
x: pt[0],
y: pt[1]
});
}
points = arr;
if (!isArray(thickness)) {
var t2 = thickness;
thickness = [];
for (var i2 = 0; i2 < points.length; i2++) {
thickness.push(t2);
}
}
var off, off2, poly = [], isFirst, isLast, prevA, prevB, interA, interB, p0a, p1a, p0b, p1b;
for (var i2 = 0, il = points.length - 1; i2 < il; i2++) {
isFirst = !i2;
isLast = i2 === points.length - 2;
off = getOffsets(points[i2], points[i2 + 1], thickness[i2]);
off2 = getOffsets(points[i2], points[i2 + 1], thickness[i2 + 1]);
p0a = { x: points[i2].x + off.x, y: points[i2].y + off.y };
p1a = { x: points[i2 + 1].x + off2.x, y: points[i2 + 1].y + off2.y };
p0b = { x: points[i2].x - off.x, y: points[i2].y - off.y };
p1b = { x: points[i2 + 1].x - off2.x, y: points[i2 + 1].y - off2.y };
if (!isFirst) {
interA = getIntersection(prevA[0], prevA[1], p0a, p1a);
if (interA) {
poly.unshift(interA);
}
interB = getIntersection(prevB[0], prevB[1], p0b, p1b);
if (interB) {
poly.push(interB);
}
}
if (isFirst) {
poly.unshift(p0a);
poly.push(p0b);
}
if (isLast) {
poly.unshift(p1a);
poly.push(p1b);
}
if (!isLast) {
prevA = [p0a, p1a];
prevB = [p0b, p1b];
}
}
for (var i2 = 0; i2 < poly.length; i2++) {
var pt = poly[i2];
poly[i2] = [pt.x, pt.y];
}
poly.push(poly[0]);
return poly;
}
function polylineToPolygon(polygon, thickness) {
var points = polygon.map((pt) => [pt.x, pt.y]);
tiled.log("Running me:" + points);
var vertices = me(points, thickness);
return vertices.map((pt) => Qt.point(pt[0], pt[1]));
}

// src/new-polygon.ts
function newPolygon(oldObj) {
var object = new MapObject();
object.x = oldObj.x;
object.y = oldObj.y;
object.width = oldObj.width;
object.height = oldObj.height;
object.shape = MapObject.Polygon;
return object;
}

// src/apply-wheelsprung-fixes.ts
function applyWheelsprungFixes(mapOrLayer) {
tiled.log("Running applyWheelsprungFixes:" + mapOrLayer);
Expand All @@ -42,6 +139,15 @@
);
object.polygon = ensureWindingOrder(object.polygon);
}
if (object.shape == MapObject.Polyline && object.selected) {
var polygon = polylineToPolygon(object.polygon, 4);
var newObject = newPolygon(object);
tiled.log("New object:" + newObject);
tiled.log("new polygon:" + polygon);
newObject.polygon = polygon;
mapOrLayer.addObject(newObject);
}
;
if (object.shape == MapObject.Ellipse && object.className == "DynamicObject") {
if (object.width != object.height) {
tiled.log("Ellipses not supported for Dynamic Objects. Making circular:" + object);
Expand Down
6 changes: 3 additions & 3 deletions src/level_meta/level_data.nim
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ let officialLevels*: OrderedTable[Path, LevelMeta] = @[
newLevelMeta(name= "Novel Navigations", path="levels/novel_navigations.flatty", theme= Bookshelf, hash="83D025E12A1140BC3B86831F20FF4622"),
newLevelMeta(name= "Shelf Swinger", path="levels/shelf_swinger.flatty", theme= Bookshelf, hash="E91EE82424E715F5C6F9A439F1096F1B"),
newLevelMeta(name= "Under Covers", path="levels/under_covers.flatty", theme= Bookshelf, hash="07C4F9B28FA27A1EDB706A9432544979"),
newLevelMeta(name= "Rollercoaster", path="levels/rollercoaster.flatty", theme= Bookshelf, hash="92330B17118385D29D0549DB1A823312"),
newLevelMeta(name= "Rollercoaster", path="levels/rollercoaster.flatty", theme= Bookshelf, hash="EB073CA2B150DF7EF20C31E8ECB01F86"),
newLevelMeta(name= "Hooked", path="levels/hooked.flatty", theme= Bookshelf, hash="C83A58916A6F97F1AA0A2952E12BFABA"),
newLevelMeta(name= "Dominoes", path="levels/dominoes.flatty", theme= Bookshelf, hash="19A67112C03DA92C9D51FB268956F93C"),
newLevelMeta(name= "Backflip", path="levels/backflip.flatty", theme= Bookshelf, hash="513A5202C29C322690EE9B33068D6789"),
Expand All @@ -64,11 +64,11 @@ let officialLevels*: OrderedTable[Path, LevelMeta] = @[
newLevelMeta(name= "Treasure Tunnel", path="levels/treasure_tunnel.flatty", theme= Plants, hash="6E5F2C44C7ED48F25ED86E834C68149B"),
newLevelMeta(name= "Half-Pipe Jungle", path="levels/halfpipe.flatty", theme= Plants, hash="31609EFBA4AB9DEFD10A4BF90CB5300D"),
newLevelMeta(name= "Rickety Bridge", path="levels/rickety_bridge.flatty", theme= Plants, hash="0CF980DB09C2EE873C16836319B51CBD"),
newLevelMeta(name = "Rolling Raiders", path="levels/boulder.flatty", theme= Plants, hash="0541EF41C104AE11FFCE43B3B3077A85"),
newLevelMeta(name = "Rolling Raiders", path="levels/boulder.flatty", theme= Plants, hash="7A93A4DD90103EF4363EB503BFAF0642"),

newLevelMeta(name= "Zig Zag Down", path="levels/zig_zag_down.flatty", theme= Desk, hash="633154C6A64C4C0EB4FCC1FE1F0490B0"),
newLevelMeta(name = "Time Traveler", path="levels/time_traveler.flatty", theme= Desk, hash="18193FB4744661DA83906690CE211469"),
newLevelMeta(name = "Tight Squeeze", path="levels/tight_squeeze.flatty", theme= Desk, hash="0541EF41C104AE11FFCE43B3B3077A85"),
newLevelMeta(name = "Tight Squeeze", path="levels/tight_squeeze.flatty", theme= Desk, hash="7A93A4DD90103EF4363EB503BFAF0642"),
newLevelMeta(name= "Ballistic Bowler", path="levels/ballistic_bowler.flatty", theme= Desk, hash="E7ED841B154ADD2B5694AD6613CCE5D1"),
newLevelMeta(name= "Ramp of Pages", path="levels/leg_up.flatty", theme= Desk, hash="6F48907EB90D6985CB66486C4A11FFEC"),
newLevelMeta(name= "Ballancing Act", path="levels/ballancing_act.flatty", theme= Desk, hash="15B0EC58F7BB8A9912DB470DE0CCA81F"),
Expand Down
2 changes: 1 addition & 1 deletion support/levels