从零开始做一款Unity3D游戏<二>——移动,相机控制与碰撞(一)

简介: 从零开始做一款Unity3D游戏<二>——移动,相机控制与碰撞

本文主要来自<<C#实践入门>>哈里森.费隆 著,仅用为做笔记。

当玩家开始玩一款新的游戏时,要做的第一件事就是熟悉角色移动和相机控制。这是一件很有意思的事情,可以让玩家对游戏玩法有一定的预期。Hero Bor 游戏中的角色将是一个胶囊,可以使用键盘上的 W、A、S、D 或方向键进行移动和旋转。在本章,你将首先学习如何通过操纵对象的 Transform 组件来进行移动,然后了解如何通过对物体施加力来控制移动,使运动效果更真实。当移动玩家时,相机会从稍微靠近后方及上方的位置进行跟随,从而使实现瞄准这一射击机制更加容易。最后,本章将使用之前制作的可拾取道具来探索 Unity 的物理系统如何处理碰撞与交互。

本章包含以下内容:

  • 移动与旋转变换。
  • 管理玩家输入。
  • 编写相机行为脚本。
  • Unity 的物理系统和力的应用
  • 基本的碰撞体与碰撞检测。

移动玩家


当决定以何种最佳方式在虚拟世界中移动玩家时,需要考虑如何才能使移动看起来最真实,并避免昂贵的计算开销。在大部分情况下,我们都需要采用折中方案,Unity也不例外。

移动游戏对象的三种常见方式及结果如下。

  • 使用游戏对象的Transform 组件来进行移动和旋转。这是最简单的方式,也是我们的首选方式。
  • 为游戏对象附加 Rigidbody 组件并在代码中施加力。这种方式需要依赖Unity的物理系统来处理繁重的工作,从而提供更真实的效果。本章后续部分会修改代码以使用这种方式。
  • 注意:Unity 建议在移动或旋转游戏对象时保持一致的方式。你可以操纵对象的Transform或RigidBody组件,但不要同时使用它们两者。

附加现有的 Unity 组件或预制体,例如CharacterController或FirstPersonController。这样可以减少样板代码,并且仍然能够提供真实的效果,另外还缩短了原型制作时间。

玩家对象的创建


我们想要把 Hero Born 设计为第三人称冒险游戏,这个游戏的起点就是一个可以通过键盘输入进行控制的胶囊以及跟随这个胶囊进行移动的相机。即使这两个对象在游戏中可以一起工作,但为了方便控制,我们还是将它们分开为好。

实践:创建胶囊

只需要执行如下步骤,即可创建出用来表示玩家的胶囊。

(1)在 Hierarchy 面板中使用 Create|3D Object|Capsule创建一个新的 Capsule对象,命名为Player。

(2)选择 Player 对象,单击 Inspector 面板底部的 Add Component 按钮。搜索Rigidbody 并按Enter 键,将 Rigidbody 组件添加到Player 对象上。

(3)展开Rigidbody组件底部的 Constraint 属性并选中 Freeze Rotation 中的x轴和y轴。

5c6f32ccc453407e942299608e092bb8.png

刚刚发生了什么

我们使用Capsule图形、Rigidbody 组件和亮绿色材质创建了 Player 对象。不必疑感Rigidbody 组件到底是什么,现在只需要知道 Rigdbody组件能使 Player 对象与物理系统进行交互即可。具体细节我们将在讨论 Unity 的物体系统时进行说明。

理解向量


现在已经创建好了 Player 对象和相机,可以开始了解如何通过Transform组件来移动和旋转游戏对象了。Translate 和 Rotate 方法属于 Unity 提供的 Transform类,它们都需要使用一个向量作为参数。

在Unity 中,向量用来保存2D或3D空间中的位置和方向,因而存在两种变量:Vector2和 Vector3。这两种变量能够像任何其他变量那样使用,只不过它们代表不同的信息。因为我们的游戏是三维的,所以需要使用 Vector3,这意味着你需要知道x从2的值。对于2D 向量,则只需要知道x 和y的值。记住,3D 场景的当前朝向显示在场景中右上角的几何图形上

