Take you to develop the orange light game AVG framework from scratch (imitation funeral flower)

source

Take you to develop the orange light game AVG framework from scratch [55 lessons are charged]
Take you to develop the orange light game AVG framework unity tutorial from scratch [16 lessons are free]

introduce

QuickSheet uses

bug package error

It may be the reason why I changed the untiy version
Manual sovle
insert image description here

Duplicate bug ICSharpCode.SharpZipLib

Imported a folder, has its own library, also contains GameFramework, UnityGameFramework, temporarily delete GameFramework, UnityGameFramework and it’s over

bug Chinese garbled characters

VS (Visual Studio) changed the file encoding.
It was modified before changing utf-8, and it was useless to change it to utf-8.
It is also useless to pull out these garbled characters from the compressed package to overwrite them.

stars No parameter event registration

/// <summary>存档,确定取消</summary>
public class EnterBtn : MonoBehaviour, IPointerDownHandler, IPointerEnterHandler
{
    
    
	public AudioSource EnterMusic;//悬停音效
	public AudioSource DownMusic;//点击音效

	private void Start()
	{
    
    
		EnterMusic = gameObject.FindComponentWithTag<AudioSource>(Tags.ENTERMUSIC);
		DownMusic = gameObject.FindComponentWithTag<AudioSource>(Tags.DOWNMUSIC);
	}
	/// <summary>
	/// 获得标签为 tag 的 物体 身上的 T 组件
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="go"></param>
	/// <param name="tag"></param>
	/// <returns></returns>
	/// <exception cref="System.Exception"></exception>
	public static T FindComponentWithTag<T>(this GameObject go, string tag) where T : Component
	{
    
    
		T res=	GameObject.FindGameObjectWithTag(tag).GetComponent<T>();
		if (res == null)
		{
    
    
			throw new System.Exception("异常");
		}

		return res;
	}

modify will start the code for the game interface. Detach from UIManager

Just this structure
GameStart
UIMgr etc. Mgr
Canvas
Panel

modify GamStart.cs

:MonoBehaviour is used as the game entry, used to control the sequence of scripts and store scripts.

--------------------------------------------------

modify CameraPos.cs

insert image description here

GameStart

/****************************************************
    文件:GameStart.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/14 19:58:55
	功能:游戏入口
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
 

    public class GameStart : MonoBehaviour
    {
    
    
		#region 字段
		AudioMgr audioMgr;

        #endregion

        #region 生命
        void Start()
        {
    
    
			GameObject.FindGameObjectWithTag(Tags.MAINCAMERA).AddComponent<CameraPos>().Init();
			//audioMgr.Init();
        }

CameraPos

/****************************************************

	文件:
	作者:WWS
	日期:2023/04/14 20:10:21
	功能:看起来有摇晃感

*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;



public class CameraPos : MonoBehaviour
{
    
    
    public float X;
    public float speed;//速度 鼠标移动
    public float rotateX;


	public	void Init()
	{
    
    
		speed = 0.5f;
	}


	void Update()
    {
    
    
        X = Input.GetAxis(Constants.Mouse_X);   //获得鼠标左右旋转的值
        rotateX += X * speed;       //乘以速度
		//Mathf.Clamp,就是说把一个数值规定在 X 和 Y 的数值之间
        X = Mathf.Clamp( rotateX, -5,5);      
        transform.eulerAngles = new Vector3(0,X,0);
    }
}

Tags

/****************************************************
    文件:Tags.cs
	作者:lenovo
    邮箱: 
    日期:2022/7/15 12:57:58
	功能:
*****************************************************/


public static class Tags
{
    
    
    public const string MAINCAMERA = "MainCamera";

modify LoadCGMgr.cs

The method of accessing the parent node by the child node is not completed, and the event registration is used to import QFramework

QFramework is part of the code I made following the third version of QFramework video, which includes event registration, and the keywords are Register, UnRegister, Event, Command
. . . .
Clicking the two buttons will call the method of playing different sound effects on the confirmation panel.
It can be run through with QFramework
. . . .
Calling sequence
GameStart
EnterCanvas
EnterPanel
EnterBtn
where EnterPanel is the parent node below and EnterBtn is the child node below

insert image description here

New Event

/****************************************************
    文件:OverButtonEvent.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/15 0:22:20
	功能:QFramework 第三版本 的事件
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
 
public class OverButtonEvent : Event<OverButtonEvent>
{
    
    

}

Parent node registers and calls Event

/****************************************************
    文件:EnterPanel.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/14 23:49:34
	功能:
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;


public class EnterPanel : MonoBehaviour
{
    
    
	#region 字段

	/// <summary>悬停音效</summary>
	public AudioSource EnterMusic;
	/// <summary>点击音效</summary>
	public AudioSource DownMusic;
	#endregion

	#region 生命	
   	
	public void Init()
	{
    
    
		EnterMusic = gameObject.FindComponentWithTag<AudioSource>(Tags.ENTERMUSIC);
		DownMusic = gameObject.FindComponentWithTag<AudioSource>(Tags.DOWNMUSIC);

		OverButtonEvent.Register(PlayEnterMusic);
		ClickButtonEvent.Register(PlayDownMusic);
	}

	private void OnDestroy()
	{
    
    
		OverButtonEvent.UnRegister(PlayEnterMusic);
		ClickButtonEvent.UnRegister(PlayDownMusic);
	}
	#endregion

	#region 系统

	#endregion

	#region 辅助


	public void PlayEnterMusic()
	{
    
    
		EnterMusic.Play();
	}

	public void PlayDownMusic()
	{
    
    
		DownMusic.Play();
	}
	#endregion
}

Create a new Command corresponding to the Event, and insert the Event into the Command

/****************************************************
    文件:OverButtonEvent.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/15 0:22:20
	功能:QFramework 第三版本 的事件
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;


public class ClickButtonCommand : ICommand
{
    
    
	public void Execute()
	{
    
    
		ClickButtonEvent.Trigger();
	}
}

The child node calls the Command

using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.EventSystems;


/// <summary>存档,确定取消</summary>
public class EnterBtn : MonoBehaviour, IPointerDownHandler, IPointerEnterHandler
{
    
    
	#region 系统


	public void OnPointerDown(PointerEventData eventData)
    {
    
    
		new ClickButtonCommand().Execute();
    }


    public void OnPointerEnter(PointerEventData eventData)
    {
    
    
		new OverButtonCommand().Execute();
	}
    #endregion

}

stars support Chinese

Support Chinese, try it first

using System;

public static class ResourcesName
{
    
    
    public const string Sprites_丹药 = "Sprites/WindowIMG/丹药";
    public const string Sprites_五彩石 = "Sprites/WindowIMG/五彩石";

The bug script name and node name do not correspond as much as possible

single access parameter across parent nodes between bug scripts

Modify Tag's AVGPolt to PoltCanvas

Convenience script name, label name, node name, the correspondence between the three
insert image description here

The bug changed the label Polt to Plot

insert image description here
insert image description here

watch tagged CG

Similar to AVG/MainCanvas/LoadCGPoltPanel/BG/CG Appreciation/ObjectPanel/PolePre/PoltBG/Polt

modify New script LoadCGPlotPanel.cs

The location is AVG/MainCanvas/LoadCGPlotPanel

modify filter card

modify AudioMgr.cs

AudioMgr.cs singleton, and hang on the child node of GameStart, and adjust the related references
insert image description here

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AudioMgr : MonoBehaviour
{
    
    
    public List<AudioClip> AudioList;  //音频播放的数组
    public AudioSource audioSrc;  //音频播放的组件

	#region 单例
	private static AudioMgr _instance;

	public static AudioMgr Instance
	{
    
    
		get
		{
    
    
			return _instance;
		}

		set
		{
    
    
			_instance = value;
		}
	}

	#endregion

	public void Init()
	{
    
    
	   	Instance = this;
		AudioList=new List<AudioClip>(6);
		AudioList.Add( LoadAudioClip("RPGBG") );
		AudioList.Add( LoadAudioClip("4_孤独之路") );
		AudioList.Add( LoadAudioClip("5_花散曲终") );
		AudioList.Add( LoadAudioClip("20絶体絶命の曲") );
		AudioList.Add( LoadAudioClip("zh05_燃血之时") );
		AudioList.Add( LoadAudioClip("zh08_狂乱之宴") );
	}

	/// <summary>播放音频</summary>
	public void PlayMusic(int id) 
	{
    
    
        
        audioSrc.clip = AudioList[id]; 
        audioSrc.Play();  
    }


	/// <summary>停止播放播放音频</summary>
	public void StopMusic() 
	{
    
    
        audioSrc.Stop();  
    }

	AudioClip LoadAudioClip(string name)
	{
    
    
		 AudioClip audioClip = Resources.Load<AudioClip>("Music/" + name);
		if (audioClip == null)
		{
    
    
			throw new System.Exception("异常");
		}
		return audioClip;
	}
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;


public class GameStart : MonoBehaviour
{
    
    
	#region 字段


	public AudioMgr audioMgr;
	......
	#endregion

	#region 生命
	void Start()
	{
    
    
		......
		//
		audioMgr=GetComponentInChildren<AudioMgr>();
		audioMgr.Init();

bug IsUsingDeformableBuffer

unity ‘SpriteRenderer’ does not contain a definition for ‘IsUsingDeformableBuffer’ and no accessible extension method ‘IsUsingDeformableBuffer’ accepting a first argument of type ‘SpriteRenderer’ could be found (are you missing a using

Unity spriteRenderer error what i need to do?
I am 2020.3.23fc1, tried 2 to no avail, tried 1, it worked, no error was reported, but 2D Sprite is estimated to be used, and an error will be reported later before installation
insert image description here

modify AudioSource与AudioMgr

01 Put all AudioSources on the sub-nodes of AudioMgr, and renamed 3.
After 02, the AudioSource on the node AVG is moved to the child node AVGSrc of AudioMgr.
03 Similar to AVG/MainCanvas/LoadCGPlotPanel/BG/Music Appreciation/BGMusic, there is also an AudioSource

It is not clear why so many AudioSources are used, and a dictionary should be used for memory. (Need to be placed at the same time?)
The original version is placed on the SettingPanel
insert image description here

watch SettingPanel is related to the volume

That is, to do a good job in the relationship between SettingPanel and AudioMgr
is to put the relevant code in AudioMgr and let the SettingPanel call (Slider)
insert image description here

modify EnterPanel calls AudioSource through AudioMgr

The previous EnterPanel used these two AudioSources, and put them on AudioMgr, and called them by accessing AudioMgr. Renamed
to EnterBtnSrc, DownBtnSrc, saving two Tags
insert image description here

Two AudioSource moves, renames, references and deletes Tags

insert image description here

EnterPanel call

/****************************************************
    文件:EnterPanel.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/14 23:49:34
	功能:
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;


public class EnterPanel : MonoBehaviour
{
    
    
	#region 生命	   	
	public void Init()
	{
    
    
		OverButtonEvent.Register(PlayEnterMusic);
		ClickButtonEvent.Register(PlayDownMusic);
	}


	private void OnDestroy()
	{
    
    
		OverButtonEvent.UnRegister(PlayEnterMusic);
		ClickButtonEvent.UnRegister(PlayDownMusic);
	}
	#endregion

	#region 系统

	#endregion

	#region 辅助
	public void PlayEnterMusic()
	{
    
    
		AudioMgr.Instance.EnterBtnSrc.Play();
	}

	public void PlayDownMusic()
	{
    
    
		AudioMgr.Instance.DownBtnSrc.Play();
	}
	#endregion
}

modify Split part of the code of UIMgr to EnterPanel

Scene into the game ---------------------------------

bug requires event registration for parameter passing

So I watched
the final version of framework construction: theory strengthening (third season) 53 lessons

top down

top-down approach

Bottom-up one delegation

Use delegates and events from the bottom up

The entrustment needs to be registered and unregistered.
There is a callback hell
to declare a delegate.
The disadvantage is that multiple child nodes need to access the parent node, and each child node must declare a delegate, which is troublesome.

Parent Node PlayerCtrl

namespace FrameworkDesign2021
{
    
    
    public class PlayerCtrl : MonoBehaviour
    {
    
    
        PlayerAnimationCtrl mAnimationCtrl;

        void Start()
        {
    
    
            mAnimationCtrl = transform.Find("Animation").GetComponent<PlayerAnimationCtrl>();

            // 注册完成的事件
            mAnimationCtrl.OnDoSomethingDone += OnDoSomethingDone;

            mAnimationCtrl.DoSomething();
        }
      
        void OnDoSomethingDone()
        {
    
    
            Debug.Log("动画播放完毕");
        }
      
        void OnDestroy()
        {
    
    
            // 注销完成的事件
            mAnimationCtrl.OnDoSomethingDone -= OnDoSomethingDone;
        }
    }
  
    ...
}

Child node PlayerAnimationCtrl



    public class PlayerAnimationCtrl : MonoBehaviour
    {
    
    
        // 定义委托
        public Action OnDoSomethingDone = ()=>{
    
    };

        public void DoSomething()
        {
    
    
            OnDoSomethingDone();
        }
    }
}

Interaction between event modules (Module layer)

Lift the restriction, use your own, you need to add small logic, it is a large-grained interaction with modules, and it is not suitable for small-grained interactions between objects

Interaction between command objects (Model layer)

with parameters
undo

bug found command with parameters

The bug canvas does not activate GetComonent

modify Change the event id of the UI to an enumeration to increase readability

/// <summary>
/// None=1,
/// QuitGame = 2,
/// ReturnMainPanel = 3,
/// SL = 5,
/// Loading = 6,
/// IsLoadPlotBack = 7,
/// IsLoadCG = 8,
/// </summary>
public enum EventID
{
    
    
	None = 1,
	QuitGame = 2,
	ReturnMainPanel = 3,
	/// <summary>存档</summary>
	SaveFile = 5,
	/// <summary>打开存档面板,常听的SL大法</summary>
	OpenSLPanel = 6,
	/// <summary>剧情</summary>
	LoadPlot = 7,
	/// <summary>CG(计算机动画)</summary>
	LoadCG = 8,

}

bug Google.GData.Client

Reference has errors 'Google.GData.Client'.
Unknown, inexplicably broken, okay

bug assembly reference missing

Originally all in the root directory
QFramework
QFrameworkData


If it is changed to Plugins/QFramework, an error will be reported, and QFrameworkData QFramework
QFrameworkData will always be generated in the root directory
insert image description here

modify AnimationEvent

I plan to take it out and put it under a folder AnimationEvent

bug TLS Allocator ALLOC_TEMP_THREAD

TLS Allocator ALLOC_TEMP_THREAD, underlying allocator ALLOC_TEMP_THREAD has unfreed allocations, size 40
Some threads have not been released
[Report All [useless]]](https://blog.csdn.net/wenshuai537/article/details/123558838)

bug Reference has errors ‘Google.GData.Client’.

Assembly ‘Assets/QuickSheet/GDataPlugin/Editor/Google/Google.GData.Extensions.dll’ will not be loaded due to errors:
Reference has errors ‘Google.GData.Client’.

It's gone after restarting the computer

bug Your own code base is suddenly not recognized by the CSharp project

01 I changed the using GameObject = UnityEngine.GameObject in the Component extension method;
02 Moved the QuickSheet to Plugins and reported an error; moved it out again, reported an error that the meta could not be found, restarted Unity and it was fine. 03 After restarting Unity
, it was fine if it was not recognized by the CSharp project

modify organizes animation events

Extract all animation events, name the script in the form of node name_animation name , and put it in a folder

As shown in the figure
01 Animation MainAnim has two events (that is, methods)
02 These two methods are placed in a script, and the name of the script is the name of the node to be linked_animation name
03 Mount the animation event script on the node
The original version puts all animation events in a script AnimManager. Animation events are 0 references, so it is difficult to manage.
insert image description here

bug animation events call certain property order

01 The animation event calls some properties.
02 The property is assigned in the Init() method
, but 01 is faster than 02, causing the property to be called before it is assigned a value.

So first of all, this is when learning RealFrame with Mr. Ocean from Siki Academy. Just wait for someone to work again
Crt is the English Coroutine of the coroutine, the abbreviation I chose

	/// <summary>关闭菜单按钮</summary>
	public void HideMainBtn()
	{
    
    
		StartCoroutine(HideMainBtnCrt());
		
	}


	IEnumerator HideMainBtnCrt()
	{
    
    
		while (UIMgr.Instance == null
			|| UIMgr.Instance.MainCanvas == null
			|| UIMgr.Instance.MainCanvas.MainPanel == null)//需要时间
		{
    
    
			yield return new WaitForEndOfFrame(); //等一帧 
		}

		UIMgr.Instance.MainCanvas.MainPanel.HideMainBtn();
	}

modify main interface button name

Animation name recognition [changed and turned yellow, unable to recognize] (this is not good, uuid should be recognized)
insert image description here

bug singleton is null

Click to start the game, it stands to reason that everything has been initialized at this time,
F5, and the Instance is empty
. . . .
MonoBehaviour cannot be used in the new way,
so use the following

using UnityEngine;


    public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
    {
    
    
        protected static T mInstance = null;

        public static T Instance
        {
    
    
            get
            {
    
    
                if (mInstance == null)
                {
    
    
                    mInstance = FindObjectOfType<T>();

                    if (FindObjectsOfType<T>().Length > 1)
                    {
    
    
                        Debug.LogWarning("More than 1");
                        return mInstance;
                    }

                    if (mInstance == null)
                    {
    
    
                        var instanceName = typeof(T).Name;
                        Debug.LogFormat("Instance Name: {0}", instanceName);
                        var instanceObj = GameObject.Find(instanceName);

                        if (!instanceObj)
                            instanceObj = new GameObject(instanceName);

                        mInstance = instanceObj.AddComponent<T>();
                        DontDestroyOnLoad(instanceObj); //保证实例不会被释放

                        Debug.LogFormat("Add New Singleton {0} in Game!", instanceName);
                    }
                    else
                    {
    
    
                        Debug.LogFormat("Already exist: {0}", mInstance.name);
                    }
                }

                return mInstance;
            }
        }

        protected virtual void OnDestroy()
        {
    
    
            mInstance = null;
        }
    }

insert image description here

stars SetActive()

Change a lot of SetActive() to Show() and Hide()

/****************************************************
    文件:ExtendComponent.ShowHide.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/22 15:32:47
	功能:QFramework第一季
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
 

public static partial class ExtendComponent 
{
    
    
	public static void Show(this GameObject gameObject)
	{
    
    
		gameObject.SetActive(true);
	}

	public static void Hide(this GameObject gameObject)
	{
    
    
		gameObject.SetActive(false);
	}

	public static void Show(this Transform transform)
	{
    
    
		transform.gameObject.SetActive(true);
	}

	public static void Hide(this Transform transform)
	{
    
    
		transform.gameObject.SetActive(false);
	}

	public static void Show(this MonoBehaviour monoBehaviour)
	{
    
    
		monoBehaviour.gameObject.SetActive(true);
	}

	public static void Hide(this MonoBehaviour monoBehaviour)
	{
    
    
		monoBehaviour.gameObject.SetActive(false);
	}

}



bug Unity is busy for a long time when it is running; unity suspendThread loop failed

Deadlock
Guess, the breakpoint is where mapping is used (one of my own methods that can get namespace, class name, and method name)

modify AVGMachine

Submerge the methods that can be submerged into each Manager, Canvas, and Panel.
For example, the parameters of a method are all in AudioMgr, directly mention this method to AudioMgr, and then call it indirectly

bug C# private is not displayed

C# private is not displayed for a while, and then it is displayed again

modify different node naming


The original version is named in AVGMainAnim.cs , and it is difficult to distinguish if the node is lost. (although there are comments)
insert image description here

watch main menu flower particles

/****************************************************

	文件:
	作者:WWS
	日期:2023/04/14 20:10:21
	功能:看起来有摇晃感

*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;



public class CameraPos : MonoBehaviour
{
    
    
    public float inputX;
    public float speed;//速度 鼠标移动
    public float rotateX;
    public GameObject Particle;


	public	void Init()
	{
    
    
		speed = 0.5f;
		Particle = gameObject.FindChildDeep("Particle");
		ShowParticle();
	}


	void Update()
    {
    
    
        inputX = Input.GetAxis(Constants.Mouse_X);   //获得鼠标左右旋转的值
        rotateX += inputX * speed;       //乘以速度
        inputX = Mathf.Clamp( rotateX, -5,5); 		//规定在 X 和 Y 的数值之间
        transform.eulerAngles = new Vector3(0,inputX,0);
    }


	void ShowParticle()
	{
    
    
		Particle.Show();
	}
}

insert image description here

bug UnityEditor.Graphs.Edge.WakeUp ()

Restart Unity, guess the compilation is not in time, it seems that there is no circle

NullReferenceException: Object reference not set to an instance of an object
UnityEditor.Graphs.Edge.WakeUp () (at <1bfd5359178446f5b1ac53f68c0a5db0>:0)
UnityEditor.Graphs.Graph.DoWakeUpEdges (System.Collections.Generic.List`1[T] inEdges, System.Collections.Generic.List`1[T] ok, System.Collections.Generic.List`1[T] error, System.Boolean inEdgesUsedToBeValid) (at <1bfd5359178446f5b1ac53f68c0a5db0>:0)
UnityEditor.Graphs.Graph.WakeUpEdges (System.Boolean clearSlotEdges) (at <1bfd5359178446f5b1ac53f68c0a5db0>:0)
UnityEditor.Graphs.Graph.WakeUp (System.Boolean force) (at <1bfd5359178446f5b1ac53f68c0a5db0>:0)
UnityEditor.Graphs.Graph.WakeUp () (at <1bfd5359178446f5b1ac53f68c0a5db0>:0)
UnityEditor.Graphs.Graph.OnEnable () (at <1bfd5359178446f5b1ac53f68c0a5db0>:0)

--------------------------------------------------

modify OK panel exits the game

Click the hover sound effect
The original version is to drag and drop the node directly, I changed the singleton, the front is registered with the event without parameters, learn to modify it together with the parameters

Panel main function

/****************************************************
    文件:EnterPanel.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/14 23:49:34
	功能:
*****************************************************/


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Random = UnityEngine.Random;


public class EnterPanel : MonoBehaviour	
{
    
    


