第八章 C#脚本(上)

这篇具有很好参考价值的文章主要介绍了第八章 C#脚本(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

脚本是使用 Unity 开发的所有应用程序中必不可少的组成部分。大多数应用程序都需要脚本来响应玩家的输入并安排游戏过程中应发生的事件。游戏对象的行为由附加的组件控制。虽然Unity内置了许多组件,但是我们仍然可以使用脚本来创建自定义组件。Unity支持C#编程脚本语言(不熟悉的可以单独学习一下,看看我之前发布的C#课程),开发工具使用Visual Studio。我们一般情况下,在Unity中创建C#脚本,然后在VS中编写代码,最后回到Unity中运行。

创建C#脚本非常简单,需要我们在Project工程视图下创建,可以右击Project工程视图空白区选择“Create”-> “C# Script”,也可以通过菜单栏“Assets” -> “Create” - > “C# Script”来创建。新创建的脚本文件名称将处于选中状态,提示输入新名称。最好在此时输入新脚本的名称而不是稍后编辑名称。双击新创建的脚本文件,默认将使用 Visual Studio打开。新创建的脚本文件不是一个空白文件,而是一个继承“MonoBehaviour”的C#类。

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

注意,类名和文件名必须相同,且该脚本必须附加到游戏对象上才能被运行。
这个MonoBehaviour 是Unity的一个内置类,该类中有两个方法:Start和Update。

我们知道游戏就是一个无限循环,每一次的循环都会接收和响应用户输入,渲染游戏对象(模型网格),播放游戏动画,特效声音或背景音乐等等。每一次的循环我们可以理解为一帧(一次渲染)。我们知道动画的原理就是通过一帧一帧的静态图片播放而实现的。为了能够让人眼感觉到这不是图片,而是动画的效果,1秒钟之内至少要播放24张连续图片才能达到最终的效果。游戏的本质也是如此,游戏引擎会在1秒钟之内循环渲染N次场景内的所有游戏对象,这个数值N就是我们所说的FPS(Frames Per Second)。FPS越大,游戏视觉效果越好。通常情况下,手机游戏的FPS=30就可以了,PC游戏的FPS=60就可以了,VR游戏的FPS=90就可以了。当然,如果我们的硬件允许的话,达到120的FPS是最棒的效果。这个话题我们不在细说了,回到MonoBehaviour中的Start和Update方法上来。Update 方法是放置代码的主要地方,用于处理游戏对象的帧更新(FPS值就是1秒钟update被执行了多少次)。这可能包括角色移动、响应用户输入,基本上涉及游戏运行过程中随时间推移而需要处理的任何事项。在处理游戏业务逻辑的时候,经常会使用附加到游戏对象身上的各种组件(游戏对象的大部分行为都是通过组件完成的),我们会通过组件来完成不同的功能,以及组件与组件之间的关联关系。为了使 Update 方法正常运行,在进行任何游戏操作之前,通常需要确保游戏对象身上的组件能够正确获取,相当于初始化操作。所以,在游戏开始之前(即第一次调用Update方法之前),Unity 将调用Start方法,此方法是进行游戏对象初始化的位置。我们可以在这个方法中来获取游戏对象上面的各种组件。

这里需要注意的,我们的C#脚本虽然是一个类,但是不能为其添加构造方法。这是因为C#脚本类对象的构造由Unity来实例化。如果尝试为脚本组件定义构造方法,将会干扰 Unity 的正常运行,并可能导致项目出现重大问题。如果想要在构造方法里面完成的代码逻辑,可以移植到Start方法内。

接下来,我们创建一个新工程(ScriptDemo),然后创建一个“Test.cs”脚本来测试一下Start和Update方法。创建文件成功后,文件就会自动处于重新命名的状态,我们只需要输出“Test”即可。输入完毕后,双击就会自动使用Visual Studio打开“Test.cs”脚本。

第八章 C#脚本(上)

