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

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

刚体运动


由于为Player对象添加了 Rigidbody 组件,因此我们应该使用物理引擎来控制移动而不是直接进行移动和旋转。力的施加方式有两种:

直接使用 Rigidbody 类的AddForce 和AddTorque 方法分别移动或旋转对象这种方式存在一些不足,通常需要编写额外的代码以修正非预期的物理行为.

使用其他的 Rigidbody 类方法,例如 MovePosition 和MoveRotation 方法。这种方式依然会施加力,但是系统会在幕后处理好边界情形。

实践:访问Rigidbody组件

我们首先需要从 Player 对象中获取并存储想要修改的 Rigidbody 组件。

(1)按如下代码修改 PlayerBehavior 脚本:

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

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


添加一个私有的 Rigidbody 变量,用来存储胶囊的 Rigidbody 组件信息


Start 方法会在初始化脚本时触发,也就是单击 Play 按钮时。在初始化过程中设置变量时都应该使用Start 方法。


使用GetComponent方法检查脚本上附加的对象是否包含指定的组件类型,在本例中也就是 Rigidbody 组件。如果找到了,就返回。如果没有找到,那么返回 null.但在这里,我们已经知道Player对象上附有 Rigidbody 组件。


注释掉 Update 方法中对 Transform 和 Rotate 方法的调用,从而避免同时使用两种不同的控制方式。这里依然保留获取玩家输入的方式,以便后续继续使用。

实践:移动刚体

打开PiayerBehavior脚本,在Update 方法中添加如下代码并保存文件.

void FixedUpdate()
{
  Vector3 rotation = Vector3.up * hInput;
  Quaternion angleRot = Quaternion.Euler(rotation *Time.fixedDeltaTime);
  _rb.MovePosition(this.transform.position +this.transform.forward * vInput * Time.fixedDeltaTime);
 _rb.MoveRotation( rb.rotation * angleRot);
}

下面对上述代码进行解释


任何物理的或 Rigidbody 相关的代码都要放在 FixedUpdate 方法中,而不是放在Update 或其他 MonoBehaviour 方法中


创建一个新的 Vector3 变量以存储左右旋转值。Vector3.up* hInput 与我们之前在Rotate 方法中使用的旋转向量是相同的。

Outernion.Eulcr 接收一个 Vector3 变量作为参数并使用欧拉角的格式返回旋转值。


在MoveRotation 方法中,我们需要使用Qutemion 值而不是Vector3 变量,这是 Unity 首选的旋转类型的转换。

这里乘以Timc.fixcdDeltaTime 的原因与在 Update 方法中乘以Time.deltaTime相同。

调用b组件的MovePosition 方法,该方法将接收一个 Vector3 变量作为参数并施加相应的力。


使用的向量可以如下分解:胶囊的位置向量加上前向的方向向量与垂直输入和Time.fixedDeltaTime的乘积。

Rigidbody 组件负责调整施加的力以满足输入的向量参数

调用_b组件的MoveRotate 方法,该方法也将接收一个 Vector3 变量作为参数并施加相应的力。angleRot 已经包含来自键盘的水平输入,所以只需要将当前Rigidbody组件的旋转值乘以 angleRot 就能得到同样的左右旋转值。

刚刚发生了什么

如果现在运行游戏,就会发现玩家已经可以向着你看的方向前后移动了,同时还能沿着Y轴进行旋转。施加的力提供了相比直接平移/旋转更强大的效果,所以你需要调整好 Inspector 面板中的 moveSpeed 和 rotateSpeed 变量。至此,我们重建了之前已有的移动模式,并且拥有了更真实的物理效果。

碰撞体和碰撞


Collider 组件不仅仅使游戏对象能被 Unity 的物理系统认知到,也使交互和碰撞成为可能。可将碰撞体想象为围绕在游戏对象周围的不可见力场:取决于设置,它们可能被通过,也可能被撞上,并且有一系列方法会在发生不同的交互行为时触发。


