Skip to content
Open
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
24 changes: 10 additions & 14 deletions api/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,20 @@ export const flockEvents = {
}
},
whenActionEvent(action, callback, isReleased = false) {
const actionMap = {
FORWARD: ["w", "z"],
BACKWARD: ["s"],
LEFT: ["a", "q"],
RIGHT: ["d"],
BUTTON1: ["e", "1"],
BUTTON2: ["r", "2"],
BUTTON3: ["f", "3"],
BUTTON4: [" ", "4"],
};

const actionKeys = actionMap[action];
const actionKeys = flock.getActionKeys?.(action) ?? [];

if (!actionKeys?.length) {
if (!actionKeys.length) {
return;
}

[...new Set(actionKeys.map((key) => key.toLowerCase()))].forEach((key) => {
const eventKeys = actionKeys.map((key) => {
if (key === "SPACE" || key === " ") {
return " ";
}
return key.toLowerCase();
});

[...new Set(eventKeys)].forEach((key) => {
this.whenKeyEvent(key, callback, isReleased);
});

Expand Down
33 changes: 29 additions & 4 deletions api/sensing.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ export const flockSensing = {
);
}
},
actionPressed(action) {
const actionMap = {
getActionKeys(action) {
const defaultActionMap = {
FORWARD: ["W", "Z"],
BACKWARD: ["S"],
LEFT: ["A", "Q"],
Expand All @@ -338,9 +338,34 @@ export const flockSensing = {
BUTTON4: ["SPACE", " ", "4"],
};

const actionKeys = actionMap[action];
const customKeys = flock.actionKeyMap?.[action] ?? [];
if (customKeys.length) {
return [...new Set(customKeys)];
}

return defaultActionMap[action] ?? [];
},
setActionKey(action, key) {
if (!action || typeof key !== "string") {
return;
}

if (!flock.actionKeyMap) {
flock.actionKeyMap = {};
}

// Keep special keys (e.g. ArrowLeft, " ") as-is so runtime checks match
// browser keyboard event values.
const normalizedKey = /^[a-z]$/i.test(key) ? key.toUpperCase() : key;

// Rebind behavior: setting an action key replaces previous/default bindings
// for that action instead of appending to them.
flock.actionKeyMap[action] = [normalizedKey];
},
actionPressed(action) {
const actionKeys = this.getActionKeys(action);

if (!actionKeys) {
if (!actionKeys.length) {
return false;
}

Expand Down
122 changes: 122 additions & 0 deletions blocks/sensing.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,128 @@ export function defineSensingBlocks() {
},
};

Blockly.Blocks["action_control"] = {
init: function () {
this.jsonInit({
type: "action_control",
message0: translate("action_control"),
args0: [
{
type: "field_dropdown",
name: "ACTION",
options: [
[
getOption(
"ACTION_FORWARD",
),
"FORWARD",
],
[
getOption(
"ACTION_BACKWARD",
),
"BACKWARD",
],
[
getOption(
"ACTION_LEFT",
),
"LEFT",
],
[
getOption(
"ACTION_RIGHT",
),
"RIGHT",
],
[
getOption(
"ACTION_BUTTON1",
),
"BUTTON1",
],
[
getOption(
"ACTION_BUTTON2",
),
"BUTTON2",
],
[
getOption(
"ACTION_BUTTON3",
),
"BUTTON3",
],
[
getOption(
"ACTION_BUTTON4",
),
"BUTTON4",
],
],
},
{
type: "field_grid_dropdown",
name: "KEY",
columns: 10,
options: [
getDropdownOption("0"),
getDropdownOption("1"),
getDropdownOption("2"),
getDropdownOption("3"),
getDropdownOption("4"),
getDropdownOption("5"),
getDropdownOption("6"),
getDropdownOption("7"),
getDropdownOption("8"),
getDropdownOption("9"),
getDropdownOption("a"),
getDropdownOption("b"),
getDropdownOption("c"),
getDropdownOption("d"),
getDropdownOption("e"),
getDropdownOption("f"),
getDropdownOption("g"),
getDropdownOption("h"),
getDropdownOption("i"),
getDropdownOption("j"),
getDropdownOption("k"),
getDropdownOption("l"),
getDropdownOption("m"),
getDropdownOption("n"),
getDropdownOption("o"),
getDropdownOption("p"),
getDropdownOption("q"),
getDropdownOption("r"),
getDropdownOption("s"),
getDropdownOption("t"),
getDropdownOption("u"),
getDropdownOption("v"),
getDropdownOption("w"),
getDropdownOption("x"),
getDropdownOption("y"),
getDropdownOption("z"),
getDropdownOption(" "),
getDropdownOption(","),
getDropdownOption("."),
getDropdownOption("/"),
getDropdownOption("ArrowLeft"),
getDropdownOption("ArrowUp"),
getDropdownOption("ArrowRight"),
getDropdownOption("ArrowDown"),
],
},
],
previousStatement: null,
nextStatement: null,
colour: categoryColours["Sensing"],
tooltip: getTooltip("action_control"),
});
this.setHelpUrl(getHelpUrlFor(this.type));
this.setStyle("sensing_blocks");
},
};

Blockly.Blocks["meshes_touching"] = {
init: function () {
this.jsonInit({
Expand Down
42 changes: 37 additions & 5 deletions flock.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export const flock = {
canvas: {
pressedKeys: null,
},
actionKeyMap: {},
abortController: null,
_renderLoop: null,
document: document,
Expand Down Expand Up @@ -1009,6 +1010,8 @@ export const flock = {
setFog: this.setFog?.bind(this),
keyPressed: this.keyPressed?.bind(this),
actionPressed: this.actionPressed?.bind(this),
setActionKey: this.setActionKey?.bind(this),
getActionKeys: this.getActionKeys?.bind(this),
isTouchingSurface: this.isTouchingSurface?.bind(this),
meshExists: this.meshExists?.bind(this),
seededRandom: this.seededRandom?.bind(this),
Expand Down Expand Up @@ -1240,6 +1243,7 @@ export const flock = {
flock.gridKeyReleaseObservable = gridKeyReleaseObservable;
flock.canvas.pressedButtons = new Set();
flock.canvas.pressedKeys = new Set();
flock.actionKeyMap = {};
const displayScale = (window.devicePixelRatio || 1) * 0.75; // Get the device pixel ratio, default to 1 if not available
flock.displayScale = displayScale;
flock.BABYLON.Database.IDBStorageEnabled = true;
Expand Down Expand Up @@ -1286,16 +1290,44 @@ export const flock = {
{ passive: false },
);

flock.canvas.addEventListener("keydown", function (event) {
const shouldIgnoreKeyboardEvent = (event) => {
const target = event.target;
if (!target) {
return false;
}

const tagName = target.tagName?.toLowerCase();
return (
target.isContentEditable ||
tagName === "input" ||
tagName === "textarea" ||
tagName === "select"
);
};

const handleKeyDown = (event) => {
if (shouldIgnoreKeyboardEvent(event)) {
return;
}

flock.canvas.currentKeyPressed = event.key;
flock.canvas.pressedKeys.add(event.key);
});
};

const handleKeyUp = (event) => {
if (shouldIgnoreKeyboardEvent(event)) {
return;
}

flock.canvas.addEventListener("keyup", function (event) {
flock.canvas.pressedKeys.delete(event.key);
});
};

flock.canvas.addEventListener("keydown", handleKeyDown);
flock.canvas.addEventListener("keyup", handleKeyUp);
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);

flock.canvas.addEventListener("blur", () => {
window.addEventListener("blur", () => {
// Clear all pressed keys when window loses focus
flock.canvas.pressedKeys.clear();
flock.canvas.pressedButtons.clear();
Expand Down
6 changes: 6 additions & 0 deletions generators/generators.js
Original file line number Diff line number Diff line change
Expand Up @@ -3081,6 +3081,12 @@ export function defineGenerators() {
];
};

javascriptGenerator.forBlock["action_control"] = function (block) {
const action = block.getFieldValue("ACTION");
const key = block.getFieldValue("KEY");
return `setActionKey("${action}", ${JSON.stringify(key)});\n`;
};

javascriptGenerator.forBlock["key_pressed"] = function (block) {
const key = block.getFieldValue("KEY");
return [`keyPressed("${key}")`, javascriptGenerator.ORDER_NONE];
Expand Down
3 changes: 3 additions & 0 deletions locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ export default {
// Custom block translations - Sensing blocks
key_pressed: "key pressed is %1",
action_pressed: "%1",
action_control: "set %1 key %2",
meshes_touching: "%1 touching %2",
time: "time in %1",
seconds: "seconds",
Expand Down Expand Up @@ -522,6 +523,8 @@ export default {
"Return true if the specified key is pressed.\nKeyword:ispressed",
action_pressed_tooltip:
"Return true if the specified movement or action control is active across keyboard, touch, or XR inputs.",
action_control_tooltip:
"Set an extra keyboard key for a movement or action input.",
meshes_touching_tooltip:
"Return true if the two selected meshes are touching.\nKeyword: istouching",
time_tooltip: "Return the current time in seconds.",
Expand Down
5 changes: 5 additions & 0 deletions toolbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -2272,6 +2272,11 @@ const toolboxSensing = {
type: "action_pressed",
keyword: "action",
},
{
kind: "block",
type: "action_control",
keyword: "action",
},
{
kind: "block",
type: "mesh_exists",
Expand Down