Unity 3D 游戏通用系统设置页面,自定义按键设置,背景虚化,图像设置,亮度对比度饱和度音量调节,分辨率窗口化,帧率垂直同步,抗锯齿,阴影质量,纹理质量设置

Posted 唐沢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 3D 游戏通用系统设置页面,自定义按键设置,背景虚化,图像设置,亮度对比度饱和度音量调节,分辨率窗口化,帧率垂直同步,抗锯齿,阴影质量,纹理质量设置相关的知识,希望对你有一定的参考价值。

简易的游戏通用设置页面

本文章包含所有代码及UI结构

页面效果:

UI结构(便于管理):

代码:

思路:

整个页面的父物体SettingPanel上挂载管理代码,用于获取设置页面中所有的功能按钮,拖动条,下拉框等,做一个单例以便其他Panel获取.

有三个按钮有二级页面,所以还需要分别写三个Panel管理代码管理不同的页面,他们都有一个相同点,打开关闭(渐变)激活状态等,所以把这些功能写道一个代码里作为他们的父物体,

先抛开需求如何实现,这些数据必须是要保存的,不能打开游戏又需要重新设置一遍,需要创建一个数据保存类,其功能就是,保存数据(保存到本地),读取数据,默认数据等…,可以在关闭页面时统一保存到本地,打开游戏时读取并加载本地数据,加载数据与保存数据(保存到缓存)的功能应该是SettingPanel来完成,因为所有的按钮,拖动条,下拉框都在这个代码上,也便于赋值.

功能实现问题:

1.内容中的亮度,对比饱和这种是Shader效果,所以并不能通用与各种渲染管线,目前只考虑通用渲染管线,如果有自己的渲染管线,也很好修改.
2.在制作过程中Slider不能仅仅是拖动效果,还需要显示具体的数值并修改数值,所以每一个Slider后都需要一个输入框连接拖拽值.
3.分辨率窗口化帧率等这些可以调用系统设置来完成,抗锯齿,阴影,图像质量(根据项目设定,暂时用系统),按键输入就必须是自己写功能,是时候上代码了.

其中用到了几个小工具

文件工具
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace TFramework

    public partial class FileUtil
    
        /// <summary>
        /// 错误内容
        /// </summary>
        static string Error = "错误!没有寻找到文件,建议查看文件名称是否输入错误?";

        //暂时存储的文件内容
        static List<string> datas = new List<string>();

        /// <summary>
        /// 在本地读取文件全部数据
        /// </summary>
        /// <param name="txtName">文件名</param>
        /// <returns>返回每行</returns>
        public static List<string> ReadLocalData(string txtName)
        
            datas.Clear();
            StreamReader sr = null;//读取
            if (new FileInfo(Application.persistentDataPath + "\\\\" + txtName).Exists)
                sr = File.OpenText(Application.persistentDataPath + "\\\\" + txtName);//读取文件
            else
            
                datas.Add(Error);
                return datas;
            

            //读取所有行
            string data = null;
            do
            
                data = sr.ReadLine();
                if (data != null)
                    datas.Add(data);
             while (data != null);
            sr.Close();//关闭流
            sr.Dispose();//销毁流
            return datas;
        

        /// <summary>
        /// 在本地写入一行数据
        /// </summary>
        /// <param name="txtName">文件名</param>
        /// <param name="data">写入数据</param>
        public static void WriteLocalTxt(string txtName, string data)
        
            StreamWriter sw;//写入
            FileInfo t = new FileInfo(Application.persistentDataPath + "\\\\" + txtName);//文件流 
            if (!t.Exists)
            
                sw = t.CreateText();//创建
            
            else
            
                sw = t.AppendText();//打开文件
            
            sw.WriteLine(data);//写入数据
            sw.Flush();//清除缓冲区
            sw.Close();//关闭流
            sw.Dispose();//销毁流
        

        /// <summary>
        /// 删除本地文件
        /// </summary>
        /// <param name="txtName"></param>
        public static void DeleteLocalTxt(string txtName)
        
            FileInfo t = new FileInfo(Application.persistentDataPath + "\\\\" + txtName);//文件流 
            t.Delete();
        
        /// <summary>
        /// 清空StreamingAssetsData
        /// </summary>
        /// <param name="txtName"></param>
        public static void ClearStreamingAssetsData(string txtName)
        
            string Path = GetStreamingAssetsPath();
            txtName = Path + txtName;
            StreamWriter tmpWrite = new StreamWriter(txtName);
            tmpWrite.WriteLine("");
            tmpWrite.Close();
        

        /// <summary>
        /// 读取StreamingAssets目录文件
        /// </summary>
        /// <param name="path">路径:"/文件名加后缀"</param>
        /// <returns>返回字符串</returns>
        public static List<string> ReadStreamingAssetsData(string path)
        
            FileInfo t = new FileInfo(GetStreamingAssetsPath() + "\\\\" + path);//文件流 
            if (!t.Exists)
            
                return null;
            
            string Path = GetStreamingAssetsPath();
            path = Path + path;

            //打开文件
            StreamReader tmpReader = new StreamReader(path);
            datas.Clear();
            string ReadRow = tmpReader.ReadLine();
            while (ReadRow != null)
            
                datas.Add(ReadRow);
                ReadRow = tmpReader.ReadLine();
            
            tmpReader.Close();
            return datas;
        

        /// <summary>
        /// StreamingAssets目录写入一行数据
        /// </summary>
        /// <param name="path"></param>
        public static void WriteStreamingAssetsData(string path, string data)
        
            ReadStreamingAssetsData(path);
            //string Path = GetStreamingAssetsPath();
            //path = Path + path;
            //StreamWriter tmpWrite = new StreamWriter(path);
            StreamWriter tmpWrite;
            FileInfo t = new FileInfo(GetStreamingAssetsPath() + "\\\\" + path);//文件流 
            if (!t.Exists)
            
                tmpWrite = t.CreateText();//创建
            
            else
            
                tmpWrite = t.AppendText();//打开文件
            
            //foreach (string linedata in datas)
            //
            //    tmpWrite.WriteLine(linedata);
            //
            tmpWrite.WriteLine(data);
            tmpWrite.Close();
        

        /// <summary>
        /// 得到StreamingAssets目录
        /// </summary>
        /// <returns></returns>
        static string GetStreamingAssetsPath()
        
            string str = Application.streamingAssetsPath + "/";
            return str;
        

    