Pickup_Prefab 对象层次中的Capsule 对象

bfbcdf390cad481e8c5d5ff8d948475d.png

Capsule 对象周围的绿色形状是 Capsule Collider,可以通过 Center、Radius、Heig等属性进行移动和缩放。当创建基础图元时,碰撞体默认与图元形状匹配;因为现在创建了Capsule 图元,因此也会同时创建 Capule Collider。


碰撞体还支持Box、Sphere 和 Mesh 形状,可以手动从Compoent| Physics 菜单或单击Inpector 面板中的Add Component 按钮进行添加。


举个例子,当两个带有碰撞体的游戏对象碰在一起时,它们都会发送OnCollisionEnter 消息,其中包含将要碰到的对象的引用。这种消息可用于各种交互式事件,比如拾取物品。

实践:拾取物品

为了给 Pickup Item 更新碰撞逻辑,需要执行以下步骤。

(1)在Scripts 文件夹中创建一个新的C#脚本,命名为ItemBehavior,然后拖放至场景中Pickup Item 预制体之下的 Capsule 对象上,如图7-9 所示。注意,任何使用了碰撞检测的脚本都必须被附加到包含了 Collider 组件的游戏对象上,即使是预制体的子对象。

(2)使用Pickup Item 更新根预制体

49754132e3674d5d8d27401347df4d0b.png

(3)在ItemBehavior脚本中添加如下代码并保存:

public class ItemBehavior : MonoBehaviour
{
  void OnCollisionEnter(Collision collision)
  {
    if(collision.gameObject.name == “Player")
    {
     Destroy(this.transform.parent.gameObject);
     Debug.Log("Item collected!");
    }
   }
}

(4)单击 Play 按钮,移动玩家至胶囊处并捡起胶囊!

下面对步骤(3)中的代码进行解释。

1.当把另一个对象移至 Pikcup_Item 且 isTrigger 处于关态时,Umy 会自动调用OnCollisionEnter 方法。

