Skip to content

Commit

Permalink
WIP: replicate mouse/trackpad movement from the existing editor
Browse files Browse the repository at this point in the history
  • Loading branch information
4ian committed Jan 20, 2025
1 parent 4afb2de commit ce68001
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 67 deletions.
111 changes: 90 additions & 21 deletions GDJS/Runtime/InGameEditor/InGameEditor.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,75 @@
namespace gdjs {
const LEFTKEY = 37;
const UPKEY = 38;
const RIGHTKEY = 39;
const DOWNKEY = 40;
const LSHIFTKEY = 1016;
const RSHIFTKEY = 2016;
const SPACEKEY = 32;
const LEFT_KEY = 37;
const UP_KEY = 38;
const RIGHT_KEY = 39;
const DOWN_KEY = 40;
const ALT_KEY = 18;
const LEFT_ALT_KEY = gdjs.InputManager.getLocationAwareKeyCode(ALT_KEY, 1);
const RIGHT_ALT_KEY = gdjs.InputManager.getLocationAwareKeyCode(ALT_KEY, 2);
const SHIFT_KEY = 16;
const LEFT_SHIFT_KEY = gdjs.InputManager.getLocationAwareKeyCode(
SHIFT_KEY,
1
);
const RIGHT_SHIFT_KEY = gdjs.InputManager.getLocationAwareKeyCode(
SHIFT_KEY,
2
);
const SPACE_KEY = 32;
const CTRL_KEY = 17;
const LEFT_CTRL_KEY = gdjs.InputManager.getLocationAwareKeyCode(CTRL_KEY, 1);
const RIGHT_CTRL_KEY = gdjs.InputManager.getLocationAwareKeyCode(CTRL_KEY, 2);
const LEFT_META_KEY = gdjs.InputManager.getLocationAwareKeyCode(91, 1);
const RIGHT_META_KEY = gdjs.InputManager.getLocationAwareKeyCode(93, 2);

// TODO: factor this?
const isMacLike =
typeof navigator !== 'undefined' &&
navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i)
? true
: false;

const isControlOrCmdPressed = (inputManager: gdjs.InputManager) => {
// On macOS, meta key (Apple/Command key) acts as Control key on Windows/Linux.
return (
inputManager.isKeyPressed(LEFT_CTRL_KEY) ||
inputManager.isKeyPressed(RIGHT_CTRL_KEY) ||
inputManager.isKeyPressed(LEFT_META_KEY) ||
inputManager.isKeyPressed(RIGHT_META_KEY)
);
};

const isAltPressed = (inputManager: gdjs.InputManager) => {
return (
inputManager.isKeyPressed(LEFT_ALT_KEY) ||
inputManager.isKeyPressed(RIGHT_ALT_KEY)
);
};

const isShiftPressed = (inputManager: gdjs.InputManager) => {
return (
inputManager.isKeyPressed(LEFT_SHIFT_KEY) ||
inputManager.isKeyPressed(RIGHT_SHIFT_KEY)
);
};

const shouldScrollHorizontally = isAltPressed;

const shouldZoom = (inputManager: gdjs.InputManager) => {
// Browsers trigger a wheel event with ctrlKey or metaKey to true when the user
// does a pinch gesture on a trackpad. If this is the case, we zoom.
// see https://dev.to/danburzo/pinch-me-i-m-zooming-gestures-in-the-dom-a0e
if (isControlOrCmdPressed(inputManager)) return true;
if (isMacLike) {
return isControlOrCmdPressed(inputManager);
} else {
return (
!isControlOrCmdPressed(inputManager) &&
!isAltPressed(inputManager) &&
!isShiftPressed(inputManager)
);
}
};