字符串功能扩展
using System.Collections.Generic;

namespace TFramework

    public partial class StringUtil
    
        /// <summary>
        /// 替换字符
        /// </summary>
        /// <param name="str">需要修改的字符串</param>
        /// <param name="Target">需要替换的字符串</param>
        /// <param name="ModifyTarget">替换为ModifyTarget</param>
        /// <returns></returns>
        public static string Replace(string str, string Target, string ModifyTarget)
        
            string ModifyStr = "";
            ModifyStr = System.Text.RegularExpressions.Regex.Replace(str, Target, ModifyTarget);
            return ModifyStr;
        
        /// <summary>
        /// 替换字符
        /// </summary>
        /// <param name="str">需要修改的字符串</param>
        /// <param name="Target1">需要替换的其中一个字符串</param>
        /// <param name="Target2">需要替换的其中一个字符串</param>
        /// <param name="ModifyTarget1">Target1替换为ModifyTarget1</param>
        /// <param name="ModifyTarget2">Target2替换为ModifyTarget2</param>
        /// <returns></returns>
        public static string Replace(string str, string Target1, string Target2, string ModifyTarget1, string ModifyTarget2)
        
            string ModifyStr = "";
            ModifyStr = System.Text.RegularExpressions.Regex.Replace(str, Target1, ModifyTarget1);
            return System.Text.RegularExpressions.Regex.Replace(ModifyStr, Target2, ModifyTarget2);
        

        /// <summary>
        /// 字符串截取(两个字符中间的字符串)
        /// </summary>
        /// <param name="str">需要截取的字符串</param>
        /// <param name="LocationStart">从这个地方开始截取</param>
        /// <param name="LocationEnd">截取到这个地方</param>
        /// <returns></returns>
        public static string Substring(string str, char LocationStart, char LocationEnd)
        
            if (str.Length < 3)
                return "字符串少于3,无法截取";
            string ModifyStr = "";
            int index0 = 0;
            int index1 = 0;
            for (int j = 0; j < str.Length; j++)
            
                if (str[j] == LocationStart)
                
                    index0 = j;
                
                if (str[j] == LocationEnd)
                
                    index1 = j;
                
            
            ModifyStr = str.Substring(index0 + 1, index1 - index0 - 1);
            return ModifyStr;
        
        /// <summary>
        /// 字符串截取(字符到开始或结束)
        /// </summary>
        /// <param name="str"></param>
        /// <param name="TargetChar"></param>
        /// <param name="IsAback"></param>
        /// <returns></returns>
        public static string Substring(string str, char TargetChar, bool IsAback)
        
            if (str.Length < 3)
                return "字符串少于3,无法截取";
            string ModifyStr = "";
            int index = 0;
            for (int j = 0; j < str.Length; j++)
            
                if (str[j] == TargetChar)
                
                    index = j;
                
            
            if (IsAback)
            
                ModifyStr = str.Substring(index + 1, str.Length - 1 - index);
            
            else
            
                ModifyStr = str.Substring(0, index);
            
            return ModifyStr;
        

        /// <summary>
        /// 字符串截取
        /// </summary>
        /// <param name="str">需要截取的字符串</param>
        /// <param name="LocationStart">从这个地方开始截取</param>
        /// <param name="LocationEnd">截取到这个地方</param>
        /// <returns></returns>
        public static List<string> Substrings(string str, char LocationStart, char LocationEnd)
        
            List<string> ModifyStrs = new List<string>();
            if (str.Length < 3)
                return null;

            int index0 = 0;
            int index1 = 0;
            for (int j = 0; j < str.Length; j++)
            
                if (str[j] == LocationStart)
                
                    index0 = j;
                
                if (str[j] == LocationEnd)
                
                    index1 = j;
                    ModifyStrs.Add(str.Substring(index0 + 1, index1 - index0 - 1));
                
            
            return ModifyStrs;
        
        public static List<string> Substrings(string str, char LocationStart1, char LocationEnd1, char LocationStart2, char LocationEnd2)
        
            List<string> ModifyStrs = new List<string>();
            if (str.Length < 3)
                return null;

            int index0 = -1;
            int index1 = -1;
            int index2 = -1;
            int index3 = -1;
            for (int j = 0; j < str.Length; j++)
            
                if (str[j] == LocationStart1)
                    index0 = j;
                if (str[j] == LocationStart2)
                    index2 = j;
                if (str[j] == LocationEnd1 && index0 != -1)
                
                    index1 = j;
                    ModifyStrs.Add(str.Substring(index0 + 1, index1 - index0 - 1));
                
                if (str[j] == LocationEnd2 && index2 != -1)
                
                    index3 = j;
                    ModifyStrs.Add(str.Substring(index2 + 1, index3 - index2 - 1));
                
            
            return ModifyStrs;
        
    


