Unity3D——打飞碟游戏(2)

上次的打飞碟游戏是利用Transform来实现飞碟的位移,以此模仿物体运动的轨迹。事实上,如果游戏对象是一个刚体,就可以按照现实世界中物体运动那样,给它一个力,然后让它“自由发挥”,不需要我们在脚本里Update每一帧手动写对象的位置。

关于刚体的学习

游戏对象添加Rigidbody组件后即具备物理属性,也就是说“成为了”刚体。

刚体变量

类型 变量 备注
Vector3 velocity 速度向量
Vector3 angularVelocity 角速度向量
float drag 阻力
float angularDrag 角阻力
float mass 物体的质量
bool useGravity 是否受重力影响
bool isKnematic 是否开启空气动力学

向刚体施加力

给具有刚体的gameobject施加力,常用的方法是void Rigidbody.AddForce();
具体有四个重载:

  • void Rigidbody.AddForce(vector3 Force);
  • void Rigidbody.AddForce(Vector3 Force,ForceMode mode);
  • void Rigidbody.AddForce(float x,float y,float z);
  • void Rigidbody.AddForce(float x,float y,float z,ForceMode mode)

其中,ForceMode有四种形式

  • ForceMode.Force:给物体添加一个持续的力并使用其质量
  • ForceMode.Acceleration:给物体添加一个持续的加速度,但是忽略其质量(采用默认质量1,忽略设置的质量)
  • ForceMode.Impulse:给物体添加一个瞬间的力并使用其质量
  • ForceMode.VelocityChange:给物体添加一个瞬间的加速度,但是忽略其质量

还可以在物体表面施加力:利用AddForceAtPosition(force:Vector3, position:Vector3, FoceMode)在position位置应用force力。
作为结果这个将在这个物体上应用一个力矩和力。为了效果的真实性,position的位置应在刚体的表面。

刚体的移动

除了可以用AddForce,添加一个力到刚体,作为结果刚体将开始移动之外,还可以

  • function AddRelativeForce:添加一个力到刚体,相对于本地坐标
  • MovePosition: 移动刚体到position

刚体的旋转

  • AddTorque (Vector3, ForceMode):添加一个转矩到刚体。作为结果刚体将绕着torque轴旋转,torque的长度决定转速。
  • AddTorque (float x, float y, float z, ForceMode) : 添加一个转矩到刚体。作为结果刚体将绕着torque轴旋转,torque的长度决定转速。
  • AddRelativeTorque (Vector3, ForceMode): 添加一个转矩到刚体,相对于本地坐标。
  • AddRelativeTorque (float x, float y, float z, ForceMode) : 添加一个转矩到刚体,相对于本地坐标。
  • MoveRotation (rot : Quaternion):旋转刚体到rot

游戏实现部分

游戏规则

点击start开始游戏,每一轮出现的飞碟颜色、位置随机,飞行速度随着关卡增加而增加。当分数大于轮数x50时(如第一关需要大于50分),可以点击start进入下一关,否则提示GameOver,只能按restart开始。在每一轮结束的时候,如果符合进入下一关的条件,可以选择start进入下一关,也可以点击restart从第一关开始。

飞碟的运动

直接修改了DiskData部分的代码,颜色材质这些保留上周的内容不变,把Update里根据startPoint和endPoint移动position部分修改成施加力让飞碟运动。

    void Start()
    {
        //获取自身 Transform组件和Rigidbody组件的引用
        mmTransform = gameObject.GetComponent<Transform>();
        mmRigidbody = gameObject.GetComponent<Rigidbody>();
        //    Debug.Log(mmRigidbody);
        //mmRigidbody.position = new Vector3(5, 5, 5);
        mmRigidbody.velocity = new Vector3(0, 0, 5);
    }//给一个向远处飞行的初速度
x = rules * 3;
y = rules *3;
z =  rules * 3;
mmRigidbody.AddForce(new Vector3(x, y, z));
void FixedUpdate()
    {
        if (isEnabled)
        {
            mmRigidbody.AddForce(new Vector3(x, y, z));
        }
    }

