使用unity3d需要注意到细节 (含timescale)

2024-02-06 05:38

本文主要是介绍使用unity3d需要注意到细节 (含timescale),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

操作transform.localPosition的时候请小心

移动GameObject是非常平常的一件事情,一下代码看起来很简单:

transform.localPosition += new Vector3 ( 10.0f * Time.deltaTime, 0.0f, 0.0f );但是小心了,假设上面这个GameObject有一个parent, 并且这个parent GameObject的localScale是(2.0f,2.0f,2.0f)。你的GameObject将会移动20.0个单位/秒。因为该 GameObject的world position等于: 
Vector3 offset = new Vector3( my.localPosition.x * parent.lossyScale.x,my.localPosition.y * parent.lossyScale.y,my.localPosition.z * parent.lossyScale.z );
Vector3 worldPosition = parent.position + parent.rotation * offset;换句话说,上面这种直接操作localPosition的方式是在没有考虑scale计算的时候进行的,为了解决这个问题,Unity3D提供了Translate函数,所以正确的做法应该是: 
transform.Translate ( 10.0f * Time.deltaTime, 0.0f, 0.0f );

曝出在Inspector的变量同样的也能被Animation View Editor所使用

有时候我们会想用Unity3D自带的Animation View Editor来做一些简单的动画操作。而Animation Editor不仅可以操作Unity3D自身的component,还可以操作我们自定义的MonoBehavior中的各个Property。所以加入 你有个float值需要用曲线操作,你可以简单的将它曝出到成可以serialize的类型,如:

public float foobar = 1.0f;

这样,这个变量不仅会在Inspector中出现,还可以在animation view中进行操作,生成AnimationClip供我们通过AnimationComponent调用。

范例:

public class TestCurve : MonoBehaviour {public float foobar = 0.0f;IEnumerator Start () {yield return new WaitForSeconds (2.0f);animation.Play("foobar_op");InvokeRepeating ( "LogFoobar", 0.0f, 0.2f );yield return new WaitForSeconds (animation["foobar_op"].length);CancelInvoke ("LogFoobar");}void LogFoobar () {Debug.Log("foobar = " + foobar);}
}

GetComopnent<T> 可以取父类类型

Unity3D 允许我们对MonoBehavior做派生,所以你可能有以下代码:

public class foo : MonoBehaviour {...
}public class bar : foo {...
}

假设我们现在有A,B两个GameObject, A包含foo, B包含bar, 当我们写

foo comp1 = A.GetComponent<foo>();
bar comp2 = B.GetComponent<bar>();

可以看到comp1, comp2都得到了应得的Component。那如果我们对B的操作改成:

foo comp2 = B.GetComponent<foo>();

答案是comp2还是会返回bar Component并且转换为foo类型。你同样可以用向下转换得到有效变量:

bar comp2_bar = comp2 as bar;

合理利用GetComponent<base_type>()可以让我们设计Component的时候耦合性更低。

Invoke, yield 等函数会受 Time.timeScale 影响

Unity3D提供了一个十分方便的调节时间的函数Time.timeScale。对于初次使用Unity3D的使用者,会误导性的认为Time.timeScale同样可以适用于游戏中的暂停(Pause)和开始(Resume)。所以很多人有习惯写:

Time.timeScale = 0.0f

对于游戏的暂停/开始,是游戏系统设计的一部分,而Time.timeScale不不是用于这个部分的操作。正确的做法应该是搜集需要暂停的脚本或 GameObject,通过设置他们的enabled = false 来停止他们的脚本活动或者通过特定函数来设置这些物件暂停时需要关闭那些操作。

Time.timeScale 更多的是用于游戏中慢镜头的播放等操作,在服务器端主导的游戏中更应该避免此类操作。值得一提的是,Unity3D的许多时间相关的函数都和 timeScale挂钩,而timeScale = 0.0f将使这些函数或动画处于完全停止的状态,这也是为什么它不适合做暂停操作的主要原因。