	#region 字属


	 Button yesBtn;
	 Button noBtn;   //确认和取消两个按钮
	 Text contentText;
	 public GameObject EnterPanelGo;  //确认面板
	#endregion


	#region 生命	   	
	public void Init()
	{
    
    
		InitButton();
		EnterPanelGo = gameObject;
		contentText = gameObject.GetComponentDeep<Text>("ContentText");

	}

	void InitButton()
	{
    
     
	   	//以后采用事件注册
		//this.RegisterEvent<OverButtonEvent>( PlayEnterMusic);
		//this.RegisterEvent<ClickButtonEvent>(PlayDownMusic);
		yesBtn = gameObject.GetComponentDeep<Button>("YesBtn");
		noBtn = gameObject.GetComponentDeep<Button>("NoBtn");
		//
		//yesBtn.gameObject.GetComponent<EnterBtn>();	//mark
		yesBtn.onClick.AddListener( UIMgr.Instance.YesEvent );
		//
		//yesBtn.gameObject.GetComponent<EnterBtn>();
		noBtn.onClick.AddListener( NoEvent );

	}


	private void OnDestroy()
	{
    
    
	//	OverButtonEvent.UnRegister(PlayEnterMusic);
	//	ClickButtonEvent.UnRegister(PlayDownMusic);

	}
	#endregion

