Improve InputMap and add nodes to it

This commit is contained in:
Henrique 2021-07-07 16:33:20 -03:00
parent 14b18408aa
commit 919512fad0
7 changed files with 322 additions and 295 deletions

View file

@ -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;
}
}

View file

@ -0,0 +1,35 @@
package armory.logicnode;
import armory.system.InputMap;
class OnInputMapNode extends LogicNode {
var inputMap: Null<InputMap>;
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;
}
}

View file

@ -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);
}
}

View file

@ -4,347 +4,209 @@ import kha.FastFloat;
import iron.system.Input;
class InputMap {
var commands = new Map<String, Null<Array<InputCommand>>>();
static var inputMaps(default, null) = new Map<String, InputMap>();
public var inputs(default, null) = new Array<InputMapKey>();
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<InputMap> {
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<InputCommand>();
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<InputMapKey> {
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<String>();
var modifiers = new Array<String>();
var displacementKeys = new Array<String>();
var displacementModifiers = new Array<String>();
var deadzone: FastFloat = 0.0;
var scale: FastFloat = 1.0;
public function new() {}
public function setKeys(keys: Array<String>) {
return this.keys = keys;
}
public function setMods(modifiers: Array<String>) {
return this.modifiers = modifiers;
}
public function setDisplacementKeys(keys: Array<String>) {
return displacementKeys = keys;
}
public function setDisplacementMods(modifiers: Array<String>) {
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;
}
}
}
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);
}
}

View file

@ -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')

View file

@ -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')

View file

@ -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')