当前位置: 首页 > news >正文

Unity3D学习FPS游戏(4)重力模拟和角色跳跃

前言:前面两篇文章,已经实现了角色的移动和视角转动,但是角色并没有办法跳跃,有时候还会随着视角移动跑到天上。这是因为缺少重力系统,本篇将实现重力和角色跳跃功能。觉得有帮助的话可以点赞收藏支持一下!

重力模拟和角色跳跃

  • 问题-太空人
  • 地面检测
  • 重力模拟
  • 跳跃
  • 完整代码
  • 效果
  • 补充知识
    • Property Attributes自定义属性
    • Time.fixedDeltaTime

问题-太空人

回到我们第二篇讲角色控制的三种方法中,提到了CharacterController虽然有碰撞但是是没有力的作用的,也就意味着没有重力效果。

在这里插入图片描述

地面检测

可以利用CharacterController.isGrounded来判断是否碰到地面。

但是要注意一下函数的功能定义:

isGrounded: Was the CharacterController touching the ground during the last move?

意思是判断的是上一次调用CharacterController.Move时有没有触地。

如果遇到isGrounded如果恒为false可能要注意,判断之前是不是还没有调用过Move。

重力模拟

非常简单,利用学过物理基本的公式a*t=v(加速度*时间=速度)、v*t=s(速度*时间=距离),就可以模拟出来。

新增重力加速度playerGravity和垂直速度verticalVelocity,当碰到地面时候垂直速度是0;当没有碰到地面的时候,垂直速度会随着受力一直变化,速度+=加速度*单位时间。在空中只有重力,对应代码就是verticalVelocity-=playerGravity*Time.fixedDeltaTime,为什么是减号因为重力是向下的,有方向。

最后把因为重力导致位移变化也一起Move就可以了。

public float playerGravity = 9.8F;// 重力加速度
public float verticalVelocity = 0;// 垂直速度
public void PlayerMovement()
{Vector3 moveDirection = Vector3.zero;// 获取键盘输入:Horizontal左右移动;Vertical前后移动// 加入自身tranform方向moveDirection = Vector3.zero;moveDirection += transform.forward  * Input.GetAxis("Vertical");moveDirection += transform.right * Input.GetAxis("Horizontal");moveDirection *= Time.deltaTime * moveSpeed;// 重力if (!m_Controller.isGrounded)verticalVelocity -= playerGravity * Time.fixedDeltaTime;// a*t=velseverticalVelocity = 0.0F;moveDirection.y += verticalVelocity * Time.fixedDeltaTime;// v*t=s// 移动m_Controller.Move(moveDirection);
}

由于涉及到了物理模拟,所以时间增量都改用了Time.fixedDeltaTime,并在FixedUpdate更新。这个使用Time.fixedDeltaTime具体原因在补充知识中有详细说明。

跳跃

有了重力,跳跃才有作用。

简单跳跃

跳跃的思路,首先不能多段跳,就是要碰到地面才能响应跳跃按键,跳跃后角色会上升一定高度。

添加一个玩家跳跃高度参数jumpHeight,直接让角色位移到jumpHeight,就能实现一个简单的跳跃效果

public float jumpHeight = 2F;
public void PlayerMovement()
{Vector3 moveDirection = Vector3.zero;// 获取键盘输入:Horizontal左右移动;Vertical前后移动// 加入自身tranform方向moveDirection = Vector3.zero;moveDirection += transform.forward  * Input.GetAxis("Vertical");moveDirection += transform.right * Input.GetAxis("Horizontal");moveDirection *= Time.deltaTime * moveSpeed;// 重力if (!m_Controller.isGrounded)verticalVelocity -= playerGravity * Time.fixedDeltaTime;// a*t=velseverticalVelocity = 0.0F;moveDirection.y += verticalVelocity * Time.fixedDeltaTime;// v*t=s// 跳跃if (Input.GetButton("Jump")){// 得在地面才能跳if (m_Controller.isGrounded){moveDirection.y += jumpHeight;}}// 移动m_Controller.Move(moveDirection);
}

跳跃优化

上面简单的跳跃,虽然能够实现跳跃功能,但是非常不自然,就是一下子跳到最高,又慢慢下来。

实际游戏中,我们的跳跃真正其实是一个抛物线。

在这里插入图片描述

也就向上跳到最顶的时候,也有个速度变化。

跳起来的时候会有一个向上的速度,之后不触地都是只受到重力作用了。所以点击跳跃按钮后,我们只需要算出这个跳起来一瞬间的向上速度是多少就行了。

还是最基础的物理公式推导:
a*t=v(加速度*时间=速度)、v*t=s(速度*时间=距离),设定跳跃的最高的高度h(jumpHeight)。
从最低点到最高点,通过h=0.5*a*t2,可以把总共的时长算出来,由于受力只有重力,通过重力加速度*总时长=初始向上速度。

verticalVelocity = Mathf.Sqrt(jumpHeight * 2 / playerGravity) * playerGravity;// 初始向上速度

于是新的代码就是:

public float jumpHeight = 2F;
public float verticalVelocity = 0;// 垂直速度
public void PlayerMovement()
{Vector3 moveDirection = Vector3.zero;// 获取键盘输入:Horizontal左右移动;Vertical前后移动// 加入自身tranform方向moveDirection = Vector3.zero;moveDirection += transform.forward  * Input.GetAxis("Vertical");moveDirection += transform.right * Input.GetAxis("Horizontal");moveDirection *= Time.fixedDeltaTime * moveSpeed;// 重力if (!m_Controller.isGrounded)verticalVelocity -= playerGravity * Time.fixedDeltaTime;// a*t=velseverticalVelocity = 0.0F;// 跳跃if (Input.GetButton("Jump")){// 得在地面才能跳if (m_Controller.isGrounded){verticalVelocity = Mathf.Sqrt(jumpHeight * 2 / playerGravity) * playerGravity;// 初始向上速度}}moveDirection.y += verticalVelocity * Time.fixedDeltaTime;// v*t=s// 移动m_Controller.Move(moveDirection);
}

完整代码

具有角色移动、视角、重力和跳跃的完整PlayerController代码。

public class PlayerController : MonoBehaviour
{[Header("Unity组件")]public CharacterController m_Controller;public Transform playerCamera;[Header("玩家数值")]public float moveSpeed = 6.0F;public float mouseSensitivity = 1000.0F;public float playerGravity = 9.8F;public float jumpHeight = 2F;public float verticalVelocity = 0;// 垂直速度private float x_RotationOffset = 0;// 累计x旋转private float y_RotationOffset = 0;// 累计y旋转void Start(){m_Controller = this.GetComponent<CharacterController>();Cursor.lockState = CursorLockMode.Locked;// 鼠标锁定}private void FixedUpdate(){PlayerRotation();PlayerMovement();}// 控制角色移动public void PlayerMovement(){Vector3 moveDirection = Vector3.zero;// 获取键盘输入:Horizontal左右移动;Vertical前后移动// 加入自身tranform方向moveDirection = Vector3.zero;moveDirection += transform.forward  * Input.GetAxis("Vertical");moveDirection += transform.right * Input.GetAxis("Horizontal");moveDirection *= Time.fixedDeltaTime * moveSpeed;// 重力if (!m_Controller.isGrounded)verticalVelocity -= playerGravity * Time.fixedDeltaTime;// a*t=velseverticalVelocity = 0.0F;// 跳跃if (Input.GetButton("Jump")){// 得在地面才能跳if (m_Controller.isGrounded){verticalVelocity = Mathf.Sqrt(jumpHeight * 2 / playerGravity) * playerGravity;// 初始向上速度}}moveDirection.y += verticalVelocity * Time.fixedDeltaTime;// v*t=s// 移动m_Controller.Move(moveDirection);}// 控制角色视角private void PlayerRotation(){// 获取鼠标移动x_RotationOffset += Input.GetAxis("Mouse X")* Time.fixedDeltaTime * mouseSensitivity;// 水平方向y_RotationOffset += Input.GetAxis("Mouse Y")* Time.fixedDeltaTime * mouseSensitivity;// 垂直方向// 限制垂直旋转角度y_RotationOffset = Mathf.Clamp(y_RotationOffset, -45f, 45f);// 旋转transform.rotation = Quaternion.Euler(new Vector3(0, x_RotationOffset, 0));// Player旋转playerCamera.localRotation= Quaternion.Euler(new Vector3(y_RotationOffset, playerCamera.localEulerAngles.y, playerCamera.localEulerAngles.z));// Camera旋转}
}

