Unity读书系列《Unity3D游戏开发》——脚本(一)

文章目录

  • 前言
  • 一、脚本模版及其拓展
    • 1、脚本模版
    • 2、拓展脚本模版
  • 二、脚本的生命周期
  • 三、脚本的执行顺序
  • 四、脚本序列化
    • 1、序列化数据
    • 2、serializedObject
    • 3、监听部分元素修改事件
  • 五、定时器与间隔定时器
  • 六、工作线程(多线程)
  • 总结


前言

脚本在Unity的重要程度不用多说,她是大部分软件的核心组件。
我们将在此篇文章学习脚本模版及其拓展、脚本的生命周期、脚本的执行顺序、脚本序列化,下一篇为脚本编译与调试。


一、脚本模版及其拓展

1、脚本模版

如下图我们可以在Project视图右键进行脚本创建,除了C#脚本,还有两类脚本;Testing用来做单元测试,Playables是TimeLine引入的新概念。
在这里插入图片描述
通常来讲我们会根据项目修改脚本模版,位置在Unity安装位置的Resource文件夹内,例如:“C:\Program Files\Unity 2021.3.16f1\Editor\Data\Resources\ScriptTemplates”。除了按照项目修改模版,通常会将脚本编码改成UTF-8并在脚本模版中加入中文或中文字符。
在这里插入图片描述

2、拓展脚本模版

如果按上述方法修改脚本模版会十分麻烦,不说每个版本的unity都需要修改,项目里每个成员都需要修改,当模版变动难道每个人都要重新修改吗。我们想做到版本管理可以拓展脚本的方式添加模版。

二、脚本的生命周期

Unity脚本有一套完整的生命周期,无需手动调用。其中包含初始化、更新回调、渲染、销毁,我们经常使用的协程等也在其内。
官方解释:
在这里插入图片描述
书中解释:
在这里插入图片描述

三、脚本的执行顺序

在上一章中当有两个脚本标记了"[CustomEditor(typeof(Camera))]",只会执行第一个创建的脚本逻辑。
为什么呢?Unity的脚本可以预先挂载场景中,也可以在运行时动态添加,所以用Script Execution Order使用来管理脚本的执行顺序,我们可以在此添加脚本并设置顺序。
在这里插入图片描述
我们考虑一件事,现在有多个脚本,A脚本在Awake获取B脚本的数据,A如果比B先执行那就会报错。实际上这种时序的问题还会发生在项目越发复杂,初始化过多的情况。不仅如此,多个脚本还会产生多余消耗,假设每个脚本都有初始化(Awake、Start等)和更新(Update)的方法,几百个脚本同时运行,性能差的主机可能分分钟卡死。
解决方法:将系统分类,每个系统的初始化等功能都设置入口,功能统一调用。初学者推荐尝试单例的写法来管理小项目,再根据项目尝试工厂模式、适配器模式等设计模式,最后学习框架的思想。

四、脚本序列化

想了解脚本序列化,首先我们需要明白脚本本身并没有保存数据,而是将数据保存于文件中,也就是脚本可以通过序列化和反序列化来保存游戏。
书中举例,给场景其中一个物体加上脚本Test.cs,再找一个预制体Prefab.prefab加上脚本Test.cs。接下来我们修改场景中的脚本数据,也就是Id,那么数据将保存在Scene.unity;同理,在Project下修改预制体上的脚本Id,那么数据会保存在预制体文件夹内。

如果把预制体赋值到场景的脚本中(脚本中的public GameObject prefab;),那么数据会存在Scene.unity。大家仔细想想,平常雀氏是这样操作的,只是不明所以罢了。

public class Test : MonoBehaviour
{
	public int Id;
	public GameObject prefab;
}

1、序列化数据

打开上面的预制体和场景,就会发现里面存着序列化的数据,这里不做展示。
通常,公开的对象会支持序列化格式,如果不想显示可以加上[HideInInspector],私有序列化需要再代码上加上[SerializeField]。