例如,如果想要创建向量来保存场景中原点的位置,可以使用如下代码:

Vector3 origin = new Vector(0f,0f,0f);

上述代码将创建一个 Vector3 变量并使用0按顺序初始化位置值。foat 类型的值带不带小数点都可以,但是必须以小写的f结尾。

我们还可以使用 Vector2和 Vector3 类的属性来创建方向向量:

Vector3 forwardDirection = Vector3.forward;

forwardDirection 变量指的是3D 空间中沿着z轴的场景方向,也就是前方,其中存储的并不是位置。本章后续部分会使用向量,现在只需要考虑 3D 运动的位置和朝向即可。

获取玩家输入


位置和朝向是很有用的概念,但只靠它们无法形成运动,还需要配合玩家输入才行。这就是引入 Input 类的原因所在,Input 类能将所有的按键输入和鼠标位置处理为相应的加速及陀螺仪数据。


对于 Hero Bomn 游戏来说,可使用键盘上的 W、A、S、D 键以及方向键来控制移动,并配合使用脚本,让相机能够跟随玩家光标所指的位置。为此,你需要理解输入轴是如何工作的。


使用 Edit|Project Settings|Input 打开InputManager 面板,

image.png

从中可以看到已配置好的 Unity 默认的输入列表,以 Horizontal 输入轴为例:Horizontal输入轴将Negative Button和 Positive Button 按钮分别设置为键位left和right;并且将AItNegative Button和Alt Positive Button 设置为键位a和d。


任何时候,当从代码中获取输入轴时,值的范围始终是 -1~1。例如,当左方向键或A 键被按下时,水平轴的值变为-1;释放按键时,值变回 0。同样,当右方向键或D键被按下时,水平输入轴的值会变化为 1。这种行为使你可以从代码中获取某个轴的不同输入,并且只需要一行代码,你不需要为了获取不同的值而输入一长串的if/else 语句。


获取输入轴很简单,只需要调用 Input.GetAxis 方法并指定输入类型的名称即可,稍后我们将采用这种方式来获取水平和垂直输入。


既可以按自己的需要修改默认的输入配置,也可以通过递增 Size 的值来创建自定义输入轴,然后重命名创建出来的副本。

实践:移动玩家

为了使玩家可以移动,需要为 Player 对象添加脚本。

(1)在 Scripts 文件夹中创建一个新的 C#脚本,命名为 PlayerBehavior,然后将这个脚本拖动至Player对象上。

public class PlayerBehavior:MonoBehaviour
{
  public float moveSpeed=10f;
  public float rotateSpeed=75f;
  private float vInput;
  private float hInput;
  void Update()
  {
   vInput=Input.GetAxis("Vertical")*moveSpeed;
   hInput=Input.GetAxis("Horizontal")*rotateSpeed;
   this.transform.Translate(Vector3.forward*vInput*Time.Time*deltaTime);
   this.transform.Rotate(Vector3.up*hInput*Time.deltaTime);
  }
}

提示:

如果存在空的方法,例如本例中的 Start 方法,可以将其删除以保持代码清晰。当然,如果倾向于在脚本中保留它们,也可以。

声明两个公共变量作为乘数:

  • moveSpeed表示玩家可以向前或向后移动的速度
  • rotateSpeed 表示玩家可以向左或向右旋转的速度

声明两个私有变量来保存来自玩家的输入,刚开始时不设置任何值:

  • vInput用来保存来自垂直轴的输入
  • hInput用来保存来自水平轴的输入

