Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by segment · Dec 30, 2014 at 09:12 AM · architectureoopdependency injection

Inversion of Control questions

Hi folks, I'm very new to architectureing and designing applications (in particular games). I've had a big headache developing games before (as I now understand is because of a bad design). So now I roughly decided to dig into SOLID principle and it's 'D' letter which stands for dependency inversion. Unfortunately, I have already developed a small part of my new game without following DI principle and have to refactor code in order to move further. I've read a couple of articles but still have a questions.

I would realy appreciate any help here to understand this principle and apply it on real life.

I have a 'WelcomeScene' and three buttons on it: 'Tryout', 'Signup' and 'Login'.

Tryout simply goes to 'main scene'. Signup shows 'RegisterUser' window. Login shows 'Login' window. User can reset password in 'ResetPassword' window.

WelcomeMenu.cs

 using UnityEngine;
 using UnityEngine.UI;
 
 namespace MyWorldTraveler.UI.Menus
 {
     public sealed class WelcomeMenu : MonoBehaviour
     {
         public GameObject TestPopup;
         public GameObject LoginButton;
         public GameObject SignupButton;
         public GameObject TryoutButton;
         public GameObject CreateUserWindow;
         public GameObject LoginWindow;
 
         private Text loginButtonText;
 
         void Awake()
         {
             loginButtonText = LoginButton.GetComponentInChildren<Text>();
         }
 
         // Use this for initialization
         void Start()
         {
             checkFacebookInitialize();
         }
 
         void OnDestroy()
         {
             //prevent memory leak here.
             FB.OnInitComplete -= menuButtonsInitialize;
         }
 
         public void OnTryoutButtonPressed()
         {
 
         }
 
         public void OnSignupButtonPressed()
         {
             //TODO: Check internet availability here
             CreateUserWindow.SetActive(true);
         }
 
         public void OnLoginButtonPressed()
         {
             LoginWindow.SetActive(true);
 
             
         }
 
         private void OnSuccessfulLogin()
         {
             TestPopup.SetActive(true);
             var content = TestPopup.transform.Find("Content").GetComponent<Text>();
             content.text = "Successfuly logged in!";
             loginButtonText.text = "Logout";
         }
 
         public void OnOkButtonPressed()
         {
             TestPopup.SetActive(false);
         }
 
         private void checkFacebookInitialize()
         {
             if (FB.IsInitialized)
             {
                 menuButtonsInitialize();
             }
             else
             {
                 FB.OnInitComplete = menuButtonsInitialize;
             }
         }
 
         private void menuButtonsInitialize()
         {
             loginButtonText.text = "Logout";
             TryoutButton.GetComponent<Button>().enabled = false;
             SignupButton.GetComponent<Button>().enabled = false;
         }
     }
 }

Login.cs

 using System;
 using UnityEngine;
 using UnityEngine.UI;
 using MyWorldTraveler.Social;
 using MyWorldTraveler.Tools;
 using com.shephertz.app42.paas.sdk.csharp.user;
 using com.shephertz.app42.paas.sdk.csharp;
 
 namespace MyWorldTraveler.UI.Social
 {
     /// <summary>
     /// Login window's script at welcome scene.
     /// </summary>
     public sealed class Login : MonoBehaviour
     {
         public InputField LoginField;
         public InputField PasswordField;
         public GameObject ResetPasswordPopup;
         public Button LoginButton;
 
         private string _login = string.Empty;
         private string _password = string.Empty;
 
         void OnEnable()
         {
             ResetPasswordPopup.SetActive(false);
             LoginButton.gameObject.SetActive(false);
             UsersManager.Instance.OnPasswordResetted += OnPasswordResettedHandler;    
         }
 
         void OnDisable()
         {
             LoginField.text.text = string.Empty;
             PasswordField.text.text = string.Empty;
             UsersManager.Instance.OnPasswordResetted -= OnPasswordResettedHandler;    
         }
 
         void OnPasswordResettedHandler()
         {
             //TODO: Somehow tell a user that password has been successfuly resetted.
 
         }
 
         public void OnLoginFieldValueChanged(InputField input)
         {
             _login = input.value;
             if (_login.Length.IsPositive() && _password.Length.IsPositive())
             {
                 LoginButton.gameObject.SetActive(true);
             }
             else
             {
 
             }
         }
 
         public void OnPasswordFieldValueChanged(InputField input)
         {
             _password = input.value;
             if (_password.Length.IsPositive())
             {
                 LoginButton.gameObject.SetActive(true);
             }
             else
             {
 
             }
         }
 
         public void OnFacebookLoginButtonPressed()
         {
             BasicFacebookSocial.Instance.Authenticate(authenticationSuccessResponse =>
             {
                 if (authenticationSuccessResponse) GoTo.MainScene();
             });
         }
 
         public void OnLoginButtonPressed()
         {
             if (_login.IsEmail())
             {
                 UsersManager.Instance.app42loginUserByEmail(_login, _password, successAction(), failAction());
             }
             else
             {
                 UsersManager.Instance.app42loginUser(_login, _password, successAction(), failAction());
             }
         }
 
         public void OnForgotPasswordButtonPressed()
         {
             ResetPasswordPopup.SetActive(true);
         }
 
         public void OnCancelButtonPressed()
         {
             gameObject.SetActive(false);
         }
 
         private Action<User> successAction()
         {
             return (user) =>
                 {
                     GoTo.MainScene();
                 };
         }
 
         private Action<App42Exception> failAction()
         {
             return (exception) =>
                 {
                     var code = exception.GetAppErrorCode();
                     workoutLoginFail(code);
                 };
         }
 
         private void workoutLoginFail(int errorCode)
         {
 
         }
     }
 }

