从零开始学习Unity学习笔记:Day04 角色水平移动逻辑

本文讲解了如何设置Unity脚本,控制角色的水平移动、方向切换以及禁用Sprite旋转。通过Input.GetAxis和刚体组件,实现了按键响应并遵循物理规则。还介绍了如何在Update和FixedUpdate方法中放置逻辑,以及防止角色旋转的设置。

在继续本节教程之前,需要设置好脚本编辑器。最简单的方法是安装Visual Studio 2019/2022,如果喜欢轻量级的VSCode(需要经过相对复杂的设置),可以参考M_Studio老师提供的教程来操作设置。

按键设置

在菜单栏中的“编辑”菜单打开“项目设置”,找到 输入管理器 这一栏,展开轴线(Axes)设置项,可以看到Unity预设的若干个输入按键,中文版翻译的有些问题,我这里解释在图中了。
可以更改这些按键,具体按键设置见 官方文档
根据官方文档:键盘上的按钮只会产生–1作为负值、1作为正值,什么都不按就为0。而某些手柄的按键/摇杆则可能产生-1~1之间的值。

为Sprite添加控制脚本

为了告诉Unity当玩家按下指定的按钮时应当执行什么操作,需要为该Sprite添加脚本。
选择好相应的Sprite后,在检查器面板中点击“添加组件”按钮-“新建脚本”,然后为脚本命名。在项目窗口中可以看到:Unity会将新建好的脚本存放在Assets文件夹中。打开脚本文件即可对其查看和编辑。
建议新建一个Scripts文件夹来专门存放脚本。 一般情况下,控制玩家所代表的的Sprite的脚本可以称为Player Controller(玩家控制器)。
如果希望将项目窗口中已有的脚本添加到Sprite中,可以直接将脚本拖拽到相应Sprite的检查器窗口中。
Unity使用 C#语言 作为脚本语言。
新建的脚本大概长这样:
    
