Unity与C#学习记录 - 06

14 篇文章 0 订阅

01 C#内部类

C#有内部类的概念,以前遇到的主要是一个类内部又定义了一个类这种用法,自己却基本不用这种方式,现在学习一下。比如:

这几行代码就最简单的内部类的例子,对于外部是private类型的变量,内部类是无法直接使用的,也就是内部类无法访问外部类的示例变量,所以在int前简单加上static,则内部类就能访问外部类的变量了。这里以变量举例,实际上对于方法也是,内部类无法访问外部类的实例方法。

接着:

public class OuterClass
{
    public void OuterClassMethod()
    {
        k = 0;
    }

    public class InnerClass
    {
        public int k;
    }
}

这里外部类有个方法,试图访问内部类的一个公共变量,则会提示k不存在,也就是外部类无法访问内部类的实例变量,这里和前面类似,静态的可以访问。

内部类实际上还是另外的类了,所以必须用类的实例来访问别人的非静态成员,因为静态成员是类本身的,能访问类,就能访问类的静态成员。

另外,外部类所有访问级别的静态成员对内部类始终可见,如外部类的一个private static void方法,内部类是可以调用的。而内部类则和普通类一样,如一个private static int参数,外部类是访问不到的。

这些介绍只是使用上的知识点,那么C#内部类主要好处是什么,为什么用内部类?根据网上找的,其作用主要是能更好封装,把内部类作为外部类的一个扩展,外部类则类似于内部类的一个命名空间。

02 C# params关键字

学习下params关键字 ,其主要作用是定义方法参数,参数数目是可变的。参数数组长度是可变的,但是必须是一维的,使用如下:

void Start ()
{
    Test(1, 2, 3);
    int[] paramsArray = new int[3] { 4, 5, 6 };
    Test(paramsArray);
}

void Test(params int[] list)
{
    for(int i = 0; i < list.Length; i++)
    {
        Debug.Log(list[i]);
    }
}

params关键字后跟着是参数类型,如这里是int数组,传参的时候可以直接用逗号隔开参数,或者新生成一个参数数组。

03 C#委托和事件等再探

重新学习下C#的委托和事件等知识点,争取写一些例子深入学习。

参考:

https://www.cnblogs.com/qwg123/p/4641133.html

C#的事件是基于Windows的消息处理机制的,无需知道底层也可以开发出基于事件的程序。基于事件的好处是避免等待机制,不用频繁检测判断变量了。而且能方便确定程序执行顺序,占用资源少。事件和委托联系在一起,其关系类似于:租房是一个事件,中介就是委托。

委托可以理解为函数指针,是面向对象且类型安全的。事件一般分为事件发生器和接收器,发射器出发事件,但是不知道哪个对象或者方法会处理该事件,因此发送方和接收方之间存在一个媒介,也就是委托。而事件接收器中则需要一个处理事件的方法,下面是一个例子:

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

public class LearningEvent : MonoBehaviour
{
    void Start ()
    {

    }
    
    void Update ()
    {
        if(Input.GetKeyDown(KeyCode.S))
        {
            KeyInputMonitor keyInputMonitor = new KeyInputMonitor();
            EventReceiver eventReceiver = new EventReceiver(keyInputMonitor);
            keyInputMonitor.Run();
        }
    }
}

internal class KeyEventArgs : EventArgs
{
    public KeyEventArgs(char keyChar) : base()
    {
        KeyChar = keyChar;
    }

    public char KeyChar
    {
        get;
    }
}

internal class KeyInputMonitor
{
    public delegate void KeyDownHandler(object sender, KeyEventArgs e);
    public event KeyDownHandler KeyDown;

    public void Run()
    {
        KeyEventArgs keyEventArgs = new KeyEventArgs('d');
        KeyDown(this, keyEventArgs);
    }
}

internal class EventReceiver
{
    public EventReceiver(KeyInputMonitor monitor)
    {
        monitor.KeyDown += new KeyInputMonitor.KeyDownHandler(OnKeyDown);
    }