PanelBase(页面父类)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PanelBase : MonoBehaviour

    CanvasGroup CanvasGroup_Panel;
    bool ActivateChangeAlpha = false;
    float AlphaValue = 0;
    [HideInInspector]
    public bool ActivateState=false;
    protected virtual void Start()
    
        CanvasGroup_Panel = GetComponent<CanvasGroup>();
    
    public virtual void ShowPanel()
    
        AlphaValue = 1;
        ActivateChangeAlpha = true;
        CanvasGroup_Panel.blocksRaycasts = true;
        ActivateState = true;
    
    public virtual void HidePanel()
    
        AlphaValue = 0;
        ActivateChangeAlpha = true;
        CanvasGroup_Panel.blocksRaycasts = false ;
        ActivateState = false;
    
    protected virtual void Update()
    
        if (ActivateChangeAlpha)
        
            CanvasGroup_Panel.alpha = Mathf.Lerp(CanvasGroup_Panel.alpha, AlphaValue, 0.1f);
            if (Mathf.Abs(CanvasGroup_Panel.alpha - AlphaValue) < .1f)
            
                CanvasGroup_Panel.alpha = AlphaValue;
                ActivateChangeAlpha = false;
            
        
    


DataProcessing(数据保存类)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TFramework;

public class DataProcessing : MonoBehaviour

    public float Data_LuminanceValue=1, Data_ContrastValue=1, Data_SaturationValue=1, Data_AudioValue=1, Data_VisibilityValue=200;
    public int Data_ResolutionIndex = 0, Data_FPSIndex = 1, Data_AntiAliasingIndex=0, Data_ShadowQualityIndex=2, Data_GrainQualityIndex=2;
    public bool Data_IsWindow=false, Data_IsVsync=false;
    public List<int> Keypads = new List<int>();
    private void Awake()
    
        ReadDate();
    
    /// <summary>
    /// 数据保存在本地StreamingAssets文件夹
    /// </summary>
    public void SaveDate()
    
        FileUtil.ClearStreamingAssetsData("SettingData");//清空之前的数据
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_LuminanceValue=" + Data_LuminanceValue);
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_ContrastValue=" + Data_ContrastValue);
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_SaturationValue=" + Data_SaturationValue);
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_AudioValue=" + Data_AudioValue);
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_VisibilityValue=" + Data_VisibilityValue);
        FileUtil.WriteStreamingAssetsData("SettingData", "");
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_ResolutionIndex=" + Data_ResolutionIndex);
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_FPSIndex=" + Data_FPSIndex);
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_AntiAliasingIndex=" + Data_AntiAliasingIndex);
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_ShadowQualityIndex=" + Data_ShadowQualityIndex);
        FileUtil.WriteStreamingAssetsData("SettingData", "Data_GrainQualityIndex=" + Data_GrainQualityIndex);
        FileUtil.WriteStreamingAssetsData("SettingData", "");
        FileUtil.WriteStrea

