2019年7月16日学习日记

**

2019年7月16日学习日记

**

Morning----------------------------------------------------------------------------------------------------------------------------------------------------

今天主要学习前两个小游戏的制作,没有昨天那个游戏那么复杂,显得没有基础做起来比较费劲。今天是第一次用外接显示屏学习,以前都是直接用作放大的屏幕。win10对于外接显示屏有很好的兼容性,在滑动过程中虽然有一些累手腕,却没有什么不适感。能打打提高学习效率。
相比昨天做的横版过关游戏,今天这个简单多了。主要分为几个步骤。

第一步第二步第三步第四步
构思游戏结构模型的调试脚本的编写程序debug
  1. 就像今天这个比较像重力球的游戏,需要一个平面plane,四面cube当作墙壁,而且需要物理空间Box
    collider来让模型具有物理属性,其中Rigi Body:

**1、Rigidbody组件可以让一个物体受到物理影响。比如添加Rigidbody组建后,物体会立马对重力作出反应。如果物体上还添加了Collider,物体在受到碰撞时也会移动。
2、他们只需要阻挡别的物体别穿过他们就行了,所以它们只需要添加Collider就行。因为添加了Rigidbody组件后会带来很多的物理计算,所以只需要给会移动的物体添加Rigidbody就行。
3、有些情况,我们不想让物体受力,但是仍然能够和其他物体发生碰撞,影响其他物体。比如这个物体上有动画,在播放动画的时候,我们想让动画来控制物体的位置,这就是 Is Kinematic的作用”
4、Collision Detection就是针对快速移动的小物体,比如说子弹,但是通常游戏射击并不用实体的子弹,因为子弹多的时候性能太差了 **

Rigi Body
--------------------------------------------------------------------------------------------------------
Mass 刚体的质量,单位是千克(kg)
Drag 空气阻力,0代表没有空气阻力,无限大的值代表物体会立即停下来(惯性消失)。
Angular Drag 物体受到一个扭力旋转时的阻力,0代表没有阻力,但是需要注意的是无限大的值并不能让物体立即停止旋转。
Use Gravity 是否受重力影响
Is Kinematic 选中时,物体不会受到物理物理引擎的影响,只能通过修改Transform移动物体。
Interpolate 插值,如果发现刚体移动有卡顿,可以尝试选择此选项。 
None 不使用插值
Interpolate 根据上一帧的Transform进行平滑
Extrapolate 根据估算的下一帧的Transform进行平滑
Collision Detection 碰撞检测的方式,当你的刚体快速运动时,可能会出现穿透的现象,可以设置这个选项。 
Discrete 离散检测,性能较高,默认值
Continuous 连续检测。使用此选项时,物体与其他动态Collider(刚体)使用离散检测;与其他静态Collider使用连续检测。如果其他刚体设置为了Continuous Dynamic,会使用连续检测和这个刚体进行碰撞检测。这个选项非常影响性能,如果没有快速运动物体的碰撞检测问题,保持Discrete设置
Continuous Dynamic 动态连续检测。如果其他物体是Continuous或Continuous Dynamic,与这个物体碰撞时会使用连续检测。也会和静态Collider使用连续检测。对于其他的collider(标记为Discrete的Rigidbody)使用离散检测。。用于快速移动的物体。
Constraints 约束刚体的运动 
Freeze Position 选中后刚体不会在对应的轴上移动
Freeze Rotation 选中后刚体不会在对应的轴上旋转