接下来,我们要做的就是添加如下的两行代码。

    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("start method...");
    }

    // Update is called once per frame
    void Update()
    {
        Debug.Log("update method...");
    }

为了减少文档篇幅长度,我们省略了其他代码。

Debug.Log 是一个简单的命令,只是将消息输出到 Unity 的控制台Console面板。

由于默认创建的场景中只有“Main Camera”和“Directional Light”两个游戏对象,因此我们暂且将“Test.cs”的脚本文件附加到“Main Camera”游戏对象上面吧。这个操作非常简单,我们先在Hierarchy层次面板中选中“Main Camera”游戏对象,然后就会在Inspector检视面板中显示“Main Camera”的各种属性控件。最后我们将Project视图中的脚本文件拖动到“Main Camera”的Inspector检视视图上面即可。

第八章 C#脚本(上)

接下来我们Play当前工程,应该会在 Unity Editor底部的Console 视图中看到此消息。

如果找不到Console 视图,可以在菜单栏Window -> General -> Console 重新打开。

第八章 C#脚本(上)

我们发现,Start方法执行了一次,而Update方法则再不停的执行直到停止运行工程。在上面的截图中,我们会发现“Collapse”的按钮,它会重叠相同代码方式的输出。而重叠的次数则会在最右端以数字的形式展示处理。例如,上图中的update方法输出“update method...”被重复执行了94次。那么这个update方法一秒钟执行多少次呢(FPS值)?

我们可以使用代码来计算1秒钟内Update执行的次数来获取:

public class Test : MonoBehaviour
{
    private int count = 0;
    private float detaTime = 0.0f;

    void Update(){

	    //Debug.Log("update method...");
	
        // 累加帧数
        count++;
        // 累加时间
        detaTime += Time.deltaTime;

        // 累加时间超过1秒
        if (detaTime >= 1.0f)
        {
            // 计算FPS值
            float fps = count / detaTime;
            Debug.Log("FPS = " + fps);

            // 帧数和累加时间清零
            count = 0;
            detaTime = 0;
        }
    }
}

上面的代码逻辑非常简单,就是使用一个变量来累计Update方法执行的次数,同时累计当前执行的时间,Time.deltaTime 是Unity提供给我们的一个属性值,它代表当前帧和上一帧之间的时间差。因此,我们只需要累加这个属性值就可以获取update执行的时间长度detaTime。由于我们的代码运行都是毫秒级别的,所以当detaTime超过等于1秒钟的时候,我们就可以使用count/detaTime获取FPS值了。为什么不是detaTime等于1秒钟直接输出count值呢,因为这个detaTime不能非常非常精准的等于1,多数情况它的值可能会是1.001之类的,因此我们还需要使用count/detaTime做一个除法计算,得到一个包含小数的FPS值。

接下来,我们就Play当前工程,查看控制台视图输出。

第八章 C#脚本(上)

我们发现这个FPS值并非是一个固定的数值,大概是在300-400之间(跟电脑配置有关)。

在Game窗口的右上角有一排按钮,其中有一个是“Stats”,我们点击一下就会出现一个新弹窗,在这个新弹窗上面,我们就也能看到FPS数值。

第八章 C#脚本(上)

两者大致相同。既然FPS不是一个固定的数值,那么我们在上面提到过手机端(30),PC端(60)以及VR端(90)的FPS值,其实就是一个期望的平均值而已。我们工程中展示的FPS值是300-400之间,明显高于PC端的平均FPS值60啊?这么高的FPS值我们完全不需要啊(浪费电脑性能),我们如何设置其为60呢?这个问题稍微有些复杂。

首先,我们需要了解FPS值与显卡,显示器的关系?