黑魂复刻游戏的按键长按功能——Unity随手记

今天实现的内容:

按键长按

长按是判断我们按下一个按键的持续时间是否大于一个固定值,持续时间大于该值说明当前我们正在长按,在黑魂游戏中,玩家的翻滚/后跳和冲刺都是一个按键,区别在于长按该键是冲刺,短按就是翻滚/后跳。我们依然会用到计时器来实现按钮长按。

 

 

在按下按键后,我们会开启delaying计时器,在delaying计时器执行期间按键的isDelaying信号会被设置为true。所以,按住按钮并且isDelaying为false表明按键为长按状态,松开按键并且isDelaying为true表明按键为短按。
下列代码为最新的MyButton。

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

// 自制按钮类
public class MyButton
{
    public float extendingDuration = 0.2f; //extending的时间长度
    public float delayingDuration = 0.2f; //delaying的时间长度

    public bool isPressing = false; //正在按压
    public bool onPressed = false; //刚刚按下
    public bool onRelease = false; //刚刚被释放
    public bool isDoubleClick = false; //双击
    public bool isLongPress = false; //长按
    public bool isShortPress = false; //长按

    public bool isExtending = false; //释放按键后的一段时间内为true 用于双击判断  
    public bool isDelaying = false; //刚刚按下后的一段时间内为true 用于长按判断

    private bool currentState = false; //当前状态
    private bool lastState = false; //上一帧的状态
    private MyTimer extendingTimer = new MyTimer(); //extending计时器
    private MyTimer delayingTimer = new MyTimer(); //delaying计时器

    // 更新MyButton
    public void Tick(bool _input)
    {
        extendingTimer.Tick(Time.deltaTime);
        delayingTimer.Tick(Time.deltaTime);

        onPressed = false; //OnPressd只有一种情况下是true 所以每次都先设置为false
        onRelease = false; //与OnPressed同理

        currentState = _input; //按键的当前状态永远和对应物理按键的状态一致

        isPressing = currentState; //是否被按下 按下就是true

        if (currentState != lastState) //判断按键信号是否改变 改变说明刚刚按下按键或刚刚松开按键
        {
            if (currentState == true) //刚刚按下按键
            {
                onPressed = true;
                StartTimer(delayingTimer, delayingDuration);
            }
            else //刚刚松开按键
            {
                onRelease = true;
                StartTimer(extendingTimer, extendingDuration);
            }
        }

        lastState = currentState; //结束时将上一帧状态更新为当前帧状态

        isExtending = (extendingTimer.state == MyTimer.TIMER_STATE.RUN) ? true : false; //设置extending
        isDelaying = (delayingTimer.state == MyTimer.TIMER_STATE.RUN) ? true : false; //设置delaying

        isLongPress = (isPressing && !isDelaying) ? true : false; //长按判断
        isShortPress = (isDelaying && onRelease) ? true : false; //短按判断
        isDoubleClick = (isExtending && isPressing) ? true : false; //双击判断
    }

    private void StartTimer(MyTimer _timer, float _extDuration)
    {
        _timer.duration = _extDuration;
        _timer.Go();
    }
}

有了新的长按/短按信号,我们就可以直接使用。

        // 翻滚/后跳
        jab_roll = buttonRun_jab_roll.isShortPress;
        // 冲刺
        run = buttonRun_jab_roll.isLongPress;

 

以上是关于Unity 3D 游戏通用系统设置页面,自定义按键设置,背景虚化,图像设置,亮度对比度饱和度音量调节,分辨率窗口化,帧率垂直同步,抗锯齿,阴影质量,纹理质量设置的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D 官方移动游戏优化指南11.动画

Unity3D 官方移动游戏优化指南11.动画

Unity3D 官方移动游戏优化指南11.动画

在 Unity3D 游戏中自定义 iOS 音量 HUD

Unity3D 官方移动游戏优化指南7.资源

Unity3D 官方移动游戏优化指南7.资源