虽然力与力是相互的,再U3d中却又这一定的界限,在目前掌握的情况分析,在Unity中参与碰撞的物体分2大块:
一.发起碰撞的物体。
二.接收碰撞的物体。

  1. 发起碰撞物体有:Rigodbody , CharacterController .
  2. 接收碰撞物体由:所有的Collider .
    工作的原理为:发生碰撞的物体中必须要有“发起碰撞”的物体。否则,碰撞不响应。
    比如:墙用BoxCollider ,所以墙与墙之间无反应。
    比如:一个带有Rigidbody属性的箱子,能落到带有MeshCollider属性的地面上。
    比如:一个带有Rigidbody属性的箱子,可以被一个带有CharacterController 属性的人推着跑。
    就是此原因。
    在所有Collider上有一个Is Trigger 的boolean型参数。
    当发生碰撞反应的时候,会先检查此属性。
    当激活此选项时,会调用碰撞双方的脚本 OnTrigger***, 反之,脚本方面没有任何反应。
    当激活此选项时,不会发生后续物理的反应。反之,发生后续的物理反应。
    总结:Is Trigger 好比是一个物理功能的开关, 是要“物理功能”还是要“OnTrigger脚本”。
    在Rigodbody 上有一个Use Gravity 的boolean型参数.
    Unity 物理引擎,处理的一个细节:
    当一个CharacterController不发生位置变化,一个Collier发生位置变化后,产生碰撞。将不会调用任何碰撞反映。
    物理引擎视为CharacterController无碰撞.

**

.

  1. 可见,发起碰撞的可以和发起碰撞的东西碰撞,但是被碰撞物品间却无法互相作用,因此要给力嗷。RigiBody和CharacterController在角色中一般是要有一个的。
    好的,继续游戏的构建。有了场景自然就要有游戏角色,是一个球—>Sphere,且要让它具有物理碰撞属性,即RigiBody。有了游戏角色的物理碰撞属性,随之一起出现的被撞属性就要一起被安排在场景上了,不然又要飞流直下三千尺了。给场景们一起搞上Box
    Collider。之后球儿落在了地上,可无法进行操作,这时就要在后台编写脚本了。创建的脚本最好放在自己创建的Script文件夹中,让自己的程序解构更加系统化,不然之后不好管理自己的脚本和材质(Material也一样要创建自己的为你文件夹)。
    由于球儿调用了RigiBody脚本(控件),我们要建立自己书写的脚本和球儿已经调用脚本之间的联系,以便于调用其脚本的方法和查看属性。因此,直接在Start方法中:

    rigid = GetComponent<Rigidbody>();//连接控件rigidbody,是一个初始化过程
    GetComponent方法我在昨天的笔记中已经提到,是连接当前脚本和控件rigibody,方便调用。
    而在Update方法中,我们要书写让球动起来的代码。由于球只是在一个平面上进行运动,因此只是涉及到x和z轴的变化,我们就要想办法得到关于x和z轴方向上当前的运动并数值化。有:

    var h = Input.GetAxis("Horizontal");//得到水平速度 var v = Input.GetAxis("Vertical");//得到y速度
    这段代码是用来得到平面中是否在水平和竖直方向运动,其运动方式也要进行定义,这个只是给出了是否运动,还需要对其进行组合变成运动方向,即:
    var movment = new Vector3(h,0,v);//定义速度方向
    建立三维向量,其方向和两个方向是否有速度,和速度方向的正反有关。很明显,这是一个层次的关系,层层递进,从控件的连接,到经过方法取到我们需要的值,取到两个方向是否进行了运动,并以“0“、”1“、”-1“来表示是否运动,运动正反。再把一维向量进行组合变成三维向量,也可以理解为由x,z组成的二维向量。最后,接收了键盘上的上下左右,经过转换,有了运动方向,就需要我们自己来定义运动的速度了。
    rigid.AddForce(movment * speed);//还有一个relativeforce是相对力
    此时,终于用到了我们最初对于Start函数中的连接。调用了已经实例化的rigid,并通过他来调用RigidBody的方法,给了运动目标一个力,大小即为速度乘以运动方向,很显然,力也是一个向量(向量标量)。
    到现在,我们已经完成了大一半任务了,球儿已经动了起来,为了不让被我们吃掉的小方块那么单调化,在创建新cube的时候也要编写相应的脚本让它旋转旋转旋转旋转旋转旋转。这里由一个必须注意的点,由于不只是一个方快,我们需要新建一个文件夹存放这一堆cubes,因此旋转的脚本需要在文件根就挂上。
    旋转是关于物体本身最基本的变化,我们在基础控件transform中就可以调用其rotate方法:
transform.Rotate(new Vector3(30,30,30)*Time.deltaTime);

这里直接new出随意一个三维方向,这就是轴,决定了旋转方向,而速度随时间均匀旋转。因此调用Time函数中的deltaTime,利用时间增量来对速度进行定义。时间增量是前后帧的时间差(一帧走多少秒),如果不想这么写,也可以自己决定其旋转速度,不过这个挺标准的。

Afternoon----------------------------------------------------------------------------------------------------------------------------------------------------
有点闹肚子,难sou(四声)。对上午的最后一项工作做一下总结之后对第一个游戏进行结尾。由于游戏的得分需要通过大球吃掉旋转的小方快来完成,所以,我们需要通过设置脚本来实现大球碰到小方快之后小方快消失。

private void OnTriggerEnter(Collider other)
    {
       if(other.GetComponent<PickUps>())
        {
            other.gameObject.SetActive(false);
        }
    }

这段代码是写在我们操作的游戏脚本中写的,利用了Collider中的Is Trigger的Boolean(布尔逻辑)参数。当激活这个项,就会调用双方的碰撞脚本OnTrigger xxxxx系列脚本。这里就体现了脚本和方法的区别。我虽然把脚本叫做方法,但脚本的方法调用规则和最基本的C#调用规则有一些不一样。一般情况下我们调用方法都是直接先在同命名空间内继承,调用方法的时候也是直接输入形参或者调用无参方法,直接给出对应的值或做出相应的反应。而这个控件的“反应”需要我们自己给出。即OnTriggerEnter虽然是一个方法,却要用私有函数创建的方式来构建碰撞发生后的事件。————
“两种碰撞,一种是直接阻挡你,一种是不会阻挡,却有互相阻挡的消息”
————注意!!! Collider是其他控件的脚本,并不一定存在与自身(这里球是RigiBody),由于碰撞的特殊关系,在一个3D控件在碰撞另外一个控件的时候就是需要这样构建!


在把一个球复制粘贴成多个球的时候发现了自己的问题,不应该在创建装方块控件的文件夹的时候直接将各种控件放到其中,因为根目录对其子目录有影响作用。若直接在根目录挂上控制旋转的控件,其整体的旋转就会以这个根目录的旋转方向为主方向,以XOZ面为面直接进行旋转,很奇葩。因此不是什么时候都适用于控件的继承(就是根目录挂控件)

16点05分这个游戏的制作终于结束了,很粗略不过很有意思哦~在触发事件OnTriggerEnter中任何带Collider的控件碰到了这个RigidBody都会让这个控件隐藏,并且计数加一。这里也涉及到一个语言问题。在C#中,变量要是没有特定值,是没有必要初始化的(如int初值为0)。而伴随着每一次控件的隐藏都需要加一分,这时候就需要承载显示分数的text控件,这个控件在C#基础和WPF中用处都非常广,在U3d中的调用是用了U3d引擎中的UI板块:

public UnityEngine.UI.Text tips;//在球控件被调用的时候调用U3d引擎中的UI方法的方法text,创建一个叫tips的文本框,用来显示分数

同样这个也有特殊性,这个不同于一般变量,我们是无法new出来的(我试过,权限不够)。因此需要调用这个方法后面加需要创建的变量名来直接写关于这个控件的方法。光在后台创建这个控件还不够,前台也需要有与之对应的控件,因此需要在scen中创建UI部分的text并改名成和我们在后台书写方法一样的。这样才可以进行正确的方法调用

