Search Unity

How do you handle an input script with thousands of lines?

Discussion in 'Scripting' started by Deleted User, Aug 24, 2016.

  1. Deleted User

    Deleted User

    Guest

    Do you split it up into say 1k lines scripts and inherit? Feels like it would be very hard to use multiple files without any connection.
     
  2. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    419
    I think the best idea is to not have an input script with thousands of lines. The responsibility of the input script should just be to interpret some input, and send a relevant command to the relevant object.
     
  3. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    why does your input script have "thousands" of lines?
     
  4. Deleted User

    Deleted User

    Guest

    The inputs themselves don't take up that many lines but it's rather the logic that decides what to do based on the inputs. Currently sitting at 2095 lines which is a mess to read. Splitting up the logic is a must but not sure what approach use.
     
  5. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    oh ok, literal thousands :oops:

    what kind of game is it? are we talking different game "modes" (i.e. an rts with different controls in "battle" and "build" mode) or... going to need to know a little about where the complexity is coming from I think.
     
    Deleted User likes this.
  6. Deleted User

    Deleted User

    Guest

    Working on making a separate file for inputs but that will only save me a few 100 lines at most.

    The game is a first person RPG with parkour which makes it a bit complicated. Is it not a good idea to use two scripts and inherit from one of them? What would you recommend.

    This was one of the first scripts I wrote and I have improved a lot since then and going back to improve it is a huge task.
     
    Last edited by a moderator: Aug 24, 2016
  7. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    419
    Could you post a snippet of the script? If you're doing everything regarding input and movement and stuff in the same script, you should probably do it in another way.
     
  8. Deleted User

    Deleted User

    Guest

    Currently trying to create a few more scripts to handle the input logic. Thanks.
     
  9. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
  10. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    If you need to refactor thousands line of code, but the code seems to be too complicated to figure out line by line what's going on. Then I would tackle this problem by reverse engineering:

    1. Don't look at the existing code at all (consider it as a black box).
    2. Observe and write down an exhaustive description of the system (from a user perspective).
    3. Re-implement the system in a more structured way.

    (Though, you don't need to apply this literally, there is probably plenty of existing code you can reuse.)

    Once you have a description/specification of the system, you want to try dividing it into smaller and modular sub-systems, ideally independent from each other and self contained. At this point, you should have a firm idea of the overall architecture.

    For the implementation, you have a lot of techniques and paradigms at your disposition. Not applying one would surely result in an incomprehensible code listing. After all, you could write a complete game using only one function, if you really want to. All of the paradigms in the history of programming boil down to methodologies to better organize your code. Going for OOP is generally a good idea. Unity is built upon a component-based architecture as well, so adopting a similar architecture would be consistent.

    For managing input, I would suggest to organize your logic around a Finite State Machine or a Behaviour Tree. These techniques come in handy to model behaviours running over long period of time (several frames).
     
    Last edited: Aug 24, 2016
    Boz0r and KelsoMRK like this.
  11. Deleted User

    Deleted User

    Guest

    Thank you for the extended explanation. Like I mentioned above I'm currently splitting the input logic into several smaller scripts, it's taking forever but it'll be worth it in the end. Dreading all the other scripts I have to split as well, one for the enemy ai which consists of over 3k lines lol. That's one of the major downsides of learning programming, making so damn many mistakes.

    The code is not hard to figure out except for a few methods I have to look up and bounce around like a maniac and it's really frustrating, so I won't have to rewrite it at least.

    One thing I forgot to mention earlier is that I use 2 lines of space between each method to increase the readability which adds a lot of extra lines. Still the script is way too big and working hard to make it right this time. Being a noob is painful in programming.
     
  12. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    A few suggestion in case you weren't aware:

    Try to think of actions your code needs to as black boxes. Try to group functions that might be related into one blackbox, and that blackbox is your c# script. Everythning outside of that blackbox should have no idea whats going on inside of it and just expect an answer. This way if you change internally how something works nothing outside is depending on how it got its answer. Here's a concrete example:

    I have a Player. He can walk forward/backward, strafe left/right. jump up, Fire his main weapon, fire offhand weapon, swap weapons, talk to another person..

    I would Create a PlayerMove script and add following functions:
    1. Public Vector3 PlayerWalk (float dist) // this code would move the player forward/back and return new position
    2. Public Vector3 PlayerStrafe(float dist) // this code would strafe left/right and return a new position
    3. Public Vector3 PlayerJump(float dist) // this code would jump up the player and return a new position
    I would Create a PlayerWeapon Script and add the following function
    1. Public GameObject PlayerFire(Vector3 aimSpot,bool mainHand) // this code would return any Gameobject the player hit or null . Mainhand would determine if it was mainhandor offhand shot
    2. Public void SwapWeapons() // code to swap the players' weapons
    The Player Action script would be similiar to above but handle any code like talking to other people, maybe buying/selling items, etc. if it grew too large.. you could take smaller subsections like buying / selling at shops out into its own script.

    Attach all these scripts to the same Player object, and it will be very readable and easy to figure out where to go. Say jumping isn't looking right or he jumps through ceilings.. You could easily look in your hierarchy and see PlayerMove and just find PlayerJump in there since there would only be 3-4 functions at most.

    Some other things if you really need to access a single function from a script with a lot of functions.. you don't have to attach the entire script. you can use the following code to access the one function
    1. SomeOtherClass myObject = new global::SomeOtherClass() //(you must use global if SomeOtherClass inhereits Monobehaviour
    2. SomeOtherClass myObject = :new SomeOtherClass() // this works fine for a normal class
    3. myObject.SomeOtherClassFunction() //then you can call that one function

    If you have some functions that don't need to keep copies of their own data (basically utitlity functions) you can declare them static and use them from anywhere. A good example is Loading/Saving game information. Make a c# script called Utility or even more specifically GameSave and declare it like this:

    1. public struct GameData { // variables that have your Game Data here };
    2. public static class GameSaveLoad {
    3. public static void GameSave(GameData data) { // code to save here }
    4. public static GameData GameLoad() { // code to load data }
    5. }

    Then in another file you can just type GameSaveLoad.GameLoad();
     
  13. lloydsummers

    lloydsummers

    Joined:
    May 17, 2013
    Posts:
    359
    Just reiterating what the others said above. I'm a huge fan of abstraction layers - and I love building interchangable input systems (so my users can go from VR, to Gamepad, to Keyboard and Mouse, to Touch) without needing to close and reopen my games.

    If you want to build and stay structural, your "input" class should only handle input, trigger appropriate events, and go away.

    The "what to do" after part, the business logic, you usually would offload to other script (or a series of scripts). This structure would vary depending on what is best for your project.

    But I wouldn't include input & business logic in the same script unless I'm trying to quickly prototype. This way, your Input event system can be modular, and used in any other project without business logic dependency. And to simplify input methodologies...
     
  14. Deleted User

    Deleted User

    Guest

    I have a couple of monster scripts with more than 500 lines and it's very tedious to restructure them, it's not as simple as copy pasting to a new file. The enemy ai script containing more than 3k lines will be a nightmare but I'll save that one for last. Thanks to everyone for your replies!
     
  15. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    419
    If you throw one of your larger scripts up, I can take a look, if I have the time. Since I'm such a swell guy.
     
  16. Deleted User

    Deleted User

    Guest

    Thanks but I think I got it covered. I just have to spend a lot of time to split up my scripts into smaller ones.
     
  17. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    @lloydsummers that's pretty much what I think the new input system is going to be like, have you looked at the test versions? it'll be interesting to see whether they're doing it right :)