export class InGameEditor {
_runtimeGame: RuntimeGame;
Expand Down Expand Up @@ -114,8 +178,9 @@ namespace gdjs {
// TODO: replace everything by "real 3D movement".

// Mouse wheel: forward/backward movement.
const wheelDelta = inputManager.getMouseWheelDelta();
if (wheelDelta !== 0) {
const wheelDeltaY = inputManager.getMouseWheelDelta();
const wheelDeltaX = inputManager.getMouseWheelDeltaX();
if (shouldZoom(inputManager)) {
// TODO: factor this?
const assumedFovIn2D = 45;
const layerRenderer = layer.getRenderer();
Expand All @@ -126,26 +191,31 @@ namespace gdjs {
: threeCamera.fov
: assumedFovIn2D;

layer.setCameraZ(layer.getCameraZ(fov) + wheelDelta, fov);
layer.setCameraZ(layer.getCameraZ(fov) - wheelDeltaY, fov);
} else if (shouldScrollHorizontally(inputManager)) {
layer.setCameraX(layer.getCameraX() + wheelDeltaY / 5);
} else {
layer.setCameraX(layer.getCameraX() + wheelDeltaX / 5);
layer.setCameraY(layer.getCameraY() - wheelDeltaY / 5);
}

// Movement with the keyboard
if (inputManager.isKeyPressed(LEFTKEY)) {
if (inputManager.isKeyPressed(LEFT_KEY)) {
layer.setCameraX(layer.getCameraX() - 5);
}
if (inputManager.isKeyPressed(RIGHTKEY)) {
if (inputManager.isKeyPressed(RIGHT_KEY)) {
layer.setCameraX(layer.getCameraX() + 5);
}
if (inputManager.isKeyPressed(UPKEY)) {
if (inputManager.isKeyPressed(UP_KEY)) {
layer.setCameraY(layer.getCameraY() - 5);
}
if (inputManager.isKeyPressed(DOWNKEY)) {
if (inputManager.isKeyPressed(DOWN_KEY)) {
layer.setCameraY(layer.getCameraY() + 5);
}

// Space + click: move the camera on its plane.
if (
inputManager.isKeyPressed(SPACEKEY) &&
inputManager.isKeyPressed(SPACE_KEY) &&
inputManager.isMouseButtonPressed(0)
) {
const xDelta = this._lastCursorX - inputManager.getCursorX();
Expand Down Expand Up @@ -179,21 +249,20 @@ namespace gdjs {
}
}

reloadInstances(payload: {
layoutName: string;
reloadInstances(
instances: Array<{
persistentUuid: string;
position: { x: number; y: number; z: number };
}>;
}) {
}>
) {
const currentScene = this._runtimeGame.getSceneStack().getCurrentScene();
if (!currentScene || currentScene.getName() !== payload.layoutName) {
if (!currentScene) {
return;
}
// TODO: Might be worth indexing instances data and runtime objects by their
// persistentUuid (See HotReloader.indexByPersistentUuid).
currentScene.getAdhocListOfAllInstances().forEach((runtimeObject) => {
const instance = payload.instances.find(
const instance = instances.find(
(instance) => instance.persistentUuid === runtimeObject.persistentUuid
);
if (instance) {
Expand Down
20 changes: 10 additions & 10 deletions GDJS/Runtime/debugger-client/abstract-debugger-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ namespace gdjs {
} else if (data.command === 'profiler.stop') {
runtimeGame.stopCurrentSceneProfiler();
} else if (data.command === 'instances.updated') {
runtimeGame._editor.reloadInstances(data.payload);
runtimeGame._editor.reloadInstances(data.payload.instances);
} else if (data.command === 'hotReload') {
that._hotReloader.hotReload().then((logs) => {
that.sendHotReloaderLogs(logs);
Expand All @@ -276,7 +276,9 @@ namespace gdjs {
const sceneName = data.sceneName || null;
const externalLayoutName = data.externalLayoutName || null;
if (!sceneName) {
logger.warn('No scene name specified, switchForInGameEdition aborted');
logger.warn(
'No scene name specified, switchForInGameEdition aborted'
);
return;
}

Expand All @@ -293,14 +295,12 @@ namespace gdjs {
}
}

runtimeGame
.getSceneStack()
.replace({
sceneName,
externalLayoutName,
skipCreatingInstancesFromScene: !!externalLayoutName,
clear: true,
});
runtimeGame.getSceneStack().replace({
sceneName,
externalLayoutName,
skipCreatingInstancesFromScene: !!externalLayoutName,
clear: true,
});

// Update initialRuntimeGameStatus so that a hard reload
// will come back to the same state, and so that we can check later
Expand Down
83 changes: 55 additions & 28 deletions GDJS/Runtime/inputmanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,37 @@ namespace gdjs {
* variants and should default to their left variant values
* if location is not specified.
*/
static _DEFAULT_LEFT_VARIANT_KEYS: integer[] = [16, 17, 18, 91];
_pressedKeys: Hashtable<boolean>;
_releasedKeys: Hashtable<boolean>;
_lastPressedKey: float = 0;
_pressedMouseButtons: Array<boolean>;
_releasedMouseButtons: Array<boolean>;
private static _DEFAULT_LEFT_VARIANT_KEYS: integer[] = [16, 17, 18, 91];
private _pressedKeys: Hashtable<boolean>;
private _releasedKeys: Hashtable<boolean>;
private _lastPressedKey: float = 0;
private _pressedMouseButtons: Array<boolean>;
private _releasedMouseButtons: Array<boolean>;
/**
* The cursor X position (moved by mouse and touch events).
*/
_cursorX: float = 0;
private _cursorX: float = 0;
/**
* The cursor Y position (moved by mouse and touch events).
*/
_cursorY: float = 0;
private _cursorY: float = 0;
/**
* The mouse X position (only moved by mouse events).
*/
_mouseX: float = 0;
private _mouseX: float = 0;
/**
* The mouse Y position (only moved by mouse events).
*/
_mouseY: float = 0;
_isMouseInsideCanvas: boolean = true;
_mouseWheelDelta: float = 0;
private _mouseY: float = 0;
private _isMouseInsideCanvas: boolean = true;
private _wheelDeltaX: float = 0;
private _wheelDeltaY: float = 0;
private _wheelDeltaZ: float = 0;

// TODO Remove _touches when there is no longer SpritePanelButton 1.2.0
// extension in the wild.
_touches = {
// @ts-ignore
private _touches = {
firstKey: (): string | number | null => {
for (const key in this._mouseOrTouches.items) {
// Exclude mouse key.
Expand All @@ -60,22 +64,23 @@ namespace gdjs {
return null;
},
};
_mouseOrTouches: Hashtable<Touch>;

private _mouseOrTouches: Hashtable<Touch>;
//Identifiers of the touches that started during/before the frame.
_startedTouches: Array<integer> = [];
private _startedTouches: Array<integer> = [];

//Identifiers of the touches that ended during/before the frame.
_endedTouches: Array<integer> = [];
_touchSimulateMouse: boolean = true;
private _endedTouches: Array<integer> = [];
private _touchSimulateMouse: boolean = true;

/**
* @deprecated
*/
_lastStartedTouchIndex = 0;
private _lastStartedTouchIndex = 0;
/**
* @deprecated
*/
_lastEndedTouchIndex = 0;
private _lastEndedTouchIndex = 0;

constructor() {
this._pressedKeys = new Hashtable();
Expand All @@ -94,7 +99,7 @@ namespace gdjs {
* @param keyCode The raw key code
* @param location The location
*/
_getLocationAwareKeyCode(
static getLocationAwareKeyCode(
keyCode: number,
location: number | null | undefined
): integer {
Expand All @@ -119,7 +124,7 @@ namespace gdjs {
* @param location The location of the event.
*/
onKeyPressed(keyCode: number, location?: number): void {
const locationAwareKeyCode = this._getLocationAwareKeyCode(
const locationAwareKeyCode = InputManager.getLocationAwareKeyCode(
keyCode,
location
);
Expand All @@ -135,7 +140,7 @@ namespace gdjs {
* @param location The location of the event.
*/
onKeyReleased(keyCode: number, location?: number): void {
const locationAwareKeyCode = this._getLocationAwareKeyCode(
const locationAwareKeyCode = InputManager.getLocationAwareKeyCode(
keyCode,
location
);
Expand Down Expand Up @@ -348,17 +353,37 @@ namespace gdjs {

/**
* Should be called whenever the mouse wheel is used
* @param wheelDelta The mouse wheel delta
* @param wheelDeltaY The mouse wheel delta
*/
onMouseWheel(wheelDelta: number): void {
this._mouseWheelDelta = wheelDelta;
onMouseWheel(
wheelDeltaY: number,
wheelDeltaX: number,
wheelDeltaZ: number
): void {
this._wheelDeltaY = wheelDeltaY;
if (wheelDeltaX !== undefined) this._wheelDeltaX = wheelDeltaX;
if (wheelDeltaZ !== undefined) this._wheelDeltaZ = wheelDeltaZ;
}

/**
* Return the mouse wheel delta
* Return the mouse wheel delta on Y axis.
*/
getMouseWheelDelta(): float {
return this._mouseWheelDelta;
return this._wheelDeltaY;
}

/**
* Return the mouse wheel delta on X axis.
*/
getMouseWheelDeltaX(): float {
return this._wheelDeltaX;
}

/**
* Return the mouse wheel delta on Z axis.
*/
getMouseWheelDeltaZ(): float {
return this._wheelDeltaZ;
}

/**
Expand Down Expand Up @@ -546,7 +571,9 @@ namespace gdjs {
this._endedTouches.length = 0;
this._releasedKeys.clear();
this._releasedMouseButtons.length = 0;
this._mouseWheelDelta = 0;
this._wheelDeltaX = 0;
this._wheelDeltaY = 0;
this._wheelDeltaZ = 0;
this._lastStartedTouchIndex = 0;
this._lastEndedTouchIndex = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion GDJS/Runtime/pixi-renderers/runtimegame-pixi-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ namespace gdjs {
};
// @ts-ignore
canvas.onwheel = function (event) {
manager.onMouseWheel(-event.deltaY);
manager.onMouseWheel(-event.deltaY, event.deltaX, event.deltaZ);
};

// Touches:
Expand Down
Loading

0 comments on commit ce68001

Please sign in to comment.