	#region 系统

	#endregion

	#region 辅助


	public void NoEvent()
	{
    
    
		Close();
	}


	/// <summary></summary>
	public void Close()
	{
    
    
		//当我们按下取消按钮之后
		//如果我们做动画了
		GetComponent<Animator>().SetBool(AnimatorPara.Quit, true);  
		//获得 确认面板上的动画控制器
		//如果我们没有做动画  只有面板
		//EnterObject.SetActive(false);   //隐藏确认面板
	}




	public void  SetContentText(string value)
	{
    
    
		contentText.text = value;
	}
	#endregion
}

Animation events on panels

/****************************************************
    文件:EnterPanel_EnterQuit.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/21 20:5:30
	功能:
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
 

public class EnterPanel_EnterQuit : MonoBehaviour
{
    
    


	#region 辅助
	/// <summary>退出确认面板  就是隐藏 确认面板</summary>
	public void QuitEnter()
	{
    
    
		UIMgr.Instance.EnterCanvas.Hide();
	}
	#endregion

}


button sound

Add to the following 4 buttons at the same time
insert image description here

using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.EventSystems;


/// <summary>存档,确定取消</summary>
public class EnterBtn : MonoBehaviour, IPointerDownHandler, IPointerEnterHandler
{
    
    
	#region 系统


	public void OnPointerDown(PointerEventData eventData)
    {
    
    
		//new ClickButtonCommand().Execute(); //无参成功,但是有参失败,所以暂时不用
		AudioMgr.Instance.PlayClickBtnMusic();
    }


    public void OnPointerEnter(PointerEventData eventData)
    {
    
    
		//new OverButtonCommand().Execute();
		AudioMgr.Instance.PlayHoverBtnMusic();
	}
    #endregion

}

Effect

insert image description here

The stars button monitors GetButtonDeep

Find the button named "ResetBtn" in the child node, add the ResetVolume event, and finally return the button

		ResetBtn = transform.GetButtonDeep("ResetBtn", ResetVolume);

	public static Button GetButtonDeep(this Transform root, string childName,   UnityEngine.Events.UnityAction action)
	{
    
    
		Button result   = root.GetButtonDeep(childName);
		result.onClick.AddListener( action );

		return result;
	}

    /// <summary>
    /// 深度查找子对象transform引用
    /// </summary>
    /// <param name="root">父对象</param>
    /// <param name="childName">具体查找的子对象名称</param>
    /// <returns></returns>
    public static Button GetButtonDeep(this Transform root, string childName)
    {
    
    
        Transform result = null;
        result = root.Find(childName);
        if (!result)
        {
    
    
            foreach (Transform item in root)
            {
    
    
                result = FindChildDeep(item, childName);
                if (result != null)
                {
    
    
                    return result.GetComponent<Button>();
                }
            }
        }
        return result.GetComponent<Button>();
    }




	    /// <summary>
    /// 深度查找子对象transform引用
    /// </summary>
    /// <param name="root">父对象</param>
    /// <param name="childName">具体查找的子对象名称</param>
    /// <returns></returns>
    public static Transform FindChildDeep(this Transform root, string childName)
    {
    
    
        Transform result = null;
        result = root.Find(childName);
        if (!result)
        {
    
    
            foreach (Transform item in root)
            {
    
    
                result = FindChildDeep(item, childName);
                if (result != null)
                {
    
    
                    return result;
                }
            }
        }
        return result;
    }

--------------------------------------------------

modify settings panel

Subscripts have ScreenSettings. The language setting is not done, and the screen setting seems to have no effect.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Linq;
using Slider = UnityEngine.UI.Slider;
using System;

public class SettingsPanel : MonoBehaviour
{
    
    


	#region 字属
	//这部分应该新建一个SLMgr(Save And Load,设置、存档)来保存
	public float TextSpeed = 10;   //文本显示的速度
	public float TextAutoSpeed = 10;   //文本自动跳转下一句的速度
	public float DialogBoxAlpha = 0.8F;   //对话框文本的透明度


	//
	public List<Slider> SliderLst=new List<Slider>();   //获得滚动条合集


	[SerializeField] ScreenSettings ScreenSettings ;
	[Header("Button")]
	[SerializeField] Button ResetBtn;
	[SerializeField] Button BackBtn;
	[SerializeField] Button GoMainBtn;
	[SerializeField] Button QuitGameBtn;
	#endregion



	#region 生命

	public void Init()
	{
    
    
		TextSpeed = 10;
		TextAutoSpeed = 10;
		DialogBoxAlpha = 0.8F;

		//
		InitSliderLst();

		//
		ScreenSettings = gameObject.GetComponentDeep<ScreenSettings>("ScreenSettings");
		ScreenSettings.Init();
		//
		ReadSettingIfExist();
		SetSliderValue();   //把数据赋值给滚动条的value值
		//
		InitButton();
	}

	private void Update()
    {
    
    
        UpdateValue();
        UpdateSlider();  
    }
	#endregion



	#region 辅助



	void InitButton()
	{
    
    
		ResetBtn = transform.GetButtonDeep("ResetBtn", ResetVolume);
		BackBtn = transform.GetButtonDeep("BackBtn", HideSettingPanel);
		GoMainBtn = transform.GetButtonDeep("GoMainBtn", GoMain);
		QuitGameBtn = transform.GetButtonDeep("QuitGameBtn", QuitGame);
	}

	void QuitGame()
	{
    
    
		UIMgr.Instance.QuitGame();
	}

	void GoMain()
	{
    
    
		UIMgr.Instance.GoMainPanel();
	}

	/// <summary>隐藏设置界面</summary>
	public void HideSettingPanel()
	{
    
    
		SaveValue();  
		gameObject.Hide();  
	}


	void ReadSettingIfExist()
	{
    
    
		string path = Application.persistentDataPath + "/Setting";
		if (File.Exists(path))//判断当前文件路径 是否有 Setting的 文件
		{
    
    
			//如果 有  就执行 读取文件,并且解析文件里面的数据内容
			BinaryFormatter bf = new BinaryFormatter();
			FileStream fs = File.Open(path, FileMode.Open);
			SettingData saveData = (SettingData)bf.Deserialize(fs);//反序列化数据  
			fs.Close();

			SetGameData(saveData);
		}
		else//如果没有文件
		{
    
    
			SaveValue();  //存储文件的方法
		}
	}


	void InitSliderLst()
	{
    
    
		SliderLst = gameObject.GetComponentsInChildren<Slider>().ToList();
	}


	/// <summary>更新数据</summary>
	public void UpdateValue() 
	{
    
    
		AudioMgr.Instance.UpdateValue();
		UIMgr.Instance.SetDialogBoxAlpha(DialogBoxAlpha)  ;   //把对话框文本的透明度赋值
        AVGMachine.Instance.TextSpeed = TextSpeed;   //把速度赋值过去
    }



	/// <summary>把滚动条里面的参数  赋值给   当前脚本上面的参数</summary>
	public void UpdateSlider() 
	{
    
    
		
        TextSpeed = SliderLst[0].value;   //把第一个滚动条的参数赋值给 文字速度
        TextAutoSpeed = SliderLst[1].value;
        DialogBoxAlpha = SliderLst[2].value;
		//
		AudioMgr.Instance.TotalVolume = SliderLst[3].value;
		AudioMgr.Instance.BgVolume = SliderLst[4].value;
		AudioMgr.Instance.EffectVolume = SliderLst[5].value;
		AudioMgr.Instance.RoleVolume = SliderLst[6].value;
    }



	/// <summary>把数据赋值给滚动条的value值</summary>
	public void SetSliderValue()
    {
    
    
        SliderLst[0].value = TextSpeed;   //把文字打印的速度 赋值给 第一个滚动条
        SliderLst[1].value = TextAutoSpeed;   
        SliderLst[2].value = DialogBoxAlpha; 
		//
        SliderLst[3].value = AudioMgr.Instance.TotalVolume;  
        SliderLst[4].value = AudioMgr.Instance.BgVolume;   
        SliderLst[5].value = AudioMgr.Instance.EffectVolume;   
        SliderLst[6].value = AudioMgr.Instance.RoleVolume;   
    }


	/// <summary>存储数据的方法</summary>
	public void SaveValue() 
	{
    
    
        SettingData save = CreateSaveGo();    // 接收存档数据信息 
        BinaryFormatter bf = new BinaryFormatter();  //实例化
        FileStream fs = File.Create(Application.persistentDataPath +"/Setting");  //创建一个名为 Setting的文件
        bf.Serialize(fs,save);  //序列化
        fs.Close();  //关掉
    }


	/// <summary>创建存档数据信息</summary>
	public SettingData CreateSaveGo()
	{
    
    
        SettingData save = new SettingData();    //实例化一个 存储数据

        save.TextSpeed = TextSpeed;   
        save.TextAutoSpeed = TextAutoSpeed; 
        save.WindowAlpha = DialogBoxAlpha;   
        save.MusicVolume = AudioMgr.Instance.TotalVolume;   
        save.BGMusic = AudioMgr.Instance.BgVolume;  
        save.RoleMusic = AudioMgr.Instance.RoleVolume; 
        save.EffectMusic = AudioMgr.Instance.EffectVolume; 
        return save;
    }


	/// <summary>设置游戏参数</summary>	
	public void SetGameData(SettingData save)
	{
    
    
		TextSpeed = save.TextSpeed ;   
		TextAutoSpeed = save.TextAutoSpeed ;  
		DialogBoxAlpha = save.WindowAlpha ;
		AudioMgr.Instance.TotalVolume = save.MusicVolume ;
		AudioMgr.Instance.BgVolume = save.BGMusic ;
		AudioMgr.Instance.RoleVolume = save.RoleMusic ;
		AudioMgr.Instance.EffectVolume = save.EffectMusic ;
		UpdateValue();  //音频数据更新
    }


	/// <summary>重置所有选项的按钮</summary>
	public void ResetSliderValue(int a1,int a2,float a3,float a4,float a5,float a6,float a7) 
	{
    
    
        SliderLst[0].value = a1;
        SliderLst[1].value = a2;
        SliderLst[2].value = a3;
        SliderLst[3].value = a4;
        SliderLst[4].value = a5;
        SliderLst[5].value = a6;
        SliderLst[6].value = a7;
    }


	/// <summary>重置音量</summary>	
	public void ResetVolume() 
	{
    
    
        ResetSliderValue(10,10,0.7f,0.8f,1,1,1);

    }



    #endregion

}

bug PlotCanvas Get to but not initialized

SettingsPanel is under MainCanvas
GamePanel is under PlotCanvas

SettingsPanel calls GamePanel in Update, that is, the initialization of PlotCanvas should be before MainCanvas (adjust the order)

	/// <summary>更新数据</summary>
	public void UpdateValue() 
	{
    
    
		AudioMgr.Instance.UpdateValue();
		UIMgr.Instance.SetDialogBoxAlpha(DialogBoxAlpha)  ;   //把对话框文本的透明度赋值
        AVGMachine.Instance.TextSpeed = TextSpeed;   //把速度赋值过去
    }

UIMgr call sequence

	void InitCanvas()
	{
    
    
		MainCanvas = gameObject.GetComponentDeep<MainCanvas>("MainCanvas");
		EnterCanvas = gameObject.GetComponentDeep<EnterCanvas>("EnterCanvas");
		PlotCanvas = gameObject.GetComponentDeep<PlotCanvas>("PlotCanvas");
		AnimCanvas = gameObject.GetComponentDeep<AnimCanvas>("AnimCanvas");
		WhiteCanvasGo = gameObject.Find("WhiteCanvas");
		BlackCanvasGo = gameObject.Find("BlackCanvas");
		BlackCanvasGo.Hide();
		
		PlotCanvas.Init();//在MainCanvas之前
		MainCanvas.Init();		
		
		EnterCanvas.Init();
		AnimCanvas.Init();
	}

modify screen settings

Hangs here, is called and initialized by SettingsPanel
insert image description here

/****************************************************
    文件:ScreenSettings.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/29 23:51:25
	功能:屏幕设置
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
 

public class ScreenSettings : MonoBehaviour
{
    
    
	#region 属性

	public Button FullScreenBtn;  
	public Button WindowScreenBtn; 
	public List<Sprite> SpriteLst = new List<Sprite>();  //图片

	#endregion

	#region 生命

	public void Init()
	{
    
    
		FullScreenBtn = transform.GetButtonDeep("FullScreenBtn",FullScreen); ;
		WindowScreenBtn = transform.GetButtonDeep("WindowScreenBtn", WindowScreen); 
		InitSpriteLst();
		FullScreen();

	}
	#endregion

	#region 辅助

	void InitSpriteLst()
	{
    
    
		AddSpriteLst("sys_botton_1_full_a");
		AddSpriteLst("sys_botton_1_win_a");
		AddSpriteLst("sys_botton_1_full_c #9204", "素材/zanghua/Texture2D/");
		AddSpriteLst("sys_botton_1_win_c");
	}

	void AddSpriteLst(string name, string pathPre = "素材/zanghua/Sprite/")
	{
    
    
		Sprite sprite = Resources.Load<Sprite>(pathPre + name);
		SpriteLst.Add(sprite);
	}


	/// <summary>窗口模式</summary>
	public void WindowScreen()
	{
    
    
		UnSelectBtn();
		Screen.SetResolution(1920, 1080, fullscreen: false);   
		WindowScreenBtn.GetComponent<Image>().sprite = SpriteLst[3]; 
	}


	/// <summary>全屏方法,InitSpriteLst之后</summary>
	public void FullScreen()
	{
    
    
		UnSelectBtn();
		Screen.SetResolution(1920, 1080, fullscreen: true);  
		FullScreenBtn.GetComponent<Image>().sprite = SpriteLst[2];  

	}


	/// <summary>取消按钮的激活状态</summary>	
	public void UnSelectBtn()
	{
    
    
		FullScreenBtn.GetComponent<Image>().sprite = SpriteLst[0];
		WindowScreenBtn.GetComponent<Image>().sprite = SpriteLst[1]; 
	}
	#endregion

}

--------------------------------------------------

modify Stop and recall MPCPanel

MPC, Music (music) Plot (plot) CG (computer animation)
. . . . . .
1 The total tab, there are three kinds of MPC
2 Scattered tabs, all the content of MPC
3 The content displayed by MPC on the panel
. . . . . .
The original version only has two scripts, TabGround and TabBtn, and 1 and 2 both use the same TabGround, so the initialization of this part is different, because the PanelGoLst inside and the panel position relationship are different (not all can be found in the child nodes, and it will be troublesome to lose them if you drag and drop)
insert image description here
insert image description here

TabGround base class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;


/// <summary>选项卡基类</summary>

public class TabGround : MonoBehaviour
{
    
    
    //管理按钮 并且 判断   哪个面板
    public List<TabBtn> TabBtnLst = new List<TabBtn>();
	/// <summary>存储数据面板</summary>
	public List<GameObject> PanelGoLst=new List<GameObject>();   
	/// <summary>用来存储当前点击的是哪个按钮</summary>
	public TabBtn selectTabBtn;      
    public TabBtn tabBtn1;


	#region 生命


	protected virtual void Start()
    {
    
    

		InitTabBtnLst();  	
		InitTab1();
		InitPanelGoLst();
	}





	#endregion


	#region 辅助


    public void OnTabSelected(TabBtn tabBtn)
	{
    
    
        //判断当前点击了哪个按钮,没有点击的按钮就切换成未激活的图片
        selectTabBtn = tabBtn;    //把点击的按钮 传递过去
        ResetTab();
		tabBtn.Active();
        int tarIdx = tabBtn.transform.GetSiblingIndex();   
        for (int i = 0; i < PanelGoLst.Count; i++)
        {
    
    

            if (i == tarIdx)
            {
    
    
                PanelGoLst[i].Show();
            }
            else
            {
    
    
                PanelGoLst[i].Hide();
            }
        }
    }

	/// <summary>重置所有按钮的图片</summary>
	public void ResetTab()
    {
    
    
        foreach (TabBtn tabBtn in TabBtnLst)
        {
    
    
            if (selectTabBtn != null && tabBtn == selectTabBtn) 
			{
    
     
				continue;//跳过本次循环 
			}
			//把按钮的图片切换成对应的 待机未激活 的图片
			tabBtn.Idle();
        }
    }


	protected virtual void InitTabBtnLst()
	{
    
    

	}


	protected virtual void InitPanelGoLst()
	{
    
    
	}


	protected virtual void InitTab1()
	{
    
    
		if (TabBtnLst.Count <= 0)
		{
    
    
			return;
		}
		tabBtn1 = TabBtnLst[0];
		tabBtn1.Active();
		OnTabSelected(tabBtn1);
	}
	#endregion

}

Total TabGround

Hanging on the parent node of the plot or above, I am hanging on the MPCPanel node

/****************************************************
    文件:TabGroup0.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/30 2:1:34
	功能:接受MPCPanel中的最上层的TabGround
*****************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
 

public class TabGround0 : TabGround
{
    
    


	#region 生命


	protected override void Start()
	{
    
    
		InitTabBtnLst();
		InitTab1();
		InitPanelGoLst();
	}


	#endregion


	#region 辅助

	protected override void InitTabBtnLst()
	{
    
    
		Transform t = transform.FindChildDeep("BottomRight");
		TabBtnLst = t.GetComponentsInChildren<TabBtn>(includeInactive: true).ToList();
		foreach (TabBtn btn in TabBtnLst)
		{
    
    
			btn.Idle();
		}
	}


	protected override void InitPanelGoLst()
	{
    
    
		PanelGoLst.Clear();
		PanelGoLst.Add( gameObject.FindChildDeep("剧情回放"));
		PanelGoLst.Add( gameObject.FindChildDeep("CG鉴赏"));
		PanelGoLst.Add( gameObject.FindChildDeep("音乐赏析"));
		foreach (GameObject go in PanelGoLst)
		{
    
    
			go.Hide();
		}
		PanelGoLst[0].Show();
	}



	#endregion

}







Scattered TabGround

Hang on these two nodes
PanelGoLst.Add( gameObject.FindChildDeep("Plot Playback"));
PanelGoLst.Add( gameObject.FindChildDeep("CG Appreciation"));

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary></summary>

public class TabGround1 : TabGround
{
    
     


	#region 生命


	protected override void Start()
    {
    
    

		InitTabBtnLst();  	
		InitTab1();
		InitPanelGoLst();
	}
	#endregion


	#region 辅助

	protected override void InitTabBtnLst()
	{
    
    
		List<GameObject> gos= gameObject.FindChildDeep("TabGroud").GetChildrenLst();
		foreach (GameObject go in gos)
		{
    
    
			TabBtnLst.Add(go.GetComponent<TabBtn>());
		}
		foreach (TabBtn btn in TabBtnLst)
		{
    
    
			btn.Idle();
		}
		TabBtnLst[0].Active();
	}


	protected override void InitPanelGoLst()
	{
    
    
		PanelGoLst = gameObject.FindChildDeep("PanelGoLst").GetChildrenLst();
	}



	#endregion

}

TabBtn

Hang on all the buttons. (tabs like 1,2,3,4)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Security;
using System;

public class TabBtn : MonoBehaviour,IPointerDownHandler
{
    
    
    public TabGround tabGround;  
    public Image Img; 
	public Sprite idleSprite;
	public Sprite activeSprite;

	private void Awake()
    {
    
    
        tabGround = transform.GetComponentInParent<TabGround>();
		Img = GetComponent<Image>();
		InitSprite();
	}

	void InitSprite()
	{
    
     
		string pathPre = "素材/zanghua/Sprite/";
		int selfIdx = transform.GetSiblingIndex() + 1;
		string idlePath = String.Format(pathPre + "sl_menu_page_{0}_a", selfIdx);
		string activePath = String.Format(pathPre + "sl_menu_page_{0}_c", selfIdx);
		idleSprite =Resources.Load<Sprite>(idlePath);
		activeSprite = Resources.Load<Sprite>(activePath);	
	}


    public void OnPointerDown(PointerEventData eventData)  
    {
    
    
        //执行当前 UI 的 逻辑   
        tabGround.OnTabSelected(this);  
		//TODO 事件注册的做法
		//new OnTabSelectCommand().Execute();

    }


	public void Idle()
	{
    
     
		Img.sprite = idleSprite;
	}

	public void Active()
	{
    
    
		 Img.sprite = activeSprite;
	}
}

modify music appreciation

insert image description here

/****************************************************
    文件:MPCPanel.Music.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/30 4:0:58
	功能:
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
 

public partial class MPCPanel : MonoBehaviour
{
    
    
	#region 属性

	[Header("音乐赏析")]
	/// <summary>有时面板上看不到按钮事件,测试看的</summary>
	[SerializeField]  List<Button> btnLst = new List<Button>();
	[SerializeField] Button StopMusicBtn;
	[SerializeField] int curId;
	#endregion


	#region 生命
	public void InitMusic()
	{
    
    
		curId = -1;
		Transform t = transform.FindChildDeep("MusicLst");
		for (int i = 0; i < t.childCount; i++)
		{
    
    
			Button btn = t.GetChild(i).GetComponent<Button>();
			btn.onClick.AddListener(()=>ClickMusicBtn(btn.transform.GetSiblingIndex()) ); //用i不行
			btnLst.Add(btn);//测试看
		}
		//
		StopMusicBtn = transform.GetButtonDeep("StopMusicBtn",() => AudioMgr.Instance.StopMPCMusic());
		//
	}
	#endregion

	#region 辅助
	void ClickMusicBtn(int i)
	{
    
    				
		AudioMgr.Instance.PlayMPCMusic(i);
		curId= i; 
	}
	#endregion

}


--------------------------------------------------

continue the journey

Delete the original TabGround, and use TabGroundSL: TabGroundSL, and SaveLoadPanel are all hung on the SaveLoadPanel node
insert image description here

SaveLoadPanel

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine.UI;

/// <summary>用来存储和读取文件</summary>
public class SaveLoadPanel : MonoBehaviour
{
    
    


	#region 字属


	[SerializeField] Image LogoImg;		
	[SerializeField] Sprite SaveSprite; 
	[SerializeField] Sprite LoadSprite; 
	[SerializeField] Button GoMainBtn; 
	/// <summary>判断当前是存储还是读取</summary>
	public bool isSave;   
	/// <summary>获取自身子集下面的 存档预制体的数组</summary>
	public List<SaveSlot> slotList = new List<SaveSlot>();  
	#endregion


	public void Init()
	{
    
    
		LogoImg = gameObject.GetComponentDeep<Image>("LogoImg");
		SaveSprite = Resources.Load<Sprite>("素材/zanghua/Sprite/sl_title1");
		LoadSprite = Resources.Load<Sprite>("素材/zanghua/Sprite/sl_title2 #9468");
		GoMainBtn = transform.GetButtonDeep("GoMainBtn",()=>UIMgr.Instance.GoMainPanel());
	}




	#region 辅助


	/// <summary>把存档预制体 添加进入数据</summary>
	public void InitSlot(SaveSlot slot)
	{
    
    
		slotList.Add(slot);
	}


	/// <summary>把加载界面的logo赋值</summary>
	public void SetLogoImgLoad()
	{
    
    
		LogoImg.sprite = LoadSprite;
	}

	public void SetLogoImgSave()
	{
    
    
		LogoImg.sprite = SaveSprite;
	}

	/// <summary>加载已拥有的文件数据</summary>
	public  void LoadFileData()
	{
    
    
		for (int i = 0; i < slotList.Count; i++)
		{
    
    
			if (File.Exists(Application.persistentDataPath + slotList[i].path))  //查询是否有文件  如果有的话
			{
    
    
				BinaryFormatter bf = new BinaryFormatter();  //实例化
				FileStream fs = File.Open(Application.persistentDataPath + slotList[i].path, FileMode.Open);  //打开i数据文件
				SaveData save = (SaveData)bf.Deserialize(fs);   //把二进制文件 反序列化    然后在强制转换成Save形式
				slotList[i].saveImg.sprite = Resources.Load<Sprite>("BG/" + save.SaveImg);    //获取存储预制体上面的图片
				slotList[i].Des.text = save.SaveDes;    //读取 文本 然后赋值

				fs.Close(); 
			}
			else
			{
    
    
				//如果没有查询到文件
				slotList[i].saveImg.sprite = Resources.Load<Sprite>("BG/" + "黑");    //获取存储预制体上面的图片
				slotList[i].Des.text = "没有数据";    //没有数据
			}
		}

	}


	/// <summary>二进制存储数据文件</summary>
	public void SaveGame(string path, SaveSlot slot)
	{
    
    
		SaveByBin(path, slot);
	}


	/// <summary>读取游戏数据文件</summary>
	public void LoadGame(string path)
	{
    
    
		LoadByBin(path);
	}


	/// <summary>二进制存储数据</summary>
	public void SaveByBin(string path, SaveSlot slot)
	{
    
    
		SaveData save = CreateSaveData(slot);
		BinaryFormatter bf = new BinaryFormatter();  //实例化
		FileStream fs = File.Create(Application.persistentDataPath + path);  //创建文件
		bf.Serialize(fs, save);
		fs.Close();  //
	}


	/// <summary>创建存储文件信息</summary>
	public SaveData CreateSaveData(SaveSlot slot)
	{
    
    
		SaveData save = new SaveData();   //实例化一下  序列化的脚本
		save.CurLine = AVGMachine.Instance.curLine;   //把文本下标  保存在save序列化脚本里面
		save.StoryID = AVGMachine.Instance.curStoryID;
		save.CurPolt = AVGMachine.Instance.TextInfo;
		save.Alpha = UIMgr.Instance.PlotCanvas.GamePanel.BG2Alpha;    //把背景图片2的透明度 保存在序列化脚本里面
		save.BG1 = UIMgr.Instance.PlotCanvas.GamePanel.BG1.sprite.name;   //获得 一号背景图片里面使用的图片名称
		save.BG2 = UIMgr.Instance.PlotCanvas.GamePanel.BG2.sprite.name;   //获得 2号背景图片里面使用的图片名称
		save.SaveImg = slot.saveImg.sprite.name;     //获得 存储预制体上的图片
		save.SaveDes = slot.Des.text;   //获得 存储预制体上的文本

		return save;   //返回存储数据文件
	}


	/// <summary>读取二进制游戏文件</summary>
	public void LoadByBin(string path)
	{
    
    
		if (File.Exists(Application.persistentDataPath + path))   //判断当前的路径是否拥有文件
		{
    
    
			BinaryFormatter bf = new BinaryFormatter();  //实例化
			FileStream fs = File.Open(Application.persistentDataPath + path, FileMode.Open);  //打开i数据文件
			SaveData save = (SaveData)bf.Deserialize(fs);   //把二进制文件 反序列化    然后在强制转换成Save形式
			fs.Close();  //关闭
			SetGame(save);    //把反序列化出来的数据文件 传递给setgame
		}
	}


	/// <summary>把读取出来的游戏数据 在赋值回去</summary>
	public void SetGame(SaveData save)
	{
    
    
		AVGMachine.Instance.curLine = save.CurLine;   //把下标赋值
		AVGMachine.Instance.curStoryID = save.StoryID;
		AVGMachine.Instance.TextInfo = save.CurPolt;
		AVGMachine.Instance.LoadUpdateBG(save.BG1, save.BG2, save.Alpha);   //传递  背景1和2的图片名称 和 背景图片2的透明值
		AVGMachine.Instance.GoState(TypeState.TYPING);   //把当前的状态切换成 typing 打字状态

		UIMgr.Instance.PlotCanvas.enabled = true;   //显示剧情面板
		gameObject.SetActive(false);  //关闭自身面板
	}
	#endregion

}

TabGroundSL:TabGroundSL

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary></summary>

public class TabGroundSL : TabGround
{
    
     


	#region 生命


	protected override void Start()
    {
    
    

		InitTabBtnLst();  	
		InitTab1();
		InitPanelGoLst();
	}
	#endregion


	#region 辅助

	protected override void InitTabBtnLst()
	{
    
    
		List<GameObject> gos= gameObject.FindChildDeep("TabGround").GetChildrenLst();
		foreach (GameObject go in gos)
		{
    
    
			TabBtnLst.Add(go.GetComponent<TabBtn>());
		}
		foreach (TabBtn btn in TabBtnLst)
		{
    
    
			btn.Idle();
		}
		TabBtnLst[0].Active();
	}


	protected override void InitPanelGoLst()
	{
    
    
		PanelGoLst = gameObject.FindChildDeep("SaveLoadObjLst").GetChildrenLst();
	}



	#endregion

}

--------------------------------------------------

modify start the game

01 Run the original version, first the black screen Canvas flashes (displays and hides). MainCanvas remains unchanged, and MainPanel (main menu interface) is hidden. Then display the GamePanel (StartAVG)
02 black screen Canvas slide, there are animation events, extract them separately (it’s troublesome to see the animations one by one), and put them in BlackCanvas_BlackCanvas (node ​​name_animation name)

insert image description here

insert image description here

BlackCanvas_BlackCanvas

/****************************************************
    文件:BlackCanvas_BlackCanvas.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/21 20:23:34
	功能:
*****************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
 

public class BlackCanvas_BlackCanvas : MonoBehaviour
{
    
    
	#region 辅助(方法顺序就是在动画中的顺序。不要移动顺序)

	/// <summary>关闭菜单按钮</summary>
	public void HideMainBtn()
	{
    
    
		StartCoroutine(HideMainBtnCrt());
	}


	/// <summary>开始游戏</summary>
	public void StartGame()
	{
    
    
		StartCoroutine(StartGameCrt());//在MonoBehaviour中使用
	}

	/// <summary>avg开始运行</summary>
	public void StartAVG()
	{
    
    
		AVGMachine.Instance.StartAVG();
	}

	/// <summary>关闭黑屏</summary>
	public void HideBlack()
	{
    
    
		gameObject.Hide();  //关闭 自身
	}
	#endregion



	#region 协程


	IEnumerator StartGameCrt()
	{
    
    
		//第一种写法
		while (UIMgr.Instance == null)//需要时间
		{
    
    
			yield return new WaitForEndOfFrame(); //等一帧 
		}
		UIMgr.Instance.StartGame();  //调用开始游戏方法
	}


	IEnumerator HideMainBtnCrt()
	{
    
    
		while (UIMgr.Instance == null
			|| UIMgr.Instance.MainCanvas == null
			|| UIMgr.Instance.MainCanvas.MainPanel == null)//需要时间
		{
    
    
			yield return new WaitForEndOfFrame(); //等一帧 
		}
		UIMgr.Instance.HideMainBtn();
	}
	#endregion

}




stars enabled

/****************************************************
    文件:ExtendComponent.ShowHide.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/22 15:32:47
	功能:
*****************************************************/

using Codice.Client.BaseCommands;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.TerrainAPI;
using UnityEngine;
using Random = UnityEngine.Random;
 

public static partial class ExtendComponent 
{
    
    
	......

