基于MVC+DoTween实现一个卷轴登录效果

一、引言

       在软件开发领域,设计模式是我们构建可维护、可扩展代码的重要指导原则之一。然而,MVC(Model-View-Controller)并非Gang of Four(GoF)总结的经典 23 种设计模式之一,所以确切说MVC不是一个设计模式,而是多种设计模式的组合。在MVC中,我们可以观察到类似于观察者模式、策略模式等设计模式的思想,MVC是一种思想或者软件架构模式。

二、MVC架构模式

       MVC模式是一种将应用程序分为三个独立组件的软件架构模式。这三个组件分别是:

  • 模型(Model): 负责应用程序的数据和业务逻辑。模型处理数据的获取、存储和处理,同时包含业务规则和逻辑。

  • 视图(View): 负责展示模型的数据,以用户友好的方式呈现。视图是用户与应用程序交互的界面,负责接收用户输入并将其传递给控制器。

  • 控制器(Controller): 充当模型和视图之间的协调者,处理用户的输入并更新模型和视图。控制器接收用户输入,调用模型进行相应的处理,然后更新视图以反映最新的数据状态。

       MVC的灵感来自多种设计原则,如分离关注点、模块化和松耦合等,使得每个组件可以相对独立地进行开发、测试和维护。

三、MVC的业务流程

       MVC的业务流程通常包括以下几个步骤:

  1. 用户输入: 用户与视图进行交互,通过用户输入触发事件。

  2. 控制器响应: 控制器接收用户输入事件,并根据业务逻辑调用相应的模型进行处理。

  3. 模型处理: 模型处理控制器传递过来的请求,执行相应的业务逻辑,可能涉及数据的增删改查等操作。

  4. 更新视图: 模型处理完成后,通知控制器数据的变化,控制器负责更新视图以展示最新的数据状态。

  5. 用户反馈: 视图更新后,用户可以看到相应的变化,并再次与视图进行交互。

       这个业务流程形成了一个闭环,用户的每一次操作都会触发MVC中的一系列动作,保持应用程序的稳定和响应。

四、 DoTween简介

        DoTween(DOTween)是一个用于Unity游戏引擎的强大的动画插值库。它提供了简单而强大的方式来创建平滑、高效的动画效果,包括对象的移动、旋转、缩放以及颜色等属性的变化。

1. 特性与优势
1.1 简单易用

        DoTween通过链式调用的方式,使得动画的创建和管理变得非常直观和简便。这种方式允许您在一行代码中定义多个动画效果。

1.2 高性能

        DoTween被设计为高性能的动画引擎,采用了一些优化技术,使得动画在运行时能够保持平滑且效率高。

1.3 支持多种属性

       除了基本的位移、旋转和缩放,DoTween还支持颜色渐变、透明度变化等多种属性的动画效果。

1.4 缓动函数

      DoTween内置了大量的缓动函数(easing functions),用于定义动画的变化速度曲线,从而创建更加生动和自然的动画效果。

五、基于MVC+DoTween来实现登录注册功能

下面我将用DoTween这个UI插件基于MVC的思想来实现一个卷轴效果的登入注册效果。以便更好的理解MVC以及DoTween的具体使用。以下是三个层的脚本类

1.制作UI

1.1. 创建一个名为EnterPanel的Panel物体,在该物体下面创建一个名为juanzhou的空物体,在该空物体上添加一个Horizontal Layout Group组件并修改参数

1.2. 在juanzhou物体下创建3个Image组件物体,分别作为卷轴的两个轴以及轴面。

1.3. 分别调整各种为合适大小 ,轴面需要添加一个Mask遮罩

1.4. 登录、注册、修改密码UI在卷轴中部分内

后面的那些组件的制作我就不再赘述,大家自行创建就好,主要就是上面的卷轴UI制作。

2.代码实现
2.1. 模型层
using System.Collections;
using System.Collections.Generic;
using Mr.Le.Utility.Manager;
using UnityEngine;

namespace MVC.Model
{
    public static class LoginModel
    {
        private static Dictionary<string, UserData> userData;
        public static string dataFilePath;

