栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 游戏开发 > 其他

Unity游戏开发文档(1):飞行模拟

其他 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Unity游戏开发文档(1):飞行模拟

前言

  本篇的代码是基于Unity3D 系列课程 “Create with Code” 第一章 “Player Control” 改进而来

目录
  • 背景
  • 设计
  • 代码实现
  • 效果展示
  • 参考文献


背景


  “Create with Code” 课后出了一道题,要求是做一款类似于 “Flappy Bird” 的3D小游戏。玩家仅通过键盘上下键或W/S键控制小鸟上下飞行来避开障碍物。
  出题人提供了很多精美的素材,但只是用来做这么个玩意有点大材小用了,于是一个大胆的想法浮现在笔者脑海中。




设计


  一想到飞行模拟,笔者第一反应就是《战地风云》系列游戏里的战斗机驾驶。在游戏中,飞机的运动满足以下几点:

  1. 飞机遵循牛顿力学定律框架,在游戏中主要受发动机推力,风阻力,翼面升力和自身重力的影响。
  2. 载具可在玩家鼠标和键盘的共同操作下,实现现实中飞机的绝大部分机动动作,如空翻,桶滚等。其中键盘控制飞机围绕 y y y 轴的旋转,鼠标控制飞机围绕 x x x 和 z z z 轴的旋转。
  3. 摄像机 (camera) 以第三人称视角始终位于飞机后上方,并以 “看向(Look At)” 的方式朝向飞机。


  基于上述三点,笔者做出了如下设计:

  1. 由于Unity中默认刚体(Rigit Body)遵循牛顿三大定律,因此我不需要做出额外的更改。
  2. 升力是飞机克服重力实现飞行的必要条件,当升力大于重力时,飞机就能实现飞行。在现实中,升力的计算涉及到空气的流体力学。为了简化模型,游戏飞机的升力大小仅取决于飞机的速度。升力与速度之间为线性关系,即:

f o r c e = k ∗ s p e e d + b force=k*speed+b force=k∗speed+b

  1. 在现实中,飞机的速度与加速度取决于发动机的推力和发动机功率,同时速度还会收到风阻力的影响。要逼真的模拟这么多因素一方面会消耗算力,另一方面写多错多容易引入问题。为此游戏中简化了速度模型,使得速度仅与推力呈线性关系,推力则由玩家的W/S键盘输入控制。同时速度在每时每刻都会以固定的频率减小,当玩家持续施加推力时,飞机增加的速度可以抵消见效的速度;而当玩家停止控制,飞机则会缓慢减速,借此以模拟风阻力的减速作用。需要注意的是,飞机的速度不可能无限增大,也不可能为负值。

s p e e d = { s p e e d + k e y b o a r d   i n p u t if   s p e e d < m a x   s p e e d s p e e d − f r i c t i o n if   s p e e d > 0 0 if   s p e e d < 0 speed = begin{cases} speed + keyboard input &text{if } speed < max speed \ speed - friction &text{if } speed > 0\ 0 &text{if } speed < 0 end{cases} speed=⎩⎪⎨⎪⎧​speed+keyboard inputspeed−friction0​if  speed0if  speed<0​

  1. 飞机可以分别绕 x   y   z x y z x y z 轴旋转以实现自由飞行。其中,绕 y y y 轴通过键盘A/D输入控制,绕 z z z 轴旋转通过鼠标水平输入控制,绕 x x x 轴旋转通过鼠标垂直输入控制。此外,为了模拟现实中升力和速度对飞机操纵的影响,游戏中为飞行控制添加了阻尼机制,当飞机速度越低时,每单位输入能造成的旋转角度越小,用以对应现实中飞机的“失速”情况。
  2. 为了实现摄像机能始终跟随在飞机背后且时刻看向飞机,首先可以想象一下,摄像机和飞机都处于同一个平面,当飞机旋转一定角度时,视角也在相同的方向上旋转相同的角度,但摄像机需要旋转更长的弧距,才能保证摄像机,飞机,旋转轴心三点在同一条直线上。把这个机制应用在三维球体中,则无论飞机在哪个方向旋转,旋转角度多少,视角都会在飞机后方。以此为基础,通过调用Unity的 LookAt() 接口,就可以使摄像机朝向飞机



代码实现

  • 飞机控制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerControllerX : MonoBehaviour
{
    //public GameObject mainCamera;
    private float speed = 0.0f;
    private float rotationSpeed = 30.0f;
    private float damping = 0.0f;
    private float keyboardXInput;
    private float keyboardYInput;
    private float mouseYInput;
    private float mouseXInput;
    private float zoomScale;
    private float gravity = 9.81f;
    private float lift = 0.0f;
    private Rigidbody rb;

    // Start is called before the first frame update
    void Start() {
        rb = GetComponent();
    }

    // Update is called once per frame
    void Update() {
        keyboardYInput = Input.GetAxis("Vertical");
        keyboardXInput = Input.GetAxis("Horizontal");
        mouseYInput = Input.GetAxis("Mouse Y");
        mouseXInput = Input.GetAxis("Mouse X");

        
        
        if (speed <= 20.0f)
            speed = speed + keyboardYInput*0.1f;
        if (speed <= 0.0f)
            speed = 0.0f;
        else
            speed = speed - 0.05f;

        
        
        lift = 0.9f * speed;
        if (lift > 9.81f)
            lift = 9.81f;

        rb.AddForce(Vector3.up*lift - Vector3.up*gravity);

        
        
        damping = 0.1f * speed;
        if (damping > 1.0f)
            damping = 1.0f;

        
        transform.Translate(Vector3.forward * speed * Time.deltaTime);
        
        transform.Rotate(Vector3.up * rotationSpeed * keyboardXInput * damping * Time.deltaTime);
        
        transform.Rotate(-1 * Vector3.right * rotationSpeed * mouseYInput * damping * Time.deltaTime);
        
        transform.Rotate(-1 * Vector3.forward * rotationSpeed * mouseXInput * damping * Time.deltaTime);
    }
}

  • 摄像机控制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FollowPlayerX : MonoBehaviour
{
    public GameObject player;
    private Vector3 offset;
    private Vector3 zoom;
    public float zoomScale = 2.0f;
    private float playerRotateY;
    private float playerRotateX;
    private float scrollWheelInput;

    void Start() {}

    void LateUpdate() {
        
        scrollWheelInput = Input.GetAxis("Mouse ScrollWheel");

        zoom = new Vector3(0, -1*zoomScale*scrollWheelInput, zoomScale*scrollWheelInput);
        offset = offset - zoom;

        
        transform.rotation = player.transform.rotation;

        
        
        playerRotateY = player.transform.eulerAngles.y;
        playerRotateX = player.transform.eulerAngles.x;

        
        Quaternion rotatiomXY = Quaternion.Euler(playerRotateX, playerRotateY, 0);

        //transform.position = Vector3.Lerp(transform.position, player.transform.position + (rotatiomXY*offset), Time.deltaTime);
        transform.position = player.transform.position + (rotatiomXY*offset);
    }
}



效果展示

Unity3D-飞行模拟



参考文献

Unity Technologies. 2020. Create with Code, Unit 1: Player Control. Retrieved from: https://learn.unity.com/course/create-with-code?uv=2020.3

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/906245.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号