From 919512fad0c4f8e0b9838b5a04cb95781615f042 Mon Sep 17 00:00:00 2001 From: Henrique Date: Wed, 7 Jul 2021 16:33:20 -0300 Subject: [PATCH] Improve InputMap and add nodes to it --- .../armory/logicnode/GetInputMapKeyNode.hx | 24 + Sources/armory/logicnode/OnInputMapNode.hx | 35 ++ .../armory/logicnode/SetInputMapKeyNode.hx | 47 ++ Sources/armory/system/InputMap.hx | 452 ++++++------------ .../logicnode/input/LN_get_input_map_key.py | 15 + .../arm/logicnode/input/LN_on_input_map.py | 16 + .../logicnode/input/LN_set_input_map_key.py | 28 ++ 7 files changed, 322 insertions(+), 295 deletions(-) create mode 100644 Sources/armory/logicnode/GetInputMapKeyNode.hx create mode 100644 Sources/armory/logicnode/OnInputMapNode.hx create mode 100644 Sources/armory/logicnode/SetInputMapKeyNode.hx create mode 100644 blender/arm/logicnode/input/LN_get_input_map_key.py create mode 100644 blender/arm/logicnode/input/LN_on_input_map.py create mode 100644 blender/arm/logicnode/input/LN_set_input_map_key.py diff --git a/Sources/armory/logicnode/GetInputMapKeyNode.hx b/Sources/armory/logicnode/GetInputMapKeyNode.hx new file mode 100644 index 00000000..251a6d12 --- /dev/null +++ b/Sources/armory/logicnode/GetInputMapKeyNode.hx @@ -0,0 +1,24 @@ +package armory.logicnode; + +import armory.system.InputMap; + +class GetInputMapKeyNode extends LogicNode { + + public function new(tree: LogicTree) { + super(tree); + } + + override function get(from: Int): Dynamic { + var inputMap = inputs[0].get(); + var key = inputs[1].get(); + + var k = InputMap.getInputMapKey(inputMap, key); + + if (k != null) { + if (from == 0) return k.scale; + else if (from == 1) return k.deadzone; + } + + return null; + } +} diff --git a/Sources/armory/logicnode/OnInputMapNode.hx b/Sources/armory/logicnode/OnInputMapNode.hx new file mode 100644 index 00000000..3e354f29 --- /dev/null +++ b/Sources/armory/logicnode/OnInputMapNode.hx @@ -0,0 +1,35 @@ +package armory.logicnode; + +import armory.system.InputMap; + +class OnInputMapNode extends LogicNode { + + var inputMap: Null; + + public function new(tree: LogicTree) { + super(tree); + + tree.notifyOnUpdate(update); + } + + function update() { + var i = inputs[0].get(); + + inputMap = InputMap.getInputMap(i); + + if (inputMap != null) { + if (inputMap.started()) { + runOutput(0); + } + + if (inputMap.released()) { + runOutput(1); + } + } + } + + override function get(from: Int): Dynamic { + if (from == 2) return inputMap.value(); + else return inputMap.lastKeyPressed; + } +} diff --git a/Sources/armory/logicnode/SetInputMapKeyNode.hx b/Sources/armory/logicnode/SetInputMapKeyNode.hx new file mode 100644 index 00000000..a449575d --- /dev/null +++ b/Sources/armory/logicnode/SetInputMapKeyNode.hx @@ -0,0 +1,47 @@ +package armory.logicnode; + +import armory.system.InputMap; + +class SetInputMapKeyNode extends LogicNode { + + public var property0: String; + + public function new(tree: LogicTree) { + super(tree); + } + + override function run(from: Int) { + var inputMap = inputs[1].get(); + var key = inputs[2].get(); + var scale = inputs[3].get(); + var deadzone = inputs[4].get(); + var index = inputs[5].get(); + + var i = InputMap.getInputMap(inputMap); + + if (i == null) { + i = InputMap.addInputMap(inputMap); + } + + var k = InputMap.getInputMapKey(inputMap, key); + + if (k == null) { + switch(property0) { + case "keyboard": k = i.addKeyboard(key, scale); + case "mouse": k = i.addMouse(key, scale, deadzone); + case "gamepad": { + k = i.addGamepad(key, scale, deadzone); + k.setIndex(index); + } + } + + } else { + k.key = key; + k.scale = scale; + k.deadzone = deadzone; + k.setIndex(index); + } + + runOutput(0); + } +} diff --git a/Sources/armory/system/InputMap.hx b/Sources/armory/system/InputMap.hx index 79b998e1..9b631cf9 100644 --- a/Sources/armory/system/InputMap.hx +++ b/Sources/armory/system/InputMap.hx @@ -4,347 +4,209 @@ import kha.FastFloat; import iron.system.Input; class InputMap { - var commands = new Map>>(); + + static var inputMaps(default, null) = new Map(); + + public var inputs(default, null) = new Array(); + public var lastKeyPressed(default, null) = ""; public function new() {} - public function addKeyboard(config: String) { - var command = new KeyboardCommand(); - return addCustomCommand(command, config); + public static function getInputMap(inputMap: String): Null { + if (inputMaps.exists(inputMap)) { + return inputMaps[inputMap]; + } + + return null; } - public function addGamepad(config: String) { - var command = new GamepadCommand(); - return addCustomCommand(command, config); + public static function addInputMap(inputMap: String): InputMap { + return inputMaps[inputMap] = new InputMap(); } - public function addCustomCommand(command: InputCommand, config: String) { - if (commands[config] == null) commands[config] = new Array(); - commands[config].push(command); - return command; - } -} - -class ActionMap extends InputMap { - - public inline function started(config: String) { - var started = false; - - for (c in commands[config]) { - if (c.started()) { - started = true; - break; + public static function getInputMapKey(inputMap: String, key: String): Null { + if (inputMaps.exists(inputMap)) { + for (i in inputMaps[inputMap].inputs) { + if (i.key == key) { + return i; + } } } - return started; + return null; } - public inline function released(config: String) { - var released = false; + public function addKeyboard(key: String, scale: FastFloat = 1.0): InputMapKey { + return addInput(new KeyboardKey(key, scale)); + } - for (c in commands[config]) { - if (c.released()) { - released = true; - break; - } + public function addMouse(key: String, scale: FastFloat = 1.0, deadzone: FastFloat = 0.0): InputMapKey { + return addInput(new MouseKey(key, scale, deadzone)); + } + + public function addGamepad(key: String, scale: FastFloat = 1.0, deadzone: FastFloat = 0.0): InputMapKey { + return addInput(new GamepadKey(key, scale, deadzone)); + } + + public function addInput(input: InputMapKey): InputMapKey { + inputs.push(input); + return input; + } + + public function removeInput(input: InputMapKey): Bool { + return inputs.remove(input); + } + + public function value(): FastFloat { + var v = 0.0; + + for (i in inputs) { + v += i.value(); } - return released; - } -} - -class AxisMap extends InputMap { - var scale: FastFloat = 1.0; - - public inline function getAxis(config: String) { - var axis = 0.0; - - for (c in commands[config]) { - var tempAxis = c.getAxis(); - - if (tempAxis != 0.0 && tempAxis != axis) { - axis += tempAxis; - scale = c.getScale(); - } - } - - return axis; - } - - public inline function getScale() { - return scale; - } -} - -class InputCommand { - var keys = new Array(); - var modifiers = new Array(); - var displacementKeys = new Array(); - var displacementModifiers = new Array(); - var deadzone: FastFloat = 0.0; - var scale: FastFloat = 1.0; - - public function new() {} - - public function setKeys(keys: Array) { - return this.keys = keys; - } - - public function setMods(modifiers: Array) { - return this.modifiers = modifiers; - } - - public function setDisplacementKeys(keys: Array) { - return displacementKeys = keys; - } - - public function setDisplacementMods(modifiers: Array) { - return displacementModifiers = modifiers; - } - - public function setDeadzone(deadzone: FastFloat) { - return this.deadzone = deadzone; - } - - public function setScale(scale: FastFloat) { - return this.scale = scale; - } - - public function getScale() { - return scale; + return v; } public function started() { + for (i in inputs) { + if (i.started()) { + lastKeyPressed = i.key; + return true; + } + } + return false; } public function released() { + for (i in inputs) { + if (i.released()) { + lastKeyPressed = i.key; + return true; + } + } + + return false; + } +} + +class InputMapKey { + + public var key: String; + public var scale: FastFloat; + public var deadzone: FastFloat; + + public function new(key: String, scale = 1.0, deadzone = 0.0) { + this.key = key.toLowerCase(); + this.scale = scale; + this.deadzone = deadzone; + } + + public function started(): Bool { return false; } - public function getAxis(): FastFloat { + public function released(): Bool { + return false; + } + + public function value(): FastFloat { return 0.0; } -} -class KeyboardCommand extends InputCommand { - var keyboard = Input.getKeyboard(); - var mouse = Input.getMouse(); + public function setIndex(index: Int) {} - public inline override function started() { - for (k in keys) { - if (keyboard.started(k)) { - for (m in modifiers) { - if (!keyboard.down(m)) return false; - } + function evalDeadzone(value: FastFloat): FastFloat { + var v = 0.0; - for (m in displacementModifiers) { - if (!mouse.down(m)) return false; - } + if (value > deadzone) { + v = value - deadzone; - return true; - } + } else if (value < -deadzone) { + v = value + deadzone; } - for (k in displacementKeys) { - if (mouse.started(k)) { - for (m in modifiers) { - if (!keyboard.down(m)) return false; - } - - for (m in displacementModifiers) { - if (!mouse.down(m)) return false; - } - - return true; - } - } - - return false; + return v * scale; } - public inline override function released() { - for (k in keys) { - if (keyboard.released(k)) { - for (m in modifiers) { - if (!keyboard.down(m)) return false; - } + function evalPressure(value: FastFloat): FastFloat { + var v = value - deadzone; - for (m in displacementModifiers) { - if (!mouse.down(m)) return false; - } + if (v > 0.0) { + v /= (1.0 - deadzone); - return true; - } + } else { + v = 0.0; } - - for (k in displacementKeys) { - if (mouse.released(k)) { - for (m in modifiers) { - if (!keyboard.down(m)) return false; - } - - for (m in displacementModifiers) { - if (!mouse.down(m)) return false; - } - - return true; - } - } - - return false; - } - - public inline override function getAxis() { - var axis = 0.0; - var movementX = mouse.movementX; - var movementY = mouse.movementY; - var wheelDelta = mouse.wheelDelta; - - for (k in keys) { - if (keyboard.down(k)) { - axis++; - break; - } - } - - for (m in modifiers) { - if (keyboard.down(m)) { - axis --; - break; - } - } - - for (k in displacementKeys) { - switch (k) { - case "moved x": if (movementX > deadzone) axis++; - case "moved y": if (movementY > deadzone) axis--; - case "wheel": if (wheelDelta < -deadzone) axis++; - case "movement x": if (movementX > deadzone) return movementX - deadzone; - case "movement y": if (movementY > deadzone) return movementY - deadzone; - default: { - if (mouse.down(k)) { - axis ++; - break; - } - } - } - } - - for (m in displacementModifiers) { - switch (m) { - case "moved x": if (movementX < -deadzone) axis--; - case "moved y": if (movementY < -deadzone) axis++; - case "wheel": if (wheelDelta > deadzone) axis--; - case "movement x": if (movementX < -deadzone) return movementX + deadzone; - case "movement y": if (movementY < -deadzone) return movementY + deadzone; - default: { - if (mouse.down(m)) { - axis --; - break; - } - } - } - } - - return axis > 1 ? 1 : axis < -1 ? -1 : axis; + + return v; } } -class GamepadCommand extends InputCommand { - var gamepad = Input.getGamepad(0); +class KeyboardKey extends InputMapKey { + + var kb = Input.getKeyboard(); public inline override function started() { - for (k in keys) { - if (gamepad.started(k)) { - for (m in modifiers) { - if (gamepad.down(m) < deadzone) return false; - } - - return true; - } - } - - return false; + return kb.started(key); } public inline override function released() { - for (k in keys) { - if (gamepad.released(k)) { - for (m in modifiers) { - if (gamepad.down(m) < deadzone) return false; - } - - return true; - } - } - - return false; + return kb.released(key); } - public inline override function getAxis() { - var axis = 0.0; - var rsMovementX = gamepad.rightStick.movementX; - var rsMovementY = gamepad.rightStick.movementY; - var lsMovementX = gamepad.leftStick.movementX; - var lsMovementY = gamepad.leftStick.movementY; - var rtPressure = gamepad.down("r2") > 0.0 ? (gamepad.down("r2") - deadzone) / (1 - deadzone) : 0.0; - var ltPressure = gamepad.down("l2") > 0.0 ? (gamepad.down("r2") - deadzone) / (1 - deadzone) : 0.0; - - for (k in keys) { - switch(k) { - case "rtPressure": axis += rtPressure; - case "ltPressure": axis += ltPressure; - default: { - if (gamepad.down(k) > deadzone) { - axis++; - break; - } - } - } - } - - for (m in modifiers) { - switch (m) { - case "rtPressure": axis -= rtPressure; - case "ltPressure": axis -= ltPressure; - default: { - if (gamepad.down(m) > deadzone) { - axis--; - break; - } - } - } - } - - for (k in displacementKeys) { - switch(k) { - case "rs moved x": if (rsMovementX > deadzone) axis++; - case "rs moved y": if (rsMovementY > deadzone) axis++; - case "ls moved x": if (lsMovementX > deadzone) axis++; - case "ls moved y": if (lsMovementY > deadzone) axis++; - case "rs movement x": if (rsMovementX > deadzone) return rsMovementX - deadzone; - case "rs movement y": if (rsMovementY > deadzone) return rsMovementY - deadzone; - case "ls movement x": if (lsMovementX > deadzone) return lsMovementX - deadzone; - case "ls movement y": if (lsMovementY > deadzone) return lsMovementY - deadzone; - } - } - - for (m in displacementModifiers) { - switch (m) { - case "rs moved x": if (rsMovementX < -deadzone) axis--; - case "rs moved y": if (rsMovementY < -deadzone) axis--; - case "ls moved x": if (lsMovementX < -deadzone) axis--; - case "ls moved y": if (lsMovementY < -deadzone) axis--; - case "rs movement x": if (rsMovementX < -deadzone) return rsMovementX + deadzone; - case "rs movement y": if (rsMovementY < -deadzone) return rsMovementY + deadzone; - case "ls movement x": if (lsMovementX < -deadzone) return lsMovementX + deadzone; - case "ls movement y": if (lsMovementY < -deadzone) return lsMovementY + deadzone; - - } - } - - return axis > 1 ? 1 : axis < -1 ? -1 : axis; + public inline override function value(): FastFloat { + return kb.down(key) ? scale : 0.0; } -} \ No newline at end of file +} + +class MouseKey extends InputMapKey { + + var m = Input.getMouse(); + + public inline override function started() { + return m.started(key); + } + + public inline override function released() { + return m.released(key); + } + + public override function value(): FastFloat { + return switch (key) { + case "movement x": evalDeadzone(m.movementX); + case "movement y": evalDeadzone(m.movementY); + case "wheel": evalDeadzone(m.wheelDelta); + default: m.down(key) ? scale : 0.0; + } + } +} + +class GamepadKey extends InputMapKey { + + var g = Input.getGamepad(); + + public inline override function started() { + return g.started(key); + } + + public inline override function released() { + return g.released(key); + } + + public override function value(): FastFloat { + return switch(key) { + case "ls movement x": evalDeadzone(g.leftStick.movementX); + case "ls movement y": evalDeadzone(g.leftStick.movementY); + case "rs movement x": evalDeadzone(g.rightStick.movementX); + case "rs movement y": evalDeadzone(g.rightStick.movementY); + case "lt pressure": evalDeadzone(evalPressure(g.down("l2"))); + case "rt pressure": evalDeadzone(evalPressure(g.down("r2"))); + default: evalDeadzone(g.down(key)); + } + } + + public override function setIndex(index: Int) { + g = Input.getGamepad(index); + } +} diff --git a/blender/arm/logicnode/input/LN_get_input_map_key.py b/blender/arm/logicnode/input/LN_get_input_map_key.py new file mode 100644 index 00000000..12d98935 --- /dev/null +++ b/blender/arm/logicnode/input/LN_get_input_map_key.py @@ -0,0 +1,15 @@ +from arm.logicnode.arm_nodes import * + +class GetInputMapKeyNode(ArmLogicTreeNode): + """Get key data if it exists in the input map.""" + bl_idname = 'LNGetInputMapKeyNode' + bl_label = 'Get Input Map Key' + arm_version = 1 + + def init(self, context): + super(GetInputMapKeyNode, self).init(context) + self.add_input('NodeSocketString', 'Input Map') + self.add_input('NodeSocketString', 'Key') + + self.add_output('NodeSocketFloat', 'Scale', default_value = 1.0) + self.add_output('NodeSocketFloat', 'Deadzone') \ No newline at end of file diff --git a/blender/arm/logicnode/input/LN_on_input_map.py b/blender/arm/logicnode/input/LN_on_input_map.py new file mode 100644 index 00000000..0cc540f5 --- /dev/null +++ b/blender/arm/logicnode/input/LN_on_input_map.py @@ -0,0 +1,16 @@ +from arm.logicnode.arm_nodes import * + +class OnInputMapNode(ArmLogicTreeNode): + """Send a signal if any input map key is started or released.""" + bl_idname = 'LNOnInputMapNode' + bl_label = 'On Input Map' + arm_version = 1 + + def init(self, context): + super(OnInputMapNode, self).init(context) + self.add_input('NodeSocketString', 'Input Map') + + self.add_output('ArmNodeSocketAction', 'Started') + self.add_output('ArmNodeSocketAction', 'Released') + self.add_output('NodeSocketFloat', 'Value') + self.add_output('NodeSocketString', 'Key Pressed') \ No newline at end of file diff --git a/blender/arm/logicnode/input/LN_set_input_map_key.py b/blender/arm/logicnode/input/LN_set_input_map_key.py new file mode 100644 index 00000000..a2157745 --- /dev/null +++ b/blender/arm/logicnode/input/LN_set_input_map_key.py @@ -0,0 +1,28 @@ +from arm.logicnode.arm_nodes import * + +class SetInputMapKeyNode(ArmLogicTreeNode): + """Set input map key.""" + bl_idname = 'LNSetInputMapKeyNode' + bl_label = 'Set Input Map Key' + arm_version = 1 + + property0: EnumProperty( + items = [('keyboard', 'Keyboard', 'Keyboard input'), + ('mouse', 'Mouse', 'Mouse input'), + ('gamepad', 'Gamepad', 'Gamepad input')], + name='', default='keyboard') + + def init(self, context): + super(SetInputMapKeyNode, self).init(context) + self.add_input('ArmNodeSocketAction', 'In') + self.add_input('NodeSocketString', 'Input Map') + self.add_input('NodeSocketString', 'Key') + self.add_input('NodeSocketFloat', 'Scale', default_value=1.0) + self.add_input('NodeSocketFloat', 'Deadzone') + self.add_input('NodeSocketInt', 'Index') + + self.add_output('ArmNodeSocketAction', 'Out') + + + def draw_buttons(self, context, layout): + layout.prop(self, 'property0') \ No newline at end of file