显卡负责绘制图像再输送到显示器上,每个图像可以称为一帧。游戏帧数(FPS)就是显卡每秒绘制图像的数量。显示器则会将显卡绘制的图像显示到屏幕上。显示器刷新频率就是显示器画面每秒呈现图像的数量。一般情况下,我们电脑屏幕的刷新频率是60HZ,也就是说显示器1秒钟显示60张图像,当然我们也可以手动修改这个数值。那么,现在就存在一个问题,如果FPS值和显示器刷新频率不一样会出现什么情况?如果FPS高于显示器的刷新频率,那么多余的图像将不会被显示到屏幕上。因为动画的产生就是通过连续图像产生的,如果屏幕只显示一部分图像的话,那么这动画效果显然是不连贯的。如果FPS低于显示器的刷新频率的话,那么动画效果就会出现卡顿现象,达不到连贯效果。请注意,第一种情况是因为丢失图像而造成动画不连贯,后一种情况是显示太慢造成动画卡顿不连贯。想到这里,大家应该比较清楚了,最好的效果应该是让两个值大致相等,最好是FPS稍微大于显示器刷新频率,这样呈现的动画效果是最好的。为了解决这个问题,出现了垂直同步技术。开启垂直同步后,电脑就会等待上一张图像渲染完成后才会发出开始下一张渲染的命令,也就是说让显卡按照显示器的输出去绘制图像(强制游戏帧数最大不超过刷新率)。这样做唯一的缺点就是限制了显卡性能的发挥。但是,大家一定要明白的是,越高的FPS值越能让动画播放越流畅,给玩家非常棒的游戏体验,这一点是不变的。

在Unity中可以通过Application.targetFrameRate 指定的游戏使用的指定的FPS平均值。默认的targetFrameRate是 -1 数值,表示游戏应以平台的默认帧率渲染。

此默认速率取决于平台:

- 在独立平台上(例如PC),默认的帧率是可实现的最大帧率。

- 在移动平台上,默认帧率通常为每秒 30 帧。

- 在 WebGL 上,默认值允许浏览器选择帧率来匹配其渲染循环时序。

- 使用 VR 时,Unity 将使用 SDK 指定的目标帧率并忽略游戏指定的值。

看到上面的解释,我们就不难理解刚刚运行的工程的FPS是300-400之间了,因为PC平台的默认是能实现多大就实现多大,这个就跟个人电脑显卡档次有关系了。既然这样的话,我们就将Application.targetFrameRate 设置为 60,因为我的电脑显示器刷新频率就是60。

第八章 C#脚本(上)

我们在“Test.cs”的脚本中的“Start”方法来设置FPS值,如下所示:

void Start()
{
	//Debug.Log("start method...");
	
    Application.targetFrameRate = 60;
}

再次Play我们的工程,查看控制台输出以及“Stats”弹窗。

第八章 C#脚本(上)

 第八章 C#脚本(上)

我们发现两者大致也是相同的,都是近似等于60,这就说明我们设置起作用了。先不要着急,我们忽略了一个垂直同步技术。在Unity中我们可以通过QualitySettings.vSyncCount来设置是否开启垂直同步技术,0代表不开启,大于0代表开启。同时我们还可以点击菜单栏Edit->Project Setting->Quality,有一个VSync Count参数,该参数同样表示垂直同步。

第八章 C#脚本(上)

它有三个值可以选择:Don’t Sync,Every V Blank和Every Second V Blank

Don't Sync:数值0,不设置垂直同步,通过Application.targetFrameRate来指定帧率

Every V Blank:数值1,帧率为60,Application.targetFrameRate无效

Every Second V Blank:数值2,帧率为30,Application.targetFrameRate无效

默认值是Every V Blank(数值1)。按照官方的解释,如果设置了 QualitySettings.vSyncCount 属性,将忽略targetFrameRate,而游戏将使用 vSyncCount 和平台的默认渲染率来确定目标帧率。上文中也给出了vSyncCount设置值与帧率的关系。另外,移动平台下这个vSyncCount不会起作用,而是使用targetFrameRate来设置帧率。还有VR平台下,vSyncCount也不会起作用,而是通过VR SDK来设置。这一点对于Unity开发游戏来讲,差距确实很大。但是当我们将VSync Count设置为Every Second V Blank的时候,FPS值没有改变。不知道到底是哪里的问题,貌似vSyncCount从开始就没有起作用,不讨论了。文章来源地址https://www.toymoban.com/news/detail-428397.html

