0
\$\begingroup\$

I'm a web developer, new to C# and trying to learn Unity. I've learned the C# syntax, I understand how to write working code, although I'm having a hard time understanding when and to what classes should I split my code.

At the moment I'm doing a simple 2D fighting game, similar to Mortal Kombat, I've started out with creating some basic sprites and basic scripts for the environment, like clouds spawning and moving (the action takes places on a rooftop), created a fighter character with animations and started with writing the movement script.

At this point, the Movement script deals with moving, jumping, animations (also triggers for punches and kicks) and player input (I'm using the new Input System), also I want to make the game a two player game, so the Movement script also checks if the the fighter is controlled by player 1 or player 2 and everything is crammed in this little Movement script, not that it's too large, it's just funny that a Movement script is doing so much and furthermore I'll need to add health and attacks (not just animations).

I think it's about time I refactor, my questions are:

  1. Should I create a Character, CharacterController, CharacterManager or whatever script that inherits from MonoBehaviour and other scripts as simple C# scripts, or should all of my scripts inherit from MonoBehaviour and be attached as components to my GameObject with references to each other?

  2. Should I have a separate script for my animations or should they be at their respective scripts as in Attack, Movement, maybe Jumping or Death, whatsoever?

  3. What would be the best way or what would be the ways of managing my Fighter GameObject to determine if it is controlled by player 1 or player 2 and if I'll plan to add an AI for example? Should I have a PlayerController/AIController inherit from Character script, or have a separate AI class, or just have some variable to check against?

My problem with various tutorials is that most of them don't give a larger overview of the whole picture, most of them just focus on a single subject: movement, animations, spawning, pathfinding or some other concrete thing or term, etc. and don't show how they are intertwined together.

\$\endgroup\$
0
0
\$\begingroup\$

There are lots of ways to structure an Unity project. There are no right or wrong ways, just ways which work or don't work for you.

But personally I am a fan of the single responsibility principle. This principle interpreted in the context of Unity scripting would mean that each MonoBehaviour should be responsible for one thing the object it's on does. Unity supports this pattern very well by its philosophy of composition over inheritance: A game object does not have a specific class. The properties and behaviors of each game object are the sum of its components.

A "Character" in a usual game does quite a lot of things. Attacking, walking, jumping, animating, taking damage and more. So each of these functionalities should be represented by a separate script. You often need to communicate between scripts (like temporarily disable movement while attacking or cancel an attack when taking damage). Such script-script communication can be realized with GetComponent<OtherClass>(), Messages or Unity Events.

Controllers (which I would call scripts which control a different game object than the one they are attached to) or Managers (which I would call scripts which orchestrates multiple game objects at once) do have their purposes. But in my opinion they should generally be avoided if the same feature can be feasibly implemented by a Component which acts on the object it's attached to.

Applying this philosophy to the topic of player input vs. ai input would be to create two different components AIInput and PlayerInput (when you are using the new input system, you might be able to use the PlayerInput component already provided). Those scripts should communicate with other classes in exactly the same way. This ensures that the AI can not accidentally cheat by doing things the player can not do. The difference is that one relays decisions made by the player through input, while the other relays decision made by code. And if you later want to add multiplayer, you can even create a 3rd component NetworkInput which relays decisions communicated through network messages. Only one of these components would be attached to each character.

\$\endgroup\$
2
  • \$\begingroup\$ Cool, I've read about the SOLID principles and COI, with experience I hope I'll be able to use them efficiently. Are there any major differences in GetComponent<Class>() vs. dragging the references in the inspector when doing script communication? And about the input, would it be good to call AddComponent(AIInput/PlayerInput) or better to have both components on and turn them on/off if I'm instantiating the gameObjects through code? I'm pretty fascinated by the idea of having as little as possible in the hierarchy and generating all through code, maybe I just impede myself as a beginner? \$\endgroup\$
    – Adam
    Apr 8 at 7:25
  • \$\begingroup\$ @Adam Regarding GetComponent vs. references: I usually use GetComponent to get components on the same object. I usually store the reference in a private variable in Start to avoid the overhead (albeit small) of that method during runtime. Regarding code vs hierarchy for setting up objects: I would advise you to try to use the editor instead of creating things with code. It makes your game far easier to design and to test. Doing too much in code and too little in the editor is a common anti-pattern or people coming to Unity from a pure-code development background. \$\endgroup\$
    – Philipp
    Apr 8 at 8:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.