public class Test : MonoBehaviour
{
	[SerializeField]
	private int Id;
	[SerializeField]
	private GameObject prefab;
}

假如我此时还想访问呢,直接请出serializedObject.FindProperty()访问私有属性。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class Script_04_08 : MonoBehaviour
{
    [SerializeField]
    private int id;
    [SerializeField]
    private string name;
    [SerializeField]
    private GameObject prefab;
}

#if UNITY_EDITOR
[CustomEditor(typeof(Script_04_08))]
public class ScriptInsector : Editor
{
    public override void OnInspectorGUI()
    {
        //更新最新数据
        serializedObject.Update();
        //获取数据信息
        SerializedProperty property = serializedObject.FindProperty("id");
        //赋值数据
        property.intValue = EditorGUILayout.IntField("主键", property.intValue);

        property = serializedObject.FindProperty("prefab");
        property.objectReferenceValue = EditorGUILayout.ObjectField("游戏对象",
            property.objectReferenceValue,typeof(GameObject),true);

        //全部保存数据
        serializedObject.ApplyModifiedProperties();
    }
}
#endif

2、serializedObject

serializedObject只能在Editor中使用,它专门用于获取设置的序列化信息。通常,要开发复杂的编辑组件,都需要重写OnInspectorGUI()方法,但是如果希望有些用源生的绘制结构,同时兼容有些自定义渲染的话,那该怎么办呢?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class SerializedObjectTest : MonoBehaviour
{
    [SerializeField]
    private int id;
    [SerializeField]
    private GameObject[] targets;
}

#if UNITY_EDITOR
[CustomEditor(typeof(SerializedObjectTest))]
public class ScriptInsector : Editor
{
    public override void OnInspectorGUI()
    {
        //更新最新数据
        serializedObject.Update();
        //获取数据信息
        SerializedProperty property = serializedObject.FindProperty("id");
        //赋值数据
        property.intValue = EditorGUILayout.IntField("主键", property.intValue);
        //以默认样式绘制数组数据
        EditorGUILayout.PropertyField(serializedObject.FindProperty("targets"), true);
        //全部保存数据
        serializedObject.ApplyModifiedProperties();
    }
}
#endif

效果如下:
在这里插入图片描述

3、监听部分元素修改事件

脚本面板中,参与绘制的元素都是在OninspectorGUI中绘制的。我们想监听其中的一个元素有两种方法,第一种适用于简单的脚本,在脚本中写入Onvalidate(),当面板信息发生改变就会回调该方法;

void Onvalidate(){
Debug.log("信息改变");
}

第二种需要监听GUI的元素写在EditorGUI.BeginChangeCheck()。我们监听变化则需要在if(EditorGUI.EndChangeCheck()) 中处理。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class Test : MonoBehaviour
{
    [SerializeField]
    private GameObject[] targets;
}

#if UNITY_EDITOR
[CustomEditor(typeof(Test))]
public class ScriptInsector : Editor
{
    public override void OnInspectorGUI()
    {
        //更新最新数据
        serializedObject.Update();
        //标记检查
        EditorGUI.BeginChangeCheck();
        EditorGUILayout.PropertyField(serializedObject.FindProperty("targets"), true);
        //标记检查发生变化
        if(EditorGUI.EndChangeCheck()) {
            Debug.Log("元素发生变化");
}
        //判断面板元素是否任意发生改变
        if(GUI.changed) {

        }
        //全部保存数据
        serializedObject.ApplyModifiedProperties();

    }
}
#endif

五、定时器与间隔定时器

通常我们可以用协程做定时器,缺陷是依赖于脚本,所以封装一个不依赖脚本实现的定时器是很有必要的。
详细使用请看定时器与间隔定时器。

六、工作线程(多线程)

工作线程(多线程)是指在一个程序中同时执行多个任务的能力。多线程编程可以提高程序的性能和响应性,特别是在需要同时执行多个任务的情况下。工作线程通常用于执行耗时的任务,以避免阻塞主线程,从而保持程序的流畅性。
目前很多主流游戏或软件在启动或下载等待时会使用多线程技术,应用十分广泛。
详细使用请看Unity多线程。