这里列出受timeScale影响的一些主要函数和Component:

  • MonoBehaviour.Invoke(…)
  • MonoBehaviour.InvokeRepeating(…)
  • yield WaitForSeconds(…)
  • GameObject.Destroy(…)
  • Animation Component
  • Time.time, Time.deltaTime

Coroutine 和 IEnumerator的关系

初写Unity3D C#脚本的时候,我们经常会犯的错误是调用Coroutine函数忘记使用StartCoroutine的方式。如:

TestCoroutine.cs

IEnumerator CoLog () {yield return new WaitForSeconds (2.0f);Debug.Log("hello foobar");
}

当我们用以下代码去调用上述函数:

TestCoroutine  testCo = GetComponent<TestCoroutine>();
testCo.CoLog ();
testCo.StartCoroutine ( "CoLog" );

那么testCo.CoLog()的调用将不会起任何作用。

StartCoroutine, InvokeRepeating 和其调用者关联

通常我们只在一份GameObject中去调用StartCoroutine或者InvokeRepeating, 我们写:

StartCoroutine ( Foobar() );
InvokeRepeating ( "Foobar", 0.0f, 0.1f );

所以如果这个GameObject被disable或者destroy了,这些coroutine和invokes将会被取消。就好比我们手动调用:

StopAllCoroutines ();
CancelInvoke ();

这看上去很美妙,对于AI来说,这就像告诉一个NPC你已经死了,你自己的那些小动作就都听下来吧。

但是注意了,假如这样的代码用在了一个Manager类型的控制AI上,他有可能去控制其他的AI, 也有可能通过Invoke, Coroutine去做一些微线程的操作,这个时候就要明确StartCoroutine或者InvokeRepeating的调用者的设计。讨论之前我 们先要理解,StartCoroutine或InvokeRepeating的调用会在该MonoBehavior中开启一份Thread State, 并将需要操作的函数,变量以及计时器放入这份Stack中通过并在引擎每帧Update的最后,Renderer渲染之前统一做处理。所以如果这个 MonoBehavior被Destroy了,那么这份Thread State也就随之消失,那么所有他存储的调用也就失效了。

如果有两份GameObject A和B, 他们互相知道对方,假如A中通过StartCoroutine或InvokeRepeating去调用B的函数从而控制B,这个时候Thread State是存放在A里,当A被disable或者destroy了,这些可能需要一段时间的控制函数也就失效了,这个时候B明明还没死,也不会动了。更 好的做法是让在A的函数中通过B.StartCoroutine ( … ) 让这份Thread State存放于B中。