判断飞碟“落地”

在上一次作业中,规定了随机的startPoint和endPoint,判断一个飞碟是否可用(也就是是否“落地”)是通过判断这两个Vector3是否相等,但是这里我们不能规定endPoint,所以需要利用其他的方法。
1.规定一个范围,大概估计Camera的视线范围,然后判断position.x、position.y、position.z是否超出这个范围,超出就通知Factory进行回收。

2.依然是利用Camera视角,但是参考unity3d 如何判断一点是不是在一个相机的视锥内 做了一些改动,这样就比较科学。

static public bool IsAPointInACamera(Camera cam, Vector3 wordPos)
{
    // 是否在视野内
    bool result1 = false;
    Vector3 posViewport = cam.WorldToViewportPoint(wordPos);
    Debug.Log("posViewport:" + posViewport.ToString());
    Rect rect = new Rect(0, 0, 1, 1);
    result1 = rect.Contains(posViewport);
    Debug.Log("result1:" + result1.ToString());
    // 是否在远近平面内
    bool result2 = false;
    if(posViewport.z >= cam.nearClipPlane && posViewport.z<=cam.farClipPlane)
    {
        result2 = true;
    }
    Debug.Log("result2:" + result2.ToString());
    // 综合判断
    bool result = result1 && result2;
    Debug.Log("result:" + result.ToString());
    return result;
}

3.设置一个plane,是否碰撞plane作为判断“落地”的标准。
这个也比较简单,在场景中Create一个plane,设置位置,然后打开box collision,写一个onCollisionEnter就好了。

三种方法都试了一次,最后用的是第二种。

补一个天空盒制作

收集前后左右上下六张图,在Resources文件夹Create一个Material,在Inspector窗口
这里写图片描述
只会贴六张图的所以选6 Sided,分别拖六张图进去

这里写图片描述这里写图片描述
(感谢大佬在群里分享的skybox素材)
一个游戏效果图:
这里写图片描述


遇到的bug和难点:
1.实在没办法在短时间内搞清楚导演场记动作管理的模式,模仿Priest and Devil强行拆代码遇到了很多问题(牧师与魔鬼的实现是看别人的博客,知道哪个函数放哪里怎么通信,这次作业自己按框架写的时候就不知道怎么划分了),修修补补能够勉强跑没有Physics的部分,加上了切换就不知道怎么办了。所以本周作业其实并不算完成…..在没有真正理解之前我只好上交自己弄懂的部分,以后搞清楚了应该会再写一次。

2.关于useGravity和AddForce在y轴正方向增加力,实验发现只要勾选使用重力,飞碟就会永远往下,无论自己加的力有多大。思考了一下应该是因为我是在FixedUpdate里使用AddForce,每一次刷新才施加一次力,但是重力是一直存在的,所以总体呈现就是下降的轨迹。可以考虑利用Drag,但是这样调起来比较不方便,所以我把使用重力给去掉了。

3.关于Update和FixedUpdate,只记住要在刚体对象的Update处用FixedUpdate,没有同步更新Factory处的代码,就出现了一些微妙的延迟情况。这个具体的机制并没有很清楚,尝试用Debug输出结果,但是每次测试也并不相同,因此没有得出一个确切的结论。关于FixedUpdate,可以看看FixedUpdate真的是固定的时间间隔执行吗?聊聊游戏定时器

4.因为要求飞碟出现位置、飞行方向随机,而Camera视角有限,因此一开始直接Random就出现了有几个飞碟还没看见就消失的情况:微调了一下上一次的Random范围,顺利解决。遇到比较难处理的部分就是判断飞碟是否“落地”,出现明明还在范围内但是点击却无效的情况,前面已经给出具体解决方式,不再赘述。

猜你喜欢

转载自blog.csdn.net/qq_32335095/article/details/80039149