Search Unity

[Released] cInput 2 - Unitys custom inputmanager got improved !

Discussion in 'Assets and Asset Store' started by Roidz99, Apr 4, 2012.

  1. hodge_podge

    hodge_podge

    Joined:
    Feb 22, 2015
    Posts:
    30
    Thanks, that helps, but how would I go about updating the text on the button itself to display the current keybinding for that action?
     
  2. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    GetText() will show you the current keybinding. If you need to know when the binding changes so you're not calling GetText() every frame, check out the OnKeyChanged delegate/event. It's all there in the documentation I linked you to.
     
  3. Doghelmer

    Doghelmer

    Joined:
    Aug 30, 2014
    Posts:
    120
    I'm having an issue (possibly bug?) that may or may not be caused by the latest version of cInput-- I'm not exactly sure when it began occurring in my game.

    I'm using an XBox controller, and the left analog stick moves my character. I started noticing today that moving the stick Right or Up would cause the character to continue walking for a bit after I had reverted the stick to the center. Upon further investigation with some Debug.Logs, it looks like my GetInput value for these axes is not reverting to 0 as quickly as it should be-- it reverts to 0 much more quickly when I move the stick Left or Down. It's as if my SetGravity value (which I had set very high) is being ignored.

    I should also note that this issue doesn't occur with Unity's regular Input, just cInput.

    I have no idea what would have caused this to happen, and I don't think I changed any of my related code. Any ideas off the top of your head?
     
    Last edited: Apr 12, 2015
  4. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    It's possible that there's a bug with the gravity being applied. Can you show me the code you're using so I know specifically what to look for?

    Also, does the issue persist when using GetAxisRaw instead of GetAxis?
     
  5. Doghelmer

    Doghelmer

    Joined:
    Aug 30, 2014
    Posts:
    120
    The bug with Gravity seems to disappear when using GetAxisRaw. However, I noticed that SetAxisDeadZone has no effect on the Right and Up directions (this also happens with GetAxis).

    The code I'm using is pretty typical I think, even if my values might be a bit extreme. I haven't changed any of this recently.
    cInput.SetKey("Left", Keys.Xbox1LStickLeft);
    cInput.SetKey("Right", Keys.Xbox1LStickRight);
    cInput.SetKey("Down", Keys.Xbox1LStickDown);
    cInput.SetKey("Up", Keys.Xbox1LStickUp);
    cInput.SetAxis("Joy1 Axis 1", "Left", "Right");
    cInput.SetAxis("Joy1 Axis 2", "Down", "Up");
    cInput.SetAxisDeadzone("Joy1 Axis 1", 0.19f);
    cInput.SetAxisDeadzone("Joy1 Axis 2", 0.19f);
    cInput.SetAxisSensitivity("Joy1 Axis 1", 10);
    cInput.SetAxisSensitivity("Joy1 Axis 2", 10);
    cInput.SetAxisGravity("Joy1 Axis 1", 100);
    cInput.SetAxisGravity("Joy1 Axis 2", 100);
     
  6. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Thanks. I'll look into the issue with Gravity/Deadzone (and I suspect sensitivity) not working with Right & Up. In the meantime, using GetAxisRaw may be a decent workaround for your initial issue.
     
  7. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Things finally settled down enough for me after Ludum Dare 32 for me to take some time to track this down.

    As I suspected, this bug also affected sensitivity as well. It was introduced in the latest version of cInput (2.8.2) when I fixed the other error you were having, where SetAxisDeadzone/Sensitivity/Gravity would cause an error on axes that used only one input. I had used an if statement to set the deadzone/sensitivity/gravity for the second/positive axis input only if it was set, but I wrote the logic statement incorrectly, which caused it to always return false. Thus, it never set the deadzone/gravity/sensitivity values for the positive axis input.

    The fix will be included in the next version of cInput.

    Thanks for the thorough and detailed bug report.
     
  8. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    For an RTS game I'm working on, I have commands rigged with inputs but I also want to be able to call commands from the UI. How can I implement a method PressKeyDown(string description) which will virtually press down the key of 'description'? This would simplify the UI design a lot.

    While I don't plan on waiting, I think the ability to virtually press buttons would be a very useful for developers and something to make cInput stand out.

    Note: I have cInput Pro, access to source code
     
    Last edited: Apr 29, 2015
  9. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Hi folks,

    An update to cInput has been submitted to the Asset Store. If you bought cInput from the Asset Store then the update should be live within a few (business) days. If you bought cInput from our website, then the update is available immediately.

    cInput changes:

    v2.8.3
    • Fixed gravity/sensitivity/deadzone not working for positive axis inputs. (Thanks Doghelmer)
     
  10. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    This is not a feature that cInput currently has. So for now I suppose you could keep a track of your own booleans and have your code do something like:
    Code (csharp):
    1. public bool virtualJump = false; // set this to true via your UI to virtually press the jump key
    2.  
    3. if (cInput.GetKeyDown("Jump") || virtualJump) {
    4.     //do jumping stuff
    5. }
    If cInput were to implement this feature, how do you see it working? Would you want to have to manually set KeyDown, Key, and KeyUp values? Or would you want to just say something like VirtualKeyPress(description, pressedState) where pressedState is a bool of whether it is pressed or not. Then cInput would automatically set KeyDown as true on the first frame, and KeyUp as true on the last frame when you set VirtualKeyPress(description, false)?

    And what other information would you need to know? Would you need to be able to get the current forced status? Or just set it? GetForcedStatus() and SetForcedStatus()?
     
    Last edited: Apr 29, 2015
  11. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Thanks for the suggestion. I'm going to do something similar - overload the GetKey___() calls for whether or not to check the virtual the input of my own array.

    Personally, I'd like for it to be as simple and easy to use as possible - just like cInput is now. I don't think that there should be a pressedState because that introduces low-level information. The call should be similar to GetKey___(string KeyName) where the user calls it, uses it, then forgets about it.

    Then in the same frame, the user can call GetKey___("VirtualKey") and return as if the player had done the action of the virtual key press.
     
    Last edited: Apr 30, 2015
  12. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    If you guys are brainstorming how to implement virtual key presses, here's what I did:

    I had a HashSet that got added to with the call of VirtualPressDown (string description) which added description.GetHashCode().

    Though I implemented virtual key presses on a layer above cInput, cInput could do something very similar. In the method where the input's're checked, you can do a simple KeysDownSet.Contains() call for each input. Then at the end, just clear the set.
     
  13. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    How are you handling virtual keypresses that last longer than a single frame? Are you setting a VirtualKeyDown() and then later setting a VirtualKeyUp()? Or are you just virtually pressing the key for a single frame?
     
  14. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    I don't hehe. Yeah, I'm only implementing Down.

    I think having a VirtualKeyUp would be too complicated for the users. What if there was a VirtualKeyDownOnce?

    If there is a VirtualKeyUp, you could have another dictionary of booleans called VritualKeysPressed, which is what I have. Instead of setting every boolean to false at the end of a frame, only set the boolean to false when VirtualKeyUp is called. You'll still have to have hashsets for Up and Down detection but this dictionary will provide Pressed detection, any time the virtual key is pressed.
     
    Last edited: May 1, 2015
  15. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    This is a little demo of the UI input I rigged up with cInput. Skip to about 0:45 for that part.

    This would actually be an extremely cool thing to have in cInput - a keyboard on the UI. There's so many great uses for this other than mine. If you guys want, I can take a bit of time to whip up the virtual key presses and send it to you (but you guys will have to do the UI; that take too much time).
     
    Last edited: May 1, 2015
  16. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    I think you forgot the link to a video.
     
  17. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Haha my bad. Here it is:
    .

    By the way, I just had a stretch of headache because of that darn _cInputLoaded bool. Apparently it doesn't get set to true if usePlayerPrefs isn't true, and if usePlayerPrefs is true, my inputs get all screwy. Fortunately, it only took me 2 hours to find this bug :p. Least I had good internet and Lindsey Stirling playing in the background, and I know for sure none of my code is bugged (if it is, I will shoot my computer).

    I think you should just get rid of that boolean and all its checks. You already mention in the documentation not to get input before initialization, so the user most likely won't.
     
    Last edited: May 1, 2015
  18. Jesse_Pixelsmith

    Jesse_Pixelsmith

    Joined:
    Nov 22, 2009
    Posts:
    296
    Hi There. Trying to find an input solution for a game jam I'm doing (with GearVR(Android)) and a bunch of issues with trying to get a solution to handle someone using one of several different Bluetooth controllers.

    I've tried using other solutions to set up "profiles" for each one, but I gave up after struggling with it for too long.

    I'd been using cInput for my other prototype and I remembered that you can remap keys with it pretty easily. And I think if I can just start my VR app and cycle through the main actions of the game and ask the user to press a button they want to use for each action, it should solve all those issues of not knowing which controller they're using. So I made a little test on android:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. public class InputRemapping : MonoBehaviour {
    6.   public Text ButtonText;
    7.     // Use this for initialization
    8.     void Awake () {
    9.     cInput.SetKey("Shoot", Keys.E);
    10.     }
    11.   void OnEnable() {
    12.     cInput.OnKeyChanged += KeyChanged;
    13.   }
    14.  
    15.   void Start()
    16.   {
    17.     ButtonText.text = cInput.GetText("Shoot");
    18.   }
    19.   //Called by uGUI button
    20.   public void RemapKey()
    21.   {
    22.     cInput.ChangeKey("Shoot");
    23.   }
    24.   //Called when Key Change was detected
    25.   void KeyChanged() {
    26.         ButtonText.text = cInput.GetText("Shoot");
    27.   }
    28. }
    29.  
    And this works pretty well. You click the button which calls "RemapKey" function. and press a button and lo and behold I get output like "Joystick1Button5" and it even handles multiple controllers at once :)

    I think I should be able to then map this over to my game with no problem.

    -HOWEVER- and this is my question - how do I save this input data, so that they don't need to remap their controller each time they start the game. (I will give them an option to remap the controller again if they so choose in the main menu) But I'd like to be able to detect if they've mapped the controller once and set a boor or something, so they don't need to do it again, and still keep those values.

    I saw some in the reference manual about PlayerPrefs, but don't see clearly how to save those inputs
     
  19. Jesse_Pixelsmith

    Jesse_Pixelsmith

    Joined:
    Nov 22, 2009
    Posts:
    296
    Ooops I realized above that I'm initializing with:
    1. void Awake () {
    2. cInput.SetKey("Shoot", Keys.E);
    3. }
    Just to be able to define "Shoot" as a key/action, and that's probably overwriting anything that's saved. But my question still stands, what is the best practice to do this?
     
  20. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    I had a huge headache with this too. If you open up the caution logs, you might see a message about using ChangeKey instead of SetKey for keys that are already set. You can use SetKey with a ChangeKey right after to guarantee the key will be the one you want, or you can turn off usePlayerPrefs and just use SetKey. If you choose the latter, you'll also have to go through the code and do something about the _cInputLoaded bool because that doesn't get set to true without usePlayerPrefs, so your input won't be registered.
     
  21. Jesse_Pixelsmith

    Jesse_Pixelsmith

    Joined:
    Nov 22, 2009
    Posts:
    296
    I didn't get any warnings about changing keys if they're already set. And I wrote my own litle function to interface with player prefs. I just save them like this: PlayerPrefs.SetString("Input_Shoot", cInput.GetText("Shoot"));

    What I'm curious about now is if there's a way to use the OnKeyChanged event with a parameter?

    for instance I currently have this in Awake:
    cInput.OnKeyChanged += KeyChanged;

    and when I call this:
    cInput.ChangeKey("Shoot");

    it waits for input , and when it gets it it will call the "KeyChanged" method.
    What i'd like to know is if it can call KeyChanged("Shoot"); because Shoot is the action that had the key changed.
     
  22. jpthek9

    jpthek9

    Joined:
    Nov 28, 2013
    Posts:
    944
    Sorry, but I'm no expert concerning player prefs (I actually deleted that bit from cInput). They generously provided the source code, if you'd like to take a crack at it. I found the comments to be really comprehensive but some of the design gets messy (like why is there a _SetKey() and a SetKey() that do the same thing?).

    If you're still having problems using even when using both SetKey and ChangeKey, you could try to call ResetInput(). Shot in the dark, but it might give you a clean slate and work.
     
  23. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    If you have cInput.usePlayerPrefs enabled (which is the default) then it should save and load any changes made automatically. Is this not happening?

    Using cInput.Clear() after making some changes can often fix some problems. Then again, this might also be the cause of your problems. If you're calling Clear() or ResetInputs() then you are erasing any changes the player has made to the inputs.

    cInput doesn't support this at the moment, but that does seem like a useful feature. Though it makes me wonder what information would be the most useful to pass back to you.

    KeyChanged(string description);
    KeyChanged(int index);
    or KeyChanged(int hashCode);

    Which do you think would be simplest and best?

    SetKey() and _SetKey() don't do the same thing. SetKey() is a public function which validates the passed in parameters before calling the private function _SetKey() (among other things) which actually creates the key to be used with cInput.
     
  24. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    I missed this one in my most recent response.
    You're right that _cKeysLoaded can cause problems if usePlayerPrefs isn't true. This is a bug that was introduced about 5 weeks ago in v2.8.1 when disabling PlayerPrefs became an option. I'll fix that for the next release. In the meantime, you can just set _cKeysLoaded = true on line ~1659, like so:
    Code (csharp):
    1. if (!usePlayerPrefs) {
    2.     _cKeysLoaded = true;
    3.     return;
    4. }
     
  25. SullyTheStrange

    SullyTheStrange

    Joined:
    May 17, 2013
    Posts:
    147
    Hey @Deozaan, we're having a bit of trouble getting cInput to recognize our PS3 controller (which is emulating a 360 controller through MotionInJoy) with the special Xbox keys. Input.GetJoystickNames is showing that it's called "Controller (Xbox 360 Wireless Receiver for Windows)", while our actual 360 controller is called "Controller (XBOX 360 for Windows)". The real controller is recognize by the Xbox keys no problem, but the emulated one is only recognized by the generic Joystick keys.
     
  26. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Hi @SullyTheStrange,

    Can you be more specific about the problem? I have the same setup, with a PS3 controller (Dual Shock 3) connected (by USB) using MotionInJoy and Better DS3. The name is the same as yours, but all the keys are mapped just like an Xbox controller.

    What version of Unity are you using? Do you have multiple Xbox controllers connected at the same time? Older versions of Unity have issues with multiple Xbox controllers being connected at the same time, but the latest patches/updates have made some good strides at fixing that.
     
  27. SullyTheStrange

    SullyTheStrange

    Joined:
    May 17, 2013
    Posts:
    147
    Oh, false alarm I guess! I had been launching MotionInJoy by itself to use it, which has never given me problems playing games before, but I just tried launching Better DS3 instead and now cInput's special Xbox keys are triggering. Weird, but hey, I'll take it!

    (But just so you know, I'm using Unity 4.6.3f1 and it was the only controller connected at the time.)
     
  28. CF-Games

    CF-Games

    Joined:
    Jun 2, 2013
    Posts:
    134
    Hello,

    When displaying the key bindings, is it possible to make it more user friendly by displaying the actual button instead of the name that Unity uses? Like for an Xbox controller, if something is bound to the X button, using GetText() will display "Joystick1Button2". Is there a way to get it to display "X" or something more user friendly. And for the axis, it says something like "Joy1 Axis 1-". Is there a way to make it say something like "Left Analog Stick" instead?

    Also, is there a way to check what button something is assigned to? I have a game where the A button on a Xbox controller is used to press gui buttons (default in Unity), but the A button is also used to start the gameplay in my game. So there is a problem where if a menu is up before the game starts, pressing those gui buttons with the A button can make the game start unintentionally. So I want to check if the "Launch Ball" button is assigned to A or not, and if it is to check for GetKeyUp before allowing the ball to be launched. When the gui menus are up, the game's timescale is set to 0, but the issue is when the player presses the Resume button, the timescale is set back to 1, but the game counts that button press an additional time even when I'm using GetKeyDown.
     
  29. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    @SullyTheStrange That is strange. Hopefully it was just a fluke.

    @CF Games cInput doesn't provide a way to do the things you've requested, but they can be done.

    For instance, you can make a switch statement that checks the value of GetText() and if it returns "Joystick1Button2" you can display X (or an image of the X button). Using "Left Analog Stick" in place of "Joy1 Axis 1-" could be confusing because your players might think "Left Analog Stick" includes both positive and negative values of the axis, but Joy1 Axis 1- is only the negative values.

    For your second problem, with the game starting prematurely, what I'd do is use a boolean called something like gameStarted. Set it to true when the game starts, and only let the A button do stuff when that bool is true.
     
  30. CF-Games

    CF-Games

    Joined:
    Jun 2, 2013
    Posts:
    134
    The problem with checking for something like "Joystick1Button2" is that for a Mac, it depends on the driver. So "Joystick1Button2" may not be the X button, unless cInput checks for that and makes it always the X button.

    For the second issue, I do have a boolean called ballInPlay, but it turns on right after the GUI is button is pressed and the timescale is set back to 1. So the result is the same thing where it still detects an additional button press.

    Also, it currently doesn't look like the button used to press gui buttons can be assigned to a cInput during runtime. For keyboard it's Enter, and for Xbox it's the A button. But when I press the A button on the Xbox controller to change a key and the "..." shows up on the button, pressing the A button again just presses the button again and it keeps displaying "..." until I assign it to another button.

    I'm using a custom GUI made with uGUI by the way and for the buttons I'm just changing the text and using the OnKeyChanged delegate/event to loop through each button to update the text every time there is a change.
     
  31. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    This is why we didn't build that feature into cInput. Because we can't know/guarantee which kind of gamepad or driver the player will use, so we don't know what text to replace "Joystick1Button2" with.

    When we created cInput's GUI (cGUI using the old Unity GUI) we had to create a little timer that would keep track of when the input was changed, so as to not allow the menu to immediately select the same input to be changed again. Perhaps you should store a float of the current time when OnKeyChanged is called, and if a menu button is pressed again before 0.15f seconds have passed (for example) don't call ChangeKey. It worked like this:

    Code (csharp):
    1. float clickDelay = 0;
    2.  
    3. // subscribe this function to the OnKeyChanged event
    4. void OnKeyChangedHandler() {
    5.     clickDelay = Time.realTimeSinceStartup + 0.15f;
    6. }
    7.  
    8. // later on in your code where you handle the GUI OnClick event:
    9. void OnClick(int index) {
    10.     if (Time.realTimeSinceStartup < clickDelay) {
    11.         ChangeKey(index, 1);
    12.     }
    13. }
     
  32. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Hi folks,

    An update to cInput has been submitted to the Asset Store. If you bought cInput from the Asset Store then the update should be live within a few (business) days. If you bought cInput from our website, then the update is available immediately.

    One of the changes included is the option to get input from any connected gamepad. For this new functionality to work, you'll need to reinstall the cInput InputManager.asset file by using the "Edit -> Project Settings -> cInput -> Replace InputManager.asset file" menu command in the Unity Editor.

    cInput changelog:

    v2.8.4

    • cInput can now be set up to check for input from any gamepad axis.
    • Fixed disabling PlayerPrefs causing problems. (Thanks jpthek9)
    • Keys class now has proper mappings for Xbox 360 gamepad on WebGL player.
     
  33. TheAsuro

    TheAsuro

    Joined:
    May 19, 2014
    Posts:
    1
    I would like to use CInput for my free and open-source game (licensed under MIT license). However, I'm not sure if it is allowed to include the (non-pro-version) files into the project, as they would be openly available on GitHub.
     
  34. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    cInput 2.x is not free in any sense of the word. You should not include cInput or cInput Pro in your public repositories.

    That said, we do provide a Dev Edition which is free (as in price) and licensed to be redistributable under certain conditions (though I don't think your situation fits the intended purpose). You can find the download for cInput Dev Edition at the bottom of our itch.io page.
     
  35. sacher

    sacher

    Joined:
    Jun 10, 2014
    Posts:
    6
    Good night. I would ask if anyone has tried to change the keys of a joystick on android. Since I'm using the code that gives the reference manual and everything works, except for two keys that never recognizes me. Currently my joystick is a dance mat. and I have tried several rugs and two keys that do not recognize me are never the "START" and "PAUSE" any suggestions? .. I appreciate the collaboration. And please excuse my English
     
  36. Bluestrike

    Bluestrike

    Joined:
    Sep 26, 2009
    Posts:
    256
    Hi, the contact form on your website is not working (no text field only a sumbit button in IE and Chrome)

    I am having a user expiriencing a very slow mouse in my game and I tracked it down to input.cs

    My code in case anything is wrong with that
    Code (JavaScript):
    1. cInput.SetKey ( "CursorLeft",             "Mouse Left" );
    2. cInput.SetKey ( "CursorRight",             "Mouse Right" );
    3. cInput.SetAxis ( "CursorHorizontal",     "CursorLeft",     "CursorRight" );
    4.  
    5. cInput.GetAxis ( "CursorHorizontal" );
    I used
    to show the values to the user with this problem to find out the slow mouse values were comming from there.
    He is running my game on windows 8.1 with a standard logitech mouse.

    I let the user try some different versions of cinput and here is the result:
    cInput 2.4.5 works fine.
    cInput 2.7.6 has the issue.
    cInput 2.8.3 (latest version? still has the issue)

    The user tells me his mouse works fine for a fraction and then slows down.
    I upgraded a while ago from 2.4.5 to 2.7.6 because I needed the contoller trigger buttons so using the 2.4.5 version is not really an option for me :/

    bluestrike@bluestrike.be
     
  37. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Thanks for letting me know about the contact form. Weebly is making changes to their site and I can't even login to attempt to fix it.

    Anyway, as for the issue you're experiencing, for mouse movement, you should probably be using GetAxisRaw. But if you continue to have issues, we can look more into what's causing it. That said, in the meantime if you have cInput Pro, you *should* be able to use the cKeys.cs file from 2.8.3 with cInput 2.4.5.

    We added some new things in 2.8.4 that won't be compatible with previous versions, but if I'm not mistaken, 2.8.3's Keys class should be backwards compatible.

    Of course, this is all based on the interpretation of you saying you need the controller trigger buttons to mean you need the easy access Keys.Xbox1TriggerLeft stuff. If you mean something else, please correct me and we'll work to figure it out.

    Can you get Unity to recognize those inputs without cInput? If Unity can recognize it, cInput can too. If Unity can't, then cInput probably can't either.
     
  38. paulordbm

    paulordbm

    Joined:
    Feb 9, 2013
    Posts:
    2
    Hello,

    I'm having a problem with cInput trying to support up to 4 gamepads. Here's my code:

    Code (CSharp):
    1. cInput.SetKey("test", Keys.Xbox4LStickLeft);
    2.  
    Edit: I would put a repro project link but then anyone would have your code. PM me if you need the repro project.

    Basically anytime I try to setup something related to the left stick of the fourth gamepad it give's me an IndexOutOfRange exception inside the cInput class.

    Any clues on how can I fix it myself? I have the source and I'm participating on the PDJam this week, hoping to use cInput and support 4 players for my local multiplayer game :)

    Thanks in advance!
     
  39. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Thanks for the bug report! This issue is something I missed while adding a new feature in the latest version of cInput. Previous versions of cInput shouldn't have this problem. That said, I've been able to reproduce the problem and fix it by changing line ~200 of cInput.cs from:

    Code (csharp):
    1. private static int[] _axisType = new int[10 * _numGamepads];
    to

    Code (csharp):
    1. private static int[] _axisType = new int[11 * (_numGamepads + 1)];
    Considering the seriousness of this problem, I'll try to hurry and get a patch/hotfix release out for everyone.
     
  40. willtrax

    willtrax

    Joined:
    Feb 9, 2013
    Posts:
    14
    I updated my version of cInput recently and just happened to check my profiler today. It looks like the cObject created when cInput is initialized has two scripts, CGUI and C Input GUI enabled. These are making GUI.Repaint calls which are creating unnecessary memory allocations that contribute to garbage collection issues. I'm not using the Unity GUI at all and would prefer not to make any calls to it for optimization purposes.

    I reviewed the cInput manual but didn't see any method listed for disabling the unused GUI features when initializing cInput. Is there a way to exclude these calls which I'm missing? thanks
     
  41. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    If you have cInput Pro, you can comment out the very first line of cInput.cs which should prevent the cGUI and cInputGUI components from being added to the cObject.

    If you don't have cInput Pro, then... well... We never had access to the profiler before, as it was a Pro feature until Unity 5. We assumed that because OnGUI was never called, it wouldn't be a problem having the components on there. But I Just checked and I can see that you are right about it causing GC. I'll probably add an optional argument to the cInput.Init() function which will allow you to disable it. Thanks for bringing this to our attention!
     
  42. willtrax

    willtrax

    Joined:
    Feb 9, 2013
    Posts:
    14
    Thank you for the fast reply that suggestion solved the problem.
     
  43. GodJammit

    GodJammit

    Joined:
    Feb 10, 2014
    Posts:
    32
    Clocking in at about 24ms per update. I'm getting the input from 4-axis (both joysticks). This is pretty bad, is there any reason I might be receiving this performance? I've narrowed it down to cInput.GetAxis, I'm going to see if I can find which part of it is inducing the expenses.

    I'm only polling once per update and my version is updated. Newest cInput2 (pro) & newest Unity stable (5.0.2).

    Edit: Would seem it's all _cInputInit's fault. Diving into it, might make the script an extension of the wiki's singleton pattern and see how that stacks up.
     
    Last edited: May 26, 2015
  44. GodJammit

    GodJammit

    Joined:
    Feb 10, 2014
    Posts:
    32
    Maybe I've configured something incorrectly, but switching the class to a more proper singleton pattern fixed my performance issue. I'll share what I did, despite it being shotty work.

    The class is now
    Code (CSharp):
    1. //http://wiki.unity3d.com/index.php/Singleton
    2. public Class cInput : Singleton<cInput> {}
    3. //Instead of
    4. public Class cInput : MonoBehaviour {}
    and
    Code (CSharp):
    1. private static cInput _cObject;
    2. //Is now
    3. private static cInput _cObject {
    4.     get {return cInput.Instance;}
    5.     set {/*do nothing*/}
    6. }
    The accessor's set is so I could leave the plugin's code intact. The _cInputInit needs removing, but this works. Would seem the hasty singleton implementation it did was often getting a null and running GameObject.Find("cObject") every frame. As to why, I'm uncertain.

    I'd go ahead and say this change should be made to the plugin regardless, having GameObject.Find anywhere is a no-no in my book.
     
    Last edited: May 26, 2015
  45. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    That is very unusual. Do you have some code that is deleting the cObject each frame?

    Due to willtrax's recent comments, I looked at cInput in the profiler recently and I did find some areas in which cInput's performance could be improved (and they will be in the next update), but I never saw any issue with _cInputInit using up 24ms every frame.
     
  46. GodJammit

    GodJammit

    Joined:
    Feb 10, 2014
    Posts:
    32
    No, and that Singleton implementation does the same thing, it creates a new GameObject in the root.

    I actually just switched the script back to it's original form and it seems to be operating fine now. I have no clue why, as I'd just pulled it fresh from the Asset store when I started (alongside a Unity, rebuild all, and complete computer restart when I had the problem in the first place). For some reason it's running fine now though.

    I'll see if I can recreate the problem.
     
  47. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Hi folks,

    An update to cInput has been submitted to the Asset Store. If you bought cInput from the Asset Store then the update should be live within a few (business) days. If you bought cInput from our website, then the update is available immediately.

    cInput changelog:

    v2.8.5

    • Fixed IndexOutOfRange exception introduced in 2.8.4. (Thanks paulordbm)
    • Added optional parameter to cInput.Init to disable cGUI. (Thanks willtrax)
    • No more garbage collection each frame when getting calibrated axis inputs.
     
  48. Doghelmer

    Doghelmer

    Joined:
    Aug 30, 2014
    Posts:
    120
    Just updated to version 2.8.5, and I'm still getting an IndexOutOfRange exception. It first occurs on the following line:
    cInput.SetAxisDeadzone("RightTrigger", 0.3f);

    The line was preceded by:
    cInput.SetKey("Attack", Keys.Xbox1TriggerRight, "");
    cInput.SetAxis("RightTrigger", "Attack");
     
    Last edited: Jun 1, 2015
  49. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Grr! How did that sneak in there? If you have source access, you can change ~line 771 from:

    Code (csharp):
    1. // don't try to set value for positive input if this axis only has negative input
    2. if (_FindKeyByHash(_inputName[_makeAxis[axis, 1]].GetHashCode()) >= 0) {
    3.     _individualAxisDead[_makeAxis[axis, 1]] = deadzone;
    4. }
    to
    Code (csharp):
    1. // don't try to set value for positive input if this axis only has negative input
    2. if (_makeAxis[axis, 1] >= 0) {
    3.     if (_FindKeyByHash(_inputName[_makeAxis[axis, 1]].GetHashCode()) >= 0) {
    4.         _individualAxisDead[_makeAxis[axis, 1]] = deadzone;
    5.     }
    6. }
    And similar changes are needed for the SetAxisGravity and SetAxisSensitivity functions.
     
    Last edited: Jun 1, 2015
  50. KrayonZA

    KrayonZA

    Joined:
    Mar 5, 2013
    Posts:
    52
    Does any one have a working example of using cInput Pro with the new 4.6 UI?

    I was thinking something like this may work its pseudo code i haven't had a chance to test it yet.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine.UI;
    5.  
    6. public class GUIControls : MonoBehaviour {
    7.     private float _mouseSensitivity = 2.0f;
    8.  
    9.     public GameObject InputItem;
    10.     public GameObject InputPanel;
    11.     public List<GameObject> InputItems = new List<GameObject>();
    12.     private bool _listRefreshed;
    13.     // Use this for initialization
    14.     void Start () {
    15.         SetupInput();
    16.         _listRefreshed = true;
    17.     }
    18.    
    19.     // Update is called once per frame
    20.     void Update ()
    21.     {
    22.         GenerateInputMapper();
    23.     }
    24.  
    25.     public void GenerateInputMapper()
    26.     {
    27.         if (_listRefreshed)
    28.         {
    29.             // Action
    30.             for (var n = 0; n < cInput.length; n++)
    31.             {
    32.                 var item = Instantiate(InputItem);
    33.  
    34.                 item.transform.SetParent(InputPanel.transform, false);
    35.                 InputItems.Add(item.gameObject);
    36.  
    37.                 item.transform.FindChild("KeyName").GetComponent<Text>().text = cInput.GetText(n, 0);
    38.  
    39.                 item.transform.FindChild("Primary").FindChild("Text").GetComponent<Text>().text = cInput.GetText(n, 1);
    40.                 AddButtonListener(item.transform.FindChild("Primary").GetComponent<Button>(), n, 1);
    41.  
    42.                 item.transform.FindChild("Secondary").FindChild("Text").GetComponent<Text>().text = cInput.GetText(n, 2);
    43.                 AddButtonListener(item.transform.FindChild("Secondary").GetComponent<Button>(), n, 2);
    44.  
    45.                 item.SetActive(true);
    46.             }
    47.             _listRefreshed = false;
    48.         }
    49.  
    50.     }
    51.  
    52.     public void Clear()
    53.     {
    54.         foreach (var item in InputItems)
    55.         {
    56.             Destroy(item);
    57.         }
    58.  
    59.         InputItems.Clear();
    60.     }
    61.  
    62.     //-----------------------------------------------------------------------------------------------------
    63.     private void AddButtonListener(Button button, int id, int type)
    64.     {
    65.         switch (type)
    66.         {
    67.             case 1:
    68.                 button.onClick.AddListener(() => ChangeKeyPrimary(id));
    69.                 break;
    70.  
    71.  
    72.             case 2:
    73.                 button.onClick.AddListener(() => ChangeKeySecondary(id));
    74.                 break;
    75.         }
    76.        
    77.     }
    78.  
    79.     public void ChangeKeyPrimary(int id)
    80.     {
    81.    
    82.         cInput.ChangeKey(id, 1);
    83.         Clear(); // Clear Previous List
    84.         _listRefreshed = true;
    85.      
    86.     }
    87.  
    88.     public void ChangeKeySecondary(int id)
    89.     {
    90.  
    91.         cInput.ChangeKey(id, 2);
    92.         Clear(); // Clear Previous List
    93.         _listRefreshed = true;
    94.  
    95.     }
    96.  
    97.     //-----------------------------------------------------------------------------------------------------
    98.     private void SetupInput()
    99.     {
    100.         cInput.allowDuplicates = false;
    101.         cInput.SetKey("Forward", Keys.W, Keys.ArrowUp);
    102.         cInput.SetKey("Backward", Keys.S, Keys.ArrowDown);
    103.         cInput.SetKey("Strafe Left", Keys.A, Keys.ArrowLeft);
    104.         cInput.SetKey("Strafe Right", Keys.D, Keys.ArrowRight);
    105.         cInput.SetKey("Crouch", Keys.LeftControl, Keys.RightControl);
    106.         cInput.SetKey("Jump", Keys.Space, Keys.None);
    107.         cInput.SetKey("Prone", Keys.C, Keys.None);
    108.         cInput.SetKey("Run", Keys.LeftShift, Keys.RightShift);
    109.         cInput.SetKey("Primary", Keys.Mouse0, Keys.None);
    110.         cInput.SetKey("Secondary", Keys.Mouse1, Keys.None);
    111.         cInput.SetKey("Reload", Keys.R, Keys.None);
    112.         cInput.SetKey("Knife", Keys.Q, Keys.None);
    113.         cInput.SetKey("Next Weapon", Keys.MouseWheelUp, Keys.None);
    114.         cInput.SetKey("Previous Weapon", Keys.MouseWheelDown, Keys.None);
    115.         cInput.SetKey("Camera Rotate Left", Keys.MouseLeft, Keys.None);
    116.         cInput.SetKey("Camera Rotate Right", Keys.MouseRight, Keys.None);
    117.         cInput.SetKey("Camera Rotate Up", Keys.MouseDown, Keys.None);
    118.         cInput.SetKey("Camera Rotate Down", Keys.MouseUp, Keys.None);
    119.         cInput.SetKey("Menu", Keys.Escape, Keys.None);
    120.         cInput.SetKey("Scores", Keys.Tab, Keys.None);
    121.         cInput.SetKey("Buy", Keys.B, Keys.None);
    122.         cInput.SetAxis("Horizontal", "Strafe Left", "Strafe Right");
    123.         cInput.SetAxis("Vertical", "Backward", "Forward");
    124.         cInput.SetAxis("MouseX", "Camera Rotate Left", "Camera Rotate Right");
    125.         cInput.SetAxis("MouseY", "Camera Rotate Up", "Camera Rotate Down");
    126.         cInput.SetAxis("Switch Weapon", "Previous Weapon", "Next Weapon");
    127.         cInput.SetAxisSensitivity("MouseX", _mouseSensitivity);
    128.         cInput.SetAxisSensitivity("MouseY", _mouseSensitivity);
    129.         cInput.SetAxisGravity("MouseX", 1000);
    130.         cInput.SetAxisGravity("MouseY", 1000);
    131.     }
    132.  
    133. }
    134.