// class TestCortouine
public class TestCoroutine : MonoBehaviour {public IEnumerator CoLog ( string _name ) {Debug.Log(_name + " hello foobar 01");yield return new WaitForSeconds (2.0f);Debug.Log(_name + " hello foobar 02");}
}// component attached on GameObject A
public class A: MonoBehaviour {public GameObject B;void Start () {TestCoroutine  compB = B.GetComponent<TestCoroutine>();// GOOD, thread state in B// same as: compB.StartCoroutine ( "CoLog", "B" );compB.StartCoroutine ( compB.CoLog("B") );// BAD, thread state in AStartCoroutine ( compB.CoLog("A") );Debug.Log("Bye bye A, we'll miss you");      Destroy(gameObject); // T_T I don't want to die...}	
}

以上代码,得到的结果将会是:

B hello foobar 01
A hello foobar 01
Bye bye A, we'll miss you
B hello foobar 02

如不需要Start, Update, LateUpdate函数,请去掉他们

当你的脚本里没有任何Start, Update, LateUpdate函数的时候,Unity3D将不会将它们加入到他的Update List中,有利于脚本整体效率的提升。

我们可以从这两个脚本中看到区别:

Update_01.cs

public class Update_01 : MonoBehaviour {void Start () {}void Update () {}
}

Update_02.cs

public class Update_02 : MonoBehaviour {
}

http://www.cnblogs.com/oldman/articles/2409521.html

这篇关于使用unity3d需要注意到细节 (含timescale)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

MySQL 事务的概念及ACID属性和使用详解

《MySQL事务的概念及ACID属性和使用详解》MySQL通过多线程实现存储工作,因此在并发访问场景中,事务确保了数据操作的一致性和可靠性,下面通过本文给大家介绍MySQL事务的概念及ACID属性和... 目录一、什么是事务二、事务的属性及使用2.1 事务的 ACID 属性2.2 为什么存在事务2.3 事务

使用Python实现网页表格转换为markdown

《使用Python实现网页表格转换为markdown》在日常工作中,我们经常需要从网页上复制表格数据,并将其转换成Markdown格式,本文将使用Python编写一个网页表格转Markdown工具,需... 在日常工作中,我们经常需要从网页上复制表格数据,并将其转换成Markdown格式,以便在文档、邮件或

Python使用pynput模拟实现键盘自动输入工具

《Python使用pynput模拟实现键盘自动输入工具》在日常办公和软件开发中,我们经常需要处理大量重复的文本输入工作,所以本文就来和大家介绍一款使用Python的PyQt5库结合pynput键盘控制... 目录概述:当自动化遇上可视化功能全景图核心功能矩阵技术栈深度效果展示使用教程四步操作指南核心代码解析

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

SpringCloud使用Nacos 配置中心实现配置自动刷新功能使用

《SpringCloud使用Nacos配置中心实现配置自动刷新功能使用》SpringCloud项目中使用Nacos作为配置中心可以方便开发及运维人员随时查看配置信息,及配置共享,并且Nacos支持配... 目录前言一、Nacos中集中配置方式?二、使用步骤1.使用$Value 注解2.使用@Configur

Mac备忘录怎么导出/备份和云同步? Mac备忘录使用技巧

《Mac备忘录怎么导出/备份和云同步?Mac备忘录使用技巧》备忘录作为iOS里简单而又不可或缺的一个系统应用,上手容易,可以满足我们日常生活中各种记录的需求,今天我们就来看看Mac备忘录的导出、... 「备忘录」是 MAC 上的一款常用应用,它可以帮助我们捕捉灵感、记录待办事项或保存重要信息。为了便于在不同

如何Python使用设置word的页边距

《如何Python使用设置word的页边距》在编写或处理Word文档的过程中,页边距是一个不可忽视的排版要素,本文将介绍如何使用Python设置Word文档中各个节的页边距,需要的可以参考下... 目录操作步骤代码示例页边距单位说明应用场景与高级用China编程途小结在编写或处理Word文档的过程中,页边距是一个

SpringBoot项目Web拦截器使用的多种方式

《SpringBoot项目Web拦截器使用的多种方式》在SpringBoot应用中,Web拦截器(Interceptor)是一种用于在请求处理的不同阶段执行自定义逻辑的机制,下面给大家介绍Sprin... 目录一、实现 HandlerInterceptor 接口1、创建HandlerInterceptor实

使用JavaConfig配置Spring的流程步骤

《使用JavaConfig配置Spring的流程步骤》JavaConfig是Spring框架提供的一种基于Java的配置方式,它通过使用@Configuration注解标记的类来替代传统的XML配置文... 目录一、什么是 JavaConfig?1. 核心注解2. 与 XML 配置的对比二、JavaConf

使用Python和Tkinter实现html标签去除工具

《使用Python和Tkinter实现html标签去除工具》本文介绍用Python和Tkinter开发的HTML标签去除工具,支持去除HTML标签、转义实体并输出纯文本,提供图形界面操作及复制功能,需... 目录html 标签去除工具功能介绍创作过程1. 技术选型2. 核心实现逻辑3. 用户体验增强如何运行