IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity开发日记【第二天】——角色移动的实现 -> 正文阅读

[游戏开发]Unity开发日记【第二天】——角色移动的实现

目录

一、角色移动

二、角色转向和跳跃


一、角色移动

昨天我尝试向游戏中添加了游戏角色,现在尝试让其移动起来

首先在左上角编辑菜单中找到项目设置,在输入管理器选项卡中可以看见当前控制角色移动的按键(可以自定义或者修改),这里要记住水平移动的名称——Horizontal之后要使用

对角色元素添加组件New sricpt,然后双击代码开始编辑代码,新建的代码包括两个函数:

Start():在游戏一开始的时候执行

Update():游戏过程中逐帧更新的函数

首先我们先创建一些变量,刚体和速度(这很好理解角色的移动就是刚体在力的作用下以某个速度移动)定义方式如下:

public Rigidbody2D rb; //刚体
public float speed; //速度

在定义完刚体后,我们需要返回Unity上定义角色的速度数值和关联角色的刚体(关联方法就是将对应刚体直接拖拽过来,速度的数值可以直接在脚本中定义,也可以在Unity中直接输入)

然后我们开始编写移动函数

void Update()
{
    Move();
}

void Move()
{
    float horizontalMove  = Input.GetAxis("Horizontal"); //获得玩家横向输入
    rb.velocity = new Vector2(horizontalMove * speed, rb.velocity.y)
}

这里面我们定义了一个函数Move()用于控制玩家移动,首先定义了一个float类型的变量接受Horizontal(之前我们记忆下来的变量)这里发返回值是[-1,1]的区间当玩家向右时这个变量大于0,向左时小于0,我们通过对刚体速度的修改(函数Vector2接受两个变量分别是x方向的速度和y方向的速度)实现玩家移动。最后将Move函数添加到Update让其每帧都会运行。

然后我们保存代码后发现角色在移动的过程中会出现翻滚的情况,我们需要锁定刚体的旋转:

然后我们的角色就可以正常移动了!

二、角色转向和跳跃

在该部分我们试图实现角色根据我们的移动输入自动面向某个方向和跳跃功能的实现:

不难发现我们在改变角色缩放x的数值正负的时候可以实现角色的朝向改变,所以我们使用这种思路来实现功能。

float facedirection = Input.GetAxisRaw("Horizontal"); //玩家面向方向

在Move函数中添加一个浮点变量,这里使用了GetAxisRaw函数,它与我们之前使用的GetAxis函数不同。

GetAxisRaw:返回值只有-1,0,1三个值。

GetAxis:返回值是[-1,1]的区间。

if(facedirection != 0)
{
    transform.localScale = new Vector3(facedirection, 1, 1);
}

对transform.localScal重写(重写transform中的缩放,因为是三维的所以使用Vector3来重写)

保存后运行游戏,人物已经可以正常的转向。

我们这里是通过把Move函数写进了Update里执行,但是有的电脑配置较低,帧数比较差,为了保证我们的流畅性,我们采用另一个函数替代Update就是FixUpdate,这个函数不受帧率影响以固定时间调用。

在官网文档中也提到说: 处理Rigidbody时,需要用FixedUpdate代替Update。这样可以使得人物运动更加的平滑。

【注】:FixedUpdate只适合物体逻辑不能滥用。

解决方案二:将Move中的移动代码调整一下,加上Time.deltaTime

rb.velocity = new Vector2(horizontalMove * speed * Time.deltaTime, rb.velocity.y);

官方手册中说明:这个变量是按秒为单位,完成上一帧所用的时间,我简单理解为当你需要让某个数值按照帧数的变化一起变化时乘以它就对了。

经过反复尝试我还是选择了解决方案一,比较稳定然后对代码进行了一些修改和优化,总的代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public Rigidbody2D rb; //刚体
    public float speed; //速度

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {

    }

    private void FixedUpdate()
    {
        Move();
    }

    void Move() //控制玩家移动函数
    {
        float direction = Input.GetAxisRaw("Horizontal"); //玩家移动方向
        rb.velocity = new Vector2(direction * speed, rb.velocity.y);
        if (direction != 0)
        {
            transform.localScale = new Vector3(direction, 1, 1); //控制角色翻转
        }
    }
}