    private void OnKeyDown(object sender, KeyEventArgs e)
    {
        Debug.Log("OnKeyDown");
    }
}

EventArgs是包含事件数据的类的基类,封装记录按键信息。主要的是在KeyInputMonitor中,先创建委托,然后创建特定的事件,与委托关联起来。

04 再学一点Shader

参考:

https://www.cnblogs.com/lixiang-share/p/5025662.html

相比于CPU来说,GPU有更高的并行结构,所以处理图形上效率更高。CPU大部分面积为控制器和寄存器,而GPU更多是逻辑处理单元(Arithmetic Logic Unit,ALU),适合对密集型数据进行并行处理。

Shader翻译为着色器,含义是可编程图形管线,也就是计算机处理图形显示的流水线,一般包括顶点shader(Vertex Shader)和片段shader(Fragment Shader)。二者的具体作用范围如下:

Shader的主流编程语言有HLSL、GLSL和CG等,其中HLSL是High Level Shader Language,是基于DX的,只能运行在Windows平台。GLSL是OpenGL Shading Language,是OpenGL的着色语言。OpenGL定义了一个跨语言、跨平台的编程接口,因此GLSL是跨平台的着色语言。因为底层图形驱动限制了上层的编程语言,因此一旦想要改动图形驱动库,那就要重写整个Shader Files,所以就有个CG来应对这种情况,CG在HLSL和GLSL上进行了封装,从而屏蔽了上层着色器语言对底层图形库的依赖。

Unity自己搞了一个ShaderLab,其实是对Shder语法结构的一种包装,支持surface、vertex、fragment和fixed function shader。其中Fixed function shader是较保守的,兼容性最好。surface shader则是对vertex和fragment的语法包装,其实最终也会被翻译为vertex和fragment shader。

Unity中有个MVP矩阵,主要功能是进行坐标系转换。因为Unity有四种坐标系,即模型坐标系、世界坐标系、摄像机坐标系和屏幕坐标系,显示3D场景的过程就是模型本身坐标先用_ObjectToWorld(M矩阵)转换到世界坐标系,再用_WorldToCamera(V矩阵)转换到摄像机坐标系,最后用_Projection(P矩阵)实现从摄像机到屏幕坐标系的转换,从而将图像显示到屏幕。

下面是图形学应用的一点介绍,包括光照剔除、漫反射和高光。

先是光照剔除,我们的视角是从物体到摄像机的向量,如果法线N和视线E的角度小于90,那么观察者再该面的正面,反之在该面的反面,反面的时候是无法观察到物体的,所以需要将其剔除:

image

漫反射是Diffuse,指投射到表面的光向各个方向反射的现象,可以简单理解为光照对物体表面颜色的影响,在Unity中默认的Shader就是漫反射加环境光的综合作用。使用法线和光向量的点乘作为区域颜色的因子,这样再乘以该光源的颜色信息就可以得到对应受光后的颜色了,如下:

image

高光是Specular,指光源照射到物体然后反射到人的眼睛里的时候,物体上最亮的那个点就是高光。高光其实是反射光和视角相互作用形成的。计算高光也是同样的原理,由入射光反射光,再计算反射光和视向量的点乘得到影响因子,最后算出高光强度:

image

05 Unity AudioSource Play方法

Unity播放音频中,如果再次调用Play方法会有音频回退问题,具体看下面:

audio source先设置一个time如45秒,然后停止播放,按下另一个键开始播放,比如播放到51秒,又按下,已经在播放状态,又调用了play,则时间回退,这个play好像会记住上一次的time,所以单独对其time赋值就可以了:

这个是和我想当然理解的不一样的,我理解的是,如果在播放状态,再调用Play会从当前点继续播放,其实就是相对于啥也没做,不过却出现了回退的问题。我以为暂停就是Pause,播放或者继续播放就是Play,所以才犯了这个错误。实际上,用UnPause才是真的取消暂停,而不是像我这样又调用一次Play。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值