RegisterUser.cs

 using UnityEngine;
 using UnityEngine.UI;
 using MyWorldTraveler.Social;
 using MyWorldTraveler.Settings;
 using MyWorldTraveler.Tools;
 using System.Collections;
 
 namespace MyWorldTraveler.UI.Social
 {
     /// <summary>
     /// Register a user window's script at welcome scene.
     /// </summary>
     public sealed class RegisterUser : MonoBehaviour
     {
         public Button SubmitButton;
         public Toggle AvailabilityToggle;
         public InputField Username;
         public InputField Email;
         public Text Status;
 
         private string _username;
         private string _email;
         private string _password;
         private string _repassword;
 
         private bool _isUsernameValid;
         private bool _isEmailValid;
         private bool _isPasswordValid;
 
         void Start()
         {
             SubmitButton.gameObject.SetActive(false);
             AvailabilityToggle.isOn = false;
         }
 
         public void OnSubmitButtonPressed()
         {
             UsersManager.Instance.app42CreateUser(_username, _password, _email, successCallback: user =>
             {
                 //somehow use app42's user object here
                 StartCoroutine(workoutSignUpSuccess());
             }, errorCallback: fail =>
             {
                 //tell a user that registration failed
                 var code = fail.GetAppErrorCode();
                 workoutErrorCode(code);
             });
         }
 
         public void OnCancelButtonPressed()
         {
             gameObject.SetActive(false);
         }
 
         public void OnUsernameValueChanged(InputField input)
         {
             if (input.value.Length >= GameConstants.MinimumUsernameLength)
             {
                 _username = input.value;
                 _isUsernameValid = true;
                 AvailabilityToggle.isOn = true;
                 SubmitButton.gameObject.SetActive(isSubmitAvailable());
             }
             else
             {
                 //Status.text = "Username must be at least 4 characters long";
                 AvailabilityToggle.isOn = false;
                 _isUsernameValid = false;
                 SubmitButton.gameObject.SetActive(false);
             }
         }
 
         public void OnEmailValueChanged(InputField input)
         {
             if (input.value.IsEmail())
             {
                 _email = input.value;
                 _isEmailValid = true;
                 SubmitButton.gameObject.SetActive(isSubmitAvailable());
             }
             else
             {
                 _isEmailValid = false;
                 SubmitButton.gameObject.SetActive(false);
             }
         }
 
         public void OnPasswordValueChanged(InputField input)
         {
             _password = input.value;
             if (input.value.Length >= GameConstants.MinimumPasswordLength && input.text.Equals(_repassword))
             {
                 _isPasswordValid = true;
                 SubmitButton.gameObject.SetActive(isSubmitAvailable());
             }
             else
             {
                 _isPasswordValid = false;
                 SubmitButton.gameObject.SetActive(false);
             }
         }
 
         public void OnRepasswordValueChanged(InputField input)
         {
             _repassword = input.value;
             if (input.value.Equals(_password))
             {
                 _isPasswordValid = true;
                 SubmitButton.gameObject.SetActive(isSubmitAvailable());
             }
             else
             {
                 _isPasswordValid = false;
                 SubmitButton.gameObject.SetActive(false);
             }
         }
 
         private bool isSubmitAvailable()
         {
             return _isUsernameValid && _isEmailValid && _isPasswordValid;
         }
 
         private void workoutErrorCode(int code)
         {
             if (code.Equals(GameConstants.App42UserNameExistsErrorCode))
             {
                 Username.text.text = string.Empty;
                 _isUsernameValid = false;
                 SubmitButton.gameObject.SetActive(false);
                 AvailabilityToggle.isOn = false;
                 Status.text = "This username has been already exists!";
             }
             else if (code.Equals(GameConstants.App42UserEmailExistsErrorCode))
             {
                 Email.text.text = string.Empty;
                 _isEmailValid = false;
                 SubmitButton.gameObject.SetActive(false);
                 Status.text = "User with this e-mail has been already registered!";
             }
         }
 
         IEnumerator workoutSignUpSuccess()
         {
             Status.color = Color.green;
             Status.text = "OK!";
             //TODO: Show visual effects
             yield return new WaitForSeconds(1f);
             GoTo.MainScene();
         }
     }
 }