        static LoginModel()
        {
            userData = new Dictionary<string, UserData>();
            dataFilePath = "userData";
            if (JsonManager.Instance.LoadData<Dictionary<string, UserData>>(dataFilePath) != null)
            {
                userData = JsonManager.Instance.LoadData<Dictionary<string, UserData>>(dataFilePath);
            }
        }

        /// <summary>
        /// 检查用户名是否存在
        /// </summary>
        /// <param name="username"></param>
        /// <returns></returns>
        public static bool CheckUsernameExists(string username, AccountType accountType)
        {
            if (userData != null)
            {
                if (userData.ContainsKey(username) && userData[username].AccountType == accountType)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 检查明用户密码是否正确
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static bool CheckPassword(string username, string password, AccountType accountType)
        {
            if (userData.ContainsKey(username) && userData[username].AccountType == accountType)
            {
                return userData[username].Password == password;
            }

            return false;
        }

        /// <summary>
        /// 注册账号
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="securityQuestion"></param>
        /// <param name="securityAnswer"></param>
        public static void RegisterUser(string username, string password, string securityQuestion, string securityAnswer, AccountType accountType)
        {
            UserData newUser = new UserData();
            newUser.Password = password;
            newUser.SecurityQuestion = securityQuestion;
            newUser.SecurityAnswer = securityAnswer;
            newUser.AccountType = accountType;

            userData[username] = newUser;
            JsonManager.Instance.SaveData(userData, dataFilePath);
        }

        /// <summary>
        /// 检查密保答案是否正确
        /// </summary>
        /// <param name="username"></param>
        /// <param name="securityAnswer"></param>
        /// <returns></returns>
        public static bool CheckSecurityAnswer(string username, string securityQuestion, string securityAnswer, AccountType accountType)
        {
            if (userData.ContainsKey(username) && userData[username].AccountType == accountType)
            {
                return userData[username].SecurityQuestion == securityQuestion &&
                       userData[username].SecurityAnswer == securityAnswer;
            }

            return false;
        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="username"></param>
        /// <param name="newPassword"></param>
        public static void ResetPassword(string username, string newPassword, AccountType accountType)
        {
            if (userData.ContainsKey(username) && userData[username].AccountType == accountType)
            {
                userData[username].Password = newPassword;
                JsonManager.Instance.SaveData(userData, dataFilePath);
            }
        }
    }

    //用户类型
    public enum AccountType
    {
        Common, //普通用户
        Admin //管理员
    }

    [System.Serializable]
    public class UserData
    {
        public string Password;
        public string SecurityQuestion;
        public string SecurityAnswer;
        public AccountType AccountType;
    }
}
2.2. 控制层

这里也可以采用观察者设计模式的事件管理器将方法监听,然后在视图层去调用

using System.Text.RegularExpressions;
using Mr.Le.Utility.Manager;
using MVC.Model;
using MVC.View;
using UnityEngine;

namespace MVC.Controller
{
    public class LoginController : MonoBehaviour
    {
        private LoginView _loginView;
        private RegisterView _registerView;
        private ResetPasswordView _resetPasswordView;

        [SerializeField] private GameObject LoginPanel, RegisterPanel, ResetPasswordPanel;

        #region Common

        private void Awake()
        {
            _loginView = GetComponentInChildren<LoginView>();
        }

        #endregion

        #region 登录控制公共函数

        /// <summary>
        /// 登录控制
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="accountType"></param>
        public void Login(string username, string password, AccountType accountType)
        {
            bool isUsernameCorrect = LoginModel.CheckUsernameExists(username, accountType);

            if (string.IsNullOrEmpty(username))
            {
                _loginView.HintMessage("请输入用户名!");
            }
            else if (string.IsNullOrEmpty(password))
            {
                _loginView.HintMessage("请输入密码!");
            }
            else
            {
                if (isUsernameCorrect)
                {
                    if (LoginModel.CheckPassword(username, password, accountType))
                    {
                        if (accountType == AccountType.Common)
                        {
                            _loginView.HintMessage(accountType + "用户登录成功!");
                        }
                        else if (accountType == AccountType.Admin)
                        {
                            _loginView.HintMessage(accountType + "管理员登录成功!");
                        }
                    }
                    else
                    {
                        _loginView.HintMessage("密码错误!");
                    }
                }
                else
                {
                    _loginView.HintMessage("用户名不存在,请注册!");
                }
            }
        }

        /// <summary>
        /// 注册控制
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="securityQuestion"></param>
        /// <param name="securityAnswer"></param>
        /// <param name="accountType"></param>
        public void Register(string username, string newPassword, string surePassword, string securityQuestion,
            string securityAnswer, AccountType accountType)
        {
            _registerView = GetComponentInChildren<RegisterView>();
            if (string.IsNullOrEmpty(username))
            {
                _registerView.HintMessage("用户名不能为空!");
            }
            else if (string.IsNullOrEmpty(newPassword))
            {
                _registerView.HintMessage("请设置密码!");
            }
            else if (string.IsNullOrEmpty(surePassword))
            {
                _registerView.HintMessage("确认密码不能为空!");
            }
            else if (string.IsNullOrEmpty(securityQuestion))
            {
                _registerView.HintMessage("请选择密保问题!");
            }
            else if (string.IsNullOrEmpty(securityAnswer))
            {
                _registerView.HintMessage("密保答案不能为空!");
            }
            else
            {
                if (username.Length > 10)
                {
                    _registerView.HintMessage("用户名位数不能大于10个字符!");
                }
                else if (!newPassword.Equals(surePassword))
                {
                    _registerView.HintMessage("两次密码不一致!");
                }
                else
                {
                    Regex pattern = new Regex(@"^(?=.*[A-Za-z])(?=.*d)[A-Za-zd]{8,}$");
                    Match match = pattern.Match(newPassword);
                    if (match.Success)
                    {
                        if (LoginModel.CheckUsernameExists(username, accountType))
                        {
                            _registerView.HintMessage("用户名已存在,请尝试其他用户名!");
                        }
                        else
                        {
                            LoginModel.RegisterUser(username, newPassword, securityQuestion, securityAnswer,
                                accountType);
                            _registerView.HintMessage("账号创建成功,请登录!");
                        }
                    }
                    else
                    {
                        _registerView.HintMessage("密码至少8个字符,包含1个大写字母,1个小写字母和1个数字,不能包含特殊字符(非数字字母)");
                    }
                }
            }
        }

        /// <summary>
        /// 忘记密码控制
        /// </summary>
        /// <param name="username"></param>
        /// <param name="securityQuestion"></param>
        /// <param name="securityAnswer"></param>
        /// <param name="accountType"></param>
        /// <param name="newPassword"></param>
        public void ForgetPassword(string username, string securityQuestion, string securityAnswer,
            AccountType accountType, string newPassword, string surePassword)
        {
            _resetPasswordView = GetComponentInChildren<ResetPasswordView>();
            if (string.IsNullOrEmpty(username))
            {
                _resetPasswordView.HintMessage("请输入用户名!");
            }
            else if (string.IsNullOrEmpty(securityQuestion))
            {
                _resetPasswordView.HintMessage("请选择密保问题!");
            }
            else if (string.IsNullOrEmpty(securityAnswer))
            {
                _resetPasswordView.HintMessage("请输入密码答案!");
            }
            else if (!newPassword.Equals(surePassword))
            {
                _resetPasswordView.HintMessage("两次密码不一致!");
            }
            else
            {
                if (LoginModel.CheckUsernameExists(username, accountType))
                {
                    if (LoginModel.CheckSecurityAnswer(username, securityQuestion, securityAnswer,
                            accountType))
                    {
                        Regex pattern = new Regex(@"^(?=.*[A-Za-z])(?=.*d)[A-Za-zd]{8,}$");
                        Match match = pattern.Match(newPassword);
                        if (match.Success)
                        {
                            //执行重置密码操作
                            LoginModel.ResetPassword(username, newPassword, accountType);
                            _resetPasswordView.HintMessage("密码修改成功!");
                        }
                        else
                        {
                            _resetPasswordView.HintMessage("密码至少8个字符,包含1个大写字母,1个小写字母和1个数字,不能包含特殊字符(非数字字母)");
                        }
                    }
                    else
                    {
                        _resetPasswordView.HintMessage("该密保问题或答案有误!");
                    }
                }
                else
                {
                    _resetPasswordView.HintMessage("该用户名不存在!");
                }
            }
        }

        #endregion


        #region 外部访问接口

        public GameObject GetLoginPanel() => LoginPanel;
        public GameObject GetRegisterPanel() => RegisterPanel;
        public GameObject GetResetPasswordPanel() => ResetPasswordPanel;

        #endregion
    }
}
2.3. 视图层
2.3.1. 登录
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using MVC.Model;
using MVC.Controller;
using DG.Tweening;
using Mr.Le.Utility.Manager;

namespace MVC.View
{
    /// <summary>
    /// 登录面板视图层
    /// </summary>
    public class LoginView : MonoBehaviour
    {
        [SerializeField] private TMP_InputField usernameInput, passwordInput;
        [SerializeField] private Button enterBtn, registerBtn, forgetPasswordBtn;
        [SerializeField] private Toggle userSelect, adminSelect, isShowPassword;
        [SerializeField] private TMP_Text messageText;

        [SerializeField] private GameObject infomationCavans_Obj;
        private LoginController _loginController;

        private AccountType _accountType;

        #region Common

        private void Awake()
        {
            _loginController = GetComponentInParent<LoginController>();
            passwordInput.inputType = TMP_InputField.InputType.Password;
            userSelect.isOn = true;
        }

        private void Start()
        {
            enterBtn.onClick.AddListener(OnLoginBtn);
            isShowPassword.onValueChanged.AddListener(OnShowPasswordChanged);
            registerBtn.onClick.AddListener(OnRegisterBtn);
            forgetPasswordBtn.onClick.AddListener(OnForgetPasswordBtn);
        }

        #endregion

        #region 按钮监听

        private void OnShowPasswordChanged(bool showPassword)
        {
            if (showPassword)
            {
                passwordInput.inputType = TMP_InputField.InputType.Password;
                passwordInput.Select();
                passwordInput.ActivateInputField();
            }
            else
            {
                passwordInput.inputType = TMP_InputField.InputType.Standard;
                passwordInput.Select();
                passwordInput.ActivateInputField();
            }
        }

        private void OnLoginBtn()
        {
            string username = usernameInput.text;
            string password = passwordInput.text;

            if (userSelect.isOn)
            {
                _accountType = AccountType.Common;
                _loginController.Login(username, password, _accountType);
            }
            else if (adminSelect.isOn)
            {
                _accountType = AccountType.Admin;
                _loginController.Login(username, password, _accountType);
            }
        }

        private void OnRegisterBtn()
        {
            //DoTween控制卷轴
            infomationCavans_Obj.GetComponent<RectTransform>().DOSizeDelta(new Vector2(0, 514), 1.5f).OnComplete(() =>
            {
                infomationCavans_Obj.GetComponent<RectTransform>().DOSizeDelta(new Vector2(825, 514), 3f);
                //隐藏登录面板
                this.gameObject.SetActive(false);
                //打开注册面板
                _loginController.GetRegisterPanel().SetActive(true);
            });
        }

        private void OnForgetPasswordBtn()
        {
            //DoTween控制卷轴
            infomationCavans_Obj.GetComponent<RectTransform>().DOSizeDelta(new Vector2(0, 514), 1.5f).OnComplete(() =>
            {
                infomationCavans_Obj.GetComponent<RectTransform>().DOSizeDelta(new Vector2(825, 514), 3f);
                //隐藏登录面板
                this.gameObject.SetActive(false);
                //打开重置密码面板
                _loginController.GetResetPasswordPanel().SetActive(true);
            });
        }

        #endregion

        public void HintMessage(string message)
        {
            messageText.text = message;
            TimerManager.Instance.GetOneTimer(2f, () =>
            {
                messageText.text = "";
            });
        }
    }

}
2.3.2. 注册
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using MVC.Controller;
using MVC.Model;
using DG.Tweening;
using Mr.Le.Utility.Manager;

namespace MVC.View
{
    /// <summary>
    /// 登录面板视图层
    /// </summary>
    public class RegisterView : MonoBehaviour
    {
        [SerializeField] private TMP_InputField usernameInput, NewPasswordInput, SurePasswordInput, SecurityAnswerInput;
        [SerializeField] private Button backBtn, registerBtn;
        [SerializeField] private Toggle userSelect, adminSelect, isShowPassword;
        [SerializeField] private TMP_Dropdown securityQuestionDropdown;
        [SerializeField] private TMP_Text messageText;

        [SerializeField] private GameObject infomationCavans_Obj;
        private LoginController _loginController;

        private AccountType _accountType;
        private string selectedOptionText;

        #region Common

        private void Awake()
        {
            _loginController = GetComponentInParent<LoginController>();
            NewPasswordInput.inputType = TMP_InputField.InputType.Password;
            SurePasswordInput.inputType = TMP_InputField.InputType.Password;
            userSelect.isOn = true;
        }

        private void Start()
        {
            backBtn.onClick.AddListener(() =>
            {
                //DoTween控制卷轴
                infomationCavans_Obj.GetComponent<RectTransform>().DOSizeDelta(new Vector2(0, 514), 1.5f).OnComplete(() =>
                {
                    infomationCavans_Obj.GetComponent<RectTransform>().DOSizeDelta(new Vector2(825, 514), 3f);
                    this.gameObject.SetActive(false);
                    _loginController.GetLoginPanel().SetActive(true);
                });
            });
            isShowPassword.onValueChanged.AddListener(OnShowPasswordChanged);
            registerBtn.onClick.AddListener(OnRegisterBtn);
            securityQuestionDropdown.onValueChanged.AddListener(OnsecurityQuestionDropdown);
        }

        #endregion

        #region 按钮监听

        private void OnsecurityQuestionDropdown(int value)
        {
            selectedOptionText = securityQuestionDropdown.options[value].text;
        }

        private void OnShowPasswordChanged(bool showPassword)
        {
            if (showPassword)
            {
                NewPasswordInput.inputType = TMP_InputField.InputType.Password;
                SurePasswordInput.inputType = TMP_InputField.InputType.Password;
                NewPasswordInput.Select();
                NewPasswordInput.ActivateInputField();
                SurePasswordInput.Select();
                SurePasswordInput.ActivateInputField();
            }
            else
            {
                NewPasswordInput.inputType = TMP_InputField.InputType.Standard;
                SurePasswordInput.inputType = TMP_InputField.InputType.Standard;
                NewPasswordInput.Select();
                NewPasswordInput.ActivateInputField();
                SurePasswordInput.Select();
                SurePasswordInput.ActivateInputField();
            }
        }

        private void OnRegisterBtn()
        {
            string username = usernameInput.text;
            string newPassword = NewPasswordInput.text;
            string surePassword = SurePasswordInput.text;
            string securityQuestion = selectedOptionText;
            string securityAnswer = SecurityAnswerInput.text;

            if (userSelect.isOn)
            {
                _accountType = AccountType.Common;
                _loginController.Register(username, newPassword, surePassword, securityQuestion, securityAnswer, _accountType);
            }
            else if (adminSelect.isOn)
            {
                _accountType = AccountType.Admin;
                _loginController.Register(username, newPassword, surePassword, securityQuestion, securityAnswer, _accountType);
            }
        }

        #endregion

        public void HintMessage(string message)
        {
            messageText.text = message;
            TimerManager.Instance.GetOneTimer(1f, () =>
            {
                messageText.text = "";
            });
        }
    }
}
2.3.3. 修改密码
using System;
using System.Collections;
using System.Collections.Generic;
using MVC.Controller;
using MVC.Model;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using DG.Tweening;
using Mr.Le.Utility.Manager;

namespace MVC.View
{
    public class ResetPasswordView : MonoBehaviour
    {
        [SerializeField] private TMP_InputField usernameInput, NewPasswordInput, SurePasswordInput, SecurityAnswerInput;
        [SerializeField] private Button backBtn, resetBtn;
        [SerializeField] private Toggle userSelect, adminSelect, isShowPassword;
        [SerializeField] private TMP_Dropdown securityQuestionDropdown;
        [SerializeField] private TMP_Text messageText;

        private LoginController _loginController;
        [SerializeField] private GameObject infomationCavans_Obj;

        private AccountType _accountType;
        private string selectedOptionText;

        #region Common

        private void Awake()
        {
            _loginController = GetComponentInParent<LoginController>();
            NewPasswordInput.inputType = TMP_InputField.InputType.Password;
            SurePasswordInput.inputType = TMP_InputField.InputType.Password;
            userSelect.isOn = true;
        }

        private void Start()
        {
            backBtn.onClick.AddListener(() =>
            {
                infomationCavans_Obj.GetComponent<RectTransform>().DOSizeDelta(new Vector2(0, 514), 1.5f).OnComplete(() =>
                {
                    infomationCavans_Obj.GetComponent<RectTransform>().DOSizeDelta(new Vector2(825, 514), 3f);
                    this.gameObject.SetActive(false);
                    _loginController.GetLoginPanel().SetActive(true);
                });
            });
            isShowPassword.onValueChanged.AddListener(OnShowPasswordChanged);
            resetBtn.onClick.AddListener(OnResetBtn);
            securityQuestionDropdown.onValueChanged.AddListener(OnsecurityQuestionDropdown);
        }

        #endregion

        #region 按钮监听

        private void OnShowPasswordChanged(bool showPassword)
        {
            if (showPassword)
            {
                NewPasswordInput.inputType = TMP_InputField.InputType.Password;
                SurePasswordInput.inputType = TMP_InputField.InputType.Password;
                NewPasswordInput.Select();
                NewPasswordInput.ActivateInputField();
                SurePasswordInput.Select();
                SurePasswordInput.ActivateInputField();
            }
            else
            {
                NewPasswordInput.inputType = TMP_InputField.InputType.Standard;
                SurePasswordInput.inputType = TMP_InputField.InputType.Standard;
                NewPasswordInput.Select();
                NewPasswordInput.ActivateInputField();
                SurePasswordInput.Select();
                SurePasswordInput.ActivateInputField();
            }
        }

        private void OnsecurityQuestionDropdown(int value)
        {
            selectedOptionText = securityQuestionDropdown.options[value].text;
        }
        private void OnResetBtn()
        {
            string username = usernameInput.text;
            string newPassword = NewPasswordInput.text;
            string surePassword = SurePasswordInput.text;
            string securityQuestion = selectedOptionText;
            string securityAnswer = SecurityAnswerInput.text;

            if (userSelect.isOn)
            {
                _accountType = AccountType.Common;
                _loginController.ForgetPassword(username, securityQuestion, securityAnswer, _accountType, newPassword, surePassword);
            }
            else if (adminSelect.isOn)
            {
                _accountType = AccountType.Admin;
                _loginController.ForgetPassword(username, securityQuestion, securityAnswer, _accountType, newPassword, surePassword);
            }

            usernameInput.text = "";
            NewPasswordInput.text = "";
            SurePasswordInput.text = "";
            SecurityAnswerInput.text = "";
        }

        #endregion

        public void HintMessage(string message)
        {
            messageText.text = message;
            TimerManager.Instance.GetOneTimer(1f, () =>
            {
                messageText.text = "";
            });
        }
    }
}
3.挂载对应脚本

4.调用

EnterPanel面板

using Mr.Le.Utility.Manager;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

namespace Mr.Le.Utility.UI
{
    public class LoginPanel : PanelBase
    {
        private Button button;
        protected override void Init()
        {
            button = GetController<Button>("switchButton");
            button.onClick.AddListener(SwitchButtonClick);
        }

        private void SwitchButtonClick()
        {
            UIManager.Instance.ShowPanel<GamePanel>(PanelShowLayer.Middle, Ani.Fade);
            UIManager.Instance.HidePanel<LoginPanel>(Ani.Fade, () =>
            {
                Debug.LogFormat("隐藏{0}完毕!", gameObject.name);
            });
        }
    }
}

Main脚本调用

using Mr.Le.Utility.Manager;
using UnityEngine;

public class Main : MonoBehaviour
{
    private void Awake()
    {
        UIManager.Instance.ShowPanel<EnterPanel>();
    }
}

六、实现效果

<iframe id="NsTzfaDL-1705840313178" frameborder="0" src="//i2.wp.com/live.csdn.net/v/embed/360832" allowfullscreen="true" data-mediaembed="csdn"></iframe>

基于MVC+DoTween实现卷轴登录注册效果

源码链接:https://pan.baidu.com/s/1iHcGB2VKzYKDgyS_l8C8UQ?pwd=89mn 
提取码:89mn 

七、总结

       以上就是基于MVC+DoTween实现一个卷轴效果的登录注册功能的全部内容,希望本文能够帮助大家更清晰的了解MVC思想的架构模式。如果有任何疑问或建议,欢迎留言交流!