Input.GetAxis(Vertical")用于检查上下方向键以及 W和S键何时被按下,然后将其值乘以moveSpeed.

  • 上方向键和W键会返回 1,使得玩家向前方(正方向)移动。
  • 下方向键和S键会返回 -1,使得玩家向后方(反方向)移动。

Input.GetAxis("Horizontal")用于检查左右方向键以及A和D键何时被按下,然后将其值乘以rotateSpeed

  • 右方向键和D键会返回 1,使得玩家向右旋转。
  • 左方向键和A键会返回-1,使得玩家向左旋转

使用Translate方法移动Player 对象的Transform组件

记住 this关键字指代当前脚本被附加到的游戏对象,在本例中也就是 Player对象。

将 Vector3.forward 与Input 和 TimedeltaTime 相乘,后面两者提供了玩家沿着z轴向前或向后移动的速度和方向

当游戏运行时,Time.deltaTime 会返回从上一到现在经历的时间,单位为秒.Time.deltaTime通常用于平滑 Update 方法获取的值,使其不受设备率的影响。

使用 Rotate 方法相对于传入的向量旋转玩家

  • ·将 Vector3.up 乘以hInput 和 Time.deltaTime 可得到向左或向右的旋转轴。
  • 这里使用this 关键字和TimedeltaTime 的原因与上面的相同。
  • 如前所述,在 Translate和 Rotate 方法中使用方向向量只是达成目的的方式之也可根据轴输入创建新的 Vector3 变量并用作参数。

刚刚发生了什么

运行游戏后,就可以使用上/下方向键和 W/S键控制玩家前后移动,而使用左店方向键和A/D 键控制玩家左右旋转。我们仅仅使用很少的代码,就设置好了与帧率天关且易于修改的两个独立控件。然而,相机还不会跟随玩家移动,接下来就解决这问题

相机跟随


使一个对象跟随另一个对象的最简单方式就是将其中一个对象设置为另一个对象的子对象。但是,这意味着 Player 对象发生的任何移动或旋转都会影响到相机,这并不是我们想要的效果。幸运的是,Tansform类提供的方法使得相对于 Player 对象设相机的位置和旋转变得十分简单。

实践:编写相机行为

为了使相机的行为完全与 Player 对象的移动分离开来,我们需要控制相机相对于哪个目标来摆放,目标可以在Inspector 面板中进行设置。

(1)在Scripts 文件夹中创建一个新的C#脚本,命名为CameraBehavior,然后拖放至Main Camera对象上

public class CameraBehavior : MonoBehaviour
{
 public Vector3 camoffset = new Vector3(0,1.2,-2.6);
 private Transform target;
 void Start()
 {
  target=GameObject.Find("Player").transform;
  }
 void LateUpdate()
 {
  this.transform.position=target.TransformPoint(camOffset);
  this.transform.LOOkAt(target);
 }

下面对上述代码进行解释。

声明一个Vector3变量来存储想要的 Main Camer 对象与Player 对象之间的偏郑距离

  • 可以在Inspoctor面板中手动设置相机的偏移位置,因为camOfiset 变量是公共的。
  • 现有的默认值比较合适,当然你也可以尝试修改

创建一个Transfom变量来保存 Player 对象的变换信息

  • 这使得我们可以获取位置、旋转和缩放信息
  • 这些信息不应该能够从 CameraBehavior 脚本之外进行访问,所以将 target变

量设置为私有的

使用GameObject.Find 方法在场景中按名称查找Player 对象并获取Player对象的transfomm属性,这意味着存储在target 变量中的 Player对象的位置会在每一进行更新。

LateUpdate是MonoBehaviour 脚本提供的方法,就像 Start和Update 方法一样,LateUpdate方法也在Update 方法之后执行。由于 PlayerBehavior 脚本在Update 方法中移动了Player对象,因此我们希望 CameraBehavior 脚本在移动操作完成之后执行;这祥可以确保 target变量引用的是最新位置。

每都把相机的位置设置为 target.TransformPoint(camOfset)以产生跟随效果

  • TransformPoint 方法用于计算并返回世界空间的相对位置。在这里,TransformPoint方法会返回 target 对象的偏移位置,x轴为0,y轴为1.2(将相机置于胶囊上方),z轴为 - 2.6(将相机置于胶囊后方),

LookAt方法会在每一更新胶囊的旋转值,使其朝向传入的Transform对象(本例中的 target 变量)所在的位置

同刚发生了什么

这里有大量知识需要消化吸收,如果按时间顺序进行分解的话,理解起来会简单一些。

(1)首先为相机创建了偏移位置

(2)然后查找并存储 Player 对象(也就是场景中的胶囊)的位置。

(3)最后,在每一帧都手动更新位置和朝向,使相机一直按设置好的距离跟随并朝向玩家。

使用Unity的物理系统


到目前为止,我们尚未讨论 Unity 引擎实际上是如何工作的以及如何在虚拟空间中创建出栩栩如生的交互与运动效果。本章的剩余部分将聚焦于 Unity 的物理系统

PhysX引擎中最重要的两个组件如下:

  • Rigidbody 组件,这种组件允许你使用重力以及其他因素对游戏对象施加影响
    Rigidbody 组件还会受施加的力的影响,从而产生更真实的运动效果Rigidbody组件的属性
  • image.png
  • Collider 组件,这种组件决定了游戏对象何时以及怎样进入、离开其他对象的物理空间,抑或简单地碰撞并弹开。对于给定的游戏对象来说,只能添加个RigidBody组件,但可以添加多个 Collider 组件。Collider 组件的属性

image.png

当两个游戏对象彼此碰撞时,Rigidbody 组件的属性决定了碰撞结果。举例来说如果一个游戏对象的质量比另一个大,那么轻一点的那个会被弹开,就像现实生活中一样。Rigidbody和 Collider 组件负责 Unity 中的所有物理交互。


在使用Rigidbody和Collider 组件时有一些注意事项,下面使用Unity 允许的移动类型的术语来进行解释.

  • Kincmatic移动发生在添加了 Rigidbody 组件的游戏对象上,但没有向场景t的物体系统进行注册。这种行为仅仅在某些特定情形下使用,可以通过选中Rigidbody组件的isKinematic 属性来启用。因为我们希望胶囊能够与物理系进行交互,所以这里不会使用这种运动方式。
  • Non-Kinematic移动指的是通过施加力来对 Rigidbody 组件进行移动和旋转而不是直接操作游戏对象的 transform 属性。我们的目标就是修改PlayerBehavior脚本以实现这种类型的移动。

提示:

我们现有的方式是操纵胶囊的 Transform 组件,同时使用 RigidBody 组件与物理系统进行交互,目的是想要在3D 空间中考虑移动与旋转。然而,这并不意味着可以在实际产品中使用,并且Unity 也建议避免在代码中混合使用Kinematic和Non-Kinematic 移动方式。

相关文章
|
3月前
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
183 6
|
2月前
|
测试技术 C# 图形学
掌握Unity调试与测试的终极指南:从内置调试工具到自动化测试框架,全方位保障游戏品质不踩坑,打造流畅游戏体验的必备技能大揭秘!
【9月更文挑战第1天】在开发游戏时,Unity 引擎让创意变为现实。但软件开发中难免遇到 Bug,若不解决,将严重影响用户体验。调试与测试成为确保游戏质量的最后一道防线。本文介绍如何利用 Unity 的调试工具高效排查问题,并通过 Profiler 分析性能瓶颈。此外,Unity Test Framework 支持自动化测试,提高开发效率。结合单元测试与集成测试,确保游戏逻辑正确无误。对于在线游戏,还需进行压力测试以验证服务器稳定性。总之,调试与测试贯穿游戏开发全流程,确保最终作品既好玩又稳定。
112 4
|
3月前
|
图形学 缓存 算法
掌握这五大绝招,让您的Unity游戏瞬间加载完毕,从此告别漫长等待,大幅提升玩家首次体验的满意度与留存率!
【8月更文挑战第31天】游戏的加载时间是影响玩家初次体验的关键因素,特别是在移动设备上。本文介绍了几种常见的Unity游戏加载优化方法,包括资源的预加载与异步加载、使用AssetBundles管理动态资源、纹理和模型优化、合理利用缓存系统以及脚本优化。通过具体示例代码展示了如何实现异步加载场景,并提出了针对不同资源的优化策略。综合运用这些技术可以显著缩短加载时间,提升玩家满意度。
183 5
|
2月前
|
前端开发 图形学 开发者
【独家揭秘】那些让你的游戏瞬间鲜活起来的Unity UI动画技巧:从零开始打造动态按钮,提升玩家交互体验的绝招大公开!
【9月更文挑战第1天】在游戏开发领域,Unity 是最受欢迎的游戏引擎之一,其强大的跨平台发布能力和丰富的功能集让开发者能够迅速打造出高质量的游戏。优秀的 UI 设计对于游戏至关重要,尤其是在手游市场,出色的 UI 能给玩家留下深刻的第一印象。Unity 的 UGUI 系统提供了一整套解决方案,包括 Canvas、Image 和 Button 等组件,支持添加各种动画效果。
141 3
|
2月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
188 3
|
3月前
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
159 3
|
2月前
|
图形学 C++ C#
Unity插件开发全攻略:从零起步教你用C++扩展游戏功能,解锁Unity新玩法的详细步骤与实战技巧大公开
【8月更文挑战第31天】Unity 是一款功能强大的游戏开发引擎,支持多平台发布并拥有丰富的插件生态系统。本文介绍 Unity 插件开发基础,帮助读者从零开始编写自定义插件以扩展其功能。插件通常用 C++ 编写,通过 Mono C# 运行时调用,需在不同平台上编译。文中详细讲解了开发环境搭建、简单插件编写及在 Unity 中调用的方法,包括创建 C# 封装脚本和处理跨平台问题,助力开发者提升游戏开发效率。
234 0
|
2月前
|
vr&ar 图形学 API
Unity与VR控制器交互全解:从基础配置到力反馈应用,多角度提升虚拟现实游戏的真实感与沉浸体验大揭秘
【8月更文挑战第31天】虚拟现实(VR)技术迅猛发展,Unity作为主流游戏开发引擎,支持多种VR硬件并提供丰富的API,尤其在VR控制器交互设计上具备高度灵活性。本文详细介绍了如何在Unity中配置VR支持、设置控制器、实现按钮交互及力反馈,结合碰撞检测和物理引擎提升真实感,助力开发者创造沉浸式体验。
161 0
|
2月前
|
图形学 开发者
透视与正交之外的奇妙视界:深入解析Unity游戏开发中的相机与视角控制艺术,探索打造沉浸式玩家体验的奥秘与技巧
【8月更文挑战第31天】在Unity中,相机不仅是玩家观察游戏世界的窗口,更是塑造氛围和引导注意力的关键工具。通过灵活运用相机系统,开发者能大幅提升游戏的艺术表现力和沉浸感。本文将探讨如何实现多种相机控制,包括第三人称跟随和第一人称视角,并提供实用代码示例。
140 0
|
2月前
|
图形学 开发者
【独家揭秘】Unity游戏开发秘籍:从基础到进阶,掌握材质与纹理的艺术,打造超现实游戏视效的全过程剖析——案例教你如何让每一面墙都会“说话”
【8月更文挑战第31天】Unity 是全球领先的跨平台游戏开发引擎,以其高效性能和丰富的工具集著称,尤其在提升游戏视觉效果方面表现突出。本文通过具体案例分析,介绍如何利用 Unity 中的材质与纹理技术打造逼真且具艺术感的游戏世界。材质定义物体表面属性,如颜色、光滑度等;纹理则用于模拟真实细节。结合使用两者可显著增强场景真实感。以 FPS 游戏为例,通过调整材质参数和编写脚本动态改变属性,可实现自然视觉效果。此外,Unity 还提供了多种高级技术和优化方法供开发者探索。
54 0
下一篇
无影云桌面