Closed SDFTDusername closed 1 year ago
Scratch.vm.on("BEFORE_EXECUTE") is what I used (no runtime). Have a look at animated text or Skins for examples on how to use it.
Scratch.vm.on("BEFORE_EXECUTE") is what I used (no runtime). Have a look at animated text or Skins for examples on how to use it.
i used that and I already looked at an extension to see how to use it
Scratch.vm.on("BEFORE_EXECUTE") is what I used (no runtime). Have a look at animated text or Skins for examples on how to use it.
i used that and I already looked at an extension to see how to use it
Please show us some code then, since you haven't described anything different for it to not work
Also, I mentioned Animated Text and Skins because I have worked on those extensions directly and have seen first-hand that they work.
Scratch.vm.on("BEFORE_EXECUTE") is what I used (no runtime). Have a look at animated text or Skins for examples on how to use it.
i used that and I already looked at an extension to see how to use it
Please show us some code then, since you haven't described anything different for it to not work
Scratch.vm.on("BEFORE_EXECUTE", () => {
vm.runtime.targets.forEach((target) => {
if (target[anchor_updateAnchorEveryFrame]) {
_updateAnchor({ target: target });
}
});
});
I have tried using vm.runtime and without runtime, _updateAnchor also successfully runs when run via blocks
BEFORE_EXECUTE works fine, as noted previously. It's your code that's the problem - try debugging it. Look for errors, add console.log
, debugger
, etc.
we try to be helpful here but we also are not your personal javascript assistants
BEFORE_EXECUTE is also only on vm.runtime, not on vm itself, so at least the code sample you give is expected to not work
I would guess the issue is that target[anchor_updateAnchorEveryFrame]
throws a reference error because you probably meant target.anchor_updateAnchorEveryFrame
and anchor_updateAnchorEveryFrame is not defined
I would guess the issue is that
target[anchor_updateAnchorEveryFrame]
throws a reference error because you probably meanttarget.anchor_updateAnchorEveryFrame
and anchor_updateAnchorEveryFrame is not defined
there's no errors in the console, when I also put a console log at the begin of the BEFORE_EXECUTE function, it logs nothing in the console
Do you see anything when you open a new tab and just run vm.runtime.on("BEFORE_EXECUTE", () => { console.log("test"); })
in the editor using the console? no extensions or anything, just run that
vm.runtime.on("BEFORE_EXECUTE", () => { console.log("test"); })
after typing that in the console, it prints "test" every frame just fine. in the extension I have the function outside of the class but inside the (function(Scratch) { 'use strict';
, turbowarp is also getting my extension from localhost 8000
vm.runtime.on("BEFORE_EXECUTE", () => { console.log("test"); })
after typing that in the console, it prints "test" every frame just fine. in the extension I have the function outside of the class but inside the
(function(Scratch) { 'use strict';
, turbowarp is also getting my extension from localhost 8000
oh, it just started working again. but now it's unable to run any blocks and it just stays stuck on a yellow glow
post your entire extension or we can't help you
post your entire extension or we can't help you
also it doesn't stay stuck on the yellow glow and works only if _updateAnchor
does return and the condition target[anchor_position] == 'none'
is met
// Name: Anchor
// ID: anchor
// Descriptions: Anchors sprites to screen positions
(function(Scratch) {
'use strict';
if (!Scratch.extensions.unsandboxed) {
throw new Error("Anchor must be run unsandboxed");
}
const anchor_position = Symbol('anchor.position');
const anchor_offset_x = Symbol('anchor.offset.x');
const anchor_offset_y = Symbol('anchor.offset.y');
const anchor_updateAnchorEveryBlock = Symbol('anchor.updateAnchorEveryBlock');
const anchor_updateAnchorEveryFrame = Symbol('anchor.updateAnchorEveryFrame');
const anchor_resolution = Symbol('anchor.resolution');
const anchor_retreat = Symbol('anchor.retreat');
const vm = Scratch.vm;
/**
* @param {VM.RenderedTarget} target
* @param {VM.RenderedTarget} [originalTarget] If target is a clone, the original to copy from.
*/
const implementAnchorForTarget = (target, originalTarget) => {
if (anchor_position in target) {
return;
}
target[anchor_position] = originalTarget ? originalTarget[anchor_position] : 'none';
target[anchor_offset_x] = originalTarget ? originalTarget[anchor_offset_x] : 0;
target[anchor_offset_y] = originalTarget ? originalTarget[anchor_offset_y] : 0;
target[anchor_updateAnchorEveryBlock] = originalTarget ? originalTarget[anchor_updateAnchorEveryBlock] : false;
target[anchor_updateAnchorEveryFrame] = originalTarget ? originalTarget[anchor_updateAnchorEveryFrame] : true;
target[anchor_resolution] = originalTarget ? originalTarget[anchor_resolution] : 1;
target[anchor_retreat] = originalTarget ? originalTarget[anchor_retreat] : true;
};
vm.runtime.targets.forEach((target) => implementAnchorForTarget(target));
vm.runtime.on("targetWasCreated", (target, originalTarget) =>
implementAnchorForTarget(target, originalTarget)
);
vm.runtime.on("PROJECT_LOADED", () => {
vm.runtime.targets.forEach((target) => implementAnchorForTarget(target));
});
vm.runtime.on("BEFORE_EXECUTE", () => {
vm.runtime.targets.forEach((target) => {
if (target[anchor_updateAnchorEveryFrame]) {
_updateAnchor({ target: target });
}
});
});
const _touchingEdge = (target, axis) => {
if (target.renderer) {
const stageWidth = vm.runtime.stageWidth;
const stageHeight = vm.runtime.stageHeight;
const bounds = target.getBounds();
if (axis.toLowerCase() == "x") {
return bounds.left < -stageWidth / 2 || bounds.right > stageWidth / 2;
}
if (axis.toLowerCase() == "y") {
return bounds.top > stageHeight / 2 || bounds.bottom < -stageHeight / 2;
}
}
return false;
};
const _move = (target, info, x, y, resolution = 1, retreat = true) => {
const maxAttempts = (info.size.x + info.size.y) * resolution;
let attempts = maxAttempts;
/*
while (target.isTouchingObject('_edge_') && attempts > 0) {
target.setXY(target.x + x / resolution, target.y + y / resolution);
attempts -= 1;
}
*/
if (x != 0) {
attempts = maxAttempts;
while (_touchingEdge(target, "x") && attempts > 0) {
target.setXY(target.x + x / resolution, target.y);
attempts -= 1;
}
if (retreat) {
target.setXY(target.x - x / resolution, target.y);
}
}
if (y != 0) {
attempts = maxAttempts;
while (_touchingEdge(target, "y") && attempts > 0) {
target.setXY(target.x, target.y + y / resolution);
attempts -= 1;
}
if (retreat) {
target.setXY(target.x, target.y - y / resolution);
}
}
if (x != 0) {
attempts = maxAttempts;
while (!_touchingEdge(target, "x") && attempts > 0) {
target.setXY(target.x - x / resolution, target.y);
attempts -= 1;
}
if (retreat) {
target.setXY(target.x + x / resolution, target.y);
}
}
if (y != 0) {
attempts = maxAttempts;
while (!_touchingEdge(target, "y") && attempts > 0) {
target.setXY(target.x, target.y - y / resolution);
attempts -= 1;
}
if (retreat) {
target.setXY(target.x, target.y + y / resolution);
}
}
};
const _updateAnchor = (utils) => {
const target = utils.target;
if (target[anchor_position] == 'none') {
return;
}
const renderedInfo = target._getRenderedDirectionAndScale();
const scale = renderedInfo.scale;
const direction = renderedInfo.direction;
const costumes = target.sprite.costumes_;
const costume_number = target.currentCostume;
var info = {
position: {
x: target.x,
y: target.y
},
size: {
x: costumes[costume_number].size[0] * (scale[0] / 100),
y: costumes[costume_number].size[1] * (scale[1] / 100)
}
}
switch (target[anchor_position]) {
case 'top left':
target.setXY(
vm.runtime.stageWidth / -2,
vm.runtime.stageHeight / 2
);
_move(target, info, 1, -1, target[anchor_resolution], target[anchor_retreat]);
break;
case 'top center':
target.setXY(
0,
vm.runtime.stageHeight / 2
);
_move(target, info, 0, -1, target[anchor_resolution], target[anchor_retreat]);
break;
case 'top right':
target.setXY(
vm.runtime.stageWidth / 2,
vm.runtime.stageHeight / 2
);
_move(target, info, -1, -1, target[anchor_resolution], target[anchor_retreat]);
break;
case 'middle left':
target.setXY(
vm.runtime.stageWidth / -2,
0
);
_move(target, info, 1, 0, target[anchor_resolution], target[anchor_retreat]);
break;
case 'middle center':
target.setXY(0, 0);
break;
case 'middle right':
target.setXY(
vm.runtime.stageWidth / 2,
0
);
_move(target, info, -1, 0, target[anchor_resolution], target[anchor_retreat]);
break;
case 'bottom left':
target.setXY(
vm.runtime.stageWidth / -2,
vm.runtime.stageHeight / -2
);
_move(target, info, 1, 1, target[anchor_resolution], target[anchor_retreat]);
break;
case 'bottom center':
target.setXY(
0,
vm.runtime.stageHeight / -2
);
_move(target, info, 0, 1, target[anchor_resolution], target[anchor_retreat]);
break;
case 'bottom right':
target.setXY(
vm.runtime.stageWidth / 2,
vm.runtime.stageHeight / -2
);
_move(target, info, -1, 1, target[anchor_resolution], target[anchor_retreat]);
break;
default:
break;
}
target.setXY(
target.x + target[anchor_offset_x],
target.y + target[anchor_offset_y]
);
};
class Anchor {
getInfo () {
return {
id: 'anchor',
name: 'Anchor',
color1: '#7b99a0',
color2: '#6c8990',
color3: '#51676c',
blocks: [
{
opcode: 'label1',
blockType: Scratch.BlockType.LABEL,
text: 'Every sprite has its'
},
{
opcode: 'label2',
blockType: Scratch.BlockType.LABEL,
text: 'own anchor configurations.'
},
'---',
{
opcode: 'setPosition',
blockType: Scratch.BlockType.COMMAND,
text: 'set anchor position to [POSITION]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
POSITION: {
type: Scratch.ArgumentType.STRING,
menu: 'POSITION'
}
}
},
{
opcode: 'setOffset',
blockType: Scratch.BlockType.COMMAND,
text: 'set ancher offset to x: [OFFSET_X] y: [OFFSET_Y]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
OFFSET_X: {
type: Scratch.ArgumentType.NUMBER
},
OFFSET_Y: {
type: Scratch.ArgumentType.NUMBER
}
}
},
{
opcode: 'setPositionAndOffset',
blockType: Scratch.BlockType.COMMAND,
text: 'set anchor position to [POSITION] with offset x: [OFFSET_X] y: [OFFSET_Y]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
POSITION: {
type: Scratch.ArgumentType.STRING,
menu: 'POSITION'
},
OFFSET_X: {
type: Scratch.ArgumentType.NUMBER
},
OFFSET_Y: {
type: Scratch.ArgumentType.NUMBER
}
}
},
'---',
{
opcode: 'setOffsetX',
blockType: Scratch.BlockType.COMMAND,
text: 'set ancher offset x to [OFFSET_X]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
OFFSET_X: {
type: Scratch.ArgumentType.NUMBER
}
}
},
{
opcode: 'setOffsetY',
blockType: Scratch.BlockType.COMMAND,
text: 'set ancher offset y to [OFFSET_Y]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
OFFSET_Y: {
type: Scratch.ArgumentType.NUMBER
}
}
},
'---',
{
opcode: 'changeOffsetXby',
blockType: Scratch.BlockType.COMMAND,
text: 'change ancher offset x by [CHANGE_OFFSET_X_BY]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
CHANGE_OFFSET_X_BY: {
type: Scratch.ArgumentType.NUMBER,
defaultValue: 10
}
}
},
{
opcode: 'changeOffsetYby',
blockType: Scratch.BlockType.COMMAND,
text: 'change ancher offset y by [CHANGE_OFFSET_Y_BY]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
CHANGE_OFFSET_Y_BY: {
type: Scratch.ArgumentType.NUMBER,
defaultValue: 10
}
}
},
'---',
{
opcode: 'getPosition',
blockType: Scratch.BlockType.REPORTER,
text: 'anchor position',
filter: [Scratch.TargetType.SPRITE],
disableMonitor: true
},
'---',
{
opcode: 'getOffsetX',
blockType: Scratch.BlockType.REPORTER,
text: 'anchor offset x',
filter: [Scratch.TargetType.SPRITE],
disableMonitor: true
},
{
opcode: 'getOffsetY',
blockType: Scratch.BlockType.REPORTER,
text: 'anchor offset y',
filter: [Scratch.TargetType.SPRITE],
disableMonitor: true
},
'---',
{
opcode: 'setUpdateAnchorEveryBlock',
blockType: Scratch.BlockType.COMMAND,
text: 'set update anchor every block to [UPDATE_ANCHOR_EVERY_BLOCK]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
UPDATE_ANCHOR_EVERY_BLOCK: {
type: Scratch.ArgumentType.STRING,
defaultValue: "disabled",
menu: 'UPDATE_ANCHOR_EVERY'
}
}
},
{
opcode: 'getUpdateAnchorEveryBlock',
blockType: Scratch.BlockType.BOOLEAN,
text: 'update anchor every block?',
filter: [Scratch.TargetType.SPRITE],
disableMonitor: true
},
'---',
{
opcode: 'setUpdateAnchorEveryFrame',
blockType: Scratch.BlockType.COMMAND,
text: 'set update anchor every frame to [UPDATE_ANCHOR_EVERY_FRAME]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
UPDATE_ANCHOR_EVERY_FRAME: {
type: Scratch.ArgumentType.STRING,
menu: 'UPDATE_ANCHOR_EVERY'
}
}
},
{
opcode: 'getUpdateAnchorEveryFrame',
blockType: Scratch.BlockType.BOOLEAN,
text: 'update anchor every frame?',
filter: [Scratch.TargetType.SPRITE],
disableMonitor: true
},
'---',
{
opcode: 'updateAnchor',
blockType: Scratch.BlockType.COMMAND,
text: 'update anchor',
filter: [Scratch.TargetType.SPRITE]
},
'---',
{
opcode: 'setResolution',
blockType: Scratch.BlockType.COMMAND,
text: 'set anchor resolution to [ANCHOR_RESOLUTION]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
ANCHOR_RESOLUTION: {
type: Scratch.ArgumentType.NUMBER,
defaultValue: 1
}
}
},
{
opcode: 'getResolution',
blockType: Scratch.BlockType.REPORTER,
text: 'get anchor resolution',
filter: [Scratch.TargetType.SPRITE],
disableMonitor: true
},
'---',
{
opcode: 'setRetreat',
blockType: Scratch.BlockType.COMMAND,
text: 'set anchor retreat to [ANCHOR_RETREAT]',
filter: [Scratch.TargetType.SPRITE],
arguments: {
ANCHOR_RETREAT: {
type: Scratch.ArgumentType.STRING,
menu: "TRUE_FALSE"
}
}
},
{
opcode: 'getRetreat',
blockType: Scratch.BlockType.BOOLEAN,
text: 'get anchor retreat',
filter: [Scratch.TargetType.SPRITE],
disableMonitor: true
}
],
menus: {
POSITION: {
acceptReporters: true,
items: ['top left', 'top center', 'top right', 'middle left', 'middle center', 'middle right', 'bottom left', 'bottom center', 'bottom right', 'none']
},
UPDATE_ANCHOR_EVERY: {
acceptReporters: true,
items: ['enabled', 'disabled']
},
TRUE_FALSE: {
acceptReporters: true,
items: ['true', 'false']
}
}
};
}
setPosition(args, utils) {
utils.target[anchor_position] = args.POSITION;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
setOffset(args, utils) {
utils.target[anchor_offset_x] = args.OFFSET_X;
utils.target[anchor_offset_y] = args.OFFSET_Y;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
setPositionAndOffset(args, utils) {
utils.target[anchor_position] = args.POSITION;
utils.target[anchor_offset_x] = OFFSET_X;
utils.target[anchor_offset_y] = args.args.OFFSET_Y;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
setOffsetX(args, utils) {
utils.target[anchor_offset_x] = args.OFFSET_X;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
setOffsetY(args, utils) {
utils.target[anchor_offset_y] = args.OFFSET_Y;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
changeOffsetXby(args, utils) {
utils.target[anchor_offset_x] += args.CHANGE_OFFSET_X_BY;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
changeOffsetYby(args, utils) {
utils.target[anchor_offset_y] += args.CHANGE_OFFSET_Y_BY;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
getPosition(args, utils) {
return utils.target[anchor_position];
}
getOffsetX(args, utils) {
return utils.target[anchor_offset_x];
}
getOffsetY(args, utils) {
return utils.target[anchor_offset_y];
}
setUpdateAnchorEveryBlock(args, utils) {
args.UPDATE_ANCHOR_EVERY_BLOCK = Scratch.Cast.toString(args.UPDATE_ANCHOR_EVERY_BLOCK).toLowerCase();
utils.target[anchor_updateAnchorEveryBlock] = args.UPDATE_ANCHOR_EVERY_BLOCK == 'enabled' ||
args.UPDATE_ANCHOR_EVERY_BLOCK == 'true';
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
getUpdateAnchorEveryBlock(args, utils) {
return utils.target[anchor_updateAnchorEveryBlock];
}
setUpdateAnchorEveryFrame(args, utils) {
args.UPDATE_ANCHOR_EVERY_FRAME = Scratch.Cast.toString(args.UPDATE_ANCHOR_EVERY_FRAME).toLowerCase();
utils.target[anchor_updateAnchorEveryFrame] = args.UPDATE_ANCHOR_EVERY_FRAME == 'enabled' ||
args.UPDATE_ANCHOR_EVERY_FRAME == 'true';
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
getUpdateAnchorEveryFrame(args, utils) {
return utils.target[anchor_updateAnchorEveryFrame];
}
updateAnchor(args, utils) {
_updateAnchor(utils);
}
setResolution(args, utils) {
args.ANCHOR_RESOLUTION = Scratch.Cast.toNumber(args.ANCHOR_RESOLUTION);
utils.target[anchor_resolution] = args.ANCHOR_RESOLUTION;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
getResolution(args, utils) {
return utils.target[anchor_resolution]
}
setRetreat(args, utils) {
args.ANCHOR_RETREAT = Scratch.Cast.toBoolean(args.ANCHOR_RETREAT);
utils.target[anchor_retreat] = args.ANCHOR_RETREAT;
if (utils.target[anchor_updateAnchorEveryBlock]) {
this.updateAnchor(args, utils);
}
}
getRetreat(args, utils) {
return utils.target[anchor_retreat];
}
}
Scratch.extensions.register(new Anchor());
})(Scratch);
The problem is not BEFORE_EXECUTE, it's that your BEFORE_EXECUTE moves sprites with setXY, which makes it think a redraw has been requested, so it ends up not executing the scripts. A bit silly.
If you put this at the end of your BEFORE_EXECUTE:
Scratch.vm.runtime.redrawRequested = false;
should fix it
i'm making an extension that runs code every frame by running a function when "BEFORE_EXECUTE" is emitted from Scratch.vm.runtime, but it only works when it's packaged (for example a HTML file) and not in the editor. but extensions like DeltaTime does work in the editor while also listening for "BEFORE_EXECUTE"