前言

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

目录

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


背景


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




设计


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

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


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

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

force=k∗speed+bforce=k*speed+bforce=kspeed+b

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

speed={speed+keyboardinputif  speed<maxspeedspeed−frictionif  speed>00if  speed<0speed = \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+keyboardinputspeedfriction0ifspeed<maxspeedifspeed>0ifspeed<0

  1. 飞机可以分别绕 xyzx \ y \ zxyz 轴旋转以实现自由飞行。其中,绕 yyy 轴通过键盘A/D输入控制,绕 zzz 轴旋转通过鼠标水平输入控制,绕 xxx 轴旋转通过鼠标垂直输入控制。此外,为了模拟现实中升力和速度对飞机操纵的影响,游戏中为飞行控制添加了阻尼机制,当飞机速度越低时,每单位输入能造成的旋转角度越小,用以对应现实中飞机的“失速”情况。
  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 updatevoid Start() {rb = GetComponent<Rigidbody>();}// Update is called once per framevoid Update() {keyboardYInput = Input.GetAxis("Vertical");keyboardXInput = Input.GetAxis("Horizontal");mouseYInput = Input.GetAxis("Mouse Y");mouseXInput = Input.GetAxis("Mouse X");/* Give the plane a speed by player keyboard up/down input *//* the speed will decrease when there is no player control */if (speed <= 20.0f)speed = speed + keyboardYInput*0.1f;if (speed <= 0.0f)speed = 0.0f;elsespeed = speed - 0.05f;/* Give the plane a lift force according to the magnitude *//* of speed, not larger than gravity */lift = 0.9f * speed;if (lift > 9.81f)lift = 9.81f;rb.AddForce(Vector3.up*lift - Vector3.up*gravity);/* When speed is too low, player can hardly control the *//* movement of the plane, this is control by damping */damping = 0.1f * speed;if (damping > 1.0f)damping = 1.0f;/* Let plane move forward with a speed */transform.Translate(Vector3.forward * speed * Time.deltaTime);/* Rotate the plane left/right using player's keyboard left/right input */transform.Rotate(Vector3.up * rotationSpeed * keyboardXInput * damping * Time.deltaTime);/* Rotate the plane up/down using player's mouse X axis input */transform.Rotate(-1 * Vector3.right * rotationSpeed * mouseYInput * damping * Time.deltaTime);/* Rotate the plane using player's mouse Y axis input */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() {/* Allow user to zoom in/out the camera */scrollWheelInput = Input.GetAxis("Mouse ScrollWheel");zoom = new Vector3(0, -1*zoomScale*scrollWheelInput, zoomScale*scrollWheelInput);offset = offset - zoom;/* Let the camera rotate as the player roate */transform.rotation = player.transform.rotation;/* Let the camera behind the player *//* Get the rotation angle along Y/X axis of the player */playerRotateY = player.transform.eulerAngles.y;playerRotateX = player.transform.eulerAngles.x;/* Transform the ratation angle to a Vector3 object */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

Unity游戏开发文档(1):飞行模拟相关推荐

  1. Unity游戏开发文档(3.1.1):弹窗效果

    前言      该文档为<Unity游戏开发文档(3):Dancing Line>的附属文档,亦可看作是单独的技术总结文档. 目录 综述 对话框的非匀速滑动 对话框动画的异步运行 最终效果 ...

  2. Unity游戏开发文档(3.1.3):滚动式关卡选择菜单

    前言      该文档为<Unity游戏开发文档(3):Dancing Line>的附属文档,亦可看作是单独的技术总结文档. 目录 综述 构建滚动菜单 读取关卡信息 填充菜单选项 选项自动 ...

  3. Unity游戏开发文档(3.1.2):下拉式音乐选择菜单

    前言      该文档为<Unity游戏开发文档(3):Dancing Line>的附属文档,亦可看作是单独的技术总结文档. 目录 综述 构建下拉菜单 填充下拉菜单 切换背景音乐 最终效果 ...

  4. python飞机大战概要设计_飞机大战游戏开发文档(Android版)

    飞机大战游戏 开发文档 (Android版) 课程名称:飞机大战游戏 课程类型:Android游戏编程精彩内容,尽在百度攻略:https://gl.baidu.com 姓名:苏均灿 学号:131342 ...

  5. 微信小程序游戏开发文档以及开发工具地址

    微信小程序开发交流qq群   581478349    承接微信小程序开发.扫码加微信. 正文: 微信官方于 2017 - 12 - 28 日 开发微信小程序 开发小游戏 , 微信小程序小游戏开发官方 ...

  6. 火力篮球游戏源码完整版-带游戏开发文档

    火力篮球,通过模拟现实中的投篮游戏机,而投篮游戏机又是源于街头篮球,街头篮球起源于美国,现在已经流行于世界的体育竞技项目,将投篮部分独立出来做成投篮游戏机.成为了专门的投篮类游戏设备.而本游戏就是将该 ...

  7. 火力篮球游戏源码完整版--采用标准的游戏开发文档

    火力篮球,通过模拟现实中的投篮游戏机,而投篮游戏机又是源于街头篮球,街头篮球起源于美国,现在已经流行于世界的体育竞技项目,将投篮部分独立出来做成投篮游戏机.成为了专门的投篮类游戏设备.而本游戏就是将该 ...

  8. java小组坦克大战游戏开发文档开发日志_java实现坦克大战游戏

    本文实例为大家分享了java实现坦克大战游戏的具体代码,供大家参考,具体内容如下 一.实现的功能 1.游戏玩法介绍 2.自定义游戏(选择游戏难度.关卡等) 3.自定义玩家姓名 4.数据的动态显示 二. ...

  9. php赛车游戏开发文档,React 开发一款简单的赛车游戏

    写在开始之前 最近研究egret引擎时,在论坛看到了用egret引擎写的一款赛车游戏 玩法很简单,左右控制赛车躲避来车,碰撞即游戏失败 下面将为大家一步步讲解,如何用React写出一款纯 javasc ...

最新文章

  1. js事件(Event)知识整理
  2. SpringMVC流程图示
  3. 速览EMNLP 2020上录取的知识图谱相关论文
  4. EMNLP'21 | 检索式对话情感回复
  5. B. Suffix Structures 模拟吧,情况比较多要想周全
  6. python 调用C语言DLL的方法
  7. fedora python3-mysql_centos 下安装python3 的MySQLdb
  8. 手把手教你安装Sketch破解版和measure插件 1
  9. 最常用的数据分析方法
  10. 有赞多平台推广接入与测试
  11. SuperMap根据栅格数据制作专题图
  12. 磁盘与文件系统管理--鸟哥私房菜读书笔记
  13. PAT_乙级_1001_筱筱
  14. Android 模拟器中的menu键
  15. idea之自定义注释模板
  16. 保护计算机数据库,保护Access2000数据库的安全
  17. Maven3.5.0安装与配置
  18. 二手车电商三国杀,广告大战究竟该不该打?
  19. HJS-DE1/2时间继电器
  20. net/http源码

热门文章

  1. 软件测试面试题:怎么验证一个复选框是不是被选中或者未被选中?
  2. Istio服务网格实践指南 学习笔记(二) Istio架构
  3. 数据的相似性与相异性矩阵
  4. ubuntu16中英文输入法切换快捷键
  5. 使用javascript计算1加到100的结果
  6. 玩转AgileCDN(十一)——小工单,大作用
  7. 2022 年全国职业院校技能大赛(中职组) 网络安全竞赛试题A 模块评分标准
  8. 两种启动tomcat的方法
  9. 《人民的名义》---简单的文本分析
  10. NASM import win32api