到了这里,关于第八章 C#脚本(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第八章 使用Apache服务部署静态网站

    一、网站服务程序 1、网站服务介绍 网站服务就是指Web网络服务,一般是只允许用户通过浏览器访问到互联网中各种资源的服务。Web网络服务是一种被动访问的服务程序,即只有接收到互联网中其他主机发出的请求后才会响应,最终用于提供服务程序的Web服务器,会通过HTT

    2024年02月03日
    浏览(50)
  • STM32G4 Simulink FOC开发实战--第八章:MCU内部OPAMP-电流采样

    https://www.bilibili.com/video/BV1nh4y1v72T/?spm_id_from=333.999.0.0 增益具体计算方法请参考附录一:带偏置的差分运放参数设计 R58,R59作用是为了输入的正向端和负向端输入阻抗匹配; R52,R53为分压电阻,作用是将输入正向端电压正向偏置1.65V; R56与R59形成负反馈增益,运放整体增益计算

    2024年04月23日
    浏览(54)
  • 第八章 图像压缩

    数据冗余R为 R = 1 − 1 C R=1-cfrac1C R = 1 − C 1 ​ C为压缩率,定义为 C = b b ′ C=cfrac{b}{b\\\'} C = b ′ b ​ 二维灰度阵列受如下可被识别和利用的三种主要类型的数据冗余的影响: 编码冗余。编码是用于表示信息实体或事件集合的符号系统(字母、数字、比特和类似的符号等)。每个信

    2024年02月10日
    浏览(51)
  • 第八章 常见Linux命令

    1 了解Linux帮助类命令 2 熟悉开关机命令 3 熟练文件目录类命令 4 熟悉时间日期类命令 5 熟悉用户管理命令 6 熟悉组管理命令 7 熟练文件权限命令 8 熟悉搜索查找类命令 9 熟练压缩和解压缩命令 10 熟悉磁盘分区类命令 11 熟练进程线程类命令 12 了解系统定时任务命令 man获取帮

    2024年02月11日
    浏览(40)
  • 第八章:Linux信号

    linux信号是OS的重要功能。 使用kill -l查看所有信号。使用信号时,可使用信号编号或它的宏。 1、Linux中信号共有61个,没有0、32、33号信号。 2、【1,31】号信号称为普通信号,【34,64】号信号称为实时信号。 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中

    2024年02月13日
    浏览(51)
  • C国演义 [第八章]

    力扣链接 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润 返回你可以从这笔交易中获取的最大利润。如果你不能获

    2024年02月15日
    浏览(46)
  • 第八章:多线程

    目录 八:多线程 8.1:基本概念 8.2:线程的创建与使用         8.2.1:Thread类的有关方法         8.2.2:线程的调度         8.2.3:两种创建线程方式的比较 8.3:线程的生命周期 8.4:线程的同步         8.4.1:同步代码块同步方法         8.4.2:单例模式的懒汉式修改

    2024年02月09日
    浏览(36)
  • 第八章,帖子列表

     

    2024年02月11日
    浏览(39)
  • 第八章 函数探幽

    提出的目的 :为了提高程序运行速度。 内联函数和普通函数的区别: 编译方式 : 内联函数在编译时会被直接替换到调用处,而不是像普通函数那样通过函数调用的方式执行。这样可以减少函数调用的开销,提高程序执行效率。 普通函数则是通过函数调用的方式执行,会涉

    2024年03月13日
    浏览(39)
  • 第八章 贪心

    Leetcode 455 思路一:大饼干喂给大胃口 上面的代码一定要是 for 控制胃口,if 控制饼干,因为 for 中的 i 使固定移动的! 思路二:小饼干喂给小胃口 Leetcode 1005 Leetcode 860 三种情况: 情况一:账单是5,直接收下。 情况二:账单是10,消耗一个5,增加一个10 情况三: 账单是20,

    2024年02月06日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包