From fd3eff9bd10a52c4a33937446a230a3c5b680390 Mon Sep 17 00:00:00 2001 From: George Kurelic Date: Thu, 9 May 2024 17:46:45 -0500 Subject: [PATCH] allow multiple inputs of the same type (#3134) * allow multiple inputs of the same type * fix error * use addInput * add InputFrontEnd tests --- flixel/FlxG.hx | 27 +++--- flixel/system/frontEnds/InputFrontEnd.hx | 95 +++++++++---------- tests/unit/src/FlxAssert.hx | 20 ++++ .../system/frontEnds/InputFrontEndTest.hx | 70 ++++++++++++++ 4 files changed, 150 insertions(+), 62 deletions(-) create mode 100644 tests/unit/src/flixel/system/frontEnds/InputFrontEndTest.hx diff --git a/flixel/FlxG.hx b/flixel/FlxG.hx index d98913926a..705819cc52 100644 --- a/flixel/FlxG.hx +++ b/flixel/FlxG.hx @@ -630,23 +630,23 @@ class FlxG // Instantiate inputs #if FLX_KEYBOARD - keys = inputs.add(new FlxKeyboard()); + keys = inputs.addInput(new FlxKeyboard()); #end #if FLX_MOUSE - mouse = inputs.add(new FlxMouse(game._inputContainer)); + mouse = inputs.addInput(new FlxMouse(game._inputContainer)); #end #if FLX_TOUCH - touches = inputs.add(new FlxTouchManager()); + touches = inputs.addInput(new FlxTouchManager()); #end #if FLX_GAMEPAD - gamepads = inputs.add(new FlxGamepadManager()); + gamepads = inputs.addInput(new FlxGamepadManager()); #end #if android - android = inputs.add(new FlxAndroidKeys()); + android = inputs.addInput(new FlxAndroidKeys()); #end #if FLX_ACCELEROMETER @@ -756,21 +756,24 @@ class FlxG } #if FLX_MOUSE - static function set_mouse(NewMouse:FlxMouse):FlxMouse + static function set_mouse(newMouse:FlxMouse):FlxMouse { - if (mouse == null) // if no mouse, just add it + // if there's no mouse, add it + if (mouse == null) { - mouse = inputs.add(NewMouse); // safe to do b/c it won't add repeats! + mouse = inputs.addUniqueType(newMouse); return mouse; } - var oldMouse:FlxMouse = mouse; - var result:FlxMouse = inputs.replace(oldMouse, NewMouse); // replace existing mouse + + // replace existing mouse + final oldMouse:FlxMouse = mouse; + final result:FlxMouse = inputs.replace(oldMouse, newMouse, true); if (result != null) { mouse = result; - oldMouse.destroy(); - return NewMouse; + return newMouse; } + return oldMouse; } #end diff --git a/flixel/system/frontEnds/InputFrontEnd.hx b/flixel/system/frontEnds/InputFrontEnd.hx index ebbdf387b7..c1249e5ccf 100644 --- a/flixel/system/frontEnds/InputFrontEnd.hx +++ b/flixel/system/frontEnds/InputFrontEnd.hx @@ -22,76 +22,71 @@ class InputFrontEnd /** * Add an input to the system - * - * @param Input The input to add - * @return The input */ @:generic - public function add(Input:T):T + @:deprecated("add is deprecated, use addUniqueType") + public inline function add(input:T):T { - // Don't add repeats - for (input in list) - { - if (FlxStringUtil.sameClassName(Input, input)) - { - return Input; - } - } + return addUniqueType(input); + } + + /** + * Add an input to the system, unless the same instance was already added + */ + @:generic + public function addInput(input:T):T + { + if (!list.contains(input)) + list.push(input); + + return input; + } - list.push(Input); - return Input; + /** + * Add an input to the system, unless the same type was already added + */ + @:generic + public function addUniqueType(input:T):T + { + // Don't add repeat types + if (!Lambda.exists(list, FlxStringUtil.sameClassName.bind(_, input))) + list.push(input); + + return input; } /** * Removes an input from the system * - * @param Input The input to remove - * @return Bool indicating whether it was removed or not + * @param Input The input to remove + * @return Bool indicating whether it was removed or not */ @:generic - public function remove(Input:T):Bool + public inline function remove(input:T):Bool { - var i:Int = 0; - for (input in list) - { - if (input == Input) - { - list.splice(i, 1); - return true; - } - i++; - } - return false; + return list.remove(input); } /** * Replace an existing input in the system with a new one * - * @param Old The old input to replace - * @param New The new input to put in its place - * @return If successful returns New. Otherwise returns null. + * @param oldInput The old input to replace + * @param newInput The new input to put in its place + * @param destroyOld Whether to destroy the old input + * @return If successful returns `newInput`. Otherwise returns `null`. */ @:generic - public function replace(Old:T, New:T):T + public function replace(oldInput:T, newInput:T, destroyOld = false):Null { - var i:Int = 0; - var success:Bool = false; - for (input in list) - { - if (input == Old) - { - list[i] = New; // Replace Old with New - success = true; - break; - } - i++; - } - - if (success) - { - return New; - } - return null; + final index = list.indexOf(oldInput); + if (index == -1) + return null; + + if (destroyOld) + oldInput.destroy(); + + list[index] = newInput; + return newInput; } public function reset():Void diff --git a/tests/unit/src/FlxAssert.hx b/tests/unit/src/FlxAssert.hx index 0d5b174a88..1c501493ac 100644 --- a/tests/unit/src/FlxAssert.hx +++ b/tests/unit/src/FlxAssert.hx @@ -59,6 +59,26 @@ class FlxAssert Assert.fail('\nValue\n ${actual}\nwas equal to\n ${expected}\n', info); } + public static function arrayContains(array:Array, item:T, ?msg:String, ?info:PosInfos):Void + { + if (array.contains(item)) + Assert.assertionCount++; + else if (msg != null) + Assert.fail(msg, info); + else + Assert.fail('\nValue\n ${item}\nwas not found in array\n ${array}\n', info); + } + + public static function arrayNotContains(array:Array, item:T, ?msg:String, ?info:PosInfos):Void + { + if (!array.contains(item)) + Assert.assertionCount++; + else if (msg != null) + Assert.fail(msg, info); + else + Assert.fail('\nValue\n ${item}\nwas found in array\n ${array}\n', info); + } + public static function pointsEqual(expected:FlxPoint, actual:FlxPoint, ?msg:String, ?info:PosInfos) { if (expected.equals(actual)) diff --git a/tests/unit/src/flixel/system/frontEnds/InputFrontEndTest.hx b/tests/unit/src/flixel/system/frontEnds/InputFrontEndTest.hx new file mode 100644 index 0000000000..43e6272e59 --- /dev/null +++ b/tests/unit/src/flixel/system/frontEnds/InputFrontEndTest.hx @@ -0,0 +1,70 @@ +package flixel.system.frontEnds; + +import flixel.system.frontEnds.InputFrontEnd; +import flixel.FlxG; +import flixel.input.IFlxInputManager; +import massive.munit.Assert; + +class InputFrontEndTest +{ + var inputs:InputFrontEnd; + + @Before + function before():Void + { + @:privateAccess + inputs = new InputFrontEnd(); + } + + @Test + @:haxe.warning("-WDeprecated") + function testAdd() + { + final input1 = new CustomInputManager(); + inputs.add(input1); + FlxAssert.arrayContains(inputs.list, input1); + + final input2 = new CustomInputManager(); + inputs.add(input2); + FlxAssert.arrayNotContains(inputs.list, input2); + } + + @Test + function testAddUniqueType() + { + final input1 = new CustomInputManager(); + inputs.addUniqueType(input1); + FlxAssert.arrayContains(inputs.list, input1); + + final input2 = new CustomInputManager(); + inputs.addUniqueType(input2); + FlxAssert.arrayNotContains(inputs.list, input2); + } + + @Test + function testAddInput() + { + final input1 = new CustomInputManager(); + inputs.addInput(input1); + FlxAssert.arrayContains(inputs.list, input1); + + final oldLength = inputs.list.length; + // add again + inputs.addInput(input1); + Assert.areEqual(inputs.list.length, oldLength); + + final input2 = new CustomInputManager(); + inputs.addInput(input2); + FlxAssert.arrayContains(inputs.list, input2); + } +} + +class CustomInputManager implements IFlxInputManager +{ + public function new () {} + public function destroy() {} + public function reset():Void {} + function update():Void {} + function onFocus():Void {} + function onFocusLost():Void {} +}