有时候会遇到一些情况,脚本和unity编辑器写得都跟书上一模一样效果却还是不尽如人意,这时候重启一下unity,或者什么把脚本代码剪切再粘贴就好了。玄学
这些if之间的顺序会影响往斜上走时是显示上的动画还是左右的动画
tracked object offset 相机偏离人物中心程度
damp:相机回拉时的缓慢、迅速
自制条目方便使用
人物显示不出来可能是因为z轴出了问题
z轴按理来说应该是0
注意预制件之间的引用也要用预制件,不然会死得很惨【萌新做到后面快吐了】
看不懂这啥玩意
书本p169
这时候我感觉只移去playerobject有所不妥?感觉报了一万个错,什么healthBar和Inventory都没有一个引用的对象了,可能是我之前预制件的部分处理得不好
我的解决方法是,删去hierarchy中的healthBar和inventory,并设置好预制件之间的关系。但是还有一个问题,就是虚拟摄像机也需要一个Player对象跟随,如果贸然拖上去Player预制件,会发现,RPGGameManager创建的那个static sharedInstance里跟随的那个player对象,跟此时虚拟摄像机里的player对象是两个东西,感觉此时的player也应该有单例思想。于是乎,为了同步虚拟摄像机和sharedInstance的两个player对象,我先给RPGGameManager中的player方法字段改成了实例字段,再为虚拟相机添加一个用代码来填充实例对象的脚本。具体代码如下图:
对RPGGameManager类的修改:(改造字段)
虚拟摄像机新脚本ControllingAim:
解释说明:1.由于要附加到虚拟摄像机上,故派生自MonoBehaviour
2.得到该虚拟摄像机的CinemachineVirtualCamera组件
3.修改组件的Transform类型的Follow属性,使它不断与sharedInstance的player更新对接
注:这里我是怎么写出这段代码的呢?可以右键虚拟摄像机的CinemachineVirtualCamera组件,点击EditScript,就可以跳转到follow所在的这个组件的定义。注意到Follow属性的类型是Transform,联想到Transform表示的是位置,又联想到似乎.transform可以获取到一个GameObject的类型为Transform的位置,so。
此时的hierarchy栏:
这时候我上手发现,还会有强烈的抖动。此时我把look at改成了空,把下面那个以前用来减少抖动的脚本取消勾选了,此时反而不抖了
草,结果读下去发现书写了解决方法。。。。
他这句话很骚:在当前Scene找到VirtualCamera这个gameobject。我超,我上面好像有一瞬间就是因为不知道怎么在别的脚本获取虚拟相机,才转而求其次给虚拟相机弄上一个设置实例的方法的,不然就可以直接获取虚拟相机然后设置实例,而不必弯弯绕绕。 不过也不会很绕就是了。
需要有什么碰撞时触发之类的,一定记得勾选IsTrigger!!
协程(方法太长不能在一帧来一次、固定时间间隔调用方法)
不知道为啥敌人漫游第一步全都往右走?
关于漫游的代码Wander.cs
我对这两句yield组合技出现的时机非常奇怪。
但是想了一下才发现,原来yield是针对一个协程的
对于第一个协程(循环)来说,执行完开始协程后停留不改变方向的时间,然后再执行下一轮循环改变move方向
对于第二个yeld,则是每次边move边更新状态
我超,醍醐灌顶的感觉。但是不知道为什么这里必须return WaitForFixedUpdate?
关于勾选IsTrigger的问题:
我试图增加一个DeadZone的sprite
其中boxCollider是由于调试的gizmos。
因为这里方法是OnTriggerEnter2D,所以deadzone精灵的istrigger应该得勾选,这个是没问题的。
然后问题出在哪呢,我发现,不勾选deadzone的istrigger,勾选player的,player还是会寄。同理,enemy有两层collider,外面那层圈由于勾选了istrigger,所以碰到deadzone就即死了,完全体现不出原有的效果啊。
所以似乎这里不用OnTriggerEnter2D,用OnCollisionEnter2D,此时不用勾选istrigger。
感觉稍微理解了一些什么是“碰撞”了。它不仅可以是物理上碰到【collision】,也可以是判定范围上的遇到【trigger】。因而,前者不能“穿过”,后者可以“穿过”。
update会不会就是一种协程?类似语法糖?
世界坐标?屏幕坐标?
附加脚本对附加类的引用
不知道这两处有啥区别?为什么不一样
p252
第八的那个注释,没看懂两个的逻辑关系???
还有这段代码里isFiring这个变量有啥用啊?我怎么感觉有它没他都一样
我刚刚在弄横板的跳跃,结果非常诡异。我一直以为是jump脚本出了问题,结果是因为我用了纯2d平面的move逻辑出了问题,因为原来那个move它是直接更新了rigidbody的速度的。啊啊啊,以后真得懂了原理再乱用!!
感受一下三种move的区别 。过去一直都是通过改变velocity属性来移动物体的捏。本次视频教学中使用的是MovePosition自带方法,参数中也乘了速度,感觉蛮好使的。
上面那个要乘个deltaTime原因是那个是位移的叠加。下面那个不用是因为velocity是速度值的叠加,乘个p时间
它这边set健康条是在每次受到伤害之后。之前一贯那样在Update方法里一直更新健康值真不是个聪明的办法
GetComponent还可以用于从对象的一个组件得到对象的另一个组件
为了防止shell被破坏了,它的粒子儿子也会被马上破坏,动画效果没播完,需要提前解耦。
现在复盘一下,看完了这玩意,我得到什么了呢?
我想最重要的一点,就是稍微解除了一些我对u3d的恐惧,动手去调碰撞体积,写代码上也跟2d其实没什么差别。还有得到一点很有用
这玩意。以及知道了怎么看自己在哪个平面,哪个axis需要锁住不让转或不让动取决于需求,知道了摄像机控制(包括如何跟随玩家、如何根据特定需要来放大缩小)
(学到了这个相机移动、缩放方法)
更重要的是学到了建立两个对象父子关系的思想。
想让爆炸效果附着音效,那就让音效成为爆炸效果的组件。想让爆炸效果的transform跟着子弹 (或是想让相机跟着坦克),那就让它当子弹的儿子。想管理多个东西,那就Create Empty,把这些东西都变成Empty的子对象。
【说到empty,想起黄金矿工的钩子了
血条那里,我总算知道了原来canvas是类似画布的东西,还知道了这个东西
以前我们都是把它弄成屏幕space,因为我们想让它一直保持在屏幕的特定位置。现在想让他跟着人物动,那就设成world space。
并且通过调整它的这些location、scale、rotation等参数得到需要的效果
以前对健康条和角色死亡间处理关系是,分别建立两个脚本,其中的数值关系通过ScriptableObject来连接。这里采取的做法是直接对健康条编写包括角色死亡的逻辑。两者都需要健康条直接引用角色,似乎可能ScriptableObject可以保存数据,更受青睐?毕竟一个是一局一次性的游戏,一个是rpg冒险类游戏【】
对子弹的脚本编辑,则稍微感受到了范围伤害这个概念。
(生存时间后销毁的做法)
private void OnTriggerEnter(Collider other)
{
// Collect all the colliders in a sphere from the shell's current position to a radius of the explosion radius.
Collider[] colliders = Physics.OverlapSphere(transform.position, m_ExplosionRadius, m_TankMask);
// Go through all the colliders...
for (int i = 0; i < colliders.Length; i++)
{
// ... and find their rigidbody.
Rigidbody targetRigidbody = colliders[i].GetComponent();
// If they don't have a rigidbody, go on to the next collider.
if (!targetRigidbody)
continue;
// Add an explosion force.
targetRigidbody.AddExplosionForce(m_ExplosionForce, transform.position, m_ExplosionRadius);
// Find the TankHealth script associated with the rigidbody.
TankHealth targetHealth = targetRigidbody.GetComponent();
// If there is no TankHealth script attached to the gameobject, go on to the next collider.
if (!targetHealth)
continue;
// Calculate the amount of damage the target should take based on it's distance from the shell.
float damage = CalculateDamage(targetRigidbody.position);
// Deal this damage to the tank.
targetHealth.TakeDamage(damage);
}
// Unparent the particles from the shell.
m_ExplosionParticles.transform.parent = null;
// Play the particle system.
m_ExplosionParticles.Play();
// Play the explosion sound effect.
m_ExplosionAudio.Play();
// Once the particles have finished, destroy the gameobject they are on.
Destroy(m_ExplosionParticles.gameObject, m_ExplosionParticles.duration);
// Destroy the shell.
Destroy(gameObject);
}
(范围伤害多物体的触发范围)
(范围伤害的简单计算方式)
在开火这一节中,感觉代码上让我大开眼界。
首先是这个,我一开始真的百思不得其解定义这个有什么用
看到这里才反应过来。我们的目标是让这个条条平滑增加,而Update这种一帧一调的方法的deltaTime常用于平滑增加。speed实际上就是提供了这两个平滑之间的联系。
else if (Input.GetButtonDown(m_FireButton))
else if (Input.GetButton(m_FireButton) && !m_Fired)
else if (Input.GetButtonUp(m_FireButton) && !m_Fired)
这三个方法让我感受到了api的强大。一瞬间、长按、离开。并且在游戏中实践可得,一直长按不会连续设炮弹
这行也让我大开眼界。
其一,Instantiate原来还可以带参初始化【】其二,居然还可以这样取出rigidbody??先取出子弹,再把子弹强制类型转换。以前都是使用GetComponent。
还有此处的.forward。我都震惊了,原来.forward不是静态属性啊。而且Transform的forward和Vector3的forward不一样:
与 Vector3.forward 不同,Transform.forward 在移动 GameObject 的同时,还考虑其旋转。
旋转游戏对象时,表示游戏对象的 Z 轴的蓝色箭头也会改变方向。Transform.forward 沿蓝色箭头所在的轴 (Z) 移动游戏对象。
要在沿 Z 轴移动 GameObject 时忽略旋转,请参阅 Vector3.forward。
这节课学了GameManager,我深刻感受到了其功能之强大。它清晰串联了各个游戏阶段,且规定好了它们出现的时机。
在接星星的那个项目中,我有点想弄一个关于GameManager的东西,却一直不知道应该附着给谁,附着在哪。看到附着在Empty上的我恍然大悟【】
然后如上图。我觉得画出这样的思维导图真是really一件非常了不起的事情。未来项目应该也是这样逐级拆解需要的功能函数吧,而项目经验可能就用在这里了。下一个就弄,学习其gamemanager是怎么写的