  • OnCollisionEnter 方法有一个参数用于存储 Collider 引用。
  • 注意 collision 变量的类型是 Collision 而不是 Collider。

2.Collision 类的 gamebject 属性用于保存对 GameObject 碰撞体的引用。

以使用gameObject属性获取游戏对象的名称并使用if语检查碰撞体是否是Play对象。

3.如果碰撞体是 Player 对象,就调用 Destroy 方法,该方法接收一个游戏对象作为参数。

我们必须使整个Pickup Item对象被销毁,而不仅仅是销毁 Capsule 对象

因为 ItemBehaivor 脚本被附加到了 Capsule 对象上,而 Capsule 对象又是Pickup_Item 对象的子对象,所以可以使用 this.transform.parentgameObject将Pickup Item 对象销毁

向控制台打印一条日志,指明已经收集了道具。

image.png

刚刚发生了什么

我们在本质上相当于将 lemBehavior 脚本设置为监听与 Pikup_Item 预制体Capsule 子对象发生的任何碰撞。每当发生碰撞时,ItemBehavior 脚本就会使OnCollisionEnler 方法检查碰撞对象是否为 Player 对象。如果是,就销毁(或收集)。果感到困惑,请将编写的碰撞相关代码当作来自 Pickup Item 预制体的通知的接收者每当胶囊被碰撞时,就会触发这些代码。

提示:

也可以创建类似的包含OnCollisionEnter方法的脚本并附加到Player对象上然后检测是否与 Pickup Item 预制体发生了碰撞。碰撞逻辑取决于碰撞对象的角度

使用碰撞体触发器


默认情况下,碰撞体的 isTrigger 属性并未启用,物理系统会把这些碰撞体视为实体。然而,某些情况下我们需要使游戏对象可以穿过碰撞体,触发器就是为了处理这种情况而存在的。当isTrigger 属性被启用后,游戏对象就可以穿过碰撞体,但发送的通知会变为OnTriggerEnter、OnTriggerExit 和OnTriggerStay。


触发器多用于检测游戏对象是否进入某个特定区域或通过某个点。可使用触发器在敌人周围设置警戒区域,如果玩家进入触发区域,敌人就会受到惊扰,然后开始攻击玩家。

实践:创建敌人

为了创建敌人,需要执行以下步骤:

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

(2)在Materials 文件夹中使用Create|Material创建一个材质,命名为 Enemy_Mat,设置AIbedo属性为亮红色。然后拖动Enemy Mat 材质至 Enemy游戏对象上。


(3)选中Enemy游戏对象,单击Add Component按并搜索 Sphere Collider,然后按Enter键进行添加。选中is Trigger 复选框并将Radius设置为8.

73c5300db7934fb5a14f4b1f43e973a9.png

刚刚发生了什么

新建的Enemy游戏对象现在围绕着一个半径为8的球形触发器。任何时候,当另一个对象进入、停留或离开时,Unity 都会发送能够被捕获到的通知,就像处理碰撞时一样。

实践:捕获触发器事件

为了捕获触发器事件,需要执行如下步骤

(1)在Scripts文件夹中创建一个新的C#脚本,命名为 EnemyBehavior,然后拖至Enemy游戏对象上。

(2)添加如下代码并保存文件。

public class EnemyBehavior : MonoBehaviour
{
 void OnTriggerEnter(Collider other)
 {
  if(other.name=="Player")
  {
   Debug.Log('Player detected - attack!");
  }
 }
void OnTriggerExit(Collider other)
{
 if(other.name=="Player")
 {
  Debug.Log("Player out of range,resume patrol");
 }
}
}

(3)单击 Play 按钮,走向Enemy 游戏对象以触发第一个通知,然后远离 Enemy游戏对象以触发第二个通知。


下面对步骤(2)中的代码进行解释。


任何时候,当一个对象进入 Enemy 游戏对象的球形触发器时,OnTriggerEnter方法就会被触发。


类似于 OnCollisionEnter 方法,OnTriggerEnter 方法的参数用于存储对象的Collider组件的引用。

注意参数对象的类型是 Collider 而不是 Collision。

使用other 获取碰撞体对象的名称并使用if语句检查是不是 Player 对象。如果是,就输出 Player 对象位于危险区域的提示信息


当对象离开Enemy游戏对象的球形触发器时,触发OnTriggerExit 方法。

image.png

使用f 语句按名称检查离开球形触发器的对象。如果是 Player 对象,就将另一条信息打印到控制台,指示玩家现在是安全的

image.png

刚刚发生了什么

Enemy游戏对象的球形触发器会在自身被侵入时发送通知,EnemyBehavior脚本将捕获这些事件。任何时候,当玩家进入或离开球形触发器时,都会在控制台中打印调试日志以确保代码正常工作。

总结


  • Rigidbody组件能为附加到的对象添加真实的物理模拟。
  • Collider 组件之间可以相互交互,并且 Collider 组可以作为对象与 Rigidbo组件进行交互。
  • 如果一个对象使用了 Rigidbody 组件但没有启用 isKinematic 属性,那么得的就是运动学效果,因为物理系统会忽略这个对象。
  • 如果一个对象使用了 Rigidbody 组件并且施加了力和扭矩,那么得到的将是非运动学效果。
  • 碰撞体基于交瓦行为发送通知。

在本章,你创建了自己的第一款游戏,并积累了一定的经验。现在,你已经能使用向量和基本的向量运算来确定 3D 空间中的位置和角度,并且熟悉了玩家输入及移动和旋转 GameObject 的两种主要方法。你甚至深入接触了 Unity 的物理系统,熟悉了刚体、碰撞、触发器以及事件通知等知识。总而言之,你为 Hero Bor 游戏开了个好头。

下面将开始处理更多的游戏机制,包括跳跃、冲刺、射击以及与环境中的各个部分进行交互。




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