soiz1's picture
Upload 811 files
30c32c8 verified
raw
history blame
11.3 kB
const BlockType = require('../../extension-support/block-type');
const ArgumentType = require('../../extension-support/argument-type');
const formatMessage = require('format-message');
const Cast = require('../../util/cast');
const Clone = require('../../util/clone');
const Pathfinding = require('pathfinding');
const Nodes = require('./nodes');
const Seperator = require('./seperator');
const Map = require('./map');
/*
develope test
do the Seperator functions work?
const _testGrid = [
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0],
];
console.log(_testGrid);
const _marginGrid = Seperator.marginGrid(_testGrid, 4);
console.log(_marginGrid);
const _padGrid = Seperator.padGrid(_marginGrid, 3, 3);
console.log(_padGrid);
develope test RESULTS
no not really for some reason
one of the functions adds like 60 items to a row
but only the rows that were created inside of that function
ok now they work lol
*/
/*
develope test
do the Map functions work?
const _testMap = new Map();
console.log(Clone.simple(_testMap));
_testMap.add(0, 0, 50, 50);
_testMap.add(-50, 0, 0, -50);
console.log(Clone.simple(_testMap));
console.log(_testMap.toGrid());
develope test RESULTS
i put the offset x and y in the wrong order lol
somehow Math.abs stopped working
nvm i just messed somethin up with the offsets and X was negative
ok somehow its sitll not working even though grid is the right size
seems like after creating blank tiles, the walls create too many tiles
oh i was literally just using 2 variables i shouldnt have been using
and now grid is blank brh
nevermind i was reading the wrong grid
Map class should fully work
*/
/**
* Class for Pathfinding blocks
* @constructor
*/
class JgPathfindingBlocks {
constructor(runtime) {
/**
* The runtime instantiating this block package.
* @type {Runtime}
*/
this.runtime = runtime;
/**
* The current map and it's boxes.
*/
this.map = new Map();
/**
* The current settings for the pathfinding character.
*/
this.pather = {
x: 0,
y: 0,
width: 1,
height: 1
}
/**
* The current result of the pathfinding operation.
*/
this.pathNodes = new Nodes();
}
/**
* @returns {object} metadata for this extension and its blocks.
*/
getInfo() {
return {
id: 'jgPathfinding',
name: 'Pathfinding',
color1: '#5386E2',
color2: '#4169B1',
blocks: [
{
opcode: 'createBlockadeAt',
text: formatMessage({
id: 'jgPathfinding.blocks.createBlockadeAt',
default: 'create blockade at x1: [X1] y1: [Y1] x2: [X2] y2: [Y2]',
description: "Block that creates a blockade in the pathfinding area."
}),
arguments: {
X1: { type: ArgumentType.NUMBER, defaultValue: -70 },
Y1: { type: ArgumentType.NUMBER, defaultValue: 20 },
X2: { type: ArgumentType.NUMBER, defaultValue: 70 },
Y2: { type: ArgumentType.NUMBER, defaultValue: -20 },
},
blockType: BlockType.COMMAND
},
{
opcode: 'clearBlockades',
text: formatMessage({
id: 'jgPathfinding.blocks.clearBlockades',
default: 'clear blockades',
description: "Block that removes all blockades in the pathfinding area."
}),
blockType: BlockType.COMMAND
},
{
opcode: 'setPatherXY',
text: formatMessage({
id: 'jgPathfinding.blocks.setPatherXY',
default: 'set pather starting x: [X] y: [Y]',
description: "Block that sets the starting position for the pather."
}),
arguments: {
X: { type: ArgumentType.NUMBER, defaultValue: 0 },
Y: { type: ArgumentType.NUMBER, defaultValue: 120 },
},
blockType: BlockType.COMMAND
},
{
opcode: 'setWidthHeight',
text: formatMessage({
id: 'jgPathfinding.blocks.setWidthHeight',
default: 'set pather width: [WIDTH] height: [HEIGHT]',
description: "Block that sets the width and height of the path follower. This allows sprites to avoid clipping inside walls on the way to the destination."
}),
arguments: {
WIDTH: { type: ArgumentType.NUMBER, defaultValue: 55 },
HEIGHT: { type: ArgumentType.NUMBER, defaultValue: 95 },
},
blockType: BlockType.COMMAND
},
{
opcode: 'pathToSpot',
text: formatMessage({
id: 'jgPathfinding.blocks.pathToSpot',
default: 'find path to x: [X] y: [Y] around blockades',
description: "Block that finds a path around blockades in the pathfinding area to get to a location."
}),
arguments: {
X: { type: ArgumentType.NUMBER, defaultValue: 60 },
Y: { type: ArgumentType.NUMBER, defaultValue: -60 },
},
blockType: BlockType.COMMAND
},
'---',
{
opcode: 'setListToPath',
text: formatMessage({
id: 'jgPathfinding.blocks.setListToPath',
default: 'set [LIST] to current path',
description: "Block that sets a list to the current path."
}),
arguments: {
LIST: { type: ArgumentType.LIST },
},
hideFromPalette: true,
blockType: BlockType.COMMAND
},
{
opcode: 'getPathAs',
text: formatMessage({
id: 'jgPathfinding.blocks.getPathAs',
default: 'current path as [TYPE]',
description: "Block that returns the current path in a certain way."
}),
arguments: {
TYPE: { type: ArgumentType.STRING, menu: "pathReturnType" },
},
disableMonitor: true,
blockType: BlockType.REPORTER
},
],
menus: {
// lists: "menuLists",
pathReturnType: {
acceptReporters: true,
items: [
"json arrays",
"json array with objects",
"json object",
"comma seperated list",
].map(item => ({ text: item, value: item }))
}
}
};
}
// menus
// blocks
createBlockadeAt(args) {
const x1 = Cast.toNumber(args.X1);
const y1 = Cast.toNumber(args.Y1);
const x2 = Cast.toNumber(args.X2);
const y2 = Cast.toNumber(args.Y2);
// add to map
this.map.add(x1, y1, x2, y2);
}
clearBlockades() {
this.map.clear();
}
setPatherXY(args) {
const x = Cast.toNumber(args.X);
const y = Cast.toNumber(args.Y);
this.pather.x = x;
this.pather.y = y;
}
setWidthHeight(args) {
const width = Cast.toNumber(args.WIDTH);
const height = Cast.toNumber(args.HEIGHT);
this.pather.width = width;
this.pather.height = height;
}
pathToSpot(args) {
const goalX = Cast.toNumber(args.X);
const goalY = Cast.toNumber(args.Y);
const exported = this.map.toGrid();
// add margins
const stageSize = {
width: this.runtime.stageWidth,
height: this.runtime.stageHeight
};
const marginSize = (stageSize.height > stageSize.width ? stageSize.height : stageSize.width)
+ (this.pather.height > this.pather.width ? this.pather.height : this.pather.width)
+ 24;
// use the margins & add padding to the walls for the final matrix
const marginMatrix = Seperator.marginGrid(exported.grid, marginSize);
const matrix = Seperator.padGrid(marginMatrix, this.pather.width, this.pather.height);
// get proper offsets
const offset = exported.offset;
offset.left -= marginSize;
offset.top += marginSize;
// setup pathfinding
const grid = new Pathfinding.Grid(matrix);
const finder = new Pathfinding.AStarFinder({
allowDiagonal: true,
dontCrossCorners: true
});
// set real starts and goals
// this is based on the offset
const realPositions = Clone.simple({
start: {
x: this.pather.x - offset.left,
y: Math.abs(this.pather.y - offset.top),
},
end: {
x: goalX - offset.left,
y: Math.abs(goalY - offset.top),
}
});
const path = Pathfinding.Util.compressPath(finder.findPath(
realPositions.start.x,
realPositions.start.y,
realPositions.end.x,
realPositions.end.y,
grid
));
// we need to do more offsetting for the resulting path
// also need to convert it to nodes
const newPath = new Nodes();
for (const node of path) {
const x = node[0] + offset.left;
const y = 0 - (node[1] - offset.top);
newPath.push([x, y]);
}
this.pathNodes = newPath;
}
setListToPath(args, util) {
console.log(args);
const list = util.target.lookupOrCreateList(args.LIST.id, args.LIST.name);
list.value = push(args.ITEM);
}
getPathAs(args) {
const switchh = Cast.toString(args.TYPE).toLowerCase();
switch (switchh) {
case 'json array with objects':
return JSON.stringify(this.pathNodes.getObjects());
case 'json object':
return JSON.stringify(this.pathNodes.getAsObject());
case 'comma seperated list':
return this.pathNodes.getCommaSeperated();
default:
return JSON.stringify(this.pathNodes.getRaw());
}
}
}
module.exports = JgPathfindingBlocks;