这里简单写一下我通过查找资料对这两种方案的理解:

首先是两个函数

Update():每帧被调用一次

FixedUpdate():每隔Time.fixedDeltaTime被调用一次。Time.fixedDeltaTime默认是0.02s,可以通过Edit->ProjectSettings->Time来设置

我们都知道游戏在各种因素的影响下帧率是不断变化的,所以在游戏逻辑的控制时,我们一般使用Updata()而物理相关的处理需要根据时间变化使用FixedUpdate(),在Updata中,我们希望每隔一段时间去执行一个逻辑时,就需要使用Time.deltaTime


接下来测试运行代码(调整速度)。

在运行过程中发现角色在运行过程中经常会卡住,经过资料查找我任务是因为碰撞体之间存在缝隙卡住了,所以我把BoxCollider2D矩形碰撞器变成Capsule Collider2D胶囊碰撞器

但是这样依然存在问题,经过查找资料是需要把瓦片地图合并为一个整体

勾选Tilemap Collider的复合使用后提示需要添加一个复合的Conllider 2D,按要求添加

添加后发现碰撞体变为了一个?

?但这样的操作会导致程序自动添加一个有重力的刚体会导致一开始游戏我们的瓦片地图会掉下去

这里我选择在杆体选项中冻结刚体的位置禁止其旋转,成功解决了人物卡顿和地图掉落的问题

解决方案瓦片地图掉落的方案二:

如下图所示直接把瓦片地图的类型勾选为静态

?接下来要开始实现角色的跳跃功能,为了防止角色跳跃落地时卡墙,首先我将角色刚体的碰撞检测改为持续

首先和水平方向的speed一样我们首先定义一个表示跳跃力的变量

public float jumpforce; //跳跃力

在输入管理器中将跳跃的肯定按钮设置为空格?

在Updata函数中添加如下内容,首先判断玩家是否输入了跳跃的按键,在输入后会改变角色在y方向的速度,保存并测试(调整跳跃力让其跳的更高,调节重力,让其下落速度变快更加的真实)

if (Input.GetButtonDown("Jump"))
{
    rb.velocity = new Vector2(rb.velocity.x, jumpforce);
}

此时我们的角色已经可以正常的跳跃了?。

但是在测试过程中我们发现角色可能会出现卡墙的问题(跳跃的时候和墙壁有摩擦导致停在空中)

在Assets中新建一个材质,右键后创建> 2D>?Physics Material 2D,并将其摩擦力设为0,这样就不会卡墙了。


?进一步对Update和FixedUpdate的比较:

首先Update()在某些情况下刷新率是大于FixedUpdate()的。(比如有的电脑每秒能有300帧,FixedUpdate()的50FPS根本不够响应)
所以,FixedUpdate出现问题的最主要的原因就是两种刷新率不同步造成的。

在跳跃功能的实现中分为了按键接收和游戏响应两部分,假如我们将两部分拆开分别放进Update和FixedUpdate,就可能发生不同步。
所以跳跃的按键接收和反馈都应该在同一个函数中执行,鉴于官方文档的建议按键接受部分应该在Update中执行,所以跳跃的实现整体应该在Update中执行。

接下来我们来讨论效果问题:由于跳跃是瞬发功能,属于接收敏感,执行不敏感的操作,在我们接收到按键消息之后执行一次即可,只要反馈时间在30FPS以内,体感就不会有偏差,而移动响应之所以需要放在FixedUpadate,是因为移动需要持续稳定的推力,对执行频率更敏感,而对接收频率不敏感,移动时无论遗漏了或是多录了按键消息,FixedUpdate都可以保证执行频率稳定。但是一般仅有移动需要用到FixedUpdate,滥用FixedUpdate不仅不会让物理效果展现的丝滑,而且很容易在性能不稳定的情况下出现Bug

所以跳跃执行应当由Update()执行,并依此相应修改力度,而移动可以放在FixedUpdate()中。

综上所示,我的结论是FixedUpdate()应在且仅在需要表现持续、稳定的速度/力的时候调用,其他情况应尽可能少用。?


  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 01:19:47  更:2022-09-30 01:21:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/20 21:02:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码