ResetPasswordPopup.cs

 using System.Linq;
 using System.Collections;
 using UnityEngine;
 using UnityEngine.UI;
 using MyWorldTraveler.Tools;
 using MyWorldTraveler.Social;
 
 namespace MyWorldTraveler.UI.Social
 {
     public sealed class ResetPasswordPopup : MonoBehaviour
     {
         public Button ResetButton;
         public Text UserInputText;
 
         private IEnumerable _parentSelectables;
         private string _userInput;
 
         void Awake()
         {
             _parentSelectables = transform.parent.GetComponentsInChildren<Selectable>()
                 .Where(sl => sl.transform.parent.name != transform.name)
                 .AsEnumerable<Selectable>();
         }
 
         void OnEnable()
         {
             disableParentMonoBehaviours();
         }
 
         void OnDisable()
         {
             enableParentMonoBehaviours();
         }
 
         public void OnUserInputInfoValueChange(InputField input)
         {
             var isActive = input.value.Length.IsPositive() ? true : false;
             _userInput = input.value;
             ResetButton.gameObject.SetActive(isActive);
         }
 
         public void OnResetPasswordButtonPressed()
         {
             UsersManager.Instance.app42resetPassword(_userInput,
                 successCallback: response =>
                 {
 
                 }, errorCallback: fail =>
                 {
                     var code = fail.GetAppErrorCode();
                     workoutResetPassowrdFail(code);
                 });
         }
 
         public void OnCancelButtonPressed()
         {
             gameObject.SetActive(false);
         }
 
         private void workoutResetPassowrdFail(int code)
         {
             UserInputText.text = "";
 
         }
 
         private void disableParentMonoBehaviours()
         {
             foreach (Selectable _mb in _parentSelectables)
             {
                 _mb.enabled = false;
             }
         }
 
         private void enableParentMonoBehaviours()
         {
             foreach (Selectable _mb in _parentSelectables)
             {
                 _mb.enabled = true;
             }
         }
     }
 }



  1. Should I treat fields of types GameObject, Button, Text, Toggle, InputField as dependencies? Should I wrap them in an abstraction, lets say, IControl?

  2. In WelcomeMenu.cs I have calls to FB class of Facebook SDK but I have BasicFacebookSocial singleton class which performs init, authorize and logout and I have UsersManager singleton class which uses App42 services which provide login, logout and many other stuff. How can I merge these functionality into abstraction? Would it better to user interfaces or abstract classes?

  3. How to deal with dependencies from the same layer ?

I really appreciate any of your help folks.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by danvalho · Dec 30, 2014 at 08:02 PM

Considering that you are currently studying patterns and your target is to know the best practices in order to achieve your goals, I reccomend you to read Developer's Guide to Dependency Injection Using Unity. Unity (not Unity3d :P) is part of Microsoft's .Net framework and it has containers already implemented to permit Dependency Injection. And if you don't want to use Microsoft's Unity, reading this guide will be useful to you understand how dependency injection could be implemented using C# with some good practices, and so you can implement your own DI containers and providers. I hope I helped you.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image segment · Jan 02, 2015 at 12:43 PM 0
Share

I heard about it. But can I use it within Unity engine projects?

avatar image danvalho · Jan 07, 2015 at 05:10 PM 0
Share

I think it is a good resource for you to understand DI. But if you want to use a DI framework alongside with unity3d, you can check an existent one like Strange

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

3 People are following this question.

avatar image avatar image avatar image

Related Questions

Zenject injecting upon instantiation 1 Answer

Interface vs Base Class [C# Code Architecture Problem] 1 Answer

Is there an elegant way to having single-player class methods within a multiplayer class? 1 Answer

An OS design issue: File types associated with their appropriate programs 1 Answer

Push GUI button, change another objects variable 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges