HMR for blockly blocks
This commit is contained in:
@@ -1,24 +1,22 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['console_log_action'] = {
|
export const consoleLogAction: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Actions',
|
||||||
this.appendValueInput('VALUE')
|
block: {
|
||||||
.setAlign(Blockly.inputs.Align.RIGHT)
|
init(this: Blockly.Block) {
|
||||||
// .setCheck('String')
|
this.appendValueInput('VALUE')
|
||||||
.appendField('print');
|
.setAlign(Blockly.inputs.Align.RIGHT)
|
||||||
this.setInputsInline(false);
|
.appendField('print');
|
||||||
this.setPreviousStatement(true, null);
|
this.setInputsInline(false);
|
||||||
this.setNextStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setTooltip('Print value to console');
|
this.setNextStatement(true, null);
|
||||||
this.setHelpUrl('');
|
this.setTooltip('Print value to console');
|
||||||
this.setColour(150);
|
}
|
||||||
|
},
|
||||||
|
code(block, generator) {
|
||||||
|
const value = generator.valueToCode(block, 'VALUE', Order.ATOMIC);
|
||||||
|
return `console.log(${value});\n`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['console_log_action'] = function (block, generator) {
|
|
||||||
const valueValue = generator.valueToCode(block, 'VALUE', Order.ATOMIC);
|
|
||||||
return `console.log(${valueValue});\n`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './consoleLog';
|
export * from './consoleLog';
|
||||||
export * from './physics';
|
export * from './stopGame';
|
||||||
export * from './waitSeconds';
|
export * from './waitSeconds';
|
||||||
|
export * from './physics';
|
||||||
|
|||||||
@@ -1,29 +1,25 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['physics_apply_impulse_action'] = {
|
export const physicsApplyImpulseAction: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Actions',
|
||||||
this.appendDummyInput('')
|
block: {
|
||||||
.appendField('Push me in direction of');
|
init(this: Blockly.Block) {
|
||||||
this.appendValueInput('POSITION')
|
this.appendDummyInput('').appendField('Push me in direction of');
|
||||||
.setCheck('DPos');
|
this.appendValueInput('POSITION').setCheck('DPos');
|
||||||
this.appendDummyInput('')
|
this.appendDummyInput('')
|
||||||
.appendField('with force')
|
.appendField('with force')
|
||||||
.appendField(new Blockly.FieldNumber(1, -10, 10, 0.01), 'FORCE');
|
.appendField(new Blockly.FieldNumber(1, -10, 10, 0.01), 'FORCE');
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
this.setInputsInline(true);
|
this.setNextStatement(true, null);
|
||||||
this.setPreviousStatement(true, null);
|
this.setTooltip('Push me in a direction');
|
||||||
this.setNextStatement(true, null);
|
}
|
||||||
this.setTooltip('Push me in a direction');
|
},
|
||||||
this.setColour(150);
|
code(block, generator) {
|
||||||
|
const position = generator.valueToCode(block, 'POSITION', Order.ATOMIC);
|
||||||
|
const force = block.getFieldValue('FORCE');
|
||||||
|
return `yield helpers.actions.ApplyImpulse(${position}, ${force});\n`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['physics_apply_impulse_action'] = function (block, generator) {
|
|
||||||
const positionValue = generator.valueToCode(block, 'POSITION', Order.ATOMIC);
|
|
||||||
const forceValue = block.getFieldValue('FORCE');
|
|
||||||
return `yield helpers.actions.ApplyImpulse(${positionValue}, ${forceValue});\n`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export * from './applyImpulse';
|
export * from './applyImpulse';
|
||||||
export * from './moveInDirection';
|
export * from './moveInDirection';
|
||||||
export * from './moveToPosition';
|
export * from './moveToPosition';
|
||||||
|
|||||||
@@ -1,30 +1,28 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['move_in_direction_action'] = {
|
export const moveInDirectionAction: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Actions',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('Move me in direction');
|
init(this: Blockly.Block) {
|
||||||
this.appendValueInput('DIRECTION')
|
this.appendDummyInput().appendField('Move me in direction');
|
||||||
.setCheck('DPos');
|
this.appendValueInput('DIRECTION').setCheck('DPos');
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField('for')
|
.appendField('for')
|
||||||
.appendField(new Blockly.FieldNumber(5, 0.01, 10000, 0.1), 'DISTANCE')
|
.appendField(new Blockly.FieldNumber(5, 0.01, 10000, 0.1), 'DISTANCE')
|
||||||
.appendField('with speed')
|
.appendField('with speed')
|
||||||
.appendField(new Blockly.FieldNumber(5, 0.01, 1000, 0.1), 'SPEED');
|
.appendField(new Blockly.FieldNumber(5, 0.01, 1000, 0.1), 'SPEED');
|
||||||
this.setInputsInline(true);
|
this.setInputsInline(true);
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
this.setTooltip('Move this object in the given direction for the given distance at the given speed (units/sec), blocking until done');
|
this.setTooltip('Move this object in the given direction for the given distance at the given speed (units/sec), blocking until done');
|
||||||
this.setColour(20);
|
}
|
||||||
|
},
|
||||||
|
code(block, generator) {
|
||||||
|
const direction = generator.valueToCode(block, 'DIRECTION', Order.ATOMIC) || '[0,0,1]';
|
||||||
|
const distance = block.getFieldValue('DISTANCE');
|
||||||
|
const speed = block.getFieldValue('SPEED');
|
||||||
|
return `yield helpers.actions.MoveInDirection(${direction}, ${distance}, ${speed});\n`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['move_in_direction_action'] = function (block, generator) {
|
|
||||||
const direction = generator.valueToCode(block, 'DIRECTION', Order.ATOMIC) || '[0,0,1]';
|
|
||||||
const distance = block.getFieldValue('DISTANCE');
|
|
||||||
const speed = block.getFieldValue('SPEED');
|
|
||||||
return `yield helpers.actions.MoveInDirection(${direction}, ${distance}, ${speed});\n`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,27 +1,25 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['move_to_position_action'] = {
|
export const moveToPositionAction: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Actions',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('Move me to position');
|
init(this: Blockly.Block) {
|
||||||
this.appendValueInput('TARGET_POSITION')
|
this.appendDummyInput().appendField('Move me to position');
|
||||||
.setCheck('Pos');
|
this.appendValueInput('TARGET_POSITION').setCheck('Pos');
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField('with speed')
|
.appendField('with speed')
|
||||||
.appendField(new Blockly.FieldNumber(5, 0.01, 1000, 0.1), 'SPEED');
|
.appendField(new Blockly.FieldNumber(5, 0.01, 1000, 0.1), 'SPEED');
|
||||||
this.setInputsInline(true);
|
this.setInputsInline(true);
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
this.setTooltip('Move this object to the target position at the given speed (units/sec), blocking until arrived');
|
this.setTooltip('Move this object to the target position at the given speed (units/sec), blocking until arrived');
|
||||||
this.setColour(20);
|
}
|
||||||
|
},
|
||||||
|
code(block, generator) {
|
||||||
|
const targetPosition = generator.valueToCode(block, 'TARGET_POSITION', Order.ATOMIC) || '[0,0,0]';
|
||||||
|
const speed = block.getFieldValue('SPEED');
|
||||||
|
return `yield helpers.actions.MoveToPosition(${targetPosition}, ${speed});\n`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['move_to_position_action'] = function (block, generator) {
|
|
||||||
const targetPosition = generator.valueToCode(block, 'TARGET_POSITION', Order.ATOMIC) || '[0,0,0]';
|
|
||||||
const speed = block.getFieldValue('SPEED');
|
|
||||||
return `yield helpers.actions.MoveToPosition(${targetPosition}, ${speed});\n`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import * as Blockly from "blockly";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
|
export const stopGameAction: BlockDef = {
|
||||||
|
category: 'Actions',
|
||||||
|
block: {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
this.appendDummyInput().appendField('Stop game');
|
||||||
|
this.setInputsInline(false);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setTooltip('Stop game');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(_block, _generator) {
|
||||||
|
return `yield helpers.actions.StopGame();\n`;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,22 +1,21 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator } from "blockly/javascript";
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['wait_seconds_action'] = {
|
export const waitSecondsAction: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Actions',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('Wait')
|
init(this: Blockly.Block) {
|
||||||
.appendField(new Blockly.FieldNumber(1, 0, 3600, 0.1), 'SECONDS')
|
this.appendDummyInput()
|
||||||
.appendField('seconds');
|
.appendField('Wait')
|
||||||
this.setPreviousStatement(true, null);
|
.appendField(new Blockly.FieldNumber(1, 0, 3600, 0.1), 'SECONDS')
|
||||||
this.setNextStatement(true, null);
|
.appendField('seconds');
|
||||||
this.setTooltip('Pause execution for N seconds');
|
this.setPreviousStatement(true, null);
|
||||||
this.setColour(120);
|
this.setNextStatement(true, null);
|
||||||
|
this.setTooltip('Pause execution for N seconds');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(block, _generator) {
|
||||||
|
const seconds = block.getFieldValue('SECONDS');
|
||||||
|
return `yield helpers.actions.WaitSeconds(${seconds});\n`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['wait_seconds_action'] = function (block) {
|
|
||||||
const seconds = block.getFieldValue('SECONDS');
|
|
||||||
return `yield helpers.actions.WaitSeconds(${seconds});\n`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator } from "blockly/javascript";
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.common.defineBlocksWithJsonArray([{
|
export const gameStartEvent: BlockDef = {
|
||||||
"type": "game_start_event",
|
category: 'Events',
|
||||||
"message0": "On game start",
|
block: {
|
||||||
"nextStatement": null,
|
init(this: Blockly.Block) {
|
||||||
"style": "event_hat",
|
this.appendDummyInput().appendField('On game start');
|
||||||
"tooltip": "Runs when the game starts.",
|
this.setNextStatement(true, null);
|
||||||
"helpUrl": ""
|
this.setStyle('event_hat');
|
||||||
}]);
|
this.setTooltip('Runs when the game starts.');
|
||||||
|
}
|
||||||
javascriptGenerator.forBlock['game_start_event'] = function (_block, _generator) {
|
},
|
||||||
return '';
|
code(_block, _generator) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator } from "blockly/javascript";
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['object_clicked_event'] = {
|
export const objectClickedEvent: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Events',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('When I\'m clicked');
|
init(this: Blockly.Block) {
|
||||||
this.setStyle('event_hat');
|
this.appendDummyInput().appendField('When I\'m clicked');
|
||||||
this.setNextStatement(true);
|
this.setStyle('event_hat');
|
||||||
this.setTooltip('Fires when an object is clicked');
|
this.setNextStatement(true);
|
||||||
|
this.setTooltip('Fires when an object is clicked');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(_block, _generator) {
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['object_clicked_event'] = function (_block, _generator) {
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,27 +1,25 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['object_touch_start_event'] = {
|
export const objectTouchStartEvent: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Events',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('When');
|
init(this: Blockly.Block) {
|
||||||
this.appendValueInput('OTHER_OBJECT')
|
this.appendDummyInput().appendField('When');
|
||||||
.setCheck('Object');
|
this.appendValueInput('OTHER_OBJECT').setCheck('Object');
|
||||||
this.appendDummyInput()
|
this.appendDummyInput().appendField('touches me');
|
||||||
.appendField('touches me');
|
this.setStyle('event_hat');
|
||||||
this.setStyle('event_hat');
|
this.setNextStatement(true);
|
||||||
this.setNextStatement(true);
|
this.setTooltip('Fires when an object touches me');
|
||||||
this.setTooltip('Fires when an object touches me');
|
}
|
||||||
}
|
},
|
||||||
};
|
code(block, generator) {
|
||||||
|
const otherObjectValue = generator.valueToCode(block, 'OTHER_OBJECT', Order.NONE) || 'undefined';
|
||||||
javascriptGenerator.forBlock['object_touch_start_event'] = function (block, generator) {
|
return `
|
||||||
const otherObjectValue = generator.valueToCode(block, 'OTHER_OBJECT', Order.NONE) || 'undefined';
|
|
||||||
return `
|
|
||||||
const touchTarget = ${otherObjectValue};
|
const touchTarget = ${otherObjectValue};
|
||||||
if (!context.other || !touchTarget || context.other.id !== touchTarget.id)
|
if (!context.other || !touchTarget || context.other.id !== touchTarget.id)
|
||||||
return;
|
return;
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator } from "blockly/javascript";
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['player_touch_start_event'] = {
|
export const playerTouchStartEvent: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Events',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('When player touches me');
|
init(this: Blockly.Block) {
|
||||||
this.setStyle('event_hat');
|
this.appendDummyInput().appendField('When player touches me');
|
||||||
this.setNextStatement(true);
|
this.setStyle('event_hat');
|
||||||
this.setTooltip('Fires when player touches me');
|
this.setNextStatement(true);
|
||||||
|
this.setTooltip('Fires when player touches me');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(_block, _generator) {
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['player_touch_start_event'] = function (_block, _generator) {
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator } from "blockly/javascript";
|
import { javascriptGenerator } from "blockly/javascript";
|
||||||
|
|
||||||
export function generateCode(workspace: Blockly.WorkspaceSvg): string {
|
export function generateCode(workspace: Blockly.Workspace): string {
|
||||||
javascriptGenerator.init(workspace);
|
javascriptGenerator.init(workspace);
|
||||||
let result = '';
|
let result = '';
|
||||||
for (const block of workspace.getTopBlocks(true)) {
|
for (const block of workspace.getTopBlocks(true)) {
|
||||||
if (block.type.endsWith('_event')) {
|
if (block.type.endsWith('Event')) {
|
||||||
|
|
||||||
const eventName = block.type.replace(/_event$/, '');
|
const eventName = block.type.replace(/Event$/, '');
|
||||||
|
|
||||||
let body = javascriptGenerator.blockToCode(block, true) as string;
|
let body = javascriptGenerator.blockToCode(block, true) as string;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
export * from './events';
|
export * from './events';
|
||||||
export * from './values';
|
export * from './values';
|
||||||
export * from './actions';
|
export * from './actions';
|
||||||
|
export * from './loops';
|
||||||
export * from './theme';
|
export * from './theme';
|
||||||
export * from './generateCode';
|
export * from './generateCode';
|
||||||
export * from './fieldTypes';
|
export * from './fieldTypes';
|
||||||
export * from './loops';
|
export * from './toolbox';
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { javascriptGenerator } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
|
export const foreverLoop: BlockDef = {
|
||||||
|
category: 'Loops',
|
||||||
|
block: {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
this.appendDummyInput().appendField('Repeat forever');
|
||||||
|
this.appendStatementInput('BODY').setCheck(null);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setTooltip('Repeat the enclosed actions forever');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(block, generator) {
|
||||||
|
const body = generator.statementToCode(block, 'BODY');
|
||||||
|
return `while (true) {\n${body}${javascriptGenerator.INDENT}yield helpers.actions.WaitFrames(1);\n}\n`;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1 +1 @@
|
|||||||
export * from './repeatForever';
|
export * from './forever';
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import * as Blockly from "blockly";
|
|
||||||
import { javascriptGenerator } from "blockly/javascript";
|
|
||||||
|
|
||||||
Blockly.Blocks['loop_forever'] = {
|
|
||||||
init(this: Blockly.Block) {
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField('Repeat forever');
|
|
||||||
this.appendStatementInput('BODY')
|
|
||||||
.setCheck(null);
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setTooltip('Repeat the enclosed actions forever');
|
|
||||||
this.setColour(120);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
javascriptGenerator.forBlock['loop_forever'] = function (block, generator) {
|
|
||||||
const body = generator.statementToCode(block, 'BODY');
|
|
||||||
return `while (true) {\n${body}${generator.INDENT}yield helpers.actions.WaitFrames(1);\n}\n`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { runInAction } from "mobx";
|
||||||
|
import type { ObjectType } from "../types";
|
||||||
|
import * as blocklyBarrel from "./index";
|
||||||
|
|
||||||
|
export function recompileAll(objectTypes: Record<string, ObjectType>): void {
|
||||||
|
for (const objectType of Object.values(objectTypes)) {
|
||||||
|
if (!objectType.program)
|
||||||
|
continue;
|
||||||
|
const workspace = new Blockly.Workspace();
|
||||||
|
try {
|
||||||
|
Blockly.serialization.workspaces.load(JSON.parse(objectType.program), workspace);
|
||||||
|
const js = blocklyBarrel.generateCode(workspace);
|
||||||
|
runInAction(() => { objectType.javascript = js; });
|
||||||
|
} catch {
|
||||||
|
runInAction(() => { objectType.javascript = undefined; });
|
||||||
|
} finally {
|
||||||
|
workspace.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import * as barrel from './index';
|
||||||
|
import { registerBarrel } from './toolbox';
|
||||||
|
|
||||||
|
registerBarrel(barrel as Record<string, unknown>);
|
||||||
|
|
||||||
|
if (import.meta.hot) {
|
||||||
|
import.meta.hot.accept('./index', (newBarrel) => {
|
||||||
|
if (newBarrel)
|
||||||
|
registerBarrel(newBarrel as Record<string, unknown>);
|
||||||
|
window.dispatchEvent(new CustomEvent('blockly-hmr'));
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import * as Blockly from "blockly";
|
||||||
|
import { javascriptGenerator, type JavascriptGenerator, type Order } from "blockly/javascript";
|
||||||
|
|
||||||
|
export const CATEGORY_COLOURS = {
|
||||||
|
Events: '180',
|
||||||
|
Values: '260',
|
||||||
|
Loops: '50',
|
||||||
|
Actions: '20',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type CategoryName = keyof typeof CATEGORY_COLOURS;
|
||||||
|
|
||||||
|
export type BlockDef = {
|
||||||
|
category: CategoryName;
|
||||||
|
block: { init(this: Blockly.Block): void };
|
||||||
|
code: (block: Blockly.Block, generator: JavascriptGenerator) => string | [string, Order];
|
||||||
|
};
|
||||||
|
|
||||||
|
function isCategoryName(v: unknown): v is CategoryName {
|
||||||
|
return typeof v === 'string' && v in CATEGORY_COLOURS;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBlockDef(v: unknown): v is BlockDef {
|
||||||
|
if (typeof v !== 'object' || v === null)
|
||||||
|
return false;
|
||||||
|
const r = v as Record<string, unknown>;
|
||||||
|
return (
|
||||||
|
isCategoryName(r.category) &&
|
||||||
|
typeof r.block === 'object' && r.block !== null &&
|
||||||
|
typeof r.code === 'function'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerBarrel(barrel: Record<string, unknown>): void {
|
||||||
|
for (const [name, value] of Object.entries(barrel)) {
|
||||||
|
if (!isBlockDef(value))
|
||||||
|
continue;
|
||||||
|
const colour = CATEGORY_COLOURS[value.category];
|
||||||
|
Blockly.Blocks[name] = {
|
||||||
|
init(this: Blockly.Block) {
|
||||||
|
value.block.init.call(this);
|
||||||
|
this.setColour(colour);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
javascriptGenerator.forBlock[name] = value.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function barrelToToolbox(
|
||||||
|
barrel: Record<string, unknown>
|
||||||
|
): Blockly.utils.toolbox.ToolboxDefinition {
|
||||||
|
const categories = new Map<CategoryName, string[]>();
|
||||||
|
|
||||||
|
for (const [name, value] of Object.entries(barrel)) {
|
||||||
|
if (!isBlockDef(value))
|
||||||
|
continue;
|
||||||
|
if (!categories.has(value.category))
|
||||||
|
categories.set(value.category, []);
|
||||||
|
categories.get(value.category)!.push(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
kind: 'categoryToolbox',
|
||||||
|
contents: Array.from(categories.entries()).map(([name, blocks]) => ({
|
||||||
|
kind: 'category',
|
||||||
|
name,
|
||||||
|
colour: CATEGORY_COLOURS[name],
|
||||||
|
contents: blocks.map(type => ({ kind: 'block', type })),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,21 +1,19 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['any_object_of_type_value'] = {
|
export const anyObjectOfTypeValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendDummyInput('NAME')
|
block: {
|
||||||
.appendField('Any object of type');
|
init(this: Blockly.Block) {
|
||||||
this.appendValueInput('NAME')
|
this.appendDummyInput('NAME').appendField('Any object of type');
|
||||||
.setCheck('ObjectType');
|
this.appendValueInput('NAME').setCheck('ObjectType');
|
||||||
this.setInputsInline(true);
|
this.setInputsInline(true);
|
||||||
this.setOutput(true, 'Object');
|
this.setOutput(true, 'Object');
|
||||||
this.setTooltip('Any object of type');
|
this.setTooltip('Any object of type');
|
||||||
this.setColour(315);
|
}
|
||||||
|
},
|
||||||
|
code(_block, _generator) {
|
||||||
|
return ['123', Order.NONE];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['any_object_of_type_value'] = function (_block, _generator) {
|
|
||||||
return ['123', Order.NONE];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['current_object_value'] = {
|
export const currentObjectValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendEndRowInput('NAME')
|
block: {
|
||||||
.appendField('Me');
|
init(this: Blockly.Block) {
|
||||||
this.setInputsInline(false);
|
this.appendEndRowInput('NAME').appendField('Me');
|
||||||
this.setOutput(true, 'Object');
|
this.setInputsInline(false);
|
||||||
this.setTooltip('Returns current object instance');
|
this.setOutput(true, 'Object');
|
||||||
this.setColour(315);
|
this.setTooltip('Returns current object instance');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(_block, _generator) {
|
||||||
|
return ['thisObject', Order.NONE];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['current_object_value'] = function (_block, _generator) {
|
|
||||||
return ['thisObject', Order.NONE];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['current_object_type_value'] = {
|
export const currentObjectTypeValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendEndRowInput('NAME')
|
block: {
|
||||||
.appendField('My type');
|
init(this: Blockly.Block) {
|
||||||
this.setInputsInline(false);
|
this.appendEndRowInput('NAME').appendField('My type');
|
||||||
this.setOutput(true, 'ObjectType');
|
this.setInputsInline(false);
|
||||||
this.setTooltip('Returns current object type');
|
this.setOutput(true, 'ObjectType');
|
||||||
this.setColour(315);
|
this.setTooltip('Returns current object type');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(_block, _generator) {
|
||||||
|
return ['thisObjectType', Order.NONE];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['current_object_type_value'] = function (_block, _generator) {
|
|
||||||
return ['thisObjectType', Order.NONE];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['dpos_value'] = {
|
export const dposValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('Direction [')
|
init(this: Blockly.Block) {
|
||||||
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'X')
|
this.appendDummyInput()
|
||||||
.appendField(',')
|
.appendField('Direction [')
|
||||||
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'Y')
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'X')
|
||||||
.appendField(',')
|
.appendField(',')
|
||||||
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'Z');
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'Y')
|
||||||
this.appendDummyInput()
|
.appendField(',')
|
||||||
.appendField(']');
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'Z');
|
||||||
this.setInputsInline(true);
|
this.appendDummyInput().appendField(']');
|
||||||
this.setOutput(true, 'DPos');
|
this.setInputsInline(true);
|
||||||
this.setTooltip('Direction [dx,dy,dz]');
|
this.setOutput(true, 'DPos');
|
||||||
this.setColour(315);
|
this.setTooltip('Direction [dx,dy,dz]');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(block, _generator) {
|
||||||
|
const x = block.getFieldValue('X');
|
||||||
|
const y = block.getFieldValue('Y');
|
||||||
|
const z = block.getFieldValue('Z');
|
||||||
|
return [`[${x},${y},${z}]`, Order.ATOMIC];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['dpos_value'] = function (block, _generator) {
|
|
||||||
const xValue = block.getFieldValue('X');
|
|
||||||
const yValue = block.getFieldValue('Y');
|
|
||||||
const zValue = block.getFieldValue('Z');
|
|
||||||
return [`[${xValue},${yValue},${zValue}]`, Order.ATOMIC];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['direction_to_position_value'] = {
|
export const directionToPositionValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('Direction to');
|
init(this: Blockly.Block) {
|
||||||
this.appendValueInput('TARGET')
|
this.appendDummyInput().appendField('Direction to');
|
||||||
.setCheck('Pos');
|
this.appendValueInput('TARGET').setCheck('Pos');
|
||||||
this.setInputsInline(true);
|
this.setInputsInline(true);
|
||||||
this.setOutput(true, 'DPos');
|
this.setOutput(true, 'DPos');
|
||||||
this.setTooltip('Direction to a position');
|
this.setTooltip('Direction to a position');
|
||||||
this.setColour(315);
|
}
|
||||||
|
},
|
||||||
|
code(block, generator) {
|
||||||
|
const targetValue = generator.valueToCode(block, 'TARGET', Order.ATOMIC);
|
||||||
|
return [`(t=>{const p=helpers.positionOfObject(thisObject); const dir = [t[0]-p[0],t[1]-p[1],t[2]-p[2]]; /* helpers.debug.show('${block.id}.targetPosition', ${targetValue}); helpers.debug.show('${block.id}.result', dir); helpers.debug.show('${block.id}.thisObject.position', p); */ return dir;})(${targetValue})`, Order.NONE];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['direction_to_position_value'] = function (block, generator) {
|
|
||||||
const targetValue = generator.valueToCode(block, 'TARGET', Order.ATOMIC);
|
|
||||||
return [`(t=>{const p=helpers.positionOfObject(thisObject); const dir = [t[0]-p[0],t[1]-p[1],t[2]-p[2]]; /* helpers.debug.show('${block.id}.targetPosition', ${targetValue}); helpers.debug.show('${block.id}.result', dir); helpers.debug.show('${block.id}.thisObject.position', p); */ return dir;})(${targetValue})`, Order.NONE];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['object_by_id_value'] = {
|
export const objectByIdValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendEndRowInput()
|
block: {
|
||||||
.appendField('Object with id')
|
init(this: Blockly.Block) {
|
||||||
.appendField(new Blockly.FieldTextInput(''), 'TARGET_ID');
|
this.appendEndRowInput()
|
||||||
this.setInputsInline(false);
|
.appendField('Object with id')
|
||||||
this.setOutput(true, 'Object');
|
.appendField(new Blockly.FieldTextInput(''), 'TARGET_ID');
|
||||||
this.setTooltip('Returns object by id, if any');
|
this.setInputsInline(false);
|
||||||
this.setColour(315);
|
this.setOutput(true, 'Object');
|
||||||
|
this.setTooltip('Returns object by id, if any');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(block, _generator) {
|
||||||
|
const targetId = block.getFieldValue('TARGET_ID');
|
||||||
|
return [`context.scene.objects['${targetId}']`, Order.ATOMIC];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['object_by_id_value'] = function (block, _generator) {
|
|
||||||
const targetIdValue = block.getFieldValue('TARGET_ID');
|
|
||||||
return [`context.scene.objects['${targetIdValue}']`, Order.ATOMIC];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
import { toJS } from "mobx";
|
import { toJS } from "mobx";
|
||||||
import { state } from "../../state";
|
import { state } from "../../state";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
export function getObjectTypeDropDownOptions(): [string, string][] {
|
export function getObjectTypeDropDownOptions(): [string, string][] {
|
||||||
const types = Object.values(toJS(state.world.data.objectTypes));
|
const types = Object.values(toJS(state.world.data.objectTypes));
|
||||||
@@ -12,23 +13,22 @@ export function getObjectTypeDropDownOptions(): [string, string][] {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
Blockly.Blocks['object_type_value'] = {
|
export const objectTypeValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendEndRowInput()
|
block: {
|
||||||
.appendField(
|
init(this: Blockly.Block) {
|
||||||
new Blockly.FieldDropdown(getObjectTypeDropDownOptions),
|
this.appendEndRowInput()
|
||||||
'OBJECT_TYPE',
|
.appendField(
|
||||||
);
|
new Blockly.FieldDropdown(getObjectTypeDropDownOptions),
|
||||||
this.setInputsInline(false);
|
'OBJECT_TYPE',
|
||||||
this.setOutput(true, 'ObjectType');
|
);
|
||||||
this.setTooltip('Object type');
|
this.setInputsInline(false);
|
||||||
this.setColour(315);
|
this.setOutput(true, 'ObjectType');
|
||||||
|
this.setTooltip('Object type');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(block, _generator) {
|
||||||
|
const objectTypeValue = block.getFieldValue('OBJECT_TYPE');
|
||||||
|
return [`world.objectTypes[${objectTypeValue}]`, Order.NONE];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['object_type_value'] = function (block, _generator) {
|
|
||||||
const objectTypeValue = block.getFieldValue('OBJECT_TYPE');
|
|
||||||
return [`world.objectTypes[${objectTypeValue}]`, Order.NONE];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['player_object_value'] = {
|
export const playerObjectValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendEndRowInput()
|
block: {
|
||||||
.appendField('Player');
|
init(this: Blockly.Block) {
|
||||||
this.setInputsInline(false);
|
this.appendEndRowInput().appendField('Player');
|
||||||
this.setOutput(true, 'Object');
|
this.setInputsInline(false);
|
||||||
this.setTooltip('Returns object that is controlled by player');
|
this.setOutput(true, 'Object');
|
||||||
this.setColour(315);
|
this.setTooltip('Returns object that is controlled by player');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(_block, _generator) {
|
||||||
|
return ['(scene.playerObjectId?scene.objects[scene.playerObjectId]:undefined)', Order.ATOMIC];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['player_object_value'] = function (_block, _generator) {
|
|
||||||
return ['(scene.playerObjectId?scene.objects[scene.playerObjectId]:undefined)', Order.ATOMIC];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['pos_value'] = {
|
export const posValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendDummyInput('POSITION')
|
block: {
|
||||||
.appendField('Position [')
|
init(this: Blockly.Block) {
|
||||||
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'X')
|
this.appendDummyInput('POSITION')
|
||||||
.appendField(',')
|
.appendField('Position [')
|
||||||
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'Y')
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'X')
|
||||||
.appendField(',')
|
.appendField(',')
|
||||||
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'Z');
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'Y')
|
||||||
this.appendDummyInput()
|
.appendField(',')
|
||||||
.appendField(']');
|
.appendField(new Blockly.FieldNumber(0, -Infinity, Infinity, 0.01), 'Z');
|
||||||
this.setInputsInline(true);
|
this.appendDummyInput().appendField(']');
|
||||||
this.setOutput(true, 'Pos');
|
this.setInputsInline(true);
|
||||||
this.setTooltip('Position [x,y,z]');
|
this.setOutput(true, 'Pos');
|
||||||
this.setColour(315);
|
this.setTooltip('Position [x,y,z]');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code(block, _generator) {
|
||||||
|
const x = block.getFieldValue('X');
|
||||||
|
const y = block.getFieldValue('Y');
|
||||||
|
const z = block.getFieldValue('Z');
|
||||||
|
return [`[${x},${y},${z}]`, Order.ATOMIC];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['pos_value'] = function (block, _generator) {
|
|
||||||
const xValue = block.getFieldValue('X');
|
|
||||||
const yValue = block.getFieldValue('Y');
|
|
||||||
const zValue = block.getFieldValue('Z');
|
|
||||||
return [`[${xValue},${yValue},${zValue}]`, Order.ATOMIC];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { javascriptGenerator, Order } from "blockly/javascript";
|
import { Order } from "blockly/javascript";
|
||||||
|
import type { BlockDef } from "../toolbox";
|
||||||
|
|
||||||
Blockly.Blocks['position_of_object_value'] = {
|
export const positionOfObjectValue: BlockDef = {
|
||||||
init(this: Blockly.Block) {
|
category: 'Values',
|
||||||
this.appendDummyInput()
|
block: {
|
||||||
.appendField('Position of');
|
init(this: Blockly.Block) {
|
||||||
this.appendValueInput('TARGET')
|
this.appendDummyInput().appendField('Position of');
|
||||||
.setCheck('Object');
|
this.appendValueInput('TARGET').setCheck('Object');
|
||||||
this.setInputsInline(true);
|
this.setInputsInline(true);
|
||||||
this.setOutput(true, 'Pos');
|
this.setOutput(true, 'Pos');
|
||||||
this.setTooltip('Position of an object');
|
this.setTooltip('Position of an object');
|
||||||
this.setColour(315);
|
}
|
||||||
|
},
|
||||||
|
code(block, generator) {
|
||||||
|
const targetValue = generator.valueToCode(block, 'TARGET', Order.ATOMIC);
|
||||||
|
return [`helpers.positionOfObject(${targetValue})`, Order.NONE];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
javascriptGenerator.forBlock['position_of_object_value'] = function (block, generator) {
|
|
||||||
const targetValue = generator.valueToCode(block, 'TARGET', Order.ATOMIC);
|
|
||||||
return [`helpers.positionOfObject(${targetValue})`, Order.NONE];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { };
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const GameObjectView = observer(function (props: GameObjectViewProps) {
|
|||||||
return <PlayerObjectView object={props.object as RuntimeGameObjectInstance} objectType={objectType} />;
|
return <PlayerObjectView object={props.object as RuntimeGameObjectInstance} objectType={objectType} />;
|
||||||
|
|
||||||
function handleClick(): void {
|
function handleClick(): void {
|
||||||
state.game?.emitEvent('object_clicked', { object: props.object });
|
state.game?.emitEvent('objectClicked', { object: props.object });
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ObjectViewInternal
|
return <ObjectViewInternal
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ObjectType, ObjectInstanceRigidBody, RuntimeGameObjectInstance, RuntimeObjectInstance } from "../types";
|
import type { ObjectType, RuntimeGameObjectInstance, RuntimeObjectInstance } from "../types";
|
||||||
import { useEffect, useImperativeHandle, useRef, type Ref } from "react";
|
import { useEffect, useImperativeHandle, useRef, type Ref } from "react";
|
||||||
import { Euler, Quaternion, type Group } from "three";
|
import { Euler, Quaternion, type Group } from "three";
|
||||||
import { Instance, Instances } from "@react-three/drei";
|
import { Instance, Instances } from "@react-three/drei";
|
||||||
@@ -94,9 +94,9 @@ export const ObjectViewInternal = function ({ object, objectType, ref, ...props
|
|||||||
return;
|
return;
|
||||||
const otherObj = Object.values(game.scene.objects)
|
const otherObj = Object.values(game.scene.objects)
|
||||||
.find((o) => o.rb()?.handle === otherHandle);
|
.find((o) => o.rb()?.handle === otherHandle);
|
||||||
game.emitEvent('object_touch_start', { object: gameObj, other: otherObj });
|
game.emitEvent('objectTouchStart', { object: gameObj, other: otherObj });
|
||||||
if (otherObj?.id === game.scene.playerObjectId)
|
if (otherObj?.id === game.scene.playerObjectId)
|
||||||
game.emitEvent('player_touch_start', { object: gameObj, other: otherObj });
|
game.emitEvent('playerTouchStart', { object: gameObj, other: otherObj });
|
||||||
}}
|
}}
|
||||||
onSync={(data) => {
|
onSync={(data) => {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
|
|||||||
@@ -5,70 +5,11 @@ import * as Blockly from "blockly";
|
|||||||
import type { ObjectType } from "../../types";
|
import type { ObjectType } from "../../types";
|
||||||
import './ScriptEditorView.scss';
|
import './ScriptEditorView.scss';
|
||||||
|
|
||||||
import '../../blockly';
|
import '../../blockly/registrar';
|
||||||
import { gameTheme, generateCode } from '../../blockly';
|
import * as blocklyBarrel from '../../blockly';
|
||||||
|
import { gameTheme } from '../../blockly';
|
||||||
const TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = {
|
import { recompileAll } from '../../blockly/recompile';
|
||||||
kind: 'categoryToolbox',
|
import { state } from '../../state';
|
||||||
contents: [
|
|
||||||
{
|
|
||||||
kind: 'category',
|
|
||||||
name: 'Events',
|
|
||||||
colour: '180',
|
|
||||||
contents: [
|
|
||||||
{ kind: 'block', type: 'game_start_event' },
|
|
||||||
{ kind: 'block', type: 'object_touch_start_event' },
|
|
||||||
{ kind: 'block', type: 'player_touch_start_event' },
|
|
||||||
{ kind: 'block', type: 'object_clicked_event' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kind: 'category',
|
|
||||||
name: 'Values',
|
|
||||||
colour: '260',
|
|
||||||
contents: [
|
|
||||||
{ kind: 'block', type: 'current_object_value' },
|
|
||||||
{ kind: 'block', type: 'current_object_type_value' },
|
|
||||||
{ kind: 'block', type: 'object_type_value' },
|
|
||||||
{ kind: 'block', type: 'any_object_of_type_value' },
|
|
||||||
{ kind: 'block', type: 'position_of_object_value' },
|
|
||||||
{ kind: 'block', type: 'pos_value' },
|
|
||||||
{ kind: 'block', type: 'dpos_value' },
|
|
||||||
{ kind: 'block', type: 'direction_to_position_value' },
|
|
||||||
{ kind: 'block', type: 'object_by_id_value' },
|
|
||||||
{ kind: 'block', type: 'player_object_value' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kind: 'category',
|
|
||||||
name: 'Loops',
|
|
||||||
colour: '50',
|
|
||||||
contents: [
|
|
||||||
{ kind: 'block', type: 'loop_forever' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kind: 'category',
|
|
||||||
name: 'Actions',
|
|
||||||
colour: '20',
|
|
||||||
contents: [
|
|
||||||
{ kind: 'block', type: 'console_log_action' },
|
|
||||||
{ kind: 'block', type: 'move_to_position_action' },
|
|
||||||
{ kind: 'block', type: 'move_in_direction_action' },
|
|
||||||
{ kind: 'block', type: 'physics_apply_impulse_action' },
|
|
||||||
{ kind: 'block', type: 'wait_seconds_action' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kind: 'category',
|
|
||||||
name: 'Text',
|
|
||||||
colour: '160',
|
|
||||||
contents: [
|
|
||||||
{ kind: 'block', type: 'text' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
type ScriptEditorViewProps = {
|
type ScriptEditorViewProps = {
|
||||||
objectType: ObjectType;
|
objectType: ObjectType;
|
||||||
@@ -76,29 +17,44 @@ type ScriptEditorViewProps = {
|
|||||||
|
|
||||||
export const ScriptEditorView = observer(function ({ objectType }: ScriptEditorViewProps) {
|
export const ScriptEditorView = observer(function ({ objectType }: ScriptEditorViewProps) {
|
||||||
const [popup, setPopup] = useState<{ title: string; content: string } | null>(null);
|
const [popup, setPopup] = useState<{ title: string; content: string } | null>(null);
|
||||||
|
const [blocklyKey, setBlocklyKey] = useState(0);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const workspaceRef = useRef<Blockly.WorkspaceSvg | null>(null);
|
const workspaceRef = useRef<Blockly.WorkspaceSvg | null>(null);
|
||||||
const objectTypeRef = useRef(objectType);
|
const objectTypeRef = useRef(objectType);
|
||||||
useLayoutEffect(() => { objectTypeRef.current = objectType; });
|
useLayoutEffect(() => { objectTypeRef.current = objectType; });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!import.meta.hot)
|
||||||
|
return;
|
||||||
|
const handler = () => {
|
||||||
|
recompileAll(state.world.data.objectTypes);
|
||||||
|
setBlocklyKey(k => k + 1);
|
||||||
|
};
|
||||||
|
window.addEventListener('blockly-hmr', handler);
|
||||||
|
return () => window.removeEventListener('blockly-hmr', handler);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!containerRef.current)
|
if (!containerRef.current)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const workspace = Blockly.inject(containerRef.current, { toolbox: TOOLBOX, theme: gameTheme });
|
const toolbox = blocklyBarrel.barrelToToolbox(blocklyBarrel as Record<string, unknown>);
|
||||||
|
const workspace = Blockly.inject(containerRef.current, { toolbox, theme: gameTheme });
|
||||||
workspaceRef.current = workspace;
|
workspaceRef.current = workspace;
|
||||||
|
|
||||||
const listener = (e: Blockly.Events.Abstract) => {
|
const listener = (e: Blockly.Events.Abstract) => {
|
||||||
if (e.isUiEvent)
|
if (e.isUiEvent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
console.log('change event');
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
const current = objectTypeRef.current;
|
const current = objectTypeRef.current;
|
||||||
const serialized = JSON.stringify(Blockly.serialization.workspaces.save(workspace));
|
const serialized = JSON.stringify(Blockly.serialization.workspaces.save(workspace));
|
||||||
current.program = serialized;
|
current.program = serialized;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
current.javascript = generateCode(workspace);
|
current.javascript = blocklyBarrel.generateCode(workspace);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@@ -128,7 +84,9 @@ export const ScriptEditorView = observer(function ({ objectType }: ScriptEditorV
|
|||||||
workspace.dispose();
|
workspace.dispose();
|
||||||
workspaceRef.current = null;
|
workspaceRef.current = null;
|
||||||
};
|
};
|
||||||
}, [objectType.program]);
|
// workspace should not reload when objectType.program changes
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [blocklyKey]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const workspace = workspaceRef.current;
|
const workspace = workspaceRef.current;
|
||||||
@@ -145,7 +103,7 @@ export const ScriptEditorView = observer(function ({ objectType }: ScriptEditorV
|
|||||||
} finally {
|
} finally {
|
||||||
Blockly.Events.enable();
|
Blockly.Events.enable();
|
||||||
}
|
}
|
||||||
}, [objectType.id, objectType.program]);
|
}, [objectType.id]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
const showProgram = () => {
|
const showProgram = () => {
|
||||||
const raw = objectType.program;
|
const raw = objectType.program;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
export * from './applyImpulseAction';
|
||||||
|
export * from './moveInDirectionAction';
|
||||||
|
export * from './moveToPositionAction';
|
||||||
|
export * from './stopGameAction';
|
||||||
export * from './waitConditionAction';
|
export * from './waitConditionAction';
|
||||||
export * from './waitFramesAction';
|
export * from './waitFramesAction';
|
||||||
export * from './waitSecondsAction';
|
export * from './waitSecondsAction';
|
||||||
export * from './applyImpulseAction';
|
|
||||||
export * from './moveToPositionAction';
|
|
||||||
export * from './moveInDirectionAction';
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { state } from "../../state";
|
||||||
|
import { ScriptAction, type ScriptCoroutineContext } from "../../types";
|
||||||
|
|
||||||
|
export class StopGameScriptAction extends ScriptAction {
|
||||||
|
|
||||||
|
constructor(coroutine: ScriptCoroutineContext) {
|
||||||
|
super(coroutine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public tick(_deltaTime: number): boolean {
|
||||||
|
state.stopGame();
|
||||||
|
|
||||||
|
return true; // one shot
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -134,7 +134,7 @@ export class GameState {
|
|||||||
|
|
||||||
if (this.isFirstTick) {
|
if (this.isFirstTick) {
|
||||||
this.isFirstTick = false;
|
this.isFirstTick = false;
|
||||||
this.emitEvent('game_start');
|
this.emitEvent('gameStart');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user