大家好,我是阿赵。
作为一个游戏引擎,监听用户输入是比较常用的功能,这次学习一下怎样在UE引擎监听用户的输入。
一、 通过输入设置指定
这个是通过在输入设置里面指定某些操作,并映射对应的输入指令。这方面Unity引擎也是有类似的功能。UE其实比Unity更先进,除了按钮输入和轴输入的映射,还有语音输入的映射。不过语音映射我暂时没用过,这次先来看看操作映射和轴映射。
在编辑——>项目设置里面,找到输入的页签
然后在输入的页签里面,就可以看到操作映射和轴映射的选项了:
1、 绑定操作映射
1.设置面板的操作:
简单来说,就是通过按某个按键,触发某个行为
点击操作映射旁边的加号,可以创建一个新的操作映射,然后需要指定
(1) action名称
这个action名称很重要,之后会通过这个action名称作为事件名称,来触发输入。
(2) 输入的按键
输入什么按钮可以触发这个action事件。可以通过右边的组合键勾选,来组合输入。
如果一个action不止一种输入方式,可以点击action名称旁边的加号,添加多几个输入的按钮
比如我这里,设置了一个叫做OnFire的按钮,可以通过键盘的F键或者R键来触发。
2. 触发事件的方式:
(1) 蓝图触发
在蓝图里面直接搜索刚才OnFire的action名称,就能看到这个OnFire的事件节点
节点里面可以有2个触发条件,分别是按下和松开按钮:
(2) C++触发
绑定输入事件:
可以在begin方法里面进行绑定
auto controller = this->GetWorld()->GetFirstPlayerController();
UInputComponent* comp = controller->InputComponent;
comp->BindAction("OnFire", IE_Pressed, this, &ALevel1GameModeBase::OnFireAction);
然后回调方法:
int fireCount = 0;
void ALevel1GameModeBase::OnFireAction()
{
fireCount++;
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::White,FString::Printf( TEXT("OnFire%d"),fireCount));
}
按钮状态可选枚举比蓝图的要多,有以下这些:
enum EInputEvent : int
{
IE_Pressed =0,
IE_Released =1,
IE_Repeat =2,
IE_DoubleClick =3,
IE_Axis =4,
IE_MAX =5,
};
2、 绑定轴映射
1.设置操作
简单来说,就是类似于方向键的XY轴输入,触发某个行为。
同样回到项目设置的输入页签,点击轴映射旁边的加号,添加轴映射事件。
由于细节操作和上面的操作映射差不多的,所以我就不再啰嗦。这里我新增了一个叫做OnMoveX的轴映射事件,然后键盘A键会触发这个轴到-1,D键会触发这个轴到1,模拟一般FPS游戏的左右行走的输入。然后再添加了一个鼠标X的输入,这个就不需要指定-1了,因为鼠标X移动本身就是有正负的。
2.触发事件
(1) 蓝图触发
同样搜索刚才指定的OnMoveX的action名称,就可以看到对应的事件节点了。
这个节点和刚才的操作输入的节点不一样,它没有多种状态输出,而是一直输出的。意思是,不论我们是否输入了按键,这个轴映射都会不停的触发,只是在没有输入之前,它的value回返回0。
(2) C++ 触发
和上面的操作映射一样,轴映射同样需要绑定
auto controller = this->GetWorld()->GetFirstPlayerController();
UInputComponent* comp = controller->InputComponent;
comp->BindAxis("OnMoveX", this, &ALevel1GameModeBase::OnMoveX);
但需要注意的是,轴映射的回调方法是有参数的,参数和上面蓝图节点是一样的,是一个Axis Value,就是这个轴当前输入的值。和蓝图一样,这个回调不论是否输入,都会回调的,只是没有输入的时候,回调值是0.
void ALevel1GameModeBase::OnMoveX(float val)
{
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::White, FString::Printf(TEXT("OnMoveX:%f"), val));
}
值得注意的是,这种绑定了操作映射或者轴映射的操作,是存在唯一性的,比如在C++里面绑定了新的回调方法,那么本身在蓝图上的InpuAction,就不会再收到绑定的操作了。结果就是按下按键时,C++这边会收到输入事件,但蓝图那边不会响应。
二、 监听固定按钮
如果不想在项目设置的输入里面指定action也能得到输入监听,也是有办法的。
1、 蓝图
1. 使用PlayerController节点
在使用GetPlayerController得到控制器之后,可以用Is Input Key Down之类的节点,来判断是否按下某个键。需要注意的是,这个不是一个流程方法,所以要找带有空心三角形的节点来连接流程来触发。
2. key节点
通过Key节点,可以监听输入某个按钮。可以搜索keyboard events,或者直接输入某个键盘的键:
触发事件有按下和弹起两个状态
也可以使用Debug Key,不过这个方法是仅限开发使用的,也就是说只能用于调试,不能用于正式环境。
2、C++
1.使用PlayerController
类似于Unity在Update里面判断按键输入的操作,在Tick里面,先获取PlayerController,然后再通过IsInputKeyDown方法,判断是否输入了某个key
void ALevel1GameModeBase::Tick(float deltaTime)
{
if(this->GetWorld()->GetFirstPlayerController()->IsInputKeyDown(EKeys::J))
{
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::White, TEXT("input:J"));
}
}
IsInputKeyDown是监听按钮按下,但会有重复触发的问题,也可以换成WasInputKeyJustReleased,检查按钮弹起时触发一次
if(this->GetWorld()->GetFirstPlayerController()->WasInputKeyJustReleased(EKeys::J))
{
}
2.使用iostream
同样是在Tick里面判断按钮,但这个是C++原生的调用io的方法。估计跨平台不一定能用,但可以当做是蓝图里面的debug key方法来用吧,其实也没太大必要,用PlayerController就可以了。
#include<iostream>
#include<windows.h>
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
void ALevel1GameModeBase::Tick(float deltaTime)
{
if (KEY_DOWN('Z'))
{
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::White, TEXT("input:Z"));
}
}