总结

这篇文章将介绍Unity中脚本的核心概念和重要性。我们探讨如何创建和定制脚本以满足特定需求,以及脚本的生命周期、执行顺序和序列化等内容。后面两个示例(定时器和工作线程的运用)我分别用单独的章节说明,如果需要再去学习运用;这种安排旨在强调项目驱动的学习方式,同时鼓励读者在实践中运用这些示例来更快地提升自己的技能。逐步学习并根据需求应用所学知识,将使读者能够更有效地掌握相关技能。
最后,感谢大家观看,欢迎讨论指正错误,别忘了点赞👍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/575579.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Rust HTTP 客户端:易于使用、功能强大 | 开源日报 No.228

seanmonstar/reqwest Stars: 8.9k License: Apache-2.0 reqwest 是一个易于使用且功能强大的 Rust HTTP 客户端。 异步和阻塞客户端支持普通数据、JSON、urlencoded 和 multipart 数据格式可定制的重定向策略支持 HTTP 代理和系统原生 TLS 或 rustls 的 HTTPSCookie 存储功能…

RoadBEV:鸟瞰图中的道路表面重建

1. 代码地址 GitHub - ztsrxh/RoadBEV: Codes for RoadBEV: road surface reconstruction in Birds Eye View 2. 摘要 本文介绍了RoadBEV:鸟瞰图中的道路表面重建。道路表面条件(特别是几何形状)极大地影响了自动驾驶汽车的驾驶性能。基于…

就业班 第三阶段(nginx) 2401--4.22 day1 nginx1 http+nginx初识+配置+虚拟主机

一、HTTP 介绍 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。 HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件…

ubuntu安装Qv2ray2.7.0及配置

需要下载两个文件,一个是zip文件,一个是AppImage执行程序。 执行AppImage需要先下载fuse sudo apt install libfuse2然后为AppImage赋予执行权限 sudo chmod x ./Qv2ray-v2.7.0-linux-x64.AppImage执行,执行前可以解压zip文件 ./Qv2ray-refs.tags.v1…

操作系统(Operating System)知识点复习——第十一章 I/O管理与磁盘调度

目录 0.前言 1.I/O设备 2.I/O功能的组织 3.Operating System Design Issues 4.I/O缓冲 4.1 单缓冲Single Buffer 4.2 双缓冲Double Buffer 4.3 循环缓冲 5.磁盘调度Disk Scheduling 5.1 磁盘性能参数 5.2 磁盘调度策略 ①First-in,first-out(FIFO) ②Pr…

鸿蒙ArkUI实战开发-如何通过上下滑动实现亮度和音量调节

场景说明 在音视频应用中通常可以通过上下滑动来调节屏幕亮度和音量大小,本例即为大家介绍如何实现上述UI效果。 说明: 由于当前亮度和音量调节功能仅对系统应用开发,所以本例仅讲解UI效果的实现。 效果呈现 本例效果如下: 当在…

决策树分析及其在项目管理中的应用

决策树分析是一种分类学习方法,其主要用于解决分类和回归问题。在决策树中,每个内部节点表示一个属性上的测试,每个分支代表一个属性输出,而每个叶节点则代表类或类分布。通过从根节点到内部节点的路径,可以构建一系列…

Haystack

文章目录 关于 Haystack提供 NLP项目所有阶段的功能 Building blocks组件 Components管道 Pipelines代理 Agents 基本使用 - RAG 关于 Haystack 官网:https://haystack.deepset.ai官方文档:https://docs.haystack.deepset.ai/docs/intro教程&#xff1a…

IP地址定位是怎么实现的?

IP地址定位技术的实现是一个涉及多方面技术和方法的复杂过程。IP地址作为互联网通信中的关键元素,每个设备在网络中都被分配一个唯一的IP地址,用于标识和定位网络上的设备。通过一系列技术手段,我们可以对这些IP地址进行分析,进而…