	public static void Enabled(this Behaviour behaviour)
	{
    
    
		behaviour.enabled = true;
	}

	public static void Disabled(this Behaviour behaviour)
	{
    
    
		behaviour.enabled = false;
	}

}




bug Asset database transaction committed twice!

Although it does not affect the operation

bug Start the game, still in the main menu, and the PlotCanvas is hidden

Start the game, still in the main menu, and the PlotCanvas is hidden

The original version is HideMainBtn, I call HideMainPanel to
initialize PlotCanvas without Hide

--------------------------------------------------

modify PlotCanvas.GamePanel tool buttons (except auto, skip)

GamePanel

/****************************************************
    文件:GamePanel.cs
	作者:lenovo
    邮箱: 
    日期:2023/4/21 8:41:10
	功能:
*****************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SocialPlatforms.Impl;
using UnityEngine.UI;
using Random = UnityEngine.Random;
 

public class GamePanel : MonoBehaviour
{
    
    
	#region 字段



	[SerializeField] Button NextBtn;

	[Header("角色")]
	public GameObject RoleCGrpLstGo;  
	public CanvasGroup RoleACGrp;   //获得角色A号位置的 画布组
	public CanvasGroup RoleBCGrp;   //获得角色B号位置的 画布组
	public CanvasGroup RoleCCGrp;   //获得角色C号位置的 画布组
	public float RoleAAlpha = 0;    //A号人物的  Alpha 的值
	public float RoleBAlpha = 0;    //B号人物的  Alpha 的值
	public float RoleCAlpha = 0;    //C号人物的  Alpha 的值
	//
	public CanvasGroup BG1Group;   //第一个背景画布
	public CanvasGroup BG2Group;  //第二个背景画布

						
	[Header("选择按钮")]
	public GameObject ChoiceBtnLstGo;   
	public Button ChoiceBtnA;  
	public Button ChoiceBtnB;  
	public Button ChoiceBtnC;  
							  //
	[Header("Image")]
	/// <summary>对话框背景</summary>
	public Image ContentBGImg;   
	public Image BG1;   //获得背景图片  用来替换背景
	public Image BG2;   //获得背景图片,  只不过这个是第二个背景图片
	public Image RoleImg;   //获得人物名称 的背景图片
							//
	[Header("Text")]
	/// <summary>对话文本</summary>
	public Text DialogText;   
	/// <summary>用来显示人物名称的文本</summary>
	public Text RoleText;    
	public Text BtnDesText;    
							 
	[Header("float")]
	public float TarSpeed = 2f;    //人物显示的渐变速度
	public float BG2Alpha = 0;  //背景图片2 的 目标透明度

	[Header("右下的按钮")]
	[SerializeField] Button CloseBtn;
	[SerializeField] Button SettingsBtn;
	[SerializeField] Button SkipBtn;
	[SerializeField] Button AutoBtn;
	[SerializeField] Button LoadBtn;
	[SerializeField] Button SaveBtn;
	[SerializeField] Button ShowPlotBtnLstBtn;
	[SerializeField] GameObject PlotBtnLstGo;


	[Header("Auto Skip")]
	/// <summary>判断是否开始了自动跳转按钮功能</summary>
	public bool isAuto;   
	/// <summary>判断是否开始了快速跳过功能</summary>
	public bool isSkip;   
	/// <summary>自动跳转的待机图片</summary>
	public Sprite AutoIdleSprite;   
	/// <summary>自动跳转的激活图片</summary>
	public Sprite AutoActiveSprite;  
	/// <summary>快速跳转的待机图片</summary>
	public Sprite SkipIdleAprite;   
	/// <summary>快速跳转的激活图片</summary>
	public Sprite SkipActiveSprite;  
	/// <summary>获得自动跳转按钮身上的图片组件</summary>
	public Image AutoBtnImg;  
	/// <summary>获得快速跳转按钮身上的图片组件</summary>
	public Image SkipBtnImg;  
	#endregion

	#region 生命


	public void Init()
	{
    
    
		InitRoleCanvasGroup();
		RoleAAlpha = 0;
		RoleBAlpha = 0;
		RoleCAlpha = 0;
		//
		BG1Group = transform.GetComponentDeep<CanvasGroup>(GameObjectName.BG1);
		BG2Group = transform.GetComponentDeep<CanvasGroup>(GameObjectName.BG2);
		//
		NextBtn = transform.GetButtonDeep("NextBtn",AVGMachine.Instance.UserClicked );
		InitChoiceBtnLst();
		InitPlotBtnLstAndImg();
		//
		ContentBGImg = transform.GetComponentDeep<Image>(GameObjectName.ContentBGImg);
		BG1 = transform.GetComponentDeep<Image>(GameObjectName.BG1);
		BG2 = transform.GetComponentDeep<Image>(GameObjectName.BG2);
		RoleImg = transform.GetComponentDeep<Image>(GameObjectName.RoleImg);
		//
		DialogText = transform.GetComponentDeep<Text>(GameObjectName.DialogText);
		RoleText = transform.GetComponentDeep<Text>(GameObjectName.RoleText);
		BtnDesText = transform.GetComponentDeep<Text>(GameObjectName.BtnDesText);
		//
		TarSpeed = 2f;

		BG2Alpha = 0;
		//
		AutoIdleSprite = LoadSprite("dialog_menu_auto_a") ;
		AutoActiveSprite = LoadSprite("dialog_menu_auto_c");
		SkipIdleAprite = LoadSprite("dialog_menu_skip_a");
		SkipActiveSprite = LoadSprite("dialog_menu_skip_c");
	}



	void Update()
	{
    
    
		if (Input.GetKeyDown(KeyCode.A))
		{
    
    
			ShowRoleA(1);   
			ShowRoleB(1);   
			ShowRoleC(1);   
		}

		if (Input.GetKeyDown(KeyCode.B))
		{
    
    
			ShowRoleA(0); 
			ShowRoleB(0); 
			ShowRoleC(0); 
		}

		if (Input.GetKeyDown(KeyCode.C))
		{
    
    
			SetDialogText("jkakfkalgfhjlsglfjhgasljhfgshjafa");
		}

		if (Input.GetKeyDown(KeyCode.D))
		{
    
    
			SetRoleText(true, "不知道");
		}

		if (Input.GetKeyDown(KeyCode.E))
		{
    
    
			SetRoleText(false, "不知道");
		}


		#region   角色A的 透明渐变		    
		//如果A号角色身上的画布的透明度 不等于 我们手动设置的 透明值的话
		if (RoleACGrp.alpha != RoleAAlpha)  
		{
    
    
			RoleACGrp.alpha = Mathf.Lerp(RoleACGrp.alpha, RoleAAlpha, TarSpeed * Time.deltaTime);    //角色A的透明值    使用lerp   渐变到 我们设置的alhpa值
			if (Mathf.Abs(RoleACGrp.alpha - RoleAAlpha) < 0.1f)    //如果玩家的透明度 减去  我们设置的透明度 的绝对值   小于0.1的话   
			{
    
    
				RoleACGrp.alpha = RoleAAlpha;     //把目标的透明值 设置给  A号玩家的透明纸
			}

		}
		#endregion

		#region   角色B的 透明渐变
		if (RoleBCGrp.alpha != RoleBAlpha)   //如果A号角色身上的画布的透明度 不等于 我们手动设置的 透明值的话
		{
    
    
			RoleBCGrp.alpha = Mathf.Lerp(RoleBCGrp.alpha, RoleBAlpha, TarSpeed * Time.deltaTime);    //角色A的透明值    使用lerp   渐变到 我们设置的alhpa值
			if (Mathf.Abs(RoleBCGrp.alpha - RoleBAlpha) < 0.1f)    //如果玩家的透明度 减去  我们设置的透明度 的绝对值   小于0.1的话   
			{
    
    
				RoleBCGrp.alpha = RoleBAlpha;     //把目标的透明值 设置给  A号玩家的透明纸
			}

		}
		#endregion

		#region   角色C的 透明渐变
		if (RoleCCGrp.alpha != RoleCAlpha)   //如果A号角色身上的画布的透明度 不等于 我们手动设置的 透明值的话
		{
    
    
			RoleCCGrp.alpha = Mathf.Lerp(RoleCCGrp.alpha, RoleCAlpha, TarSpeed * Time.deltaTime);    //角色A的透明值    使用lerp   渐变到 我们设置的alhpa值
			if (Mathf.Abs(RoleCCGrp.alpha - RoleCAlpha) < 0.1f)    //如果玩家的透明度 减去  我们设置的透明度 的绝对值   小于0.1的话   
			{
    
    
				RoleCCGrp.alpha = RoleCAlpha;     //把目标的透明值 设置给  A号玩家的透明纸
			}

		}
		#endregion

		#region 背景图片2 渐变显示和隐藏
		if (BG2Group.alpha != BG2Alpha)
		{
    
    
			//如果背景图片2 身上的 画布的 透明度  不等于 我们设置的目标透明度
			BG2Group.alpha = Mathf.Lerp(BG2Group.alpha, BG2Alpha, TarSpeed * Time.deltaTime);   //背景图片2的渐变值
			if (Mathf.Abs(BG2Group.alpha - BG2Alpha) < 0.1f)
			{
    
    
				BG2Group.alpha = BG2Alpha;  //直接把透明度 赋值给  画布组上面的透明度
			}

		}

		#endregion

	}

	#endregion

	#region 系统

	#endregion

	#region 辅助


	private void InitRoleCanvasGroup()
	{
    
    
		RoleCGrpLstGo = gameObject.FindChildDeep("RoleCGrpLstGo");
		RoleACGrp = transform.GetComponentDeep<CanvasGroup>("RoleACGrp");
		RoleBCGrp = transform.GetComponentDeep<CanvasGroup>("RoleBCGrp");
		RoleCCGrp = transform.GetComponentDeep<CanvasGroup>("RoleCCGrp");
	}

	Sprite LoadSprite(string spriteName)
	{
    
    
		return Resources.Load<Sprite>("素材/zanghua/Sprite/"+ spriteName);
	}


	private void IntiPlotImg()
	{
    
    
		SkipBtnImg = SkipBtn.GetComponent<Image>();
		AutoBtnImg = AutoBtn.GetComponent<Image>();
	}

	void InitChoiceBtnLst()
	{
    
    
		ChoiceBtnLstGo = gameObject.FindChildDeep("ChoiceBtnLstGo");
		ChoiceBtnA = transform.GetButtonDeep("ChoiceBtnA",()=>AVGMachine.Instance.ProcessChoiceBtnMSG(ChoiceBtnA));
		ChoiceBtnB = transform.GetButtonDeep("ChoiceBtnB",()=>AVGMachine.Instance.ProcessChoiceBtnMSG(ChoiceBtnB));
		ChoiceBtnC = transform.GetButtonDeep("ChoiceBtnC",()=>AVGMachine.Instance.ProcessChoiceBtnMSG(ChoiceBtnC));
	}


	void InitPlotBtnLstAndImg()
	{
    
    
		PlotBtnLstGo = gameObject.FindChildDeep("PlotBtnLstGo");
		CloseBtn = transform.GetButtonDeep("CloseBtn", HideAnimPoltBtn);
		SettingsBtn = transform.GetButtonDeep("SettingsBtn", UIMgr.Instance.OpenSettingsPanel);
		SkipBtn = transform.GetButtonDeep("SkipBtn", SkipPlot);
		AutoBtn = transform.GetButtonDeep("AutoBtn", AutoPlot);
		LoadBtn = transform.GetButtonDeep("LoadBtn", UIMgr.Instance.ShowLoadPanel);
		SaveBtn = transform.GetButtonDeep("SaveBtn", UIMgr.Instance.ShowSaveLoadPanel);
		ShowPlotBtnLstBtn = transform.GetButtonDeep("ShowPlotBtnLstBtn", ShowPlotBtnLstGo);
		IntiPlotImg();
	}


	/// <summary>更新背景图片 在读取存档之后</summary>
	public void LoadUpdateBG(string bg1, string bg2, float alpha)
	{
    
    
		BG1.sprite = Resources.Load<Sprite>("BG/" + bg1);     //把背景1和2的图片赋值
		BG2.sprite = Resources.Load<Sprite>("BG/" + bg1);
		BG2Alpha = alpha;  //把透明度赋值给 背景2的透明度
	}


	public void LoadContent(Story01Data story)
	{
    
    
		ShowRoleA(story.Adisplay);  
		ShowRoleB(story.Bdisplay);  
		ShowRoleC(story.Cdisplay);  
	}

	public void ClearContent()
	{
    
    
		ShowRoleA(0);
		ShowRoleB(0);
		ShowRoleC(0);
	}


	/// <summary>给对话文本赋值</summary>
	public void SetDialogText(string value)
	{
    
    
		DialogText.text = value;

	}

	public void SetRoleText(bool isShow, string value)
	{
    
         //第一个布尔 是判断 是否要显示人物名称的背景图片   第二个 字符串 是   要显示的人物名称 
		  //判断是否要显示人物的名称,  如果要实现 就设置人物的名称
		if (isShow)
		{
    
    
			//如果当前要显示人物名称
			RoleImg.gameObject.SetActive(true);   //显示 人物名称的背景图片
			RoleText.text = value;   //把传递进来的人物名称 赋值
		}
		else
		{
    
    
			//如果不显示人物的名称和背景图片
			RoleImg.gameObject.SetActive(false);   //隐藏人物名称的背景图片
		}

	}

	/// <summary>调用显示按钮的方法</summary>
	public void ShowBtnList(Story01Data story)
	{
    
    
		ShowBtnList(story.Ischoice, story.Isa, story.Isb, story.Isc);
	}

		/// <summary></summary>
	public void ShowBtnList(bool value, bool A, bool B, bool C)
	{
    
    
		//显示或者隐藏按钮
		ChoiceBtnA.SetActive(value);
		ChoiceBtnB.SetActive(value);
		ChoiceBtnC.SetActive(value);
		// 判断当前按钮在当前剧情中是否要显示或者隐藏
		ChoiceBtnA.SetActive(A);
		ChoiceBtnB.SetActive(B);
		ChoiceBtnC.SetActive(C);
	}

	/// <summary>隐藏全部的按钮</summary>
	public void HideBtnList()
	{
    
    
		//显示或者隐藏按钮
		ChoiceBtnA.Hide();
		ChoiceBtnB.Hide();
		ChoiceBtnC.Hide();
		// 判断当前按钮在当前剧情中是否要显示或者隐藏
		ChoiceBtnA.Hide();
		ChoiceBtnB.Hide();
		ChoiceBtnC.Hide();
	}


	/// <summary>把传递进来的图片 添加到 号位置的图片</summary>
	public void ChangeRoleSprite(AVGAssetCfg cfg)
	{
    
    
		RoleACGrp.GetComponent<Image>().sprite = cfg.charaA;
		RoleBCGrp.GetComponent<Image>().sprite = cfg.charaB;
		RoleCCGrp.GetComponent<Image>().sprite = cfg.charaC;
	}



	/// <summary>设置按钮里面的内容</summary>
	public void SetChoiceBtnText(Story01Data story)
	{
    
    
		ChoiceBtnA.GetComponentInChildren<Text>().text = story.Btnatext ;
		ChoiceBtnB.GetComponentInChildren<Text>().text = story.Btnbtext;
		ChoiceBtnC.GetComponentInChildren<Text>().text = story.Btnctext;
	}


	/// <summary>设置按钮的名称</summary>
	public void SetChoiceBtnName(Story01Data story)
	{
    
    
		ChoiceBtnA.name = story.Btnaname;
		ChoiceBtnB.name = story.Btnbname;
		ChoiceBtnC.name = story.Btncname;
	}

	/// <summary> 
	/// 更换背景图片
	/// </summary>
	/// <param name="img">图片类型</param>
	/// <param name="img2"><是第二个的背景/param>
	/// <param name="alpha">第二个背景图片的alpha透明度</param>
	public void ChangeBG(Sprite img, Sprite img2, int alpha)
	{
    
    
		BG1.sprite = img;  
		BG2.sprite = img2; 
		BG2Alpha = alpha;  
	}


	/// <summary>判断是否显示人物名称和背景图片</summary>
	public void ShowRoleName(Story01Data story)
	{
    
    
		UIMgr.Instance.SetRoleText(story.Isrole, story.Roletext );    //第一个布尔 是判断 是否要显示人物名称的背景图片   第二个 字符串 是   要显示的人物名称 

	}


	#region    判断ABC三个位置的角色 是否显示或者隐藏
	bool IsAlphaLegal(int value)
	{
    
     
		if (value != 0 && value != 1)
		{
    
    
			return false;
		}
		return true;
	}
	/// <summary>调用显示角色位置的方法</summary>
	public void ShowRoleA(int value)
	{
    
    
		if (IsAlphaLegal(value) == false)
		{
    
    
			return;
		}
		RoleAAlpha = value;  
	}

	/// <summary>调用显示角色位置的方法</summary>
	public void ShowRoleB(int value)
	{
    
    
		if (IsAlphaLegal(value) == false)
		{
    
    
			return;
		}
		RoleBAlpha = value;
	}

	/// <summary>调用显示角色位置的方法</summary>
	public void ShowRoleC(int value)
	{
    
    
		if (IsAlphaLegal(value) == false)
		{
    
    
			return;
		}
		RoleCAlpha = value;  
	}

	public void SetDialogBoxAlpha(float dialogBoxAlpha)
	{
    
    
		ContentBGImg.GetComponent<CanvasGroup>().alpha = dialogBoxAlpha;  

	}

	/// <summary>隐藏对话框背景</summary>
	internal void HideContentBG()
	{
    
    
		ContentBGImg.Hide();  
	}

	internal void HideAnimPoltBtn()
	{
    
    
		PlotBtnLstGo.GetComponent<Animator>().SetBool("Open", false);
	}

	internal void ShowPlotBtnLstGo()
	{
    
    
		PlotBtnLstGo.Show();
		ContentBGImg.Show();
	}

	internal void HidePlotBtn()
	{
    
    
		PlotBtnLstGo.Hide(); 
		ContentBGImg.Hide(); 
	}

	internal void ShowAnimPoltBtn()
	{
    
    
		PlotBtnLstGo.Show(); 
		ContentBGImg.Show();
		PlotBtnLstGo.GetComponent<Animator>().SetBool("Open", true);   
	}


	#region 右下按钮


	internal void SetPlotBtnDesText(string btnName)
	{
    
    
		BtnDesText.text = btnName;
	}

	internal void EnabledBtnDesText()
	{
    
    
		BtnDesText.Enabled();
	}

	internal void DisabledBtnDesText()
	{
    
    
		BtnDesText.Disabled();
	}


	internal void SkipPlot()
	{
    
    
		if (isSkip)
		{
    
    
			//如果开启了自动跳转
			isSkip = false;
			//关闭  快速跳转的功能
			SkipBtnImg.sprite = SkipIdleAprite;  //把图片切换成待机状态
			AVGMachine.Instance.isSkip = false;  //当前不可以快速跳转剧情
		}
		else
		{
    
    
			if (isAuto)
			{
    
      //如果当前开启了自动状态 
			   //如果开启了自动跳转
				isAuto = false;
				//关闭自动跳转下一行的功能
				AutoBtnImg.sprite = AutoIdleSprite;  //图片切换成待机图片
				AVGMachine.Instance.isAuto = false;  //当前不可以自动跳转到下一句
			}

			//如果 为false 代表没有开启
			isSkip = true;   //为true 开启
							 //执行  快速跳转的功能
			SkipBtnImg.sprite = SkipActiveSprite;  //把图片切换成激活状态
			AVGMachine.Instance.isSkip = true;  //当前可以快速跳转剧情
		}
	}

	internal void AutoPlot()
	{
    
    
		if (isAuto)
		{
    
    
			isAuto = false;
			//关闭自动跳转下一行的功能
			AutoBtnImg.sprite = AutoIdleSprite;  //图片切换成待机图片
			AVGMachine.Instance.isAuto = false;  //当前不可以自动跳转到下一句
		}
		else
		{
    
    
			//如果 为false 代表没有开启
			isAuto = true;   //为true 开启
							 //执行  自动跳转下一行的功能
			AutoBtnImg.sprite = AutoActiveSprite;  //图片切换成激活图片
			AVGMachine.Instance.isAuto = true;  //当前可以自动跳转到下一句
		}
	}
	#endregion



	#endregion

	#endregion
}

modify GameBtn


/****************************************************

	文件:
	作者:WWS
	日期:2023/05/01 17:14:52
	功能:PlotCanvas.GamePanel右下的工具按钮

*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;



public class GameBtn : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler
{
    
    

	/// <summary>按钮的名称</summary>
	public string BtnName;


	#region 系统


	public void OnPointerEnter(PointerEventData eventData)
    {
    
    
		UIMgr.Instance.PlotCanvas.GamePanel.EnabledBtnDesText();
		UIMgr.Instance.PlotCanvas.GamePanel.SetPlotBtnDesText(BtnName);
    }

    public void OnPointerExit(PointerEventData eventData)
    {
    
    
		UIMgr.Instance.PlotCanvas.GamePanel.DisabledBtnDesText();
    }
    #endregion



}

stars SetActive

Button之类
Button
:Selectable
:UIBehaviour
:MonoBehaviour
:Behaviour // Behaviours are Components that can be enabled or disabled.

	public static void SetActive(this Behaviour behaviour,bool state)
	{
    
    
		behaviour.gameObject.SetActive(state);
	}

modify handles characters SO

insert image description here

/****************************************************
    文件:ResourcesInitRole.cs
	作者:lenovo
    邮箱: 
    日期:2023/5/2 15:27:9
	功能:初始化Assets/Resources/Role下的两个AVGAssetCfg,防止丢失
*****************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Random = UnityEngine.Random;
 

public class ResourcesInitRole 
{
    
    

	[MenuItem(DefinePath.MenuItem_AVG + "01 定位Role【AVGAssetCfg】", false, 0)]//按钮在菜单栏的位置
	public static void ActiveAVGAssetCfgSO() //文件夹
	{
    
    
		Common.Selection_ActiveObject( "Assets/Resources/Role");
	}


	[MenuItem(DefinePath.MenuItem_AVG + "01 初始化Role【AVGAssetCfg】", false, 0)]//按钮在菜单栏的位置
	public static void InitAVGAssetCfgSO() //文件夹
	{
    
    

		AVGAssetCfg role02 = AssetDatabase.LoadAssetAtPath<AVGAssetCfg>("Assets/Resources/Role/2.asset");
		AVGAssetCfg role03 = AssetDatabase.LoadAssetAtPath<AVGAssetCfg>("Assets/Resources/Role/3.asset");
		role02.charaA = LoadRoleSprite("cuimianshi");
		role02.charaB = LoadRoleSprite("xiao");
		role02.charaC = LoadRoleSprite("yinxiao");
		role03.charaA = LoadRoleSprite("xiao");
		role03.charaB = LoadRoleSprite("cuimianshi");
		role03.charaC = LoadRoleSprite("yinxiao");
		AssetDatabase.SaveAssets();
		AssetDatabase.Refresh();
	}

	private static Sprite LoadRoleSprite(string spriteName)
	{
    
    
		return Resources.Load<Sprite>("RoleIMG/"+spriteName);
	}
}

bug SO data loss

Resources/Role/2 will not
Resources/Role/3 The data sprite is often lost to none after running the game (after executing the option button once)

modify PlotCanvas.LoadDiaTextPanel

This is the recording panel of the previous conversation, which is triggered when the GamePanel is scrolled.
But it seems that the problem is not recorded at any time
insert image description here

--------------------------------------------------

Use of watch QuickSheet plugin

There is a documentation in it Assets/QuickSheet/Doc/Unity-Quicksheet.pdf

01 New (these two chains)
Excel Settings
Excel Machine
insert image description here

02 Create a new table, add the table to Excel Machine, and determine the Sheet and attribute types. Configure Editor, Runtime folder path (excluding Assets). Then Generate. (I made a mistake here)
insert image description here

insert image description here

03 After solving the small bug, right click to reimport
insert image description here

bug plugin small bug

Manually change it back//
insert image description here

Overall to be improved --------------------------------------------------


It is the use of access event registration between nodes

Guess you like

Origin blog.csdn.net/weixin_39538253/article/details/130131098