效果

简单跳跃。
在这里插入图片描述

优化后的跳跃。
在这里插入图片描述

补充知识

Property Attributes自定义属性

我们写代码的时候,会写一些属性在Inspector中也能修改,方便查看不同值的表现效果。
例如我们现在PlayerController中的moveSpeed和playerGravity等,但是要定义为Public。

Property Attributes提供了很多内置属性,方便Inspector查看自定义的属性和修改。

常用的有:

  • [Header(“xxx”)]给变量在Inspector中添加标题头
  • [Space(xx)]在Inspector中添加间隔
  • [Range(xx, xx)]在Inspector中变量为滑动条范围
  • [Tooltip(“xxx”)]为变量在Inspector中添加说明(像可以在Inspector查看的注释)

里面的文本文字可以是中文。
有这些能让我们代码更加优雅😀,也方便和别人共事的时候更好阅读使用我们的代码。

Time.fixedDeltaTime

fixedDeltatime是一个固定的时间增量不会随着帧率变换而变化,要在FixedUpdate中使用。

通常来说fixedDeltatime固定是0.02s,在主菜单的Edit→Project Settings→Time可以修改。

之前我们用的帧率相关的增量时间,但是现在开始已经涉及到了物理模拟了,物理更新对时间是非常敏感的,稍微差一点都不行。如果用在按帧率更新,可能由于主机差异帧率不稳定,0.5秒子弹到达敌人,帧率不稳定可能会变成0.8s。

http://www.lryc.cn/news/468257.html

相关文章:

  • C#基础知识-枚举
  • 系统架构设计师教程 第2章 2.1-2计算机系统及硬件 笔记
  • 通过使用Visual Studio将你的程序一键发布到Docker
  • vue2和vue3动态引入路由,权限控制
  • Spring Boot:植物健康的智能守护者
  • 红黑树 学习笔记
  • linux更改系统时间
  • B站C#刘铁猛笔记
  • 如何使用信号发生器产生正弦波并用数字示波器进行测量
  • XJ04、消费金融|授信基本概念及其流程设计
  • 儿童预防接种预约微信小程序springboot+论文源码调试讲解
  • nginx 修改配置
  • 孤岛架构在安全性方面
  • COSCon'24 志愿者招募令:共创开源新生活!
  • vscode使用make编译c的问题
  • 管家婆财贸ERP BB019.操作员制单日期控制
  • 从 Vue 2 到 Vue 3:全面升级指南
  • Apache paimon表操作实战-5
  • 阿里云用STS上传oss的完整程序执行流程图 和前端需要哪些参数uniapp
  • 决策树方法根据指定条件筛选方案
  • 多特征变量序列预测(四) Transformer-BiLSTM风速预测模型
  • 【开源免费】基于SpringBoot+Vue.JS蜗牛兼职平台 (JAVA毕业设计)
  • Ajax笔记
  • 软考:缓存分片和一致性哈希
  • 3109 体验积分值
  • 初识jsp
  • Ansible 的脚本 --- playbooks剧本
  • Windows 死机时 系统错误日志分析与故障排除
  • 基于pytorch搭建CNN
  • C#实现与Windows服务的交互与控制