此致,敬礼(^^ゞ


下面开始第二个游戏的学习。首先是材质包的拉入,先创建一个新的项目,之后点击材质包就可以直接加载到Assets中。我在进行各种操作的时候有一点不方便,就改变了一些布局,关闭了Inpector,这个面板在上面的Window选项里面有,也可以按Ctrl+3直接唤出,console控制面板也一样。中间出了一些问题,在拉入地板材质(已经加完了BoxCollider和RigidBody)之后,再拉入一个sphere(球)。球的外部有一个根节点,用来对球进行直接渲染,因此球可以不挂上BoxCollider控件和RigidBody控件,这些都交给根节点(包括自创脚本)。

Question:今天在调整两个控件代码的时候,出现了一些问题。主要综合为根节点的脚本是否能被其子节点全部继承,或者说有的特殊控件不能被继承,collider呢??

这第二个游戏把控制玩家角色的脚本明确的分为了两个部分,第一个部分是PlayerCharacter对主要的方法进行定义,而第二个部分PlayerCtroller是对需要的参数进行细微的定义,给出得到相应参数和控制参数的方法。在PlayerCharacter中:

    Rigidbody rigid;
    void Awake()//唤醒函数,Start
    {
        rigid = GetComponent<Rigidbody>();//得到本控件的rigidbody
    }
    public void Move(Vector3 force)
    {
        rigid.AddForce(force);
    }

开始还是要取到本角色中的Rigidbody控件,而建立本脚本和控件的联系就要用GetCompenent语法。其中给出了让球移动的主函数Move,物理中学过 ,力是影响物体运动的因素,力也有大小和方向,这里由于rigid控件中的mess为质量,其内部函数已经符合物理学基本公式。因此,这里我们只需要给出力的大小即可,这里的力是总力。要得到单位力就要调用PlayCtroller:

    PlayerCharacter character;
    PlayerCamera playerCamera;
    void Awake()
    {
        character = FindObjectOfType<PlayerCharacter>();
        playerCamera = FindObjectOfType<PlayerCamera>();
    }
    void Update()
    {
        var h = Input.GetAxis("Horizontal");
        var v = Input.GetAxis("Vertical");
        var cameraTrans = playerCamera.cameraComponent.transform;
        var movement = (v * cameraTrans.forward + h * cameraTrans.right).normalized;
        character.Move(movement);
    }

由于我们是属于第一人称视角,这里由于我们控制的运动由两方面影响,一方面是键盘上的上下左右,一方面是我们鼠标控制的视角方向。这里前两行我们为了调用控件中的方法实例化了两个对象,在唤醒的时候也要对相应控件进行连接。由网上查阅可知

FindObjectOfType(Typeof(type)) 按类型查找对象
返回type类型的第一个激活的加载的对象。
这个函数是非常慢的。不推荐在每帧使用这个函数,大多数情况下你可以使用单例模式代替。
FindObjectsOfType(typeof(type))
按类型查找对象列表
返回Type类型的所有激活的加载的物体列表。
它将返回任何资源(网格,纹理,预设,…)或未激活的物体。
请注意这个函数是非常慢的。不推荐在每帧使用这个函数,大多数情况下以使用单例模式代替。


找到相应对象后把地址交给我们的实例化名称,用以调用。在Update函数中我们还是和第一个游戏中一样,先对XOZ平面内的水平和竖直方向进行定义和接收,但后面速度的取值有一些复杂。为了得到相机的朝向方向,我们创建了新变量cameraTrans来接收实例化对象的cameraComponent方法中的transform值。后面的movement其实是运动方向,不过是由两个东西影响,其中h和v是键盘上的方向键直接影响运动的直观方向,而调用的cameraTrans.forward表示的是相机正面朝向的方向在以前,这一刻的前进方向可能不是物体的正对方向,这里可以理解为每时每刻我们都在正对方向,而键盘输入就相当于一直在调整相对于我们目前正对方向的运动方向。即每一刻都有一个新的方向并以此调整运动,这个关系式还有一些模糊,需要去请教高人,这只是我的理解。标准化后就是单位向量。

累了累了,不想了,都赶上写论文了。

愿明天一切安好。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值