MATLAB 向量

MATLAB 向量 向量是一维数字数组。MATLAB允许创建两种类型的向量 行向量 列向量 行向量 行向量通过将元素集括在方括号中并使用空格或逗号定界元素来创建。 示例 r [7 8 9 10 11] MATLAB将执行上述语句并返回以下结果- r 7 8 9 10 11 列向量 列向量 通过将元素集括在方…

大型网站系统架构演化实例_6.使用分布式文件系统和分布式数据库系统

1.使用分布式文件系统和分布式数据库系统 任何强大的单一服务器都满足不了大型网站持续增长的业务需求。数据库经过读写分离后,从一台服务器拆分成两台服务器,但是随着网站业务的发展依然不能满足需求,这时需要使用分布式数据库。文件系统也一…

【高校科研前沿】东北地理所在遥感领域顶刊RSE发布中国主要红树植物群落遥感分类成果

目录 01 文章简介 02 研究内容 03 文章引用 01 文章简介 论文名称:Mangrove species mapping in coastal China using synthesized Sentinel-2 high-separability images(基于Sentinel-2高分离度图像的中国沿海红树群落制图) 第一作者及…

python爬虫学习------scrapy第二部分(第三十天)

🎈🎈作者主页: 喔的嘛呀🎈🎈 🎈🎈所属专栏:python爬虫学习🎈🎈 ✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天…

(51单片机)第十三章-STC系列51单片机功能介绍

13.1 单片机空闲与掉电模式的应用 1. 空闲模式 当单片机进入空闲模式时,除CPU处于休眠状态外,其余硬件全部处于活动状态,芯片中程序未涉及的数据存储器和特殊功能寄存器中的数据在空闲模式期间都将保持原值。假若定时器正在运行,…

第一篇:Python简介:开启你的编程之旅

Python简介:开启你的编程之旅 在这个系列文章中,我将带领大家深入了解Python——一个极具魅力的编程语言。如果你对编程感兴趣,想要掌握一门既实用又强大的语言,那么Python无疑是一个绝佳的选择。本篇文章是这个系列的序章&#…

大数据基础

基本简介 大数据特点 数据量大 种类多样 结构化:多指关系型数据库中,信用卡号码、日期、财务金额、电话号码、地址 半结构化:xml/json 非结构化:全文文本、图象、声音、影视、超媒体等信息。 应用价值高 大数据的作用 追溯…

protobuf协议逆向解析

protobuf协议逆向解析 地址: aHR0cHM6Ly93d3cudGlrdG9rLmNvbS9tZXNzYWdlcz9sYW5nPWVu找到接口/v2/message/get_by_user_init 如图所示, 参数和响应并不是可直接使用的, 虽然部分内容可读。 跟栈到这里, 找到封包前的数据 打上断点, 查看变量t就是请…

数字安全实操AG网址漏洞扫描原理与技术手段分析

在数字化世界的大舞台上,网络安全如同守护者一般,默默保卫着我们的虚拟疆界。当我们在享受互联网带来的便利时,一场无形的战争正在上演。黑客们利用各种手段试图攻破网站的安全防线,而防守方则依靠先进的技术和策略来抵御入侵。其…

武汉星起航:创新孵化模式,一站式服务助力卖家全球化拓展

在全球化浪潮席卷而来的今天,跨境电商行业已成为推动国际贸易的重要力量。武汉星起航电子商务有限公司,作为这一领域的佼佼者,以其前瞻性的战略眼光和创新的经营模式,积极践行“走出去”战略,凭借自营店铺运营经验和跨…

Golang | Leetcode Golang题解之第50题Pow(x,n)

题目: 题解: func myPow(x float64, n int) float64 {if n > 0 {return quickMul(x, n)}return 1.0 / quickMul(x, -n) }func quickMul(x float64, n int) float64 {if n 0 {return 1}y : quickMul(x, n/2)if n%2 0 {return y * y}return y * y * …
最新文章