using System . Collections ; using System . Collections . Generic ; using UnityEngine ; public class PlayerController : MonoBehaviour { // Start is called before the first frame update void Start ( ) { } // Update is called once per frame void Update ( ) { } }
本帖 不记录 与Unity特性无关的C#具体编程细节。相关教程可以参考 C# 教程 | 菜鸟教程 (runoob.com)
Unity会根据你的脚本文件名建立一个类,其中会包含两个无返回值的函数: Start() 和 Update() ,这两个函数会自动由Unity来调用。
  • Start() :在第一帧画面被渲染前调用,一般会在这里写一些初始化用的代码。
  • Update() :每一帧画面被渲染时都会调用这个函数,这也是编写玩家操作逻辑的地方。

编写水平移动逻辑

为了Sprite的动作符合物理规则而显得更加真实,我们不应该直接操作Sprite的Transform组件下的坐标,而应该利用Sprite中的刚体组件来告诉物理引擎我们的移动速度,再由物理引擎来自动计算出Sprite的坐标。
为了操作刚体组件,我们需要先在类中定义一个公开的 RigidBody2D 成员(这个类型在 UnityEngine 命名空间定义)。此外,为了方便我们在Unity中直接控制Sprite的移动速度,我们可以再定义一个公开的 speed 成员。
    
public Rigidbody2D rigidBody ; public float speed ;
保存好脚本后,就可以在Unity的检查器窗口看到这两个成员的接口,我们可以在Unity指定接口挂载到上面地方,这里我们将检查器窗口上的Rigidbody 2D组件拖动到 Rigid Body 这一栏,并在 Speed (中文版会自动翻译成速度)这一栏填上一个速度值,比如16。这样,这两个成员将由Unity完成初始化,不需要我们写初始化代码。
在脚本中,我们可以使用 Input.GetAxis("Horizontal") 来获得之前指定按键的情况,键盘按键的情况下,会返回:
  • -1(A键或者方向键←)
  • 1(D键或者方向键→)
  • 0(什么都没按)
根据 官方文档 :该方法实际上会自动进行 平滑处理 ,也就是说,按下按键后该方法并不会立即返回对应的值,而是随时间缓慢增加到该值。例如,如果某个时刻该方法返回0,突然按住A键不放,该值每次调用会以-0.05的增速返回值,直到返回了-1,然后就一直返回-1。 如果不希望值被平滑(按下A键立即返回-1),则应当使用 Input.GetAxisRaw("Horizontal") 。
根据按键的状态,我们可以设置刚体成员 rigidBody 的 velocity 属性,这个属性在2D游戏中应当是 Vector2 类型,两个分量分别表示水平和垂直方向的速度分量。这里只需要根据输入与给定的速度值,改变水平速度就行,垂直速度则保持原来的值:
    
float horizontal_move = Input . GetAxis ( "Horizontal" ) ; // 输入管理器中出现的那个“名称” rigidBody . velocity = new Vector2 ( horizontal_move * speed , rigidBody . velocity . y ) ;
这些代码本应当在 Update() 中执行,但是考虑到今后 Update() 可能会执行非常多的逻辑,直接写在这里面会让 Update() 非常长,所以这里另行创建了一个函数 Move() 来处理移动操作的逻辑。

物理模拟逻辑应当放在固定帧率方法中

这一节本来是下个视频的内容,这里出于代码的合理性挪到这里记录。
之前放在 Update() 方法中的 Move() 方法操作了处理物理交互逻辑的刚体组件,但这会导致一个问题: Update() 方法实际上 依赖于渲染帧率 。如果因为某些原因,机器渲染的速率随时间变化起伏很大,而 Update() 中调用物理交互操作也就 必须等待渲染 ,从而只能随着渲染速率的变化进行模拟(比如说希望人物每帧行走1单位,但是1帧渲染的时间有时候是0.02s,又是是0.5s,那么人物走一单位的时间也会变成一会儿是0.02s,一会儿是0.5s),这就不符合物理规则,会给人卡顿的感觉。
一般来说,我们希望处理物理交互的逻辑以恒定的频率被执行。Unity提供了这样的方法: FixedUpdate() 。它和 Update() 一样会被Unity自动调用,但它的调用频率则和渲染速率无关。
因此,我们将 Move() 方法改换到 FixedUpdate() 中执行。
完整的脚本代码如下:
    
using System . Collections ; using System . Collections . Generic ; using UnityEngine ; public class PlayerController : MonoBehaviour { public Rigidbody2D rigidBody ; public float speed ; // Start is called before the first frame update void Start ( ) { } // Update is called once per frame void Update ( ) { } void FixedUpdate ( ) { Move ( ) ; } void Move ( ) { float horizontal_move = Input . GetAxis ( "Horizontal" ) ; rigidBody . velocity = new Vector2 ( horizontal_move * speed , rigidBody . velocity . y ) ; } }

禁止Sprite的旋转

通常情况下,我们希望Sprite保持直立行走(而不是走着走着碰到倾斜的障碍物就转起来了),可以在检查器窗口-刚体组件- Constraints (约束)设置项中把 冻结旋转 (Freeze Rotation)打上勾(2D游戏的旋转只有绕Z轴旋转,所以只有一个Z轴的选项)。

保存试玩中修改的参数

在Unity编辑器中试玩时修改检视器窗口中任何参数的值,在停止试玩后 不会被保存下来 。这里提供一个简单的技巧来在试玩结束后快速修改参数到试玩时设置的值:
1.在试玩时在修改属性的组件标题栏右键(或点最右边的三个点按钮)选择 复制组件 (Copy Component)。
2.在停止试玩时,在该组件标题栏右键(或点最右边的三个点按钮)选择 粘贴组件值 (Paste Component Values)。

随按键修改角色朝向

所谓角色的朝向,其实是Sprite的水平翻转与否。水平翻转最直观的实现方法是:将Sprite中Transform组件的Scale属性的X值从1修改为-1。在脚本中,Scale属性可以通过 transform.localScale 来修改。
由于 GetAxis 方法存在自动平滑的特性,我们不希望有平滑处理,故这里使用 GetAxisRaw 来检测按键。
【注意】由于Scale属性的X值如果被设置为0值,那么Sprite会变成一条线从而看起来被隐藏了。因此,我们的角色朝向处理的逻辑应当只处理 GetAxisRaw("Horizontal") 返回-1或1的情况,0的情况不处理。
    
float face_direction = Input . GetAxisRaw ( "Horizontal" ) ; if ( face_direction != 0 ) { transform . localScale = new Vector3 ( face_direction , transform . localScale . y , transform . localScale . z ) ; }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值