记录大四第一次找工作所遇到问题

这篇文章根据简历列举出可能问到的除了平常八股文之外可能出现的问题(超精简)

slots中使用到的MVC设计模式

我们把整个关卡大多数逻辑处理和整个流程控制都放到了Model层(逻辑模型中)在View层(视图模型)中我们放置的大多是界面元素的显隐、动画表现等效果。在C层(Contriller层)存在的目的则是确保M和V的同步,一旦M发生改变,V应该同步更新。

关于在辅助线程中访问UnityApi组件

在这里插入图片描述

使用Xlua热更新的完整流程

在这里插入图片描述

详细步骤移步至原文
链接:https://blog.csdn.net/qq_40143976/article/details/106211673
第一步:
解压 xLua-master
将 xLua-master/Assets 中所有内容复制到xlua-test/Assets中

创建个C#脚本迅速测试下刚导入的xLua是否能够正常工作:

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

public class MainController : MonoBehaviour
{
    void Start()
    {
        XLua.LuaEnv luaenv = new XLua.LuaEnv();
        luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");
        luaenv.Dispose();
    }

    void Update()
    {
        
    }
}

1.每次打开客户端,使用md5来简单计算文件的特征之后向服务器发送,服务器也是用md5进行文件比对,询问是否需要更新
2.服务器收到客户端发来的询问,对比文件差异,如果需要更新,将返回需要更新的文件列表url
3.客户端如果收到服务器发来的文件更新列表url,将立即前往下载,并存储在本地;如果收到字符串"0",表示无需更新资源,则直接进入第4步。
4.开始运行客户端的主逻辑

使用脚本查找预制体引用组件消失

在日常开发中,由于会经常修改动效给到我们的预制体或者由于公司Unity版本升级原因带来预制体组件丢失的情况产生报错,需要开发一个脚本可以检查出哪个脚本上哪个属性引用丢失。
解决思路:将脚本对象序列化,判断属性引用ObjectReferenValue是否为空,且ObjectReferenceInstanceIDValue是否不为零,以此来判断是否丢失引用。具体代码如下:


private static void CheckMissingReferenceScript(GameObject go)
    {
        if (null == go) return;
        MonoBehaviour[] scripts = go.GetComponentsInChildren<MonoBehaviour>(true);
        if (null != scripts)
        {
            string tips = string.Empty;
            for (int i = 0; i < scripts.Length; i++)
            {
                MonoBehaviour mono = scripts[i];
                if (null == mono) continue;
                SerializedObject tempObject = new SerializedObject(mono);
                SerializedProperty temProperty = tempObject.GetIterator();
                while (temProperty.NextVisible(true))
                {
                    if (temProperty.propertyType == SerializedPropertyType.ObjectReference
                        && temProperty.objectReferenceValue == null
                        && temProperty.objectReferenceInstanceIDValue != 0)
                    {
                        tips += mono.GetType().ToString() + "| |" + temProperty.propertyPath + "引用丢失\t\n";
                    }
                }
            }
            if (!string.IsNullOrEmpty(tips))
            {
                EditorUtility.DisplayDialog(tips, "", "确定");
            }
        }

Unity图集压缩优化:RGBA分离成ETC和alpha(大厅卡牌优化)

原文链接:CSDN林新发
android平台
我们把原图和生成的alpha图的压缩格式都设置成ETC 4 bits,这样大小加起来比原图大小还要小一半。

iOS平台
因为没有ETC压缩格式,可以用PVRTC 4 bits的压缩格式,但是必须是正方形尺寸的图片,否则会变形;如果是长方形尺寸的图片,就用RGB 16 bit的压缩格式。
首先更改图片设置,设置成可读写的
在这里插入图片描述

1、Unity通过RGBA图生成alpha通道的图,Editor脚本 :


```csharp

//GenAlphaTexture.cs
 
using UnityEngine;
using UnityEditor;
using System.IO;
 
public class GenAlphaTexture
{
    [MenuItem("GameTools/GenAlphaTexture")]
    public static void StartGenAlphaTexture()
    {
        var textures = Selection.GetFiltered<Texture2D>(SelectionMode.DeepAssets);
        foreach (var t in textures)
        {
            var path = AssetDatabase.GetAssetPath(t);
 
            // 如果提示图片不可读,需要设置一下isReadable为true, 操作完记得再设置为false
            // var imp = AssetImporter.GetAtPath(path) as TextureImporter;
            // imp.isReadable = true;
            // AssetDatabase.ImportAsset(path);
 
 
            var newTexture = new Texture2D(t.width, t.height, TextureFormat.RGBA32, false);
            var colors = t.GetPixels32();
            var targetColors = newTexture.GetPixels32();
            for (int i = 0, len = colors.Length; i < len; ++i)
            {
                var c = colors[i];
                targetColors[i] = new Color32(c.a, c.a, c.a, c.a);
            }
            newTexture.SetPixels32(targetColors);
 
            string fname = path.Split('.')[0] + "_a.png";
            File.WriteAllBytes(fname, newTexture.EncodeToPNG());
            
            // imp.isReadable = false;
            // AssetDatabase.ImportAsset(path);
            AssetDatabase.Refresh();
        }
    }
}

代码逻辑
:首先新建一个textures保存我们选中的图片,之后遍历我们选中的图片,获取他们的AssetPath。之后根据我们遍历的单个对象新建一个Texture2D并使用getPixels32()方法。获取它的32位颜色副本保存为var1,
同时我们使用同样的方法获取我们当前图片的32位副本数组为var2。之后我们新建一个color32并遍历var1将var1的四个通道全部赋值var2的a
通道的值。最后将我们得到的这个新的数组转换成PNG图片定义一个PNG结尾的名字保存到我们选中图片的位置

2、把上面的脚本放到Unity工程目录:Assets/Editor目录中

然后选中要处理的图片,然后点击菜单GameTools/GenAlphaTexture,就会在同目录中生成一张alpha通道的图。

3、我们把原图和生成的alpha图的压缩格式都设置成ETC 4 bits,这样大小加起来比原图大小还要小一半。

如果是iOS平台,因为没有ETC压缩格式,可以用PVRTC的压缩格式,但是必须是正方形尺寸的图片,否则就用RGB 16 bit的压缩格式。

关于不同平台压缩格式选择:
在这里插入图片描述
4、shader脚本:合并一张RGB图和一张alpha图

// 合并一张ETC压缩的RGB图和一张alpha图
Shader "Test/UIETC" 
{
    Properties 
        {
                 _MainTex ("Base (RGB)", 2D) = "white" { }
                 _AlphaTex("AlphaTex",2D) = "white"{}
                 }
    SubShader
        {

                 Tags
                 {
                        "Queue" = "Transparent+1"
                 }
         Pass
                 {
                        Lighting Off
                        ZTest Off
                        Blend SrcAlpha OneMinusSrcAlpha
                        Cull Off
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag

                        #include "UnityCG.cginc"

                        sampler2D _MainTex;
                        sampler2D _AlphaTex;

                        float _AlphaFactor;
                
                        struct v2f 
                        {
                                float4  pos : SV_POSITION;
                                float2  uv : TEXCOORD0;
                                float4 color :COLOR;
                        };

                        half4 _MainTex_ST;
                        half4 _AlphaTex_ST;

                        v2f vert (appdata_full v)
                        {
                                v2f o;
                                o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
                                o.uv =  v.texcoord;
                                o.color = v.color;
                                return o;
                        }

                        half4 frag (v2f i) : COLOR
                        {
                                half4 texcol = tex2D (_MainTex, i.uv);

                                half4 result = texcol;

                                result.a = tex2D(_AlphaTex,i.uv)*i.color.a ;

                                return result;
                        }
                        ENDCG
                 }
    }
}

我们需要创建一个新的材质用于方式我们的shader脚本,之后将两张图片分别拖入材质对应位置,最后在UI材质选择中选择我们新创建的材质即可

在这里插入图片描述

若想把合并的图集也是用这中方法进行压缩,则需要检测图集是否为正方形
原文链接:林新发

slots中ui屏幕适配:

把脚本挂载在摄像机上,之后选择我们需要适配的机型,摄像机会自动调整当前Game视图的分辨率,我们根据美术给出的效果图完成对当前机型的适配。
之后选择另一种机型,按照同样的步骤完成操作。这个过程中我们只对IOS的设备完成机型适配,安卓机型比较多,我们会有一个默认的分辨率匹配安卓机型,
对于安卓机型的适配,我们重点还是放到了使用UGUI的锚点完成,这个过程在整个在层级面板的顺序很重要:例如首先创建一个空的父物体铺满整个屏幕,1920*1080
之后创建一个空子节点并把锚点设置在屏幕右上方,将关卡玩法说明放置在这个位置,这样无论安卓机型分辨率怎么改变,我们的这个按钮会始终保持在固定位置。

制作UI扫光Shader

原文链接:链接
在slots开发过程中 我们的banner栏需要添加扫光效果,是用粒子系统也能实现,不过需要耗费性能
在这里插入图片描述

做出这样的效果仅仅需要在Image的材质下挂上material,而且还可以根据需求修改参数
在这里插入图片描述
简单介绍下原理,根据角度和时间与厚度计算出在uv上计算出一块平行四边形的光亮区域。在这个区域内的颜色进行高光提亮。
直接下载Unity对应版本的UGUI默认shader 进行修改。
首先对外暴露参数:

    	lightTime("Light Time", Float) = 0.6
        thick("Light Thick", Float) = 0.3
        nextTime("Next Light Time", Float) = 2
        angle("Light Angle", int) = 45

然后直接修改片元函数。

sampler2D _MainTex;
            half lightTime;
            int  angle;
            float thick;
            float nextTime;

            fixed4 frag(v2f IN) : SV_Target
            {
                half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);

                //-------
				fixed currentTimePassed = fmod(_Time.y, lightTime + nextTime);
				fixed x = currentTimePassed / lightTime;
				fixed tanx = tan(0.0174*angle);
				x += (x-1)/tanx;
				fixed x1 = IN.texcoord.y /tanx  + x;
				fixed x2 = x1 + thick;
				if(IN.texcoord.x > x1 && IN.texcoord.x < x2)
				{
					fixed dis = abs(IN.texcoord.x-(x1+x2)/2);
					dis = 1-dis*2/thick;
					half ca = color.a;
					color += color*(1.4*dis);
					color.a = ca;
				}

                #ifdef UNITY_UI_CLIP_RECT
                color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
                #endif

                #ifdef UNITY_UI_ALPHACLIP
                clip (color.a - 0.001);
                #endif

                return color;
            }

齐活

ARPG游戏中使用到的优化

静态批处理的优缺点

优点就是减少Draw Call。
缺点有以下几点:
①静态批处理只对运行前场景中的静态物体有效,什么意思?就是你必须先把静态物体放置到场景里面,这些物体才能被进行静态批处理。用代码动态创建的物体,即便这个物体是勾上了静态,也是不能被静态批处理的,仍然会增加一次Draw Call。(当然如果这个物体能被动态批处理除外哈)
②静态批处理的物体不能够移动,即Transform组件无效,刚体组件Rigidbody也无效。
③有动画的模型,就不要设置静态批处理属性了,因为不会降低 Batches 的数值,而且有动画的模型, 即使设置了静态批处理, 也跟没有设置是一样的。
④静态批处理会占用更多内存,因为静态批处理会额外拷贝一份网格到内存。

遮挡剔除

给场景中需要设置遮挡剔除的物体设置“遮挡静态( Occluder Static/Occludee Static)”
开始做遮挡剔除的烘焙(即点击菜单的Window–>Rendering–>Occlusion Culling)出现遮挡剔除面板,选择“Bake–bake”即可
选择遮挡剔除窗口的Visualizatior,然后运行程序移动摄像机即可看到效果

层消隐

如果场景中存在大量小“物件”,则可以使用“层消隐距离”来优化场景;”层消隐距离“就是在比较远的距离将小物体剔除,以减少绘图调用的数量
步骤
将想要隐藏的小物件放入一个单独的层级(Layer)比如我的放入了SmallObj层级里
在场景中的摄像机(其实任何物体都行)添加脚本组件,代码如下:
public class Test : MonoBehaviour {
void Start () {
float[] distance = new float[32]; //数组需要恰好包含32个浮点数的layerculldistance
distance[8] = 10; //第8层在10米外不显示
Camera.main.layerCullDistances = distance;
}
}
注意:第八层指的是在unity中要隐藏的物体的层级即我们的SmallObj层
Ok大功告成

LOD多层次细节

这就是说,根据摄像机与模型的距离,来决定显示哪一个模型,一般距离近的时候显示高精度多细节模型,距离远的时候显示低精度低细节模型,来加快整体场景的渲染速度。
作用:优化GPU
缺点:同一模型要准备多个模型,消耗内存
特点:以内存做消耗来优化GPU
创建一个空物体,并把3个精度的模型放下边,给空对象添加上 LOD组件
然后点击 LOD组件 的各个精度添加上不同精度的模型
然后此时移动 场景摄像机 或者 组件的摄像机 就可以看到效果了

通过林新发完成学习
事件管理器
在开发过程中遇到了代码耦合度过高的问题,主要是通过我们在时间管理器类中定义的事件监听缓存,和我们注册事件时候传入的事件实现这一功能。

比如背包,我们在点击物品使用之后,需要通过背包管理器使用了背包内的物体,这时候我们需要调用view层去刷新UI,而我们的View层的没有做成单例模式,这时候我们就通过使用时事件管理器去很方便的实现调用效果

我们首先在view层通过start函数和destory方法中并通关定义事件名的脚本添加注册事件和注销事件的响应函数,之后便可以在在管理器中抛出事件,在view层调用到刷新的方法,更新显示。

在我们ARPG游戏中,任务奖励模块使用到了观察者模式。首先我们在任务奖励窗口类中添加了事件监听和事件注销,我们在不同业务类中触发了完成任务的效果的时候,只需要使用事件管理器,我们抛出这个事件,携带我们完成的任务的ID作为参数,在任务奖励窗口中给遍历任务列表,将任务完成